diff options
111 files changed, 8060 insertions, 2475 deletions
@@ -105,6 +105,9 @@ endif ASTCFLAGS+=$(COPTS) ASTLDFLAGS+=$(LDOPTS) +# libxml2 cflags +ASTCFLAGS+=$(LIBXML2_INCLUDE) + #Uncomment this to see all build commands instead of 'quiet' output #NOISY_BUILD=yes @@ -481,6 +484,20 @@ datafiles: _all mkdir -p $(DESTDIR)$(AGI_DIR) $(MAKE) -C sounds install +documentation: + @echo -n "Building Documentation For: " + @echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" > doc/core-en_US.xml + @echo "<!DOCTYPE docs SYSTEM \"appdocsxml.dtd\">" >> doc/core-en_US.xml + @echo "<docs>" >> doc/core-en_US.xml + @for x in $(MOD_SUBDIRS); do \ + echo -n "$$x " ; \ + for i in $$x/*.c; do \ + $(AWK) -f build_tools/get_documentation $$i >> doc/core-en_US.xml ; \ + done ; \ + done + @echo "</docs>" >> doc/core-en_US.xml + @echo -e "\ndoc/core-en_US.xml --> $(ASTDATADIR)/documentation/core-en_US.xml" + update: @if [ -d .svn ]; then \ echo "Updating from Subversion..." ; \ @@ -529,12 +546,16 @@ bininstall: _all installdirs $(SUBDIRS_INSTALL) if [ -n "$(OLDHEADERS)" ]; then \ rm -f $(addprefix $(DESTDIR)$(ASTHEADERDIR)/,$(OLDHEADERS)) ;\ fi + mkdir -p $(DESTDIR)$(ASTDATADIR)/documentation + mkdir -p $(DESTDIR)$(ASTDATADIR)/documentation/thirdparty mkdir -p $(DESTDIR)$(ASTLOGDIR)/cdr-csv mkdir -p $(DESTDIR)$(ASTLOGDIR)/cdr-custom mkdir -p $(DESTDIR)$(ASTDATADIR)/keys mkdir -p $(DESTDIR)$(ASTDATADIR)/firmware mkdir -p $(DESTDIR)$(ASTDATADIR)/firmware/iax mkdir -p $(DESTDIR)$(ASTMANDIR)/man8 + $(INSTALL) -m 644 doc/core-*.xml $(ASTDATADIR)/documentation + $(INSTALL) -m 644 doc/appdocsxml.dtd $(ASTVARLIBDIR)/documentation $(INSTALL) -m 644 keys/iaxtel.pub $(DESTDIR)$(ASTDATADIR)/keys $(INSTALL) -m 644 keys/freeworlddialup.pub $(DESTDIR)$(ASTDATADIR)/keys $(INSTALL) -m 644 doc/asterisk.8 $(DESTDIR)$(ASTMANDIR)/man8 @@ -576,7 +597,7 @@ ifneq ($(findstring ~,$(DESTDIR)),) @exit 1 endif -install: badshell datafiles bininstall +install: badshell datafiles documentation bininstall @if [ -x /usr/sbin/asterisk-post-install ]; then \ /usr/sbin/asterisk-post-install $(DESTDIR) . ; \ fi @@ -656,7 +677,7 @@ samples: adsi echo "astrundir => $(ASTVARRUNDIR)" ; \ echo "astlogdir => $(ASTLOGDIR)" ; \ echo "" ; \ - echo ";[options]" ; \ + echo "[options]" ; \ echo ";verbose = 3" ; \ echo ";debug = 3" ; \ echo ";alwaysfork = yes ; same as -F at startup" ; \ @@ -686,6 +707,7 @@ samples: adsi echo ";runuser = asterisk ; The user to run as" ; \ echo ";rungroup = asterisk ; The group to run as" ; \ echo ";lightbackground = yes ; If your terminal is set for a light-colored background" ; \ + echo "documentation_language = en_US ; Set the Language you want Documentation displayed in. Value is in the same format as locale names" ; \ echo "" ; \ echo "; Changing the following lines may compromise your security." ; \ echo ";[files]" ; \ diff --git a/apps/app_adsiprog.c b/apps/app_adsiprog.c index 255026fbd..f35a81eea 100644 --- a/apps/app_adsiprog.c +++ b/apps/app_adsiprog.c @@ -47,14 +47,24 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") static char *app = "ADSIProg"; -static char *synopsis = "Load Asterisk ADSI Scripts into phone"; +/*** DOCUMENTATION + <application name="ADSIProg" language="en_US"> + <synopsis> + Load Asterisk ADSI Scripts into phone + </synopsis> + <syntax> + <parameter name="script" required="false"> + <para>adsi script to use. If not given uses the default script <filename>asterisk.adsi</filename></para> + </parameter> + </syntax> + <description> + <para>This application programs an ADSI Phone with the given script</para> + </description> + </application> + ***/ /* #define DUMP_MESSAGES */ -static char *descrip = -" ADSIProg(script): This application programs an ADSI Phone with the given\n" -"script. If nothing is specified, the default script (asterisk.adsi) is used.\n"; - struct adsi_event { int id; char *name; @@ -1570,7 +1580,7 @@ static int unload_module(void) static int load_module(void) { - if (ast_register_application(app, adsi_exec, synopsis, descrip)) + if (ast_register_application_xml(app, adsi_exec)) return AST_MODULE_LOAD_FAILURE; return AST_MODULE_LOAD_SUCCESS; } diff --git a/apps/app_alarmreceiver.c b/apps/app_alarmreceiver.c index db76bbdb7..12ae49d65 100644 --- a/apps/app_alarmreceiver.c +++ b/apps/app_alarmreceiver.c @@ -63,18 +63,21 @@ struct event_node{ typedef struct event_node event_node_t; static char *app = "AlarmReceiver"; - -static char *synopsis = "Provide support for receiving alarm reports from a burglar or fire alarm panel"; -static char *descrip = -" AlarmReceiver(): Only 1 signalling format is supported at this time: Ademco\n" -"Contact ID. This application should be called whenever there is an alarm\n" -"panel calling in to dump its events. The application will handshake with the\n" -"alarm panel, and receive events, validate them, handshake them, and store them\n" -"until the panel hangs up. Once the panel hangs up, the application will run the\n" -"system command specified by the eventcmd setting in alarmreceiver.conf and pipe\n" -"the events to the standard input of the application. The configuration file also\n" -"contains settings for DTMF timing, and for the loudness of the acknowledgement\n" -"tones.\n"; +/*** DOCUMENTATION + <application name="AlarmReceiver" language="en_US"> + <synopsis> + Provide support for receiving alarm reports from a burglar or fire alarm panel + </synopsis> + <syntax /> + <description> + <para>This application should be called whenever there is an alarm panel calling in to dump its events. + The application will handshake with the alarm panel, and receive events, validate them, handshake them, and store them until the panel hangs up. + Once the panel hangs up, the application will run the system command specified by the eventcmd setting in <filename>alarmreceiver.conf</filename> and pipe the events to the standard input of the application. + The configuration file also contains settings for DTMF timing, and for the loudness of the acknowledgement tones.</para> + <note><para>Only 1 signalling format is supported at this time: Ademco Contact ID.</para></note> + </description> + </application> + ***/ /* Config Variables */ static int fdtimeout = 2000; @@ -711,7 +714,7 @@ static int unload_module(void) static int load_module(void) { if (load_config()) { - if (ast_register_application(app, alarmreceiver_exec, synopsis, descrip)) + if (ast_register_application_xml(app, alarmreceiver_exec)) return AST_MODULE_LOAD_FAILURE; return AST_MODULE_LOAD_SUCCESS; } else diff --git a/apps/app_amd.c b/apps/app_amd.c index 81298f400..bf3603b3e 100644 --- a/apps/app_amd.c +++ b/apps/app_amd.c @@ -39,45 +39,88 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/config.h" #include "asterisk/app.h" +/*** DOCUMENTATION + <application name="AMD" language="en_US"> + <synopsis> + Attempt to detect answering machines. + </synopsis> + <syntax> + <parameter name="initialSilence" required="false"> + <para>Is maximum initial silence duration before greeting.</para> + <para>If this is exceeded set as MACHINE</para> + </parameter> + <parameter name="greeting" required="false"> + <para>is the maximum length of a greeting.</para> + <para>If this is exceeded set as MACHINE</para> + </parameter> + <parameter name="afterGreetingSilence" required="false"> + <para>Is the silence after detecting a greeting.</para> + <para>If this is exceeded set as HUMAN</para> + </parameter> + <parameter name="totalAnalysis Time" required="false"> + <para>Is the maximum time allowed for the algorithm</para> + <para>to decide HUMAN or MACHINE</para> + </parameter> + <parameter name="miniumWordLength" required="false"> + <para>Is the minimum duration of Voice considered to be a word</para> + </parameter> + <parameter name="betweenWordSilence" required="false"> + <para>Is the minimum duration of silence after a word to + consider the audio that follows to be a new word</para> + </parameter> + <parameter name="maximumNumberOfWords" required="false"> + <para>Is the maximum number of words in a greeting</para> + <para>If this is exceeded set as MACHINE</para> + </parameter> + <parameter name="silenceThreshold" required="false"> + <para>How long do we consider silence</para> + </parameter> + <parameter name="maximumWordLength" required="false"> + <para>Is the maximum duration of a word to accept.</para> + <para>If exceeded set as MACHINE</para> + </parameter> + </syntax> + <description> + <para>This application attempts to detect answering machines at the beginning + of outbound calls. Simply call this application after the call + has been answered (outbound only, of course).</para> + <para>When loaded, AMD reads amd.conf and uses the parameters specified as + default values. Those default values get overwritten when the calling AMD + with parameters.</para> + <para>This application sets the following channel variables:</para> + <variablelist> + <variable name="AMDSTATUS"> + <para>This is the status of the answering machine detection</para> + <value name="MACHINE" /> + <value name="HUMAN" /> + <value name="NOTSURE" /> + <value name="HANGUP" /> + </variable> + <variable name="AMDCAUSE"> + <para>Indicates the cause that led to the conclusion</para> + <value name="TOOLONG"> + Total Time. + </value> + <value name="INITIALSILENCE"> + Silence Duration - Initial Silence. + </value> + <value name="HUMAN"> + Silence Duration - afterGreetingSilence. + </value> + <value name="LONGGREETING"> + Voice Duration - Greeting. + </value> + <value name="MAXWORDLENGTH"> + Word Count - maximum number of words. + </value> + </variable> + </variablelist> + </description> + </application> + + ***/ static char *app = "AMD"; -static char *synopsis = "Attempts to detect answering machines"; -static char *descrip = -" AMD([initialSilence],[greeting],[afterGreetingSilence],[totalAnalysisTime]\n" -" ,[minimumWordLength],[betweenWordsSilence],[maximumNumberOfWords]\n" -" ,[silenceThreshold],[|maximumWordLength])\n" -" This application attempts to detect answering machines at the beginning\n" -" of outbound calls. Simply call this application after the call\n" -" has been answered (outbound only, of course).\n" -" When loaded, AMD reads amd.conf and uses the parameters specified as\n" -" default values. Those default values get overwritten when calling AMD\n" -" with parameters.\n" -"- 'initialSilence' is the maximum silence duration before the greeting. If\n" -" exceeded then MACHINE.\n" -"- 'greeting' is the maximum length of a greeting. If exceeded then MACHINE.\n" -"- 'afterGreetingSilence' is the silence after detecting a greeting.\n" -" If exceeded then HUMAN.\n" -"- 'totalAnalysisTime' is the maximum time allowed for the algorithm to decide\n" -" on a HUMAN or MACHINE.\n" -"- 'minimumWordLength'is the minimum duration of Voice to considered as a word.\n" -"- 'betweenWordsSilence' is the minimum duration of silence after a word to \n" -" consider the audio that follows as a new word.\n" -"- 'maximumNumberOfWords'is the maximum number of words in the greeting. \n" -" If exceeded then MACHINE.\n" -"- 'silenceThreshold' is the silence threshold.\n" -"- 'maximumWordLength' is the maximum duration of a word to accept. If exceeded then MACHINE\n" -"This application sets the following channel variables upon completion:\n" -" AMDSTATUS - This is the status of the answering machine detection.\n" -" Possible values are:\n" -" MACHINE | HUMAN | NOTSURE | HANGUP\n" -" AMDCAUSE - Indicates the cause that led to the conclusion.\n" -" Possible values are:\n" -" TOOLONG-<%d total_time>\n" -" INITIALSILENCE-<%d silenceDuration>-<%d initialSilence>\n" -" HUMAN-<%d silenceDuration>-<%d afterGreetingSilence>\n" -" MAXWORDS-<%d wordsCount>-<%d maximumNumberOfWords>\n" -" LONGGREETING-<%d voiceDuration>-<%d greeting>\n" -" MAXWORDLENGTH-<%d consecutiveVoiceDuration>\n"; #define STATE_IN_WORD 1 #define STATE_IN_SILENCE 2 @@ -437,7 +480,7 @@ static int load_module(void) { if (load_config(0)) return AST_MODULE_LOAD_DECLINE; - if (ast_register_application(app, amd_exec, synopsis, descrip)) + if (ast_register_application_xml(app, amd_exec)) return AST_MODULE_LOAD_FAILURE; return AST_MODULE_LOAD_SUCCESS; } diff --git a/apps/app_authenticate.c b/apps/app_authenticate.c index 1bdc1153b..10d0b2f73 100644 --- a/apps/app_authenticate.c +++ b/apps/app_authenticate.c @@ -54,31 +54,52 @@ AST_APP_OPTIONS(auth_app_options, { static char *app = "Authenticate"; - -static char *synopsis = "Authenticate a user"; - -static char *descrip = -" Authenticate(password[,options[,maxdigits[,prompt]]]): This application asks the caller\n" -"to enter a given password in order to continue dialplan execution. If the password\n" -"begins with the '/' character, it is interpreted as a file which contains a list of\n" -"valid passwords, listed 1 password per line in the file.\n" -" When using a database key, the value associated with the key can be anything.\n" -"Users have three attempts to authenticate before the channel is hung up.\n" -" Options:\n" -" a - Set the channels' account code to the password that is entered\n" -" d - Interpret the given path as database key, not a literal file\n" -" m - Interpret the given path as a file which contains a list of account\n" -" codes and password hashes delimited with ':', listed one per line in\n" -" the file. When one of the passwords is matched, the channel will have\n" -" its account code set to the corresponding account code in the file.\n" -" r - Remove the database key upon successful entry (valid with 'd' only)\n" -" maxdigits - maximum acceptable number of digits. Stops reading after\n" -" maxdigits have been entered (without requiring the user to\n" -" press the '#' key).\n" -" Defaults to 0 - no limit - wait for the user press the '#' key.\n" -" prompt - Override the agent-pass prompt file.\n" - ; -; +/*** DOCUMENTATION + <application name="Authenticate" language="en_US"> + <synopsis> + Authenticate a user + </synopsis> + <syntax> + <parameter name="password" required="true"> + <para>Password the user should know</para> + </parameter> + <parameter name="options" required="false"> + <optionlist> + <option name="a"> + <para>Set the channels' account code to the password that is entered</para> + </option> + <option name="d"> + <para>Interpret the given path as database key, not a literal file</para> + </option> + <option name="m"> + <para>Interpret the given path as a file which contains a list of account + codes and password hashes delimited with <literal>:</literal>, listed one per line in + the file. When one of the passwords is matched, the channel will have + its account code set to the corresponding account code in the file.</para> + </option> + <option name="r"> + <para>Remove the database key upon successful entry (valid with <literal>d</literal> only)</para> + </option> + </optionlist> + </parameter> + <parameter name="maxdigits" required="false"> + <para>maximum acceptable number of digits. Stops reading after + maxdigits have been entered (without requiring the user to press the <literal>#</literal> key). + Defaults to 0 - no limit - wait for the user press the <literal>#</literal> key.</para> + </parameter> + <parameter name="prompt" required="false"> + <para>Override the agent-pass prompt file.</para> + </parameter> + </syntax> + <description> + <para>This application asks the caller to enter a given password in order to continue dialplan execution.</para> + <para>If the password begins with the <literal>/</literal> character, + it is interpreted as a file which contains a list of valid passwords, listed 1 password per line in the file.</para> + <para>When using a database key, the value associated with the key can be anything.</para> + <para>Users have three attempts to authenticate before the channel is hung up.</para> + </description> + </application> + ***/ static int auth_exec(struct ast_channel *chan, void *data) { @@ -225,7 +246,7 @@ static int unload_module(void) static int load_module(void) { - if (ast_register_application(app, auth_exec, synopsis, descrip)) + if (ast_register_application_xml(app, auth_exec)) return AST_MODULE_LOAD_FAILURE; return AST_MODULE_LOAD_SUCCESS; } diff --git a/apps/app_cdr.c b/apps/app_cdr.c index 038b0a32f..ca228da03 100644 --- a/apps/app_cdr.c +++ b/apps/app_cdr.c @@ -32,13 +32,19 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/channel.h" #include "asterisk/module.h" -static char *nocdr_descrip = -" NoCDR(): This application will tell Asterisk not to maintain a CDR for the\n" -"current call.\n"; +/*** DOCUMENTATION + <application name="NoCDR" language="en_US"> + <synopsis> + Tell Asterisk to not maintain a CDR for the current call + </synopsis> + <syntax /> + <description> + <para>This application will tell Asterisk not to maintain a CDR for the current call.</para> + </description> + </application> + ***/ static char *nocdr_app = "NoCDR"; -static char *nocdr_synopsis = "Tell Asterisk to not maintain a CDR for the current call"; - static int nocdr_exec(struct ast_channel *chan, void *data) { @@ -55,7 +61,7 @@ static int unload_module(void) static int load_module(void) { - if (ast_register_application(nocdr_app, nocdr_exec, nocdr_synopsis, nocdr_descrip)) + if (ast_register_application_xml(nocdr_app, nocdr_exec)) return AST_MODULE_LOAD_FAILURE; return AST_MODULE_LOAD_SUCCESS; } diff --git a/apps/app_chanisavail.c b/apps/app_chanisavail.c index 68cab31aa..bc1adcc79 100644 --- a/apps/app_chanisavail.c +++ b/apps/app_chanisavail.c @@ -43,22 +43,54 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") static char *app = "ChanIsAvail"; -static char *synopsis = "Check channel availability"; - -static char *descrip = -" ChanIsAvail(Technology/resource[&Technology2/resource2...][,options]): \n" -"This application will check to see if any of the specified channels are\n" -"available.\n" -" Options:\n" -" a - Check for all available channels, not only the first one.\n" -" s - Consider the channel unavailable if the channel is in use at all.\n" -" t - Simply checks if specified channels exist in the channel list\n" -" (implies option s).\n" -"This application sets the following channel variable upon completion:\n" -" AVAILCHAN - the name of the available channel, if one exists\n" -" AVAILORIGCHAN - the canonical channel name that was used to create the channel\n" -" AVAILSTATUS - the status code for the available channel\n"; - +/*** DOCUMENTATION + <application name="ChanIsAvail" language="en_US"> + <synopsis> + Check channel availability + </synopsis> + <syntax> + <parameter name="Technology/Resource" required="true" argsep="&"> + <argument name="Technology2/Resource2" multiple="true"> + <para>Optional extra devices to check</para> + <para>If you need more then one enter them as + Technology2/Resource2&Technology3/Resourse3&.....</para> + </argument> + <para>Specification of the device(s) to check. These must be in the format of + <literal>Technology/Resource</literal>, where <replaceable>Technology</replaceable> + represents a particular channel driver, and <replaceable>Resource</replaceable> + represents a resource available to that particular channel driver.</para> + </parameter> + <parameter name="options" required="false"> + <optionlist> + <option name="a"> + <para>Check for all available channels, not only the first one</para> + </option> + <option name="s"> + <para>Consider the channel unavailable if the channel is in use at all</para> + </option> + <option name="t" implies="s"> + <para>Simply checks if specified channels exist in the channel list</para> + </option> + </optionlist> + </parameter> + </syntax> + <description> + <para>This application will check to see if any of the specified channels are available.</para> + <para>This application sets the following channel variables:</para> + <variablelist> + <variable name="AVAILCHAN"> + <para>The name of the available channel, if one exists</para> + </variable> + <variable name="AVAILORIGCHAN"> + <para>The canonical channel name that was used to create the channel</para> + </variable> + <variable name="AVAILSTATUS"> + <para>The status code for the available channel</para> + </variable> + </variablelist> + </description> + </application> + ***/ static int chanavail_exec(struct ast_channel *chan, void *data) { @@ -165,7 +197,7 @@ static int unload_module(void) static int load_module(void) { - return ast_register_application(app, chanavail_exec, synopsis, descrip) ? + return ast_register_application_xml(app, chanavail_exec) ? AST_MODULE_LOAD_DECLINE : AST_MODULE_LOAD_SUCCESS; } diff --git a/apps/app_channelredirect.c b/apps/app_channelredirect.c index 610f254df..f89c45225 100644 --- a/apps/app_channelredirect.c +++ b/apps/app_channelredirect.c @@ -35,14 +35,32 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/app.h" #include "asterisk/features.h" +/*** DOCUMENTATION + <application name="ChannelRedirect" language="en_US"> + <synopsis> + Redirects given channel to a dialplan target + </synopsis> + <syntax> + <parameter name="channel" required="true" /> + <parameter name="context" required="false" /> + <parameter name="extension" required="false" /> + <parameter name="priority" required="true" /> + </syntax> + <description> + <para>Sends the specified channel to the specified extension priority</para> + + <para>This application sets the following channel variables upon completion</para> + <variablelist> + <variable name="CHANNELREDIRECT_STATUS"> + <value name="NOCHANNEL" /> + <value name="SUCCESS" /> + <para>Are set to the result of the redirection</para> + </variable> + </variablelist> + </description> + </application> + ***/ static char *app = "ChannelRedirect"; -static char *synopsis = "Redirects given channel to a dialplan target."; -static char *descrip = -"ChannelRedirect(channel,[[context,]extension,]priority)\n" -" Sends the specified channel to the specified extension priority\n" -"This application sets the following channel variables upon completion:\n" -" CHANNELREDIRECT_STATUS - Are set to the result of the redirection\n" -" either NOCHANNEL or SUCCESS\n"; static int asyncgoto_exec(struct ast_channel *chan, void *data) { @@ -89,7 +107,7 @@ static int unload_module(void) static int load_module(void) { - return ast_register_application(app, asyncgoto_exec, synopsis, descrip) ? + return ast_register_application_xml(app, asyncgoto_exec) ? AST_MODULE_LOAD_DECLINE : AST_MODULE_LOAD_SUCCESS; } diff --git a/apps/app_chanspy.c b/apps/app_chanspy.c index dea2017ea..92a430546 100644 --- a/apps/app_chanspy.c +++ b/apps/app_chanspy.c @@ -52,128 +52,238 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #define AST_NAME_STRLEN 256 #define NUM_SPYGROUPS 128 -static const char *tdesc = "Listen to a channel, and optionally whisper into it"; +/*** DOCUMENTATION + <application name="ChanSpy" language="en_US"> + <synopsis> + Listen to a channel, and optionally whisper into it. + </synopsis> + <syntax> + <parameter name="chanprefix" /> + <parameter name="options"> + <optionlist> + <option name="b"> + <para>Only spy on channels involved in a bridged call.</para> + </option> + <option name="B"> + <para>Instead of whispering on a single channel barge in on both + channels involved in the call.</para> + </option> + <option name="d"> + <para>Override the typical numeric DTMF functionality and instead + use DTMF to switch between spy modes.</para> + <enumlist> + <enum name="4"> + <para>spy mode</para> + </enum> + <enum name="5"> + <para>whisper mode</para> + </enum> + <enum name="6"> + <para>barge mode</para> + </enum> + </enumlist> + </option> + <option name="g"> + <argument name="grp" required="true"> + <para>Only spy on channels in which one or more of the groups + listed in <replaceable>grp</replaceable> matches one or more groups from the + <variable>SPYGROUP</variable> variable set on the channel to be spied upon.</para> + </argument> + <note><para>both <replaceable>grp</replaceable> and <variable>SPYGROUP</variable> can contain + either a single group or a colon-delimited list of groups, such + as <literal>sales:support:accounting</literal>.</para></note> + </option> + <option name="n" argsep="@"> + <para>Say the name of the person being spied on if that person has recorded + his/her name. If a context is specified, then that voicemail context will + be searched when retrieving the name, otherwise the <literal>default</literal> context + be used when searching for the name (i.e. if SIP/1000 is the channel being + spied on and no mailbox is specified, then <literal>1000</literal> will be used when searching + for the name).</para> + <argument name="mailbox" /> + <argument name="context" /> + </option> + <option name="q"> + <para>Don't play a beep when beginning to spy on a channel, or speak the + selected channel name.</para> + </option> + <option name="r"> + <para>Record the session to the monitor spool directory. An optional base for the filename + may be specified. The default is <literal>chanspy</literal>.</para> + <argument name="basename" /> + </option> + <option name="s"> + <para>Skip the playback of the channel type (i.e. SIP, IAX, etc) when + speaking the selected channel name.</para> + </option> + <option name="v"> + <argument name="value" /> + <para>Adjust the initial volume in the range from <literal>-4</literal> + to <literal>4</literal>. A negative value refers to a quieter setting.</para> + </option> + <option name="w"> + <para>Enable <literal>whisper</literal> mode, so the spying channel can talk to + the spied-on channel.</para> + </option> + <option name="W"> + <para>Enable <literal>private whisper</literal> mode, so the spying channel can + talk to the spied-on channel but cannot listen to that channel.</para> + </option> + <option name="o"> + <para>Only listen to audio coming from this channel.</para> + </option> + <option name="X"> + <para>Allow the user to exit ChanSpy to a valid single digit + numeric extension in the current context or the context + specified by the <variable>SPY_EXIT_CONTEXT</variable> channel variable. The + name of the last channel that was spied on will be stored + in the <variable>SPY_CHANNEL</variable> variable.</para> + </option> + <option name="e"> + <argument name="ext" required="true" /> + <para>Enable <emphasis>enforced</emphasis> mode, so the spying channel can + only monitor extensions whose name is in the <replaceable>ext</replaceable> : delimited + list.</para> + </option> + </optionlist> + </parameter> + </syntax> + <description> + <para>This application is used to listen to the audio from an Asterisk channel. This includes the audio + coming in and "out of the channel being spied on. If the <literal>chanprefix</literal> parameter is specified, + only channels beginning with this string will be spied upon.</para> + <para>While spying, the following actions may be performed:</para> + <para> - Dialing <literal>#</literal> cycles the volume level.</para> + <para> - Dialing <literal>*</literal> will stop spying and look for another channel to spy on.</para> + <para> - Dialing a series of digits followed by <literal>#</literal> builds a channel name to append + to 'chanprefix'. For example, executing ChanSpy(Agent) and then dialing the digits '1234#' + while spying will begin spying on the channel 'Agent/1234'. Note that this feature will be overriden if the 'd' option + is used</para> + <note><para>The <replaceable>X</replaceable> option supersedes the three features above in that if a valid + single digit extension exists in the correct context ChanSpy will exit to it. + This also disables choosing a channel based on <literal>chanprefix</literal> and a digit sequence.</para></note> + </description> + </application> + <application name="ExtenSpy" language="en_US"> + <synopsis> + Listen to a channel, and optionally whisper into it. + </synopsis> + <syntax> + <parameter name="exten" required="true" argsep="@"> + <argument name="exten" required="true"> + <para>Specify extension.</para> + </argument> + <argument name="context"> + <para>Optionally specify a context, defaults to <literal>default</literal>.</para> + </argument> + </parameter> + <parameter name="options"> + <optionlist> + <option name="b"> + <para>Only spy on channels involved in a bridged call.</para> + </option> + <option name="B"> + <para>Instead of whispering on a single channel barge in on both + channels involved in the call.</para> + </option> + <option name="d"> + <para>Override the typical numeric DTMF functionality and instead + use DTMF to switch between spy modes.</para> + <enumlist> + <enum name="4"> + <para>spy mode</para> + </enum> + <enum name="5"> + <para>whisper mode</para> + </enum> + <enum name="6"> + <para>barge mode</para> + </enum> + </enumlist> + </option> + <option name="g"> + <argument name="grp" required="true"> + <para>Only spy on channels in which one or more of the groups + listed in <replaceable>grp</replaceable> matches one or more groups from the + <variable>SPYGROUP</variable> variable set on the channel to be spied upon.</para> + </argument> + <note><para>both <replaceable>grp</replaceable> and <variable>SPYGROUP</variable> can contain + either a single group or a colon-delimited list of groups, such + as <literal>sales:support:accounting</literal>.</para></note> + </option> + <option name="n" argsep="@"> + <para>Say the name of the person being spied on if that person has recorded + his/her name. If a context is specified, then that voicemail context will + be searched when retrieving the name, otherwise the <literal>default</literal> context + be used when searching for the name (i.e. if SIP/1000 is the channel being + spied on and no mailbox is specified, then <literal>1000</literal> will be used when searching + for the name).</para> + <argument name="mailbox" /> + <argument name="context" /> + </option> + <option name="q"> + <para>Don't play a beep when beginning to spy on a channel, or speak the + selected channel name.</para> + </option> + <option name="r"> + <para>Record the session to the monitor spool directory. An optional base for the filename + may be specified. The default is <literal>chanspy</literal>.</para> + <argument name="basename" /> + </option> + <option name="s"> + <para>Skip the playback of the channel type (i.e. SIP, IAX, etc) when + speaking the selected channel name.</para> + </option> + <option name="v"> + <argument name="value" /> + <para>Adjust the initial volume in the range from <literal>-4</literal> + to <literal>4</literal>. A negative value refers to a quieter setting.</para> + </option> + <option name="w"> + <para>Enable <literal>whisper</literal> mode, so the spying channel can talk to + the spied-on channel.</para> + </option> + <option name="W"> + <para>Enable <literal>private whisper</literal> mode, so the spying channel can + talk to the spied-on channel but cannot listen to that channel.</para> + </option> + <option name="o"> + <para>Only listen to audio coming from this channel.</para> + </option> + <option name="X"> + <para>Allow the user to exit ChanSpy to a valid single digit + numeric extension in the current context or the context + specified by the <variable>SPY_EXIT_CONTEXT</variable> channel variable. The + name of the last channel that was spied on will be stored + in the <variable>SPY_CHANNEL</variable> variable.</para> + </option> + <option name="e"> + <argument name="ext" required="true" /> + <para>Enable <emphasis>enforced</emphasis> mode, so the spying channel can + only monitor extensions whose name is in the <replaceable>ext</replaceable> : delimited + list.</para> + </option> + </optionlist> + </parameter> + </syntax> + <description> + <para>This application is used to listen to the audio from an Asterisk channel. This includes + the audio coming in and out of the channel being spied on. Only channels created by outgoing calls for the + specified extension will be selected for spying. If the optional context is not supplied, + the current channel's context will be used.</para> + <para>While spying, the following actions may be performed:</para> + <para> - Dialing <literal>#</literal> cycles the volume level.</para> + <para> - Dialing <literal>*</literal> will stop spying and look for another channel to spy on.</para> + <note><para>The <replaceable>X</replaceable> option supersedes the three features above in that if a valid + single digit extension exists in the correct context ChanSpy will exit to it. + This also disables choosing a channel based on <literal>chanprefix</literal> and a digit sequence.</para></note> + </description> + </application> + + ***/ static const char *app_chan = "ChanSpy"; -static const char *desc_chan = -" ChanSpy([chanprefix][,options]): This application is used to listen to the\n" -"audio from an Asterisk channel. This includes the audio coming in and\n" -"out of the channel being spied on. If the 'chanprefix' parameter is specified,\n" -"only channels beginning with this string will be spied upon.\n" -" While spying, the following actions may be performed:\n" -" - Dialing # cycles the volume level.\n" -" - Dialing * will stop spying and look for another channel to spy on.\n" -" - Dialing a series of digits followed by # builds a channel name to append\n" -" to 'chanprefix'. For example, executing ChanSpy(Agent) and then dialing\n" -" the digits '1234#' while spying will begin spying on the channel\n" -" 'Agent/1234'. Note that this feature will be overriden if the 'd' option\n" -" is used\n" -" Note: The X option supersedes the three features above in that if a valid\n" -" single digit extension exists in the correct context ChanSpy will\n" -" exit to it. This also disables choosing a channel based on 'chanprefix'\n" -" and a digit sequence.\n" -" Options:\n" -" b - Only spy on channels involved in a bridged call.\n" -" B - Instead of whispering on a single channel barge in on both\n" -" channels involved in the call.\n" -" d - Override the typical numeric DTMF functionality and instead\n" -" use DTMF to switch between spy modes.\n" -" 4 = spy mode\n" -" 5 = whisper mode\n" -" 6 = barge mode\n" -" g(grp) - Only spy on channels in which one or more of the groups \n" -" listed in 'grp' matches one or more groups from the\n" -" SPYGROUP variable set on the channel to be spied upon.\n" -" Note that both 'grp' and SPYGROUP can contain either a\n" -" single group or a colon-delimited list of groups, such\n" -" as 'sales:support:accounting'.\n" -" n([mailbox][@context]) - Say the name of the person being spied on if that person has recorded\n" -" his/her name. If a context is specified, then that voicemail context will\n" -" be searched when retrieving the name, otherwise the \"default\" context\n" -" will be searched. If no mailbox is specified, then the channel name will\n" -" be used when searching for the name (i.e. if SIP/1000 is the channel being\n" -" spied on and no mailbox is specified, then \"1000\" will be used when searching\n" -" for the name).\n" -" q - Don't play a beep when beginning to spy on a channel, or speak the\n" -" selected channel name.\n" -" r[(basename)] - Record the session to the monitor spool directory. An\n" -" optional base for the filename may be specified. The\n" -" default is 'chanspy'.\n" -" s - Skip the playback of the channel type (i.e. SIP, IAX, etc) when\n" -" speaking the selected channel name.\n" -" v([value]) - Adjust the initial volume in the range from -4 to 4. A\n" -" negative value refers to a quieter setting.\n" -" w - Enable 'whisper' mode, so the spying channel can talk to\n" -" the spied-on channel.\n" -" W - Enable 'private whisper' mode, so the spying channel can\n" -" talk to the spied-on channel but cannot listen to that\n" -" channel.\n" -" o - Only listen to audio coming from this channel.\n" -" X - Allow the user to exit ChanSpy to a valid single digit\n" -" numeric extension in the current context or the context\n" -" specified by the SPY_EXIT_CONTEXT channel variable. The\n" -" name of the last channel that was spied on will be stored\n" -" in the SPY_CHANNEL variable.\n" -" e(ext) - Enable 'enforced' mode, so the spying channel can\n" -" only monitor extensions whose name is in the 'ext' : \n" -" delimited list.\n" -; static const char *app_ext = "ExtenSpy"; -static const char *desc_ext = -" ExtenSpy(exten[@context][,options]): This application is used to listen to the\n" -"audio from an Asterisk channel. This includes the audio coming in and\n" -"out of the channel being spied on. Only channels created by outgoing calls for the\n" -"specified extension will be selected for spying. If the optional context is not\n" -"supplied, the current channel's context will be used.\n" -" While spying, the following actions may be performed:\n" -" - Dialing # cycles the volume level.\n" -" - Dialing * will stop spying and look for another channel to spy on.\n" -" Note: The X option superseeds the two features above in that if a valid\n" -" single digit extension exists in the correct context it ChanSpy will\n" -" exit to it.\n" -" Options:\n" -" b - Only spy on channels involved in a bridged call.\n" -" B - Instead of whispering on a single channel barge in on both\n" -" channels involved in the call.\n" -" d - Override the typical numeric DTMF functionality and instead\n" -" use DTMF to switch between spy modes.\n" -" 4 = spy mode\n" -" 5 = whisper mode\n" -" 6 = barge mode\n" -" g(grp) - Only spy on channels in which one or more of the groups \n" -" listed in 'grp' matches one or more groups from the\n" -" SPYGROUP variable set on the channel to be spied upon.\n" -" Note that both 'grp' and SPYGROUP can contain either a\n" -" single group or a colon-delimited list of groups, such\n" -" as 'sales:support:accounting'.\n" -" n([mailbox][@context]) - Say the name of the person being spied on if that person has recorded\n" -" his/her name. If a context is specified, then that voicemail context will\n" -" be searched when retrieving the name, otherwise the \"default\" context\n" -" will be searched. If no mailbox is specified, then the channel name will\n" -" be used when searching for the name (i.e. if SIP/1000 is the channel being\n" -" spied on and no mailbox is specified, then \"1000\" will be used when searching\n" -" for the name).\n" -" q - Don't play a beep when beginning to spy on a channel, or speak the\n" -" selected channel name.\n" -" r[(basename)] - Record the session to the monitor spool directory. An\n" -" optional base for the filename may be specified. The\n" -" default is 'chanspy'.\n" -" s - Skip the playback of the channel type (i.e. SIP, IAX, etc) when\n" -" speaking the selected channel name.\n" -" v([value]) - Adjust the initial volume in the range from -4 to 4. A\n" -" negative value refers to a quieter setting.\n" -" w - Enable 'whisper' mode, so the spying channel can talk to\n" -" the spied-on channel.\n" -" W - Enable 'private whisper' mode, so the spying channel can\n" -" talk to the spied-on channel but cannot listen to that\n" -" channel.\n" -" o - Only listen to audio coming from this channel.\n" -" X - Allow the user to exit ChanSpy to a valid single digit\n" -" numeric extension in the current context or the context\n" -" specified by the SPY_EXIT_CONTEXT channel variable. The\n" -" name of the last channel that was spied on will be stored\n" -" in the SPY_CHANNEL variable.\n" -; enum { OPTION_QUIET = (1 << 0), /* Quiet, no announcement */ @@ -1103,8 +1213,8 @@ static int load_module(void) { int res = 0; - res |= ast_register_application(app_chan, chanspy_exec, tdesc, desc_chan); - res |= ast_register_application(app_ext, extenspy_exec, tdesc, desc_ext); + res |= ast_register_application_xml(app_chan, chanspy_exec); + res |= ast_register_application_xml(app_ext, extenspy_exec); return res; } diff --git a/apps/app_controlplayback.c b/apps/app_controlplayback.c index f79ab6d42..4d7432d9c 100644 --- a/apps/app_controlplayback.c +++ b/apps/app_controlplayback.c @@ -33,32 +33,67 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/app.h" #include "asterisk/module.h" +/*** DOCUMENTATION + <application name="ControlPlayback" language="en_US"> + <synopsis> + Play a file with fast forward and rewind. + </synopsis> + <syntax> + <parameter name="filename" required="true" /> + <parameter name="skipms"> + <para>This is number of milliseconds to skip when rewinding or + fast-forwarding.</para> + </parameter> + <parameter name="ff"> + <para>Fast-forward when this DTMF digit is received. (defaults to <literal>#</literal>)</para> + </parameter> + <parameter name="rew"> + <para>Rewind when this DTMF digit is received. (defaults to <literal>*</literal>)</para> + </parameter> + <parameter name="stop"> + <para>Stop playback when this DTMF digit is received.</para> + </parameter> + <parameter name="pause"> + <para>Pause playback when this DTMF digit is received.</para> + </parameter> + <parameter name="restart"> + <para>Restart playback when this DTMF digit is received.</para> + </parameter> + <parameter name="options"> + <optionlist> + <option name="o"> + <argument name="time" required="true"> + <para>Start at <replaceable>time</replaceable> ms from the + beginning of the file.</para> + </argument> + </option> + </optionlist> + </parameter> + </syntax> + <description> + <para>This application will play back the given <replaceable>filename</replaceable>.</para> + <para>It sets the following channel variables upon completion:</para> + <variablelist> + <variable name="CPLAYBACKSTATUS"> + <para>Contains the status of the attempt as a text string</para> + <value name="SUCCESS" /> + <value name="USERSTOPPED" /> + <value name="ERROR" /> + </variable> + <variable name="CPLAYBACKOFFSET"> + <para>Contains the offset in ms into the file where playback + was at when it stopped. <literal>-1</literal> is end of file.</para> + </variable> + <variable name="CPLAYBACKSTOPKEY"> + <para>If the playback is stopped by the user this variable contains + the key that was pressed.</para> + </variable> + </variablelist> + </description> + </application> + ***/ static const char *app = "ControlPlayback"; -static const char *synopsis = "Play a file with fast forward and rewind"; - -static const char *descrip = -" ControlPlayback(file[,skipms[,ff[,rew[,stop[,pause[,restart,options]]]]]]]):\n" -"This application will play back the given filename. By default, the '*' key\n" -"can be used to rewind, and the '#' key can be used to fast-forward.\n" -"Parameters:\n" -" skipms - This is number of milliseconds to skip when rewinding or\n" -" fast-forwarding.\n" -" ff - Fast-forward when this DTMF digit is received.\n" -" rew - Rewind when this DTMF digit is received.\n" -" stop - Stop playback when this DTMF digit is received.\n" -" pause - Pause playback when this DTMF digit is received.\n" -" restart - Restart playback when this DTMF digit is received.\n" -"Options:\n" -" o(#) - Start at # ms from the beginning of the file.\n" -"This application sets the following channel variables upon completion:\n" -" CPLAYBACKSTATUS - This variable contains the status of the attempt as a text\n" -" string, one of: SUCCESS | USERSTOPPED | ERROR\n" -" CPLAYBACKOFFSET - This contains the offset in ms into the file where\n" -" playback was at when it stopped. -1 is end of file.\n" -" CPLAYBACKSTOPKEY - If the playback is stopped by the user this variable contains\n" -" the key that was pressed.\n"; - enum { OPT_OFFSET = (1 << 1), }; @@ -185,7 +220,7 @@ static int unload_module(void) static int load_module(void) { - return ast_register_application(app, controlplayback_exec, synopsis, descrip); + return ast_register_application_xml(app, controlplayback_exec); } AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Control Playback Application"); diff --git a/apps/app_dahdibarge.c b/apps/app_dahdibarge.c index f16b4dea6..cfa445acc 100644 --- a/apps/app_dahdibarge.c +++ b/apps/app_dahdibarge.c @@ -52,17 +52,26 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/say.h" #include "asterisk/utils.h" +/*** DOCUMENTATION + <application name="DAHDIBarge" language="en_US"> + <synopsis> + Barge in (monitor) DAHDI channel. + </synopsis> + <syntax> + <parameter name="channel"> + <para>Channel to barge.</para> + </parameter> + </syntax> + <description> + <para>Barges in on a specified DAHDI <replaceable>channel</replaceable> or prompts + if one is not specified. Returns <literal>-1</literal> when caller user hangs + up and is independent of the state of the channel being monitored. + </para> + </description> + </application> + ***/ static char *app = "DAHDIBarge"; -static char *synopsis = "Barge in (monitor) DAHDI channel"; - -static char *descrip = -" DAHDIBarge([channel]): Barges in on a specified DAHDI\n" -"channel or prompts if one is not specified. Returns\n" -"-1 when caller user hangs up and is independent of the\n" -"state of the channel being monitored."; - - #define CONF_SIZE 160 static int careful_write(int fd, unsigned char *data, int len) @@ -293,7 +302,7 @@ static int unload_module(void) static int load_module(void) { - return ((ast_register_application(app, conf_exec, synopsis, descrip)) ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_SUCCESS); + return ((ast_register_application_xml(app, conf_exec)) ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_SUCCESS); } AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Barge in on DAHDI channel application"); diff --git a/apps/app_dahdiras.c b/apps/app_dahdiras.c index 1671f8bdd..879868ea5 100644 --- a/apps/app_dahdiras.c +++ b/apps/app_dahdiras.c @@ -52,17 +52,28 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/module.h" #include "asterisk/app.h" -static char *app = "DAHDIRAS"; - -static char *synopsis = "Executes DAHDI ISDN RAS application"; +/*** DOCUMENTATION + <application name="DAHDIRAS" language="en_US"> + <synopsis> + Executes DAHDI ISDN RAS application. + </synopsis> + <syntax> + <parameter name="args" required="true"> + <para>A list of parameters to pass to the pppd daemon, + separeted by <literal>,</literal> characters.</para> + </parameter> + </syntax> + <description> + <para>Executes a RAS server using pppd on the given channel. + The channel must be a clear channel (i.e. PRI source) and a DAHDI + channel to be able to use this function (No modem emulation is included).</para> + <para>Your pppd must be patched to be DAHDI aware.</para> + </description> + </application> -static char *descrip = -" DAHDIRAS(args): Executes a RAS server using pppd on the given channel.\n" -"The channel must be a clear channel (i.e. PRI source) and a DAHDI\n" -"channel to be able to use this function (No modem emulation is included).\n" -"Your pppd must be patched to be DAHDI aware. Arguments should be\n" -"separated by , characters.\n"; + ***/ +static char *app = "DAHDIRAS"; #define PPP_MAX_ARGS 32 #define PPP_EXEC "/usr/sbin/pppd" @@ -218,7 +229,7 @@ static int unload_module(void) static int load_module(void) { - return ((ast_register_application(app, dahdiras_exec, synopsis, descrip)) ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_SUCCESS); + return ((ast_register_application_xml(app, dahdiras_exec)) ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_SUCCESS); } AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "DAHDI ISDN Remote Access Server"); diff --git a/apps/app_dahdiscan.c b/apps/app_dahdiscan.c index a8a939725..8251ffcbf 100644 --- a/apps/app_dahdiscan.c +++ b/apps/app_dahdiscan.c @@ -52,16 +52,24 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/say.h" #include "asterisk/options.h" +/*** DOCUMENTATION + <application name="DAHDIScan" language="en_US"> + <synopsis> + Scan DAHDI channels to monitor calls. + </synopsis> + <syntax> + <parameter name="group"> + <para>Limit scanning to a channel <replaceable>group</replaceable> by setting this option.</para> + </parameter> + </syntax> + <description> + <para>Allows a call center manager to monitor DAHDI channels in a + convenient way. Use <literal>#</literal> to select the next channel and use <literal>*</literal> to exit.</para> + </description> + </application> + ***/ static char *app = "DAHDIScan"; -static char *synopsis = "Scan DAHDI channels to monitor calls"; - -static char *descrip = -" DAHDIScan([group]) allows a call center manager to monitor DAHDI channels in\n" -"a convenient way. Use '#' to select the next channel and use '*' to exit\n" -"Limit scanning to a channel GROUP by setting the option group argument.\n"; - - #define CONF_SIZE 160 static struct ast_channel *get_dahdi_channel_locked(int num) { @@ -363,7 +371,7 @@ static int unload_module(void) static int load_module(void) { - return ((ast_register_application(app, conf_exec, synopsis, descrip)) ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_SUCCESS); + return ((ast_register_application_xml(app, conf_exec)) ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_SUCCESS); } AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Scan DAHDI channels application"); diff --git a/apps/app_dial.c b/apps/app_dial.c index f0fd7463d..089523ef4 100644 --- a/apps/app_dial.c +++ b/apps/app_dial.c @@ -62,188 +62,396 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/global_datastores.h" #include "asterisk/dsp.h" -static char *app = "Dial"; +/*** DOCUMENTATION + <application name="Dial" language="en_US"> + <synopsis> + Attempt to connect to another device or endpoint and bridge the call. + </synopsis> + <syntax> + <parameter name="Technology/Resource" required="true" argsep="&"> + <argument name="Technology/Resource" required="true"> + <para>Specification of the device(s) to dial. These must be in the format of + <literal>Technology/Resource</literal>, where <replaceable>Technology</replaceable> + represents a particular channel driver, and <replaceable>Resource</replaceable> + represents a resource available to that particular channel driver.</para> + </argument> + <argument name="Technology2/Resource2" required="false" multiple="true"> + <para>Optional extra devices to dial in parallel</para> + <para>If you need more then one enter them as + Technology2/Resource2&Technology3/Resourse3&.....</para> + </argument> + </parameter> + <parameter name="timeout" required="false"> + <para>Specifies the number of seconds we attempt to dial the specified devices</para> + <para>If not specified, this defaults to 136 years.</para> + </parameter> + <parameter name="options" required="false"> + <optionlist> + <option name="A"> + <argument name="x" required="true"> + <para>The file to play to the called party</para> + </argument> + <para>Play an announcement to the called party, where <replaceable>x</replaceable> is the prompt to be played</para> + </option> + <option name="C"> + <para>Reset the call detail record (CDR) for this call.</para> + </option> + <option name="c"> + <para>If the Dial() application cancels this call, always set the flag to tell the channel + driver that the call is answered elsewhere.</para> + </option> + <option name="d"> + <para>Allow the calling user to dial a 1 digit extension while waiting for + a call to be answered. Exit to that extension if it exists in the + current context, or the context defined in the <variable>EXITCONTEXT</variable> variable, + if it exists.</para> + </option> + <option name="D" argsep=":"> + <argument name="called" /> + <argument name="calling" /> + <para>Send the specified DTMF strings <emphasis>after</emphasis> the called + party has answered, but before the call gets bridged. The + <replaceable>called</replaceable> DTMF string is sent to the called party, and the + <replaceable>calling</replaceable> DTMF string is sent to the calling party. Both arguments + can be used alone.</para> + </option> + <option name="e"> + <para>Execute the <literal>h</literal> extension for peer after the call ends</para> + </option> + <option name="f"> + <para>Force the callerid of the <emphasis>calling</emphasis> channel to be set as the + extension associated with the channel using a dialplan <literal>hint</literal>. + For example, some PSTNs do not allow CallerID to be set to anything + other than the number assigned to the caller.</para> + </option> + <option name="F" argsep="^"> + <argument name="context" required="false" /> + <argument name="exten" required="false" /> + <argument name="priority" required="true" /> + <para>When the caller hangs up, transfer the called party + to the specified destination and continue execution at that location.</para> + </option> + <option name="g"> + <para>Proceed with dialplan execution at the next priority in the current extension if the + destination channel hangs up.</para> + </option> + <option name="G" argsep="^"> + <argument name="context" required="false" /> + <argument name="exten" required="false" /> + <argument name="priority" required="true" /> + <para>If the call is answered, transfer the calling party to + the specified <replaceable>priority</replaceable> and the called party to the specified + <replaceable>priority</replaceable> plus one.</para> + <note> + <para>You cannot use any additional action post answer options in conjunction with this option.</para> + </note> + </option> + <option name="h"> + <para>Allow the called party to hang up by sending the <literal>*</literal> DTMF digit.</para> + </option> + <option name="H"> + <para>Allow the calling party to hang up by hitting the <literal>*</literal> DTMF digit.</para> + </option> + <option name="i"> + <para>Asterisk will ignore any forwarding requests it may receive on this dial attempt.</para> + </option> + <option name="k"> + <para>Allow the called party to enable parking of the call by sending + the DTMF sequence defined for call parking in <filename>features.conf</filename>.</para> + </option> + <option name="K"> + <para>Allow the calling party to enable parking of the call by sending + the DTMF sequence defined for call parking in <filename>features.conf</filename>.</para> + </option> + <option name="L" argsep=":"> + <argument name="x" required="true"> + <para>Maximum call time, in milliseconds</para> + </argument> + <argument name="y"> + <para>Warning time, in milliseconds</para> + </argument> + <argument name="z"> + <para>Repeat time, in milliseconds</para> + </argument> + <para>Limit the call to <replaceable>x</replaceable> milliseconds. Play a warning when <replaceable>y</replaceable> milliseconds are + left. Repeat the warning every <replaceable>z</replaceable> milliseconds until time expires.</para> + <para>This option is affected by the following variables:</para> + <variablelist> + <variable name="LIMIT_PLAYAUDIO_CALLER"> + <value name="yes" default="true" /> + <value name="no" /> + <para>If set, this variable causes Asterisk to play the prompts to the caller.</para> + </variable> + <variable name="LIMIT_PLAYAUDIO_CALLEE"> + <value name="yes" /> + <value name="no" default="true"/> + <para>If set, this variable causes Asterisk to play the prompts to the callee.</para> + </variable> + <variable name="LIMIT_TIMEOUT_FILE"> + <value name="filename"/> + <para>If specified, <replaceable>filename</replaceable> specifies the sound prompt to play when the timeout is reached. + If not set, the time remaining will be announced.</para> + </variable> + <variable name="LIMIT_CONNECT_FILE"> + <value name="filename"/> + <para>If specified, <replaceable>filename</replaceable> specifies the sound prompt to play when the call begins. + If not set, the time remaining will be announced.</para> + </variable> + <variable name="LIMIT_WARNING_FILE"> + <value name="filename"/> + <para>If specified, <replaceable>filename</replaceable> specifies the sound prompt to play as + a warning when time <replaceable>x</replaceable> is reached. If not set, the time remaining will be announced.</para> + </variable> + </variablelist> + </option> + <option name="m"> + <argument name="class" required="false"/> + <para>Provide hold music to the calling party until a requested + channel answers. A specific music on hold <replaceable>class</replaceable> + (as defined in <filename>musiconhold.conf</filename>) can be specified.</para> + </option> + <option name="M" argsep="^"> + <argument name="macro" required="true"> + <para>Name of the macro that should be executed.</para> + </argument> + <argument name="arg" multiple="true"> + <para>Macro arguments</para> + </argument> + <para>Execute the specified <replaceable>macro</replaceable> for the <emphasis>called</emphasis> channel + before connecting to the calling channel. Arguments can be specified to the Macro + using <literal>^</literal> as a delimiter. The macro can set the variable + <variable>MACRO_RESULT</variable> to specify the following actions after the macro is + finished executing:</para> + <variablelist> + <variable name="MACRO_RESULT"> + <para>If set, this action will be taken after the macro finished executing.</para> + <value name="ABORT"> + Hangup both legs of the call + </value> + <value name="CONGESTION"> + Behave as if line congestion was encountered + </value> + <value name="BUSY"> + Behave as if a busy signal was encountered + </value> + <value name="CONTINUE"> + Hangup the called party and allow the calling party to continue dialplan execution at the next priority + </value> + <!-- TODO: Fix this syntax up, once we've figured out how to specify the GOTO syntax --> + <value name="GOTO:<context>^<exten>^<priority>"> + Transfer the call to the specified destination. + </value> + </variable> + </variablelist> + <note> + <para>You cannot use any additional action post answer options in conjunction + with this option. Also, pbx services are not run on the peer (called) channel, + so you will not be able to set timeouts via the TIMEOUT() function in this macro.</para> + </note> + </option> + <option name="n"> + <para>This option is a modifier for the call screening/privacy mode. (See the + <literal>p</literal> and <literal>P</literal> options.) It specifies + that no introductions are to be saved in the <directory>priv-callerintros</directory> + directory.</para> + </option> + <option name="N"> + <para>This option is a modifier for the call screening/privacy mode. It specifies + that if Caller*ID is present, do not screen the call.</para> + </option> + <option name="o"> + <para>Specify that the Caller*ID that was present on the <emphasis>calling</emphasis> channel + be set as the Caller*ID on the <emphasis>called</emphasis> channel. This was the + behavior of Asterisk 1.0 and earlier.</para> + </option> + <option name="O"> + <argument name="mode"> + <para>With <replaceable>mode</replaceable> either not specified or set to <literal>1</literal>, + the originator hanging up will cause the phone to ring back immediately.</para> + <para>With <replaceable>mode</replaceable> set to <literal>2</literal>, when the operator + flashes the trunk, it will ring their phone back.</para> + </argument> + <para>Enables <emphasis>operator services</emphasis> mode. This option only + works when bridging a DAHDI channel to another DAHDI channel + only. if specified on non-DAHDI interfaces, it will be ignored. + When the destination answers (presumably an operator services + station), the originator no longer has control of their line. + They may hang up, but the switch will not release their line + until the destination party (the operator) hangs up.</para> + </option> + <option name="p"> + <para>This option enables screening mode. This is basically Privacy mode + without memory.</para> + </option> + <option name="P"> + <argument name="x" /> + <para>Enable privacy mode. Use <replaceable>x</replaceable> as the family/key in the AstDB database if + it is provided. The current extension is used if a database family/key is not specified.</para> + </option> + <option name="r"> + <para>Indicate ringing to the calling party, even if the called party isn't actually ringing. Pass no audio to the calling + party until the called channel has answered.</para> + </option> + <option name="S"> + <argument name="x" required="true" /> + <para>Hang up the call <replaceable>x</replaceable> seconds <emphasis>after</emphasis> the called party has + answered the call.</para> + </option> + <option name="t"> + <para>Allow the called party to transfer the calling party by sending the + DTMF sequence defined in <filename>features.conf</filename>.</para> + </option> + <option name="T"> + <para>Allow the calling party to transfer the called party by sending the + DTMF sequence defined in <filename>features.conf</filename>.</para> + </option> + <option name="U" argsep="^"> + <argument name="x" required="true"> + <para>Name of the subroutine to execute via Gosub</para> + </argument> + <argument name="arg" multiple="true" required="false"> + <para>Arguments for the Gosub routine</para> + </argument> + <para>Execute via Gosub the routine <replaceable>x</replaceable> for the <emphasis>called</emphasis> channel before connecting + to the calling channel. Arguments can be specified to the Gosub + using <literal>^</literal> as a delimiter. The Gosub routine can set the variable + <variable>GOSUB_RESULT</variable> to specify the following actions after the Gosub returns.</para> + <variablelist> + <variable name="GOSUB_RESULT"> + <value name="ABORT"> + Hangup both legs of the call. + </value> + <value name="CONGESTION"> + Behave as if line congestion was encountered. + </value> + <value name="BUSY"> + Behave as if a busy signal was encountered. + </value> + <value name="CONTINUE"> + Hangup the called party and allow the calling party + to continue dialplan execution at the next priority. + </value> + <!-- TODO: Fix this syntax up, once we've figured out how to specify the GOTO syntax --> + <value name="GOTO:<context>^<exten>^<priority>"> + Transfer the call to the specified priority. Optionally, an extension, or + extension and priority can be specified. + </value> + </variable> + </variablelist> + <note> + <para>You cannot use any additional action post answer options in conjunction + with this option. Also, pbx services are not run on the peer (called) channel, + so you will not be able to set timeouts via the TIMEOUT() function in this routine.</para> + </note> + </option> + <option name="w"> + <para>Allow the called party to enable recording of the call by sending + the DTMF sequence defined for one-touch recording in <filename>features.conf</filename>.</para> + </option> + <option name="W"> + <para>Allow the calling party to enable recording of the call by sending + the DTMF sequence defined for one-touch recording in <filename>features.conf</filename>.</para> + </option> + <option name="x"> + <para>Allow the called party to enable recording of the call by sending + the DTMF sequence defined for one-touch automixmonitor in <filename>features.conf</filename>.</para> + </option> + <option name="X"> + <para>Allow the calling party to enable recording of the call by sending + the DTMF sequence defined for one-touch automixmonitor in <filename>features.conf</filename>.</para> + </option> + </optionlist> + </parameter> + <parameter name="URL"> + <para>The optional URL will be sent to the called party if the channel driver supports it.</para> + </parameter> + </syntax> + <description> + <para>This application will place calls to one or more specified channels. As soon + as one of the requested channels answers, the originating channel will be + answered, if it has not already been answered. These two channels will then + be active in a bridged call. All other channels that were requested will then + be hung up.</para> + + <para>Unless there is a timeout specified, the Dial application will wait + indefinitely until one of the called channels answers, the user hangs up, or + if all of the called channels are busy or unavailable. Dialplan executing will + continue if no requested channels can be called, or if the timeout expires. + This application will report normal termination if the originating channel + hangs up, or if the call is bridged and either of the parties in the bridge + ends the call.</para> + + <para>If the <variable>OUTBOUND_GROUP</variable> variable is set, all peer channels created by this + application will be put into that group (as in Set(GROUP()=...). + If the <variable>OUTBOUND_GROUP_ONCE</variable> variable is set, all peer channels created by this + application will be put into that group (as in Set(GROUP()=...). Unlike OUTBOUND_GROUP, + however, the variable will be unset after use.</para> + + <para>This application sets the following channel variables:</para> + <variablelist> + <variable name="DIALEDTIME"> + <para>This is the time from dialing a channel until when it is disconnected.</para> + </variable> + <variable name="ANSWEREDTIME"> + <para>This is the amount of time for actual call.</para> + </variable> + <variable name="DIALSTATUS"> + <para>This is the status of the call</para> + <value name="CHANUNAVAIL" /> + <value name="CONGESTION" /> + <value name="NOANSWER" /> + <value name="BUSY" /> + <value name="ANSWER" /> + <value name="CANCEL" /> + <value name="DONTCALL"> + For the Privacy and Screening Modes. + Will be set if the called party chooses to send the calling party to the 'Go Away' script. + </value> + <value name="TORTURE"> + For the Privacy and Screening Modes. + Will be set if the called party chooses to send the calling party to the 'torture' script. + </value> + <value name="INVALIDARGS" /> + </variable> + </variablelist> + </description> + </application> + <application name="RetryDial" language="en_US"> + <synopsis> + Place a call, retrying on failure allowing an optional exit extension. + </synopsis> + <syntax> + <parameter name="announce" required="true"> + <para>Filename of sound that will be played when no channel can be reached</para> + </parameter> + <parameter name="sleep" required="true"> + <para>Number of seconds to wait after a dialattempt failed before a new attempt is made</para> + </parameter> + <parameter name="retries" required="true"> + <para>Number of retries</para> + <para>When this is reached flow will continue at the next priority in the dialplan</para> + </parameter> + <parameter name="dialargs" required="true"> + <para>Same format as arguments provided to the Dial application</para> + </parameter> + </syntax> + <description> + <para>This application will attempt to place a call using the normal Dial application. + If no channel can be reached, the <replaceable>announce</replaceable> file will be played. + Then, it will wait <replaceable>sleep</replaceable> number of seconds before retrying the call. + After <replaceable>retries</replaceable> number of attempts, the calling channel will continue at the next priority in the dialplan. + If the <replaceable>retries</replaceable> setting is set to 0, this application will retry endlessly. + While waiting to retry a call, a 1 digit extension may be dialed. If that + extension exists in either the context defined in <variable>EXITCONTEXT</variable> or the current + one, The call will jump to that extension immediately. + The <replaceable>dialargs</replaceable> are specified in the same format that arguments are provided + to the Dial application.</para> + </description> + </application> + ***/ -static char *synopsis = "Place a call and connect to the current channel"; - -static char *descrip = -" Dial(Technology/resource[&Tech2/resource2...][,timeout][,options][,URL]):\n" -"This application will place calls to one or more specified channels. As soon\n" -"as one of the requested channels answers, the originating channel will be\n" -"answered, if it has not already been answered. These two channels will then\n" -"be active in a bridged call. All other channels that were requested will then\n" -"be hung up.\n" -" Unless there is a timeout specified, the Dial application will wait\n" -"indefinitely until one of the called channels answers, the user hangs up, or\n" -"if all of the called channels are busy or unavailable. Dialplan executing will\n" -"continue if no requested channels can be called, or if the timeout expires.\n\n" -" This application sets the following channel variables upon completion:\n" -" DIALEDTIME - This is the time from dialing a channel until when it\n" -" is disconnected.\n" -" ANSWEREDTIME - This is the amount of time for actual call.\n" -" DIALSTATUS - This is the status of the call:\n" -" CHANUNAVAIL | CONGESTION | NOANSWER | BUSY | ANSWER | CANCEL\n" -" DONTCALL | TORTURE | INVALIDARGS\n" -" For the Privacy and Screening Modes, the DIALSTATUS variable will be set to\n" -"DONTCALL if the called party chooses to send the calling party to the 'Go Away'\n" -"script. The DIALSTATUS variable will be set to TORTURE if the called party\n" -"wants to send the caller to the 'torture' script.\n" -" This application will report normal termination if the originating channel\n" -"hangs up, or if the call is bridged and either of the parties in the bridge\n" -"ends the call.\n" -" The optional URL will be sent to the called party if the channel supports it.\n" -" If the OUTBOUND_GROUP variable is set, all peer channels created by this\n" -"application will be put into that group (as in Set(GROUP()=...).\n" -" If the OUTBOUND_GROUP_ONCE variable is set, all peer channels created by this\n" -"application will be put into that group (as in Set(GROUP()=...). Unlike OUTBOUND_GROUP,\n" -"however, the variable will be unset after use.\n\n" -" Options:\n" -" A(x) - Play an announcement to the called party, using 'x' as the file.\n" -" C - Reset the CDR for this call.\n" -" c - If DIAL cancels this call, always set the flag to tell the channel\n" -" driver that the call is answered elsewhere.\n" -" d - Allow the calling user to dial a 1 digit extension while waiting for\n" -" a call to be answered. Exit to that extension if it exists in the\n" -" current context, or the context defined in the EXITCONTEXT variable,\n" -" if it exists.\n" -" D([called][:calling]) - Send the specified DTMF strings *after* the called\n" -" party has answered, but before the call gets bridged. The 'called'\n" -" DTMF string is sent to the called party, and the 'calling' DTMF\n" -" string is sent to the calling party. Both parameters can be used\n" -" alone.\n" -" e - execute the 'h' extension for peer after the call ends. This\n" -" operation will not be performed if the peer was parked\n" -" f - Force the callerid of the *calling* channel to be set as the\n" -" extension associated with the channel using a dialplan 'hint'.\n" -" For example, some PSTNs do not allow CallerID to be set to anything\n" -" other than the number assigned to the caller.\n" -" F(context^exten^pri) - When the caller hangs up, transfer the called party\n" -" to the specified context and extension and continue execution.\n" -" g - Proceed with dialplan execution at the current extension if the\n" -" destination channel hangs up.\n" -" G(context^exten^pri) - If the call is answered, transfer the calling party to\n" -" the specified priority and the called party to the specified priority+1.\n" -" Optionally, an extension, or extension and context may be specified. \n" -" Otherwise, the current extension is used. You cannot use any additional\n" -" action post answer options in conjunction with this option.\n" -" h - Allow the called party to hang up by sending the '*' DTMF digit, or\n" -" whatever sequence was defined in the featuremap section for\n" -" 'disconnect' in features.conf\n" -" H - Allow the calling party to hang up by hitting the '*' DTMF digit, or\n" -" whatever sequence was defined in the featuremap section for\n" -" 'disconnect' in features.conf\n" -" i - Asterisk will ignore any forwarding requests it may receive on this\n" -" dial attempt.\n" -" k - Allow the called party to enable parking of the call by sending\n" -" the DTMF sequence defined for call parking in the featuremap section of features.conf.\n" -" K - Allow the calling party to enable parking of the call by sending\n" -" the DTMF sequence defined for call parking in the featuremap section of features.conf.\n" -" L(x[:y][:z]) - Limit the call to 'x' ms. Play a warning when 'y' ms are\n" -" left. Repeat the warning every 'z' ms. The following special\n" -" variables can be used with this option:\n" -" * LIMIT_PLAYAUDIO_CALLER yes|no (default yes)\n" -" Play sounds to the caller.\n" -" * LIMIT_PLAYAUDIO_CALLEE yes|no\n" -" Play sounds to the callee.\n" -" * LIMIT_TIMEOUT_FILE File to play when time is up.\n" -" * LIMIT_CONNECT_FILE File to play when call begins.\n" -" * LIMIT_WARNING_FILE File to play as warning if 'y' is defined.\n" -" The default is to say the time remaining.\n" -" m([class]) - Provide hold music to the calling party until a requested\n" -" channel answers. A specific MusicOnHold class can be\n" -" specified.\n" -" M(x[^arg]) - Execute the Macro for the *called* channel before connecting\n" -" to the calling channel. Arguments can be specified to the Macro\n" -" using '^' as a delimiter. The Macro can set the variable\n" -" MACRO_RESULT to specify the following actions after the Macro is\n" -" finished executing.\n" -" * ABORT Hangup both legs of the call.\n" -" * CONGESTION Behave as if line congestion was encountered.\n" -" * BUSY Behave as if a busy signal was encountered.\n" -" * CONTINUE Hangup the called party and allow the calling party\n" -" to continue dialplan execution at the next priority.\n" -" * GOTO:<context>^<exten>^<priority> - Transfer the call to the\n" -" specified priority. Optionally, an extension, or\n" -" extension and priority can be specified.\n" -" You cannot use any additional action post answer options in conjunction\n" -" with this option. Also, pbx services are not run on the peer (called) channel,\n" -" so you will not be able to set timeouts via the TIMEOUT() function in this macro.\n" -" n - This option is a modifier for the screen/privacy mode. It specifies\n" -" that no introductions are to be saved in the priv-callerintros\n" -" directory.\n" -" N - This option is a modifier for the screen/privacy mode. It specifies\n" -" that if callerID is present, do not screen the call.\n" -" o - Specify that the CallerID that was present on the *calling* channel\n" -" be set as the CallerID on the *called* channel. This was the\n" -" behavior of Asterisk 1.0 and earlier.\n" -" O([x]) - \"Operator Services\" mode (DAHDI channel to DAHDI channel\n" -" only, if specified on non-DAHDI interface, it will be ignored).\n" -" When the destination answers (presumably an operator services\n" -" station), the originator no longer has control of their line.\n" -" They may hang up, but the switch will not release their line\n" -" until the destination party hangs up (the operator). Specified\n" -" without an arg, or with 1 as an arg, the originator hanging up\n" -" will cause the phone to ring back immediately. With a 2 specified,\n" -" when the \"operator\" flashes the trunk, it will ring their phone\n" -" back.\n" -" p - This option enables screening mode. This is basically Privacy mode\n" -" without memory.\n" -" P([x]) - Enable privacy mode. Use 'x' as the family/key in the database if\n" -" it is provided. The current extension is used if a database\n" -" family/key is not specified.\n" -" r - Indicate ringing to the calling party. Pass no audio to the calling\n" -" party until the called channel has answered.\n" -" S(x) - Hang up the call after 'x' seconds *after* the called party has\n" -" answered the call.\n" -" t - Allow the called party to transfer the calling party by sending the\n" -" DTMF sequence defined in the blindxfer setting in the featuremap section\n" -" of features.conf.\n" -" T - Allow the calling party to transfer the called party by sending the\n" -" DTMF sequence defined in the blindxfer setting in the featuremap section\n" -" of features.conf.\n" -" U(x[^arg]) - Execute via Gosub the routine 'x' for the *called* channel before connecting\n" -" to the calling channel. Arguments can be specified to the Gosub\n" -" using '^' as a delimiter. The Gosub routine can set the variable\n" -" GOSUB_RESULT to specify the following actions after the Gosub returns.\n" -" * ABORT Hangup both legs of the call.\n" -" * CONGESTION Behave as if line congestion was encountered.\n" -" * BUSY Behave as if a busy signal was encountered.\n" -" * CONTINUE Hangup the called party and allow the calling party\n" -" to continue dialplan execution at the next priority.\n" -" * GOTO:<context>^<exten>^<priority> - Transfer the call to the\n" -" specified priority. Optionally, an extension, or\n" -" extension and priority can be specified.\n" -" You cannot use any additional action post answer options in conjunction\n" -" with this option. Also, pbx services are not run on the peer (called) channel,\n" -" so you will not be able to set timeouts via the TIMEOUT() function in this routine.\n" -" w - Allow the called party to enable recording of the call by sending\n" -" the DTMF sequence defined in the automon setting in the featuremap section\n" -" of features.conf.\n" -" W - Allow the calling party to enable recording of the call by sending\n" -" the DTMF sequence defined in the automon setting in the featuremap section\n" -" of features.conf.\n" -" x - Allow the called party to enable recording of the call by sending\n" -" the DTMF sequence defined in the automixmon setting in the featuremap section\n" -" of features.conf.\n" -" X - Allow the calling party to enable recording of the call by sending\n" -" the DTMF sequence defined in the automixmon setting in the featuremap section\n" -" of features.conf.\n"; - -/* RetryDial App by Anthony Minessale II <anthmct@yahoo.com> Jan/2005 */ +static char *app = "Dial"; static char *rapp = "RetryDial"; -static char *rsynopsis = "Place a call, retrying on failure allowing optional exit extension."; -static char *rdescrip = -" RetryDial(announce,sleep,retries,dialargs): This application will attempt to\n" -"place a call using the normal Dial application. If no channel can be reached,\n" -"the 'announce' file will be played. Then, it will wait 'sleep' number of\n" -"seconds before retrying the call. After 'retries' number of attempts, the\n" -"calling channel will continue at the next priority in the dialplan. If the\n" -"'retries' setting is set to 0, this application will retry endlessly.\n" -" While waiting to retry a call, a 1 digit extension may be dialed. If that\n" -"extension exists in either the context defined in ${EXITCONTEXT} or the current\n" -"one, The call will jump to that extension immediately.\n" -" The 'dialargs' are specified in the same format that arguments are provided\n" -"to the Dial application.\n"; enum { OPT_ANNOUNCE = (1 << 0), @@ -2187,8 +2395,8 @@ static int load_module(void) else ast_add_extension2(con, 1, "s", 1, NULL, NULL, "KeepAlive", ast_strdup(""), ast_free_ptr, "app_dial"); - res = ast_register_application(app, dial_exec, synopsis, descrip); - res |= ast_register_application(rapp, retrydial_exec, rsynopsis, rdescrip); + res = ast_register_application_xml(app, dial_exec); + res |= ast_register_application_xml(rapp, retrydial_exec); return res; } diff --git a/apps/app_dictate.c b/apps/app_dictate.c index 86ccad875..b780182e3 100644 --- a/apps/app_dictate.c +++ b/apps/app_dictate.c @@ -40,11 +40,22 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/say.h" #include "asterisk/app.h" -static char *app = "Dictate"; -static char *synopsis = "Virtual Dictation Machine"; -static char *desc = " Dictate([<base_dir>[,<filename>]])\n" -"Start dictation machine using optional base dir for files.\n"; +/*** DOCUMENTATION + <application name="Dictate" language="en_US"> + <synopsis> + Virtual Dictation Machine. + </synopsis> + <syntax> + <parameter name="base_dir" /> + <parameter name="filename" /> + </syntax> + <description> + <para>Start dictation machine using optional <replaceable>base_dir</replaceable> for files.</para> + </description> + </application> + ***/ +static char *app = "Dictate"; typedef enum { DFLAG_RECORD = (1 << 0), @@ -332,7 +343,7 @@ static int unload_module(void) static int load_module(void) { - return ast_register_application(app, dictate_exec, synopsis, desc); + return ast_register_application_xml(app, dictate_exec); } AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Virtual Dictation Machine"); diff --git a/apps/app_directed_pickup.c b/apps/app_directed_pickup.c index 1ead1d772..5f88df85d 100644 --- a/apps/app_directed_pickup.c +++ b/apps/app_directed_pickup.c @@ -43,23 +43,48 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #define PICKUPMARK "PICKUPMARK" -static const char *app = "Pickup"; -static const char *synopsis = "Directed Call Pickup"; -static const char *descrip = -" Pickup([extension[@context][&extension2@[context]...]]): This application can\n" -"pickup any ringing channel that is calling the specified extension. If no\n" -"context is specified, the current context will be used. If you use the special\n" -"string \"PICKUPMARK\" for the context parameter, for example 10@PICKUPMARK,\n" -"this application tries to find a channel which has defined a ${PICKUPMARK}\n" -"channel variable with the same value as \"extension\" (in this example, \"10\").\n" -"When no parameter is specified, the application will pickup a channel matching\n" -"the pickup group of the active channel."; +/*** DOCUMENTATION + <application name="Pickup" language="en_US"> + <synopsis> + Directed extension call pickup. + </synopsis> + <syntax argsep="&"> + <parameter name="ext" argsep="@" required="true"> + <argument name="extension" required="true"/> + <argument name="context" /> + </parameter> + <parameter name="ext2" argsep="@" multiple="true"> + <argument name="extension2" required="true"/> + <argument name="context2"/> + </parameter> + </syntax> + <description> + <para>This application can pickup any ringing channel that is calling + the specified <replaceable>extension</replaceable>. If no <replaceable>context</replaceable> + is specified, the current context will be used. If you use the special string <literal>PICKUPMARK</literal> + for the context parameter, for example 10@PICKUPMARK, this application + tries to find a channel which has defined a <variable>PICKUPMARK</variable> + channel variable with the same value as <replaceable>extension</replaceable> + (in this example, <literal>10</literal>). When no parameter is specified, the application + will pickup a channel matching the pickup group of the active channel.</para> + </description> + </application> + <application name="PickupChan" language="en_US"> + <synopsis> + Pickup a ringing channel. + </synopsis> + <syntax> + <parameter name="channel" required="true" /> + <parameter name="channel2" multiple="true" /> + </syntax> + <description> + <para>This will pickup a specified <replaceable>channel</replaceable> if ringing.</para> + </description> + </application> + ***/ +static const char *app = "Pickup"; static const char *app2 = "PickupChan"; -static const char *synopsis2 = "Pickup a ringing channel"; -static const char *descrip2 = -" PickupChan(channel[&channel...]): This application can pickup any ringing channel\n"; - /*! \todo This application should return a result code, like PICKUPRESULT */ /* Perform actual pickup between two channels */ @@ -248,8 +273,8 @@ static int load_module(void) { int res; - res = ast_register_application(app, pickup_exec, synopsis, descrip); - res |= ast_register_application(app2, pickupchan_exec, synopsis2, descrip2); + res = ast_register_application_xml(app, pickup_exec); + res |= ast_register_application_xml(app2, pickupchan_exec); return res; } diff --git a/apps/app_directory.c b/apps/app_directory.c index b2a5741ed..2b0b6776c 100644 --- a/apps/app_directory.c +++ b/apps/app_directory.c @@ -42,50 +42,78 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/app.h" #include "asterisk/utils.h" -static char *app = "Directory"; +/*** DOCUMENTATION + <application name="Directory" language="en_US"> + <synopsis> + Provide directory of voicemail extensions. + </synopsis> + <syntax> + <parameter name="vm-context"> + <para>This is the context within voicemail.conf to use for the Directory. If not specified and + <literal>searchcontexts=no</literal> in <filename>voicemail.conf</filename>, then <literal>default</literal> + will be assumed.</para> + </parameter> + <parameter name="dial-context" required="false"> + <para>This is the dialplan context to use when looking for an + extension that the user has selected, or when jumping to the + <literal>o</literal> or <literal>a</literal> extension.</para> + </parameter> + <parameter name="options" required="false"> + <optionlist> + <option name="e"> + <para>In addition to the name, also read the extension number to the + caller before presenting dialing options.</para> + </option> + <option name="f"> + <para>Allow the caller to enter the first name of a user in the + directory instead of using the last name. If specified, the + optional number argument will be used for the number of + characters the user should enter.</para> + <argument name="n" required="true" /> + </option> + <option name="l"> + <para>Allow the caller to enter the last name of a user in the + directory. This is the default. If specified, the + optional number argument will be used for the number of + characters the user should enter.</para> + <argument name="n" required="true" /> + </option> + <option name="b"> + <para> Allow the caller to enter either the first or the last name + of a user in the directory. If specified, the optional number + argument will be used for the number of characters the user should enter.</para> + <argument name="n" required="true" /> + </option> + <option name="m"> + <para>Instead of reading each name sequentially and asking for + confirmation, create a menu of up to 8 names.</para> + </option> + <option name="p"> + <para>Pause for n milliseconds after the digits are typed. This is + helpful for people with cellphones, who are not holding the + receiver to their ear while entering DTMF.</para> + <argument name="n" required="true" /> + </option> + </optionlist> + <note><para>Only one of the <replaceable>f</replaceable>, <replaceable>l</replaceable>, or <replaceable>b</replaceable> + options may be specified. <emphasis>If more than one is specified</emphasis>, then Directory will act as + if <replaceable>b</replaceable> was specified. The number + of characters for the user to type defaults to <literal>3</literal>.</para></note> + </parameter> + </syntax> + <description> + <para>This application will present the calling channel with a directory of extensions from which they can search + by name. The list of names and corresponding extensions is retrieved from the + voicemail configuration file, <filename>voicemail.conf</filename>.</para> + <para>This application will immediately exit if one of the following DTMF digits are + received and the extension to jump to exists:</para> + <para><literal>0</literal> - Jump to the 'o' extension, if it exists.</para> + <para><literal>*</literal> - Jump to the 'a' extension, if it exists.</para> + </description> + </application> -static char *synopsis = "Provide directory of voicemail extensions"; -static char *descrip = -" Directory([vm-context][,dial-context[,options]]): This application will present\n" -"the calling channel with a directory of extensions from which they can search\n" -"by name. The list of names and corresponding extensions is retrieved from the\n" -"voicemail configuration file, voicemail.conf.\n" -" This application will immediately exit if one of the following DTMF digits are\n" -"received and the extension to jump to exists:\n" -" 0 - Jump to the 'o' extension, if it exists.\n" -" * - Jump to the 'a' extension, if it exists.\n\n" -" Parameters:\n" -" vm-context - This is the context within voicemail.conf to use for the\n" -" Directory. If not specified and searchcontexts=no in\n" -" voicemail.conf, then \"default\" will be assumed.\n" -" Otherwise, in not specified, all contexts will be searched.\n" -" dial-context - This is the dialplan context to use when looking for an\n" -" extension that the user has selected, or when jumping to the\n" -" 'o' or 'a' extension.\n\n" -" Options:\n" -" e In addition to the name, also read the extension number to the\n" -" caller before presenting dialing options.\n" -" f[(<n>)] Allow the caller to enter the first name of a user in the\n" -" directory instead of using the last name. If specified, the\n" -" optional number argument will be used for the number of\n" -" characters the user should enter.\n" -" l[(<n>)] Allow the caller to enter the last name of a user in the\n" -" directory. This is the default. If specified, the\n" -" optional number argument will be used for the number of\n" -" characters the user should enter.\n" -" b[(<n>)] Allow the caller to enter either the first or the last name\n" -" of a user in the directory. If specified, the optional number\n" -" argument will be used for the number of characters the user\n" -" should enter.\n" -" m Instead of reading each name sequentially and asking for\n" -" confirmation, create a menu of up to 8 names.\n" -" p(<n>) Pause for n milliseconds after the digits are typed. This is\n" -" helpful for people with cellphones, who are not holding the\n" -" receiver to their ear while entering DTMF.\n" -"\n" -" Only one of the f, l, or b options may be specified. If more than one is\n" -" specified, then Directory will act as if 'b' was specified. The number\n" -" of characters for the user to type defaults to 3.\n"; + ***/ +static char *app = "Directory"; /* For simplicity, I'm keeping the format compatible with the voicemail config, but i'm open to suggestions for isolating it */ @@ -809,7 +837,7 @@ static int unload_module(void) static int load_module(void) { - return ast_register_application(app, directory_exec, synopsis, descrip); + return ast_register_application_xml(app, directory_exec); } AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Extension Directory"); diff --git a/apps/app_disa.c b/apps/app_disa.c index 2ed5e15f7..515bdce9c 100644 --- a/apps/app_disa.c +++ b/apps/app_disa.c @@ -45,51 +45,69 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/callerid.h" #include "asterisk/stringfields.h" +/*** DOCUMENTATION + <application name="DISA" language="en_US"> + <synopsis> + Direct Inward System Access. + </synopsis> + <syntax> + <parameter name="passcode|filename" required="true"> + <para>If you need to present a DISA dialtone without entering a password, + simply set <replaceable>passcode</replaceable> to <literal>no-password</literal></para> + <para>You may specified a <replaceable>filename</replaceable> instead of a + <replaceable>passcode</replaceable>, this filename must contain individual passcodes</para> + </parameter> + <parameter name="context"> + <para>Specifies the dialplan context in which the user-entered extension + will be matched. If no context is specified, the DISA application defaults + to the <literal>disa</literal> context. Presumably a normal system will have a special + context set up for DISA use with some or a lot of restrictions.</para> + </parameter> + <parameter name="cid"> + <para>Specifies a new (different) callerid to be used for this call.</para> + </parameter> + <parameter name="mailbox" argsep="@"> + <para>Will cause a stutter-dialtone (indication <emphasis>dialrecall</emphasis>) + to be used, if the specified mailbox contains any new messages.</para> + <argument name="mailbox" required="true" /> + <argument name="context" required="false" /> + </parameter> + <parameter name="options"> + <optionlist> + <option name="n"> + <para>The DISA application will not answer initially.</para> + </option> + <option name="p"> + <para>The extension entered will be considered complete when a <literal>#</literal> + is entered.</para> + </option> + </optionlist> + </parameter> + </syntax> + <description> + <para>The DISA, Direct Inward System Access, application allows someone from + outside the telephone switch (PBX) to obtain an <emphasis>internal</emphasis> system + dialtone and to place calls from it as if they were placing a call from + within the switch. + DISA plays a dialtone. The user enters their numeric passcode, followed by + the pound sign <literal>#</literal>. If the passcode is correct, the user is then given + system dialtone within <replaceable>context</replaceable> on which a call may be placed. + If the user enters an invalid extension and extension <literal>i</literal> exists in the specified + <replaceable>context</replaceable>, it will be used. + </para> + <para>Be aware that using this may compromise the security of your PBX.</para> + <para>The arguments to this application (in <filename>extensions.conf</filename>) allow either + specification of a single global <replaceable>passcode</replaceable> (that everyone uses), or + individual passcodes contained in a file (<replaceable>filename</replaceable>).</para> + <para>The file that contains the passcodes (if used) allows a complete + specification of all of the same arguments available on the command + line, with the sole exception of the options. The file may contain blank + lines, or comments starting with <literal>#</literal> or <literal>;</literal>.</para> + </description> + </application> + ***/ static char *app = "DISA"; -static char *synopsis = "DISA (Direct Inward System Access)"; - -static char *descrip = -"DISA(<numeric passcode>[,<context>[,<cid>[,mailbox[,options]]]]) or\n" -"DISA(<filename>[,,,,options])\n" -"The DISA, Direct Inward System Access, application allows someone from \n" -"outside the telephone switch (PBX) to obtain an \"internal\" system \n" -"dialtone and to place calls from it as if they were placing a call from \n" -"within the switch.\n" -"DISA plays a dialtone. The user enters their numeric passcode, followed by\n" -"the pound sign (#). If the passcode is correct, the user is then given\n" -"system dialtone within <context> on which a call may be placed. If the user\n" -"enters an invalid extension and extension \"i\" exists in the specified\n" -"context, it will be used.\n" -"\n" -"If you need to present a DISA dialtone without entering a password, simply\n" -"set <passcode> to \"no-password\".\n" -"\n" -"Be aware that using this may compromise the security of your PBX.\n" -"\n" -"The arguments to this application (in extensions.conf) allow either\n" -"specification of a single global passcode (that everyone uses), or\n" -"individual passcodes contained in a file.\n" -"\n" -"The file that contains the passcodes (if used) allows a complete\n" -"specification of all of the same arguments available on the command\n" -"line, with the sole exception of the options. The file may contain blank\n" -"lines, or comments starting with \"#\" or \";\".\n" -"\n" -"<context> specifies the dialplan context in which the user-entered extension\n" -"will be matched. If no context is specified, the DISA application defaults\n" -"the context to \"disa\". Presumably a normal system will have a special\n" -"context set up for DISA use with some or a lot of restrictions.\n" -"\n" -"<cid> specifies a new (different) callerid to be used for this call.\n" -"\n" -"<mailbox[@context]> will cause a stutter-dialtone (indication \"dialrecall\")\n" -"to be used, if the specified mailbox contains any new messages.\n" -"\n" -"The following options are available:\n" -" n - the DISA application will not answer initially.\n" -" p - the extension entered will be considered complete when a '#' is entered.\n"; - enum { NOANSWER_FLAG = (1 << 0), POUND_TO_END_FLAG = (1 << 1), @@ -363,7 +381,7 @@ static int unload_module(void) static int load_module(void) { - return ast_register_application(app, disa_exec, synopsis, descrip) ? + return ast_register_application_xml(app, disa_exec) ? AST_MODULE_LOAD_DECLINE : AST_MODULE_LOAD_SUCCESS; } diff --git a/apps/app_dumpchan.c b/apps/app_dumpchan.c index 7742633fd..e2300dbea 100644 --- a/apps/app_dumpchan.c +++ b/apps/app_dumpchan.c @@ -36,15 +36,26 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/module.h" #include "asterisk/channel.h" -static char *app = "DumpChan"; -static char *synopsis = "Dump Info About The Calling Channel"; -static char *desc = - " DumpChan([<min_verbose_level>])\n" - "Displays information on channel and listing of all channel\n" - "variables. If min_verbose_level is specified, output is only\n" - "displayed when the verbose level is currently set to that number\n" - "or greater. \n"; +/*** DOCUMENTATION + <application name="DumpChan" language="en_US"> + <synopsis> + Dump Info About The Calling Channel. + </synopsis> + <syntax> + <parameter name="level"> + <para>Minimun verbose level</para> + </parameter> + </syntax> + <description> + <para>Displays information on channel and listing of all channel + variables. If <replaceable>level</replaceable> is specified, output is only + displayed when the verbose level is currently set to that number + or greater.</para> + </description> + </application> + ***/ +static char *app = "DumpChan"; static int serialize_showchan(struct ast_channel *c, char *buf, size_t size) { @@ -156,7 +167,7 @@ static int unload_module(void) static int load_module(void) { - return ast_register_application(app, dumpchan_exec, synopsis, desc); + return ast_register_application_xml(app, dumpchan_exec); } AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Dump Info About The Calling Channel"); diff --git a/apps/app_echo.c b/apps/app_echo.c index 76c701cd7..8b0d21f06 100644 --- a/apps/app_echo.c +++ b/apps/app_echo.c @@ -33,15 +33,20 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/module.h" #include "asterisk/channel.h" -static char *app = "Echo"; - -static char *synopsis = "Echo audio, video, or DTMF back to the calling party"; - -static char *descrip = -" Echo(): This application will echo any audio, video, or DTMF frames read from\n" -"the calling channel back to itself. If the DTMF digit '#' is received, the\n" -"application will exit.\n"; +/*** DOCUMENTATION + <application name="Echo" language="en_US"> + <synopsis> + Echo audio, video, DTMF back to the calling party + </synopsis> + <syntax /> + <description> + <para>Echos back any audio, video or DTMF frames read from the calling + channel back to itself. Note: If '#' detected application exits</para> + </description> + </application> + ***/ +static char *app = "Echo"; static int echo_exec(struct ast_channel *chan, void *data) { @@ -81,7 +86,7 @@ static int unload_module(void) static int load_module(void) { - return ast_register_application(app, echo_exec, synopsis, descrip); + return ast_register_application_xml(app, echo_exec); } AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Simple Echo Application"); diff --git a/apps/app_exec.c b/apps/app_exec.c index 285b8b2f0..b4a66962e 100644 --- a/apps/app_exec.c +++ b/apps/app_exec.c @@ -36,6 +36,80 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/module.h" #include "asterisk/app.h" +/*** DOCUMENTATION + <application name="Exec" language="en_US"> + <synopsis> + Executes dialplan application. + </synopsis> + <syntax> + <parameter name="appname" required="true" hasparams="true"> + <para>Application name and arguments of the dialplan application to execute.</para> + <argument name="arguments" required="true" /> + </parameter> + </syntax> + <description> + <para>Allows an arbitrary application to be invoked even when not + hardcoded into the dialplan. If the underlying application + terminates the dialplan, or if the application cannot be found, + Exec will terminate the dialplan.</para> + <para>To invoke external applications, see the application System. + If you would like to catch any error instead, see TryExec.</para> + </description> + </application> + <application name="TryExec" language="en_US"> + <synopsis> + Executes dialplan application, always returning. + </synopsis> + <syntax> + <parameter name="appname" required="true" hasparams="true"> + <argument name="arguments" required="true" /> + </parameter> + </syntax> + <description> + <para>Allows an arbitrary application to be invoked even when not + hardcoded into the dialplan. To invoke external applications + see the application System. Always returns to the dialplan. + The channel variable TRYSTATUS will be set to one of: + </para> + <variablelist> + <variable name="TRYSTATUS"> + <value name="SUCCESS"> + If the application returned zero. + </value> + <value name="FAILED"> + If the application returned non-zero. + </value> + <value name="NOAPP"> + If the application was not found or was not specified. + </value> + </variable> + </variablelist> + </description> + </application> + <application name="ExecIf" language="en_US"> + <synopsis> + Executes dialplan application, conditionally. + </synopsis> + <syntax argsep="?"> + <parameter name="expression" required="true" /> + <parameter name="execapp" required="true" argsep=":"> + <argument name="appiftrue" required="true" hasparams="true"> + <argument name="args" required="true" /> + </argument> + <argument name="appiffalse" required="false" hasparams="true"> + <argument name="args" required="true" /> + </argument> + </parameter> + </syntax> + <description> + <para>If <replaceable>expr</replaceable> is true, execute and return the + result of <replaceable>appiftrue(args)</replaceable>.</para> + <para>If <replaceable>expr</replaceable> is true, but <replaceable>appiftrue</replaceable> is not found, + then the application will return a non-zero value.</para> + </description> + </application> + ***/ + /* Maximum length of any variable */ #define MAXRESULT 1024 @@ -52,35 +126,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") */ static char *app_exec = "Exec"; -static char *exec_synopsis = "Executes dialplan application"; -static char *exec_descrip = -" Exec(appname(arguments)):\n" -"Allows an arbitrary application to be invoked even when not\n" -"hardcoded into the dialplan. If the underlying application\n" -"terminates the dialplan, or if the application cannot be found,\n" -"Exec will terminate the dialplan.\n" -" To invoke external applications, see the application System.\n" -" If you would like to catch any error instead, see TryExec.\n"; - static char *app_tryexec = "TryExec"; -static char *tryexec_synopsis = "Executes dialplan application, always returning"; -static char *tryexec_descrip = -" TryExec(appname(arguments)):\n" -"Allows an arbitrary application to be invoked even when not\n" -"hardcoded into the dialplan. To invoke external applications\n" -"see the application System. Always returns to the dialplan.\n" -"The channel variable TRYSTATUS will be set to one of:\n" -" SUCCESS if the application returned zero\n" -" FAILED if the application returned non-zero\n" -" NOAPP if the application was not found or was not specified\n"; - static char *app_execif = "ExecIf"; -static char *execif_synopsis = "Executes dialplan application, conditionally"; -static char *execif_descrip = -" ExecIF (<expr>?<appiftrue>(<args>)[:<appiffalse>(<args>)])\n" -"If <expr> is true, execute and return the result of <appiftrue>(<args>).\n" -"If <expr> is true, but <appiftrue> is not found, then the application\n" -"will return a non-zero value.\n"; static int exec_exec(struct ast_channel *chan, void *data) { @@ -237,9 +284,9 @@ static int unload_module(void) static int load_module(void) { - int res = ast_register_application(app_exec, exec_exec, exec_synopsis, exec_descrip); - res |= ast_register_application(app_tryexec, tryexec_exec, tryexec_synopsis, tryexec_descrip); - res |= ast_register_application(app_execif, execif_exec, execif_synopsis, execif_descrip); + int res = ast_register_application_xml(app_exec, exec_exec); + res |= ast_register_application_xml(app_tryexec, tryexec_exec); + res |= ast_register_application_xml(app_execif, execif_exec); return res; } diff --git a/apps/app_fax.c b/apps/app_fax.c index 9d72f3fe1..41d76b4bf 100644 --- a/apps/app_fax.c +++ b/apps/app_fax.c @@ -41,60 +41,105 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/module.h" #include "asterisk/manager.h" -static char *app_sndfax_name = "SendFAX"; -static char *app_sndfax_synopsis = "Send a FAX"; -static char *app_sndfax_desc = -" SendFAX(filename[|options]):\n" -"Send a given TIFF file to the channel as a FAX.\n" -"The option string may contain zero or more of the following characters:\n" -" 'a' - makes the application behave as an answering machine\n" -" The default behaviour is to behave as a calling machine.\n" -"\n" -"This application uses following variables:\n" -" LOCALSTATIONID to identify itself to the remote end.\n" -" LOCALHEADERINFO to generate a header line on each page.\n" -"\n" -"This application sets the following channel variables upon completion:\n" -" FAXSTATUS - status of operation:\n" -" SUCCESS | FAILED\n" -" FAXERROR - Error when FAILED\n" -" FAXMODE - Mode used:\n" -" audio | T38\n" -" REMOTESTATIONID - CSID of the remote side.\n" -" FAXPAGES - number of pages sent.\n" -" FAXBITRATE - transmition rate.\n" -" FAXRESOLUTION - resolution.\n" -"\n" -"Returns -1 in case of user hang up or any channel error.\n" -"Returns 0 on success.\n"; +/*** DOCUMENTATION + <application name="SendFAX" language="en_US"> + <synopsis> + Send a Fax + </synopsis> + <syntax> + <parameter name="filename" required="true"> + <para>Filename of TIFF file to fax</para> + </parameter> + <parameter name="a" required="false"> + <para>Makes the application behave as the answering machine</para> + <para>(Default behavior is as calling machine)</para> + </parameter> + </syntax> + <description> + <para>Send a given TIFF file to the channel as a FAX.</para> + <para>This application sets the following channel variables:</para> + <variablelist> + <variable name="LOCALSTATIONID"> + <para>To identify itself to the remote end</para> + </variable> + <variable name="LOCALHEADERINFO"> + <para>To generate a header line on each page</para> + </variable> + <variable name="FAXSTATUS"> + <value name="SUCCESS"/> + <value name="FAILED"/> + </variable> + <variable name="FAXERROR"> + <para>Cause of failure</para> + </variable> + <variable name="REMOTESTATIONID"> + <para>The CSID of the remote side</para> + </variable> + <variable name="FAXPAGES"> + <para>Number of pages sent</para> + </variable> + <variable name="FAXBITRATE"> + <para>Transmission rate</para> + </variable> + <variable name="FAXRESOLUTION"> + <para>Resolution of sent fax</para> + </variable> + </variablelist> + </description> + </application> + <application name="ReceiveFAX" language="en_US"> + <synopsis> + Receive a Fax + </synopsis> + <syntax> + <parameter name="filename" required="true"> + <para>Filename of TIFF file save incoming fax</para> + </parameter> + <parameter name="c" required="false"> + <para>Makes the application behave as the calling machine</para> + <para>(Default behavior is as answering machine)</para> + </parameter> + </syntax> + <description> + <para>Receives a FAX from the channel into the given filename + overwriting the file if it already exists.</para> + <para>File created will be in TIFF format.</para> + + <para>This application sets the following channel variables:</para> + <variablelist> + <variable name="LOCALSTATIONID"> + <para>To identify itself to the remote end</para> + </variable> + <variable name="LOCALHEADERINFO"> + <para>To generate a header line on each page</para> + </variable> + <variable name="FAXSTATUS"> + <value name="SUCCESS"/> + <value name="FAILED"/> + </variable> + <variable name="FAXERROR"> + <para>Cause of failure</para> + </variable> + <variable name="REMOTESTATIONID"> + <para>The CSID of the remote side</para> + </variable> + <variable name="FAXPAGES"> + <para>Number of pages sent</para> + </variable> + <variable name="FAXBITRATE"> + <para>Transmission rate</para> + </variable> + <variable name="FAXRESOLUTION"> + <para>Resolution of sent fax</para> + </variable> + </variablelist> + </description> + </application> + + ***/ +static char *app_sndfax_name = "SendFAX"; static char *app_rcvfax_name = "ReceiveFAX"; -static char *app_rcvfax_synopsis = "Receive a FAX"; -static char *app_rcvfax_desc = -" ReceiveFAX(filename[|options]):\n" -"Receives a fax from the channel into the given filename overwriting\n" -"the file if it already exists. File created will have TIFF format.\n" -"The option string may contain zero or more of the following characters:\n" -" 'c' -- makes the application behave as a calling machine\n" -" The default behaviour is to behave as an answering machine.\n" -"\n" -"This application uses following variables:\n" -" LOCALSTATIONID to identify itself to the remote end.\n" -" LOCALHEADERINFO to generate a header line on each page.\n" -"\n" -"This application sets the following channel variables upon completion:\n" -" FAXSTATUS - status of operation:\n" -" SUCCESS | FAILED\n" -" FAXERROR - Error when FAILED\n" -" FAXMODE - Mode used:\n" -" audio | T38\n" -" REMOTESTATIONID - CSID of the remote side.\n" -" FAXPAGES - number of pages sent.\n" -" FAXBITRATE - transmition rate.\n" -" FAXRESOLUTION - resolution.\n" -"\n" -"Returns -1 in case of user hang up or any channel error.\n" -"Returns 0 on success.\n"; #define MAX_SAMPLES 240 @@ -753,8 +798,8 @@ static int load_module(void) { int res ; - res = ast_register_application(app_sndfax_name, sndfax_exec, app_sndfax_synopsis, app_sndfax_desc); - res |= ast_register_application(app_rcvfax_name, rcvfax_exec, app_rcvfax_synopsis, app_rcvfax_desc); + res = ast_register_application_xml(app_sndfax_name, sndfax_exec); + res |= ast_register_application_xml(app_rcvfax_name, rcvfax_exec); /* The default SPAN message handler prints to stderr. It is something we do not want */ span_set_message_handler(NULL); diff --git a/apps/app_festival.c b/apps/app_festival.c index 4a929a3e5..82f1bddc5 100644 --- a/apps/app_festival.c +++ b/apps/app_festival.c @@ -53,15 +53,24 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #define MAXLEN 180 #define MAXFESTLEN 2048 -static char *app = "Festival"; - -static char *synopsis = "Say text to the user"; - -static char *descrip = -" Festival(text[,intkeys]): Connect to Festival, send the argument, get back the waveform,\n" -"play it to the user, allowing any given interrupt keys to immediately terminate and return\n" -"the value, or 'any' to allow any number back (useful in dialplan)\n"; +/*** DOCUMENTATION + <application name="Festival" language="en_US"> + <synopsis> + Say text to the user. + </synopsis> + <syntax> + <parameter name="text" required="true" /> + <parameter name="intkeys" /> + </syntax> + <description> + <para>Connect to Festival, send the argument, get back the waveform, play it to the user, + allowing any given interrupt keys to immediately terminate and return the value, or + <literal>any</literal> to allow any number back (useful in dialplan).</para> + </description> + </application> + ***/ +static char *app = "Festival"; static char *socket_receive_file_to_buff(int fd, int *size) { @@ -526,7 +535,7 @@ static int load_module(void) return AST_MODULE_LOAD_DECLINE; } ast_config_destroy(cfg); - return ast_register_application(app, festival_exec, synopsis, descrip); + return ast_register_application_xml(app, festival_exec); } AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Simple Festival Interface"); diff --git a/apps/app_getcpeid.c b/apps/app_getcpeid.c index 6ff051899..9c1009242 100644 --- a/apps/app_getcpeid.c +++ b/apps/app_getcpeid.c @@ -36,15 +36,20 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/module.h" #include "asterisk/adsi.h" +/*** DOCUMENTATION + <application name="GetCPEID" language="en_US"> + <synopsis> + Get ADSI CPE ID. + </synopsis> + <syntax /> + <description> + <para>Obtains and displays ADSI CPE ID and other information in order + to properly setup <filename>dahdi.conf</filename> for on-hook operations.</para> + </description> + </application> + ***/ static char *app = "GetCPEID"; -static char *synopsis = "Get ADSI CPE ID"; - -static char *descrip = -" GetCPEID(): Obtains and displays ADSI CPE ID and other information in order\n" -"to properly setup dahdi.conf for on-hook operations.\n"; - - static int cpeid_setstatus(struct ast_channel *chan, char *stuff[], int voice) { int justify[5] = { ADSI_JUST_CENT, ADSI_JUST_LEFT, ADSI_JUST_LEFT, ADSI_JUST_LEFT }; @@ -124,7 +129,7 @@ static int unload_module(void) static int load_module(void) { - return ast_register_application(app, cpeid_exec, synopsis, descrip); + return ast_register_application_xml(app, cpeid_exec); } AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Get ADSI CPE ID"); diff --git a/apps/app_ices.c b/apps/app_ices.c index 1da17369b..4126ad7e9 100644 --- a/apps/app_ices.c +++ b/apps/app_ices.c @@ -45,21 +45,30 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/translate.h" #include "asterisk/app.h" +/*** DOCUMENTATION + <application name="ICES" language="en_US"> + <synopsis> + Encode and stream using 'ices'. + </synopsis> + <syntax> + <parameter name="config" required="true"> + <para>ICES configuration file.</para> + </parameter> + </syntax> + <description> + <para>Streams to an icecast server using ices (available separately). + A configuration file must be supplied for ices (see contrib/asterisk-ices.xml).</para> + <note><para>ICES version 2 cient and server required.</para></note> + </description> + </application> + + ***/ + #define path_BIN "/usr/bin/" #define path_LOCAL "/usr/local/bin/" static char *app = "ICES"; -static char *synopsis = "Encode and stream using 'ices'"; - -static char *descrip = -" ICES(config.xml) Streams to an icecast server using ices\n" -"(available separately). A configuration file must be supplied\n" -"for ices (see contrib/asterisk-ices.xml). \n" -"\n" -"- ICES version 2 cient and server required.\n"; - - static int icesencode(char *filename, int fd) { int res; @@ -199,7 +208,7 @@ static int unload_module(void) static int load_module(void) { - return ast_register_application(app, ices_exec, synopsis, descrip); + return ast_register_application_xml(app, ices_exec); } AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Encode and Stream via icecast and ices"); diff --git a/apps/app_image.c b/apps/app_image.c index ac44495e3..e74397c0d 100644 --- a/apps/app_image.c +++ b/apps/app_image.c @@ -35,16 +35,35 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") static char *app = "SendImage"; -static char *synopsis = "Send an image file"; - -static char *descrip = -" SendImage(filename): Sends an image on a channel.\n" -"Result of transmission will be stored in SENDIMAGESTATUS\n" -"channel variable:\n" -" SUCCESS Transmission succeeded\n" -" FAILURE Transmission failed\n" -" UNSUPPORTED Image transmission not supported by channel\n"; - +/*** DOCUMENTATION + <application name="SendImage" language="en_US"> + <synopsis> + Sends an image file. + </synopsis> + <syntax> + <parameter name="filename" required="true"> + <para>Path of the filename (image) to send.</para> + </parameter> + </syntax> + <description> + <para>Send an image file on a channel supporting it.</para> + <para>Result of transmission will be stored in <variable>SENDIMAGESTATUS</variable></para> + <variablelist> + <variable name="SENDIMAGESTATUS"> + <value name="SUCCESS"> + Transmission succeeded. + </value> + <value name="FAILURE"> + Transmission failed. + </value> + <value name="UNSUPPORTED"> + Image transmission not supported by channel. + </value> + </variable> + </variablelist> + </description> + </application> + ***/ static int sendimage_exec(struct ast_channel *chan, void *data) { @@ -76,7 +95,7 @@ static int unload_module(void) static int load_module(void) { - return ast_register_application(app, sendimage_exec, synopsis, descrip); + return ast_register_application_xml(app, sendimage_exec); } AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Image Transmission Application"); diff --git a/apps/app_jack.c b/apps/app_jack.c index 4da4c9f8b..14546b3c4 100644 --- a/apps/app_jack.c +++ b/apps/app_jack.c @@ -73,18 +73,46 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") " running.\n" \ " c(<name>) - By default, Asterisk will use the channel name for the jack client\n" \ " name. Use this option to specify a custom client name.\n" - +/*** DOCUMENTATION + <application name="JACK" language="en_US"> + <synopsis> + Jack Audio Connection Kit + </synopsis> + <syntax> + <parameter name="options" required="false"> + <optionlist> + <option name="s"> + <argument name="name" required="true"> + <para>Connect to the specified jack server name</para> + </argument> + </option> + <option name="i"> + <argument name="name" required="true"> + <para>Connect the output port that gets created to the specified jack input port</para> + </argument> + </option> + <option name="o"> + <argument name="name" required="true"> + <para>Connect the input port that gets created to the specified jack output port</para> + </argument> + </option> + <option name="c"> + <argument name="name" required="true"> + <para>By default, Asterisk will use the channel name for the jack client name.</para> + <para>Use this option to specify a custom client name.</para> + </argument> + </option> + </optionlist> + </parameter> + </syntax> + <description> + <para>When executing this application, two jack ports will be created; + one input and one output. Other applications can be hooked up to + these ports to access audio coming from, or being send to the channel.</para> + </description> + </application> + ***/ static char *jack_app = "JACK"; -static char *jack_synopsis = -"JACK (Jack Audio Connection Kit) Application"; -static char *jack_desc = -"JACK([options])\n" -" When this application is executed, two jack ports will be created; one input\n" -"and one output. Other applications can be hooked up to these ports to access\n" -"the audio coming from, or being sent to the channel.\n" -" Valid options:\n" -COMMON_OPTIONS -""; struct jack_data { AST_DECLARE_STRING_FIELDS( @@ -982,7 +1010,7 @@ static int unload_module(void) static int load_module(void) { - if (ast_register_application(jack_app, jack_exec, jack_synopsis, jack_desc)) { + if (ast_register_application_xml(jack_app, jack_exec)) { return AST_MODULE_LOAD_DECLINE; } diff --git a/apps/app_milliwatt.c b/apps/app_milliwatt.c index 89063096c..4c6a9ea4c 100644 --- a/apps/app_milliwatt.c +++ b/apps/app_milliwatt.c @@ -37,16 +37,29 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/channel.h" #include "asterisk/pbx.h" -static char *app = "Milliwatt"; - -static char *synopsis = "Generate a Constant 1004Hz tone at 0dbm (mu-law)"; +/*** DOCUMENTATION + <application name="Milliwatt" language="en_US"> + <synopsis> + Generate a Constant 1004Hz tone at 0dbm (mu-law). + </synopsis> + <syntax> + <parameter name="options"> + <optionlist> + <option name="o"> + <para>Generate the tone at 1000Hz like previous version.</para> + </option> + </optionlist> + </parameter> + </syntax> + <description> + <para>Previous versions of this application generated the tone at 1000Hz. If for + some reason you would prefer that behavior, supply the <literal>o</literal> option to get the + old behavior.</para> + </description> + </application> + ***/ -static char *descrip = -" Milliwatt([options]): Generate a Constant 1004Hz tone at 0dbm.\n" -"Previous versions of this application generated the tone at 1000Hz. If for\n" -"some reason you would prefer that behavior, supply the 'o' option to get the\n" -"old behavior.\n" -""; +static char *app = "Milliwatt"; static char digital_milliwatt[] = {0x1e,0x0b,0x0b,0x1e,0x9e,0x8b,0x8b,0x9e} ; @@ -161,7 +174,7 @@ static int unload_module(void) static int load_module(void) { - return ast_register_application(app, milliwatt_exec, synopsis, descrip); + return ast_register_application_xml(app, milliwatt_exec); } AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Digital Milliwatt (mu-law) Test Application"); diff --git a/apps/app_mixmonitor.c b/apps/app_mixmonitor.c index 0adaa62fe..2955455d3 100644 --- a/apps/app_mixmonitor.c +++ b/apps/app_mixmonitor.c @@ -46,38 +46,78 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/app.h" #include "asterisk/channel.h" +/*** DOCUMENTATION + <application name="MixMonitor" language="en_US"> + <synopsis> + Record a call and mix the audio during the recording. + </synopsis> + <syntax> + <parameter name="file" required="true" argsep="."> + <argument name="filename" required="true"> + <para>If <replaceable>filename</replaceable> is an absolute path, uses that path, otherwise + creates the file in the configured monitoring directory from <filename>asterisk.conf.</filename></para> + </argument> + <argument name="extension" required="true" /> + </parameter> + <parameter name="options"> + <optionlist> + <option name="a"> + <para>Append to the file instead of overwriting it.</para> + </option> + <option name="b"> + <para>Only save audio to the file while the channel is bridged.</para> + <note><para>Does not include conferences or sounds played to each bridged party</para></note> + </option> + <option name="v"> + <para>Adjust the <emphasis>heard</emphasis> volume by a factor of <replaceable>x</replaceable> + (range <literal>-4</literal> to <literal>4</literal>)</para> + <argument name="x" required="true" /> + </option> + <option name="V"> + <para>Adjust the <emphasis>spoken</emphasis> volume by a factor + of <replaceable>x</replaceable> (range <literal>-4</literal> to <literal>4</literal>)</para> + <argument name="x" required="true" /> + </option> + <option name="W"> + <para>Adjust both, <emphasis>heard and spoken</emphasis> volumes by a factor + of <replaceable>x</replaceable> (range <literal>-4</literal> to <literal>4</literal>)</para> + <argument name="x" required="true" /> + </option> + </optionlist> + </parameter> + <parameter name="command"> + <para>Will be executed when the recording is over.</para> + <para>Any strings matching <literal>^{X}</literal> will be unescaped to <variable>X</variable>.</para> + <para>All variables will be evaluated at the time MixMonitor is called.</para> + </parameter> + </syntax> + <description> + <para>Records the audio on the current channel to the specified file.</para> + <variablelist> + <variable name="MIXMONITOR_FILENAME"> + <para>Will contain the filename used to record.</para> + </variable> + </variablelist> + </description> + </application> + <application name="StopMixMonitor" language="en_US"> + <synopsis> + Stop recording a call through MixMonitor. + </synopsis> + <syntax /> + <description> + <para>Stops the audio recording that was started with a call to <literal>MixMonitor()</literal> + on the current channel.</para> + </description> + </application> + + ***/ + #define get_volfactor(x) x ? ((x > 0) ? (1 << x) : ((1 << abs(x)) * -1)) : 0 static const char *app = "MixMonitor"; -static const char *synopsis = "Record a call and mix the audio during the recording"; -static const char *desc = "" -" MixMonitor(<file>.<ext>[,<options>[,<command>]]):\n" -"Records the audio on the current channel to the specified file.\n" -"If the filename is an absolute path, uses that path, otherwise\n" -"creates the file in the configured monitoring directory from\n" -"asterisk.conf.\n\n" -"Valid options:\n" -" a - Append to the file instead of overwriting it.\n" -" b - Only save audio to the file while the channel is bridged.\n" -" Note: Does not include conferences or sounds played to each bridged\n" -" party.\n" -" v(<x>) - Adjust the heard volume by a factor of <x> (range -4 to 4)\n" -" V(<x>) - Adjust the spoken volume by a factor of <x> (range -4 to 4)\n" -" W(<x>) - Adjust the both heard and spoken volumes by a factor of <x>\n" -" (range -4 to 4)\n\n" -"<command> will be executed when the recording is over\n" -"Any strings matching ^{X} will be unescaped to ${X}.\n" -"All variables will be evaluated at the time MixMonitor is called.\n" -"The variable MIXMONITOR_FILENAME will contain the filename used to record.\n" -""; static const char *stop_app = "StopMixMonitor"; -static const char *stop_synopsis = "Stop recording a call through MixMonitor"; -static const char *stop_desc = "" -" StopMixMonitor():\n" -"Stops the audio recording that was started with a call to MixMonitor()\n" -"on the current channel.\n" -""; struct module_symbols *me; @@ -415,8 +455,8 @@ static int load_module(void) int res; ast_cli_register_multiple(cli_mixmonitor, sizeof(cli_mixmonitor) / sizeof(struct ast_cli_entry)); - res = ast_register_application(app, mixmonitor_exec, synopsis, desc); - res |= ast_register_application(stop_app, stop_mixmonitor_exec, stop_synopsis, stop_desc); + res = ast_register_application_xml(app, mixmonitor_exec); + res |= ast_register_application_xml(stop_app, stop_mixmonitor_exec); return res; } diff --git a/apps/app_morsecode.c b/apps/app_morsecode.c index 455ee04c1..f9005296a 100644 --- a/apps/app_morsecode.c +++ b/apps/app_morsecode.c @@ -34,18 +34,33 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/module.h" #include "asterisk/indications.h" +/*** DOCUMENTATION + <application name="Morsecode" language="en_US"> + <synopsis> + Plays morse code + </synopsis> + <syntax> + <parameter name="string" required="true"> + <para>String to playback as morse code to channel</para> + </parameter> + </syntax> + <description> + <para>Plays the Morse code equivalent of the passed string.</para> + + <para>This application uses the following variables:</para> + <variablelist> + <variable name="MORSEDITLEN"> + <para>Use this value in (ms) for length of dit</para> + </variable> + <variable name="MORSETONE"> + <para>The pitch of the tone in (Hz), default is 800</para> + </variable> + </variablelist> + </description> + </application> + ***/ static char *app_morsecode = "Morsecode"; -static char *morsecode_synopsis = "Plays morse code"; - -static char *morsecode_descrip = -" Morsecode(<string>):\n" -"Plays the Morse code equivalent of the passed string. If the variable\n" -"MORSEDITLEN is set, it will use that value for the length (in ms) of the dit\n" -"(defaults to 80). Additionally, if MORSETONE is set, it will use that tone\n" -"(in Hz). The tone default is 800.\n"; - - static char *morsecode[] = { "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", /* 0-15 */ "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", /* 16-31 */ @@ -159,7 +174,7 @@ static int unload_module(void) static int load_module(void) { - return ast_register_application(app_morsecode, morsecode_exec, morsecode_synopsis, morsecode_descrip); + return ast_register_application_xml(app_morsecode, morsecode_exec); } AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Morse code"); diff --git a/apps/app_mp3.c b/apps/app_mp3.c index 23db94fbc..688be6a00 100644 --- a/apps/app_mp3.c +++ b/apps/app_mp3.c @@ -44,16 +44,26 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #define LOCAL_MPG_123 "/usr/local/bin/mpg123" #define MPG_123 "/usr/bin/mpg123" +/*** DOCUMENTATION + <application name="MP3Player" language="en_US"> + <synopsis> + Play an MP3 file or stream. + </synopsis> + <syntax> + <parameter name="Location" required="true"> + <para>Location of the file to be played. + (argument passed to mpg123)</para> + </parameter> + </syntax> + <description> + <para>Executes mpg123 to play the given location, which typically would be a filename or a URL. + User can exit by pressing any key on the dialpad, or by hanging up.</para> + </description> + </application> + + ***/ static char *app = "MP3Player"; -static char *synopsis = "Play an MP3 file or stream"; - -static char *descrip = -" MP3Player(location): Executes mpg123 to play the given location,\n" -"which typically would be a filename or a URL. User can exit by pressing\n" -"any key on the dialpad, or by hanging up."; - - static int mp3play(char *filename, int fd) { int res; @@ -221,7 +231,7 @@ static int unload_module(void) static int load_module(void) { - return ast_register_application(app, mp3_exec, synopsis, descrip); + return ast_register_application_xml(app, mp3_exec); } AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Silly MP3 Application"); diff --git a/apps/app_nbscat.c b/apps/app_nbscat.c index 5bc920f50..dd071ef0e 100644 --- a/apps/app_nbscat.c +++ b/apps/app_nbscat.c @@ -43,6 +43,19 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/translate.h" #include "asterisk/app.h" +/*** DOCUMENTATION + <application name="NBScat" language="en_US"> + <synopsis> + Play an NBS local stream. + </synopsis> + <syntax /> + <description> + <para>Executes nbscat to listen to the local NBS stream. + User can exit by pressing any key.</para> + </description> + </application> + ***/ + #define LOCAL_NBSCAT "/usr/local/bin/nbscat8k" #define NBSCAT "/usr/bin/nbscat8k" @@ -52,13 +65,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") static char *app = "NBScat"; -static char *synopsis = "Play an NBS local stream"; - -static char *descrip = -" NBScat(): Executes nbscat to listen to the local NBS stream.\n" -"User can exit by pressing any key.\n"; - - static int NBScatplay(int fd) { int res; @@ -204,7 +210,7 @@ static int unload_module(void) static int load_module(void) { - return ast_register_application(app, NBScat_exec, synopsis, descrip); + return ast_register_application_xml(app, NBScat_exec); } AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Silly NBS Stream Application"); diff --git a/apps/app_page.c b/apps/app_page.c index 33ff1b489..7aacbd9d6 100644 --- a/apps/app_page.c +++ b/apps/app_page.c @@ -44,24 +44,57 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/devicestate.h" #include "asterisk/dial.h" +/*** DOCUMENTATION + <application name="Page" language="en_US"> + <synopsis> + Page series of phones + </synopsis> + <syntax> + <parameter name="Technology/Resource" required="true" argsep="&"> + <argument name="Technology/Resource" required="true"> + <para>Specification of the device(s) to dial. These must be in the format of + <literal>Technology/Resource</literal>, where <replaceable>Technology</replaceable> + represents a particular channel driver, and <replaceable>Resource</replaceable> represents a resource + available to that particular channel driver.</para> + </argument> + <argument name="Technology2/Resource2" multiple="true"> + <para>Optional extra devices to dial inparallel</para> + <para>If you need more then one enter them as Technology2/Resource2& + Technology3/Resourse3&.....</para> + </argument> + </parameter> + <parameter name="options"> + <optionlist> + <option name="d"> + <para>Full duplex audio</para> + </option> + <option name="q"> + <para>Quiet, do not play beep to caller</para> + </option> + <option name="r"> + <para>Record the page into a file (meetme option <literal>r</literal>)</para> + </option> + <option name="s"> + <para>Only dial channel if devicestate says its <literal>notinuse</literal></para> + </option> + </optionlist> + </parameter> + <parameter name="timeout"> + <para>Specify the length of time that the system will attempt to connect a call. + After this duration, any intercom calls that have not been answered will be hung up by the + system.</para> + </parameter> + </syntax> + <description> + <para>Places outbound calls to the given <replaceable>technology</replaceable>/<replaceable>resource</replaceable> + and dumps them into a conference bridge as muted participants. The original + caller is dumped into the conference as a speaker and the room is + destroyed when the original callers leaves.</para> + </description> + </application> + ***/ static const char *app_page= "Page"; -static const char *page_synopsis = "Pages phones"; - -static const char *page_descrip = -"Page(Technology/Resource&Technology2/Resource2[,options][,timeout])\n" -" Places outbound calls to the given technology / resource and dumps\n" -"them into a conference bridge as muted participants. The original\n" -"caller is dumped into the conference as a speaker and the room is\n" -"destroyed when the original caller leaves. Valid options are:\n" -" d - full duplex audio\n" -" q - quiet, do not play beep to caller\n" -" r - record the page into a file (see 'r' for app_meetme)\n" -" s - only dial channel if devicestate says it is not in use\n" -"The timeout parameter specifies the length of time that the system\n" -"will attempt to connect a call. After this duration, any intercom\n" -"calls that have not been answered will be hung up by the system.\n"; - enum { PAGE_DUPLEX = (1 << 0), PAGE_QUIET = (1 << 1), @@ -216,7 +249,7 @@ static int unload_module(void) static int load_module(void) { - return ast_register_application(app_page, page_exec, page_synopsis, page_descrip); + return ast_register_application_xml(app_page, page_exec); } AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Page Multiple Phones"); diff --git a/apps/app_playback.c b/apps/app_playback.c index 4e6c3f530..63dd30857 100644 --- a/apps/app_playback.c +++ b/apps/app_playback.c @@ -39,26 +39,49 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/say.h" /* provides config-file based 'say' functions */ #include "asterisk/cli.h" -static char *app = "Playback"; - -static char *synopsis = "Play a file"; - -static char *descrip = -" Playback(filename[&filename2...][,option]): Plays back given filenames (do not put\n" -"extension). Options may also be included following a comma.\n" -"The 'skip' option causes the playback of the message to be skipped if the channel\n" -"is not in the 'up' state (i.e. it hasn't been answered yet). If 'skip' is \n" -"specified, the application will return immediately should the channel not be\n" -"off hook. Otherwise, unless 'noanswer' is specified, the channel will\n" -"be answered before the sound is played. Not all channels support playing\n" -"messages while still on hook.\n" -"This application sets the following channel variable upon completion:\n" -" PLAYBACKSTATUS The status of the playback attempt as a text string, one of\n" -" SUCCESS | FAILED\n" -"See Also: Background (application) -- for playing soundfiles that are interruptible\n" -" WaitExten (application) -- wait for digits from caller, optionally play music on hold\n" -; +/*** DOCUMENTATION + <application name="Playback" language="en_US"> + <synopsis> + Play a file. + </synopsis> + <syntax> + <parameter name="filenames" required="true" argsep="&"> + <argument name="filename" required="true" /> + <argument name="filename2" multiple="true" /> + </parameter> + <parameter name="options"> + <para>Comma separated list of options</para> + <optionlist> + <option name="skip"> + <para>Do not play if not answered</para> + </option> + <option name="noanswer"> + <para>Playback without answering, otherwise the channel will + be answered before the sound is played.</para> + <note><para>Not all channel types support playing messages while still on hook.</para></note> + </option> + </optionlist> + </parameter> + </syntax> + <description> + <para>Plays back given filenames (do not put extension of wav/alaw etc). + The playback command answer the channel if no options are specified. + If the file is non-existant it will fail</para> + <para>This application sets the following channel variable upon completion:</para> + <variablelist> + <variable name="PLAYBACKSTATUS"> + <para>The status of the playback attempt as a text string.</para> + <value name="SUCCESS"/> + <value name="FAILED"/> + </variable> + </variablelist> + <para>See Also: Background (application) -- for playing soundfiles that are interruptible</para> + <para>WaitExten (application) -- wait for digits from caller, optionally play music on hold</para> + </description> + </application> + ***/ +static char *app = "Playback"; static struct ast_config *say_cfg = NULL; /* save the say' api calls. @@ -520,7 +543,7 @@ static int load_module(void) } ast_cli_register_multiple(cli_playback, sizeof(cli_playback) / sizeof(struct ast_cli_entry)); - return ast_register_application(app, playback_exec, synopsis, descrip); + return ast_register_application_xml(app, playback_exec); } AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Sound File Playback Application", diff --git a/apps/app_privacy.c b/apps/app_privacy.c index 09f698861..71811de1c 100644 --- a/apps/app_privacy.c +++ b/apps/app_privacy.c @@ -41,25 +41,41 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/app.h" #include "asterisk/config.h" -static char *app = "PrivacyManager"; - -static char *synopsis = "Require phone number to be entered, if no CallerID sent"; +/*** DOCUMENTATION + <application name="PrivacyManager" language="en_US"> + <synopsis> + Require phone number to be entered, if no CallerID sent + </synopsis> + <syntax> + <parameter name="maxretries"> + <para>Total tries caller is allowed to input a callerid. Defaults to <literal>3</literal>.</para> + </parameter> + <parameter name="minlength"> + <para>Minimum allowable digits in the input callerid number. Defaults to <literal>10</literal>.</para> + </parameter> + <parameter name="context"> + <para>Context to check the given callerid against patterns.</para> + </parameter> + </syntax> + <description> + <para>If no Caller*ID is sent, PrivacyManager answers the channel and asks + the caller to enter their phone number. The caller is given + <replaceable>maxretries</replaceable> attempts to do so. The application does + <emphasis>nothing</emphasis> if Caller*ID was received on the channel.</para> + <para>The application sets the following channel variable upon completion:</para> + <variablelist> + <variable name="PRIVACYMGRSTATUS"> + <para>The status of the privacy manager's attempt to collect a phone number from the user.</para> + <value name="SUCCESS"/> + <value name="FAILED"/> + </variable> + </variablelist> + </description> + </application> + ***/ -static char *descrip = - " PrivacyManager([maxretries][,minlength][,context]): If no Caller*ID \n" - "is sent, PrivacyManager answers the channel and asks the caller to\n" - "enter their phone number. The caller is given 'maxretries' attempts to do so.\n" - "The application does nothing if Caller*ID was received on the channel.\n" - " maxretries default 3 -maximum number of attempts the caller is allowed \n" - " to input a callerid.\n" - " minlength default 10 -minimum allowable digits in the input callerid number.\n" - " context context to check the given Caller*ID against patterns.\n" - "The application sets the following channel variable upon completion: \n" - "PRIVACYMGRSTATUS The status of the privacy manager's attempt to collect \n" - " a phone number from the user. A text string that is either:\n" - " SUCCESS | FAILED \n" -; +static char *app = "PrivacyManager"; static int privacy_exec (struct ast_channel *chan, void *data) { @@ -178,7 +194,7 @@ static int unload_module(void) static int load_module(void) { - return ast_register_application(app, privacy_exec, synopsis, descrip); + return ast_register_application_xml(app, privacy_exec); } AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Require phone number to be entered, if no CallerID sent"); diff --git a/apps/app_queue.c b/apps/app_queue.c index 5733d0bc4..bc04deb46 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -108,6 +108,344 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") * to this order! */ +/*** DOCUMENTATION + <application name="Queue" language="en_US"> + <synopsis> + Queue a call for a call queue. + </synopsis> + <syntax> + <parameter name="queuename" required="true" /> + <parameter name="options"> + <optionlist> + <option name="c"> + <para>Continue in the dialplan if the callee hangs up.</para> + </option> + <option name="d"> + <para>data-quality (modem) call (minimum delay).</para> + </option> + <option name="h"> + <para>Allow <emphasis>callee</emphasis> to hang up by pressing <literal>*</literal>.</para> + </option> + <option name="H"> + <para>Allow <emphasis>caller</emphasis> to hang up by pressing <literal>*</literal>.</para> + </option> + <option name="n"> + <para>No retries on the timeout; will exit this application and + go to the next step.</para> + </option> + <option name="i"> + <para>Ignore call forward requests from queue members and do nothing + when they are requested.</para> + </option> + <option name="r"> + <para>Ring instead of playing MOH. Periodic Announcements are still made, if applicable.</para> + </option> + <option name="t"> + <para>Allow the <emphasis>called</emphasis> user to transfer the calling user.</para> + </option> + <option name="T"> + <para>Allow the <emphasis>calling</emphasis> user to transfer the call.</para> + </option> + <option name="w"> + <para>Allow the <emphasis>called</emphasis> user to write the conversation to + disk via Monitor.</para> + </option> + <option name="W"> + <para>Allow the <emphasis>calling</emphasis> user to write the conversation to + disk via Monitor.</para> + </option> + <option name="k"> + <para>Allow the <emphasis>called</emphasis> party to enable parking of the call by sending + the DTMF sequence defined for call parking in <filename>features.conf</filename>.</para> + </option> + <option name="K"> + <para>Allow the <emphasis>calling</emphasis> party to enable parking of the call by sending + the DTMF sequence defined for call parking in <filename>features.conf</filename>.</para> + </option> + <option name="x"> + <para>Allow the <emphasis>called</emphasis> user to write the conversation + to disk via MixMonitor.</para> + </option> + <option name="X"> + <para>Allow the <emphasis>calling</emphasis> user to write the conversation to + disk via MixMonitor.</para> + </option> + </optionlist> + </parameter> + <parameter name="URL"> + <para><replaceable>URL</replaceable> will be sent to the called party if the channel supports it.</para> + </parameter> + <parameter name="announceoverride" /> + <parameter name="timeout"> + <para>Will cause the queue to fail out after a specified number of + seconds, checked between each <filename>queues.conf</filename> <replaceable>timeout</replaceable> and + <replaceable>retry</replaceable> cycle.</para> + </parameter> + <parameter name="AGI"> + <para>Will setup an AGI script to be executed on the calling party's channel once they are + connected to a queue member.</para> + </parameter> + <parameter name="macro"> + <para>Will run a macro on the calling party's channel once they are connected to a queue member.</para> + </parameter> + <parameter name="gosub"> + <para>Will run a gosub on the calling party's channel once they are connected to a queue member.</para> + </parameter> + <parameter name="rule"> + <para>Will cause the queue's defaultrule to be overridden by the rule specified.</para> + </parameter> + </syntax> + <description> + <para>In addition to transferring the call, a call may be parked and then picked + up by another user.</para> + <para>This application will return to the dialplan if the queue does not exist, or + any of the join options cause the caller to not enter the queue.</para> + <para>This application sets the following channel variable upon completion:</para> + <variablelist> + <variable name="QUEUESTATUS"> + <para>The status of the call as a text string.</para> + <value name="TIMEOUT" /> + <value name="FULL" /> + <value name="JOINEMPTY" /> + <value name="LEAVEEMPTY" /> + <value name="JOINUNAVAIL" /> + <value name="LEAVEUNAVAIL" /> + <value name="CONTINUE" /> + </variable> + </variablelist> + </description> + </application> + <application name="AddQueueMember" language="en_US"> + <synopsis> + Dynamically adds queue members. + </synopsis> + <syntax> + <parameter name="queuename" required="true" /> + <parameter name="interface" /> + <parameter name="penalty" /> + <parameter name="options" /> + <parameter name="membername" /> + <parameter name="stateinterface" /> + </syntax> + <description> + <para>Dynamically adds interface to an existing queue. If the interface is + already in the queue it will return an error.</para> + <para>This application sets the following channel variable upon completion:</para> + <variablelist> + <variable name="AQMSTATUS"> + <para>The status of the attempt to add a queue member as a text string.</para> + <value name="ADDED" /> + <value name="MEMBERALREADY" /> + <value name="NOSUCHQUEUE" /> + </variable> + </variablelist> + </description> + </application> + <application name="RemoveQueueMember" language="en_US"> + <synopsis> + Dynamically removes queue members. + </synopsis> + <syntax> + <parameter name="queuename" required="true" /> + <parameter name="interface" /> + <parameter name="options" /> + </syntax> + <description> + <para>If the interface is <emphasis>NOT</emphasis> in the queue it will return an error.</para> + <para>This application sets the following channel variable upon completion:</para> + <variablelist> + <variable name="RQMSTATUS"> + <value name="REMOVED" /> + <value name="NOTINQUEUE" /> + <value name="NOSUCHQUEUE" /> + </variable> + </variablelist> + <para>Example: RemoveQueueMember(techsupport,SIP/3000)</para> + </description> + </application> + <application name="PauseQueueMember" language="en_US"> + <synopsis> + Pauses a queue member. + </synopsis> + <syntax> + <parameter name="queuename" /> + <parameter name="interface" required="true" /> + <parameter name="options" /> + <parameter name="reason"> + <para>Is used to add extra information to the appropriate queue_log entries and manager events.</para> + </parameter> + </syntax> + <description> + <para>Pauses (blocks calls for) a queue member. The given interface will be paused in the given queue. + This prevents any calls from being sent from the queue to the interface until it is + unpaused with UnpauseQueueMember or the manager interface. If no queuename is given, + the interface is paused in every queue it is a member of. The application will fail if the + interface is not found.</para> + <para>This application sets the following channel variable upon completion:</para> + <variablelist> + <variable name="PQMSTATUS"> + <para>The status of the attempt to pause a queue member as a text string.</para> + <value name="PAUSED" /> + <value name="NOTFOUND" /> + </variable> + </variablelist> + <para>Example: PauseQueueMember(,SIP/3000)</para> + </description> + </application> + <application name="UnpauseQueueMember" language="en_US"> + <synopsis> + Unpauses a queue member. + </synopsis> + <syntax> + <parameter name="queuename" /> + <parameter name="interface" required="true" /> + <parameter name="options" /> + <parameter name="reason"> + <para>Is used to add extra information to the appropriate queue_log entries and manager events.</para> + </parameter> + </syntax> + <description> + <para>Unpauses (resumes calls to) a queue member. This is the counterpart to <literal>PauseQueueMember()</literal> + and operates exactly the same way, except it unpauses instead of pausing the given interface.</para> + <para>This application sets the following channel variable upon completion:</para> + <variablelist> + <variable name="UPQMSTATUS"> + <para>The status of the attempt to unpause a queue member as a text string.</para> + <value name="UNPAUSED" /> + <value name="NOTFOUND" /> + </variable> + </variablelist> + <para>Example: UnpauseQueueMember(,SIP/3000)</para> + </description> + </application> + <application name="QueueLog" language="en_US"> + <synopsis> + Writes to the queue_log file. + </synopsis> + <syntax> + <parameter name="queuename" required="true" /> + <parameter name="uniqueid" required="true" /> + <parameter name="agent" required="true" /> + <parameter name="event" required="true" /> + <parameter name="additionalinfo" /> + </syntax> + <description> + <para>Allows you to write your own events into the queue log.</para> + <para>Example: QueueLog(101,${UNIQUEID},${AGENT},WENTONBREAK,600)</para> + </description> + </application> + <function name="QUEUE_VARIABLES" language="en_US"> + <synopsis> + Return Queue information in variables. + </synopsis> + <syntax> + <parameter name="queuename" required="true"> + <enumlist> + <enum name="QUEUEMAX"> + <para>Maxmimum number of calls allowed.</para> + </enum> + <enum name="QUEUESTRATEGY"> + <para>The strategy of the queue.</para> + </enum> + <enum name="QUEUECALLS"> + <para>Number of calls currently in the queue.</para> + </enum> + <enum name="QUEUEHOLDTIME"> + <para>Current average hold time.</para> + </enum> + <enum name="QUEUECOMPLETED"> + <para>Number of completed calls for the queue.</para> + </enum> + <enum name="QUEUEABANDONED"> + <para>Number of abandoned calls.</para> + </enum> + <enum name="QUEUESRVLEVEL"> + <para>Queue service level.</para> + </enum> + <enum name="QUEUESRVLEVELPERF"> + <para>Current service level performance.</para> + </enum> + </enumlist> + </parameter> + </syntax> + <description> + <para>Makes the following queue variables available.</para> + <para>Returns <literal>0</literal> if queue is found and setqueuevar is defined, <literal>-1</literal> otherwise.</para> + </description> + </function> + <function name="QUEUE_MEMBER" language="en_US"> + <synopsis> + Count number of members answering a queue. + </synopsis> + <syntax> + <parameter name="queuename" required="true" /> + <parameter name="option" required="true"> + <enumlist> + <enum name="logged"> + <para>Returns the number of logged-in members for the specified queue.</para> + </enum> + <enum name="free"> + <para>Returns the number of logged-in members for the specified queue available to take a call.</para> + </enum> + <enum name="count"> + <para>Returns the total number of members for the specified queue.</para> + </enum> + </enumlist> + </parameter> + </syntax> + <description> + <para>Returns the number of members currently associated with the specified <replaceable>queuename</replaceable>.</para> + </description> + </function> + <function name="QUEUE_MEMBER_COUNT" language="en_US"> + <synopsis> + Count number of members answering a queue. + </synopsis> + <syntax> + <parameter name="queuename" required="true" /> + </syntax> + <description> + <para>Returns the number of members currently associated with the specified <replaceable>queuename</replaceable>.</para> + <warning><para>This function has been deprecated in favor of the <literal>QUEUE_MEMBER()</literal> function</para></warning> + </description> + </function> + <function name="QUEUE_WAITING_COUNT" language="en_US"> + <synopsis> + Count number of calls currently waiting in a queue. + </synopsis> + <syntax> + <parameter name="queuename" /> + </syntax> + <description> + <para>Returns the number of callers currently waiting in the specified <replaceable>queuename</replaceable>.</para> + </description> + </function> + <function name="QUEUE_MEMBER_LIST" language="en_US"> + <synopsis> + Returns a list of interfaces on a queue. + </synopsis> + <syntax> + <parameter name="queuename" required="true" /> + </syntax> + <description> + <para>Returns a comma-separated list of members associated with the specified <replaceable>queuename</replaceable>.</para> + </description> + </function> + <function name="QUEUE_MEMBER_PENALTY" language="en_US"> + <synopsis> + Gets or sets queue members penalty. + </synopsis> + <syntax> + <parameter name="queuename" required="true" /> + <parameter name="interface" required="true" /> + </syntax> + <description> + <para>Gets or sets queue members penalty.</para> + </description> + </function> + + ***/ + enum { QUEUE_STRATEGY_RINGALL = 0, QUEUE_STRATEGY_LEASTRECENT, @@ -150,128 +488,15 @@ static struct ast_taskprocessor *devicestate_tps; static char *app = "Queue"; -static char *synopsis = "Queue a call for a call queue"; - -static char *descrip = -" Queue(queuename[,options[,URL][,announceoverride][,timeout][,AGI][,macro][,gosub][,rule]):\n" -"Queues an incoming call in a particular call queue as defined in queues.conf.\n" -"This application will return to the dialplan if the queue does not exist, or\n" -"any of the join options cause the caller to not enter the queue.\n" -"The option string may contain zero or more of the following characters:\n" -" 'c' -- continue in the dialplan if the callee hangs up.\n" -" 'd' -- data-quality (modem) call (minimum delay).\n" -" 'h' -- allow callee to hang up by hitting '*', or whatver disconnect sequence\n" -" that is defined in the featuremap section in features.conf.\n" -" 'H' -- allow caller to hang up by hitting '*', or whatever disconnect sequence\n" -" that is defined in the featuremap section in features.conf.\n" -" 'n' -- no retries on the timeout; will exit this application and \n" -" go to the next step.\n" -" 'i' -- ignore call forward requests from queue members and do nothing\n" -" when they are requested.\n" -" 'r' -- ring instead of playing MOH. Periodic Announcements are still made, if applicable.\n" -" 't' -- allow the called user transfer the calling user by pressing '#' or\n" -" whatever blindxfer sequence defined in the featuremap section in\n" -" features.conf\n" -" 'T' -- to allow the calling user to transfer the call by pressing '#' or\n" -" whatever blindxfer sequence defined in the featuremap section in\n" -" features.conf\n" -" 'w' -- allow the called user to write the conversation to disk via Monitor\n" -" by pressing the automon sequence defined in the featuremap section in\n" -" features.conf\n" -" 'W' -- allow the calling user to write the conversation to disk via Monitor\n" -" by pressing the automon sequence defined in the featuremap section in\n" -" features.conf\n" -" 'k' -- Allow the called party to enable parking of the call by sending\n" -" the DTMF sequence defined for call parking in features.conf.\n" -" 'K' -- Allow the calling party to enable parking of the call by sending\n" -" the DTMF sequence defined for call parking in features.conf.\n" -" 'x' -- allow the called user to write the conversation to disk via MixMonitor\n" -" by pressing the automixmon sequence defined in the featuremap section in\n" -" features.conf\n" -" 'X' -- allow the calling user to write the conversation to disk via MixMonitor\n" -" by pressing the automixmon sequence defined in the featuremap section in\n" -" features.conf\n" -" The optional URL will be sent to the called party if the channel supports\n" -"it.\n" -" The optional AGI parameter will setup an AGI script to be executed on the \n" -"calling party's channel once they are connected to a queue member.\n" -" The optional macro parameter will run a macro on the \n" -"calling party's channel once they are connected to a queue member.\n" -" The optional gosub parameter will run a gosub on the \n" -"calling party's channel once they are connected to a queue member.\n" -" The optional rule parameter will cause the queue's defaultrule to be\n" -"overridden by the rule specified.\n" -" The timeout will cause the queue to fail out after a specified number of\n" -"seconds, checked between each queues.conf 'timeout' and 'retry' cycle.\n" -" This application sets the following channel variable upon completion:\n" -" QUEUESTATUS The status of the call as a text string, one of\n" -" TIMEOUT | FULL | JOINEMPTY | LEAVEEMPTY | JOINUNAVAIL | LEAVEUNAVAIL | CONTINUE\n"; - static char *app_aqm = "AddQueueMember" ; -static char *app_aqm_synopsis = "Dynamically adds queue members" ; -static char *app_aqm_descrip = -" AddQueueMember(queuename[,interface[,penalty[,options[,membername[,stateinterface]]]]]):\n" -"Dynamically adds interface to an existing queue.\n" -"If the interface is already in the queue it will return an error.\n" -" This application sets the following channel variable upon completion:\n" -" AQMSTATUS The status of the attempt to add a queue member as a \n" -" text string, one of\n" -" ADDED | MEMBERALREADY | NOSUCHQUEUE \n" -"Example: AddQueueMember(techsupport,SIP/3000)\n" -""; static char *app_rqm = "RemoveQueueMember" ; -static char *app_rqm_synopsis = "Dynamically removes queue members" ; -static char *app_rqm_descrip = -" RemoveQueueMember(queuename[,interface[,options]]):\n" -"Dynamically removes interface to an existing queue\n" -"If the interface is NOT in the queue it will return an error.\n" -" This application sets the following channel variable upon completion:\n" -" RQMSTATUS The status of the attempt to remove a queue member as a\n" -" text string, one of\n" -" REMOVED | NOTINQUEUE | NOSUCHQUEUE \n" -"Example: RemoveQueueMember(techsupport,SIP/3000)\n" -""; static char *app_pqm = "PauseQueueMember" ; -static char *app_pqm_synopsis = "Pauses a queue member" ; -static char *app_pqm_descrip = -" PauseQueueMember([queuename],interface[,options[,reason]]):\n" -"Pauses (blocks calls for) a queue member.\n" -"The given interface will be paused in the given queue. This prevents\n" -"any calls from being sent from the queue to the interface until it is\n" -"unpaused with UnpauseQueueMember or the manager interface. If no\n" -"queuename is given, the interface is paused in every queue it is a\n" -"member of. The application will fail if the interface is not found.\n" -"The reason string is entirely optional and is used to add extra information\n" -"to the appropriate queue_log entries and manager events.\n" -" This application sets the following channel variable upon completion:\n" -" PQMSTATUS The status of the attempt to pause a queue member as a\n" -" text string, one of\n" -" PAUSED | NOTFOUND\n" -"Example: PauseQueueMember(,SIP/3000)\n"; static char *app_upqm = "UnpauseQueueMember" ; -static char *app_upqm_synopsis = "Unpauses a queue member" ; -static char *app_upqm_descrip = -" UnpauseQueueMember([queuename],interface[,options[,reason]]):\n" -"Unpauses (resumes calls to) a queue member.\n" -"This is the counterpart to PauseQueueMember and operates exactly the\n" -"same way, except it unpauses instead of pausing the given interface.\n" -"The reason string is entirely optional and is used to add extra information\n" -"to the appropriate queue_log entries and manager events.\n" -" This application sets the following channel variable upon completion:\n" -" UPQMSTATUS The status of the attempt to unpause a queue \n" -" member as a text string, one of\n" -" UNPAUSED | NOTFOUND\n" -"Example: UnpauseQueueMember(,SIP/3000)\n"; static char *app_ql = "QueueLog" ; -static char *app_ql_synopsis = "Writes to the queue_log" ; -static char *app_ql_descrip = -" QueueLog(queuename,uniqueid,agent,event[,additionalinfo]):\n" -"Allows you to write your own events into the queue log\n" -"Example: QueueLog(101,${UNIQUEID},${AGENT},WENTONBREAK,600)\n"; /*! \brief Persistent Members astdb family */ static const char *pm_family = "Queue/PersistentMembers"; @@ -5088,69 +5313,31 @@ static int queue_function_memberpenalty_write(struct ast_channel *chan, const ch static struct ast_custom_function queuevar_function = { .name = "QUEUE_VARIABLES", - .synopsis = "Return Queue information in variables", - .syntax = "QUEUE_VARIABLES(<queuename>)", - .desc = -"Makes the following queue variables available.\n" -"QUEUEMAX maxmimum number of calls allowed\n" -"QUEUESTRATEGY the strategy of the queue\n" -"QUEUECALLS number of calls currently in the queue\n" -"QUEUEHOLDTIME current average hold time\n" -"QUEUECOMPLETED number of completed calls for the queue\n" -"QUEUEABANDONED number of abandoned calls\n" -"QUEUESRVLEVEL queue service level\n" -"QUEUESRVLEVELPERF current service level performance\n" -"Returns 0 if queue is found and setqueuevar is defined, -1 otherwise", .read = queue_function_var, }; static struct ast_custom_function queuemembercount_function = { .name = "QUEUE_MEMBER", - .synopsis = "Count number of members answering a queue", - .syntax = "QUEUE_MEMBER(<queuename>, <option>)", - .desc = -"Returns the number of members currently associated with the specified queue.\n" -"One of three options may be passed to determine the count returned:\n" - "\"logged\" - Returns the number of logged-in members for the specified queue\n" - "\"free\" - Returns the number of logged-in members for the specified queue available to take a call\n" - "\"count\" - Returns the total number of members for the specified queue\n", .read = queue_function_qac, }; static struct ast_custom_function queuemembercount_dep = { .name = "QUEUE_MEMBER_COUNT", - .synopsis = "Count number of members answering a queue", - .syntax = "QUEUE_MEMBER_COUNT(<queuename>)", - .desc = -"Returns the number of members currently associated with the specified queue.\n\n" -"This function has been deprecated in favor of the QUEUE_MEMBER function\n", .read = queue_function_qac_dep, }; static struct ast_custom_function queuewaitingcount_function = { .name = "QUEUE_WAITING_COUNT", - .synopsis = "Count number of calls currently waiting in a queue", - .syntax = "QUEUE_WAITING_COUNT(<queuename>)", - .desc = -"Returns the number of callers currently waiting in the specified queue.\n", .read = queue_function_queuewaitingcount, }; static struct ast_custom_function queuememberlist_function = { .name = "QUEUE_MEMBER_LIST", - .synopsis = "Returns a list of interfaces on a queue", - .syntax = "QUEUE_MEMBER_LIST(<queuename>)", - .desc = -"Returns a comma-separated list of members associated with the specified queue.\n", .read = queue_function_queuememberlist, }; static struct ast_custom_function queuememberpenalty_function = { .name = "QUEUE_MEMBER_PENALTY", - .synopsis = "Gets or sets queue members penalty.", - .syntax = "QUEUE_MEMBER_PENALTY(<queuename>,<interface>)", - .desc = -"Gets or sets queue members penalty\n", .read = queue_function_memberpenalty_read, .write = queue_function_memberpenalty_write, }; @@ -6430,12 +6617,12 @@ static int load_module(void) reload_queue_members(); ast_cli_register_multiple(cli_queue, sizeof(cli_queue) / sizeof(struct ast_cli_entry)); - res = ast_register_application(app, queue_exec, synopsis, descrip); - res |= ast_register_application(app_aqm, aqm_exec, app_aqm_synopsis, app_aqm_descrip); - res |= ast_register_application(app_rqm, rqm_exec, app_rqm_synopsis, app_rqm_descrip); - res |= ast_register_application(app_pqm, pqm_exec, app_pqm_synopsis, app_pqm_descrip); - res |= ast_register_application(app_upqm, upqm_exec, app_upqm_synopsis, app_upqm_descrip); - res |= ast_register_application(app_ql, ql_exec, app_ql_synopsis, app_ql_descrip); + res = ast_register_application_xml(app, queue_exec); + res |= ast_register_application_xml(app_aqm, aqm_exec); + res |= ast_register_application_xml(app_rqm, rqm_exec); + res |= ast_register_application_xml(app_pqm, pqm_exec); + res |= ast_register_application_xml(app_upqm, upqm_exec); + res |= ast_register_application_xml(app_ql, ql_exec); res |= ast_manager_register("Queues", 0, manager_queues_show, "Queues"); res |= ast_manager_register("QueueStatus", 0, manager_queues_status, "Queue Status"); res |= ast_manager_register("QueueSummary", 0, manager_queues_summary, "Queue Summary"); diff --git a/apps/app_readexten.c b/apps/app_readexten.c index 93ca4e670..e54741ffa 100644 --- a/apps/app_readexten.c +++ b/apps/app_readexten.c @@ -36,6 +36,82 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/indications.h" #include "asterisk/channel.h" +/*** DOCUMENTATION + <application name="ReadExten" language="en_US"> + <synopsis> + Read an extension into a variable. + </synopsis> + <syntax> + <parameter name="variable" required="true" /> + <parameter name="filename"> + <para>File to play before reading digits or tone with option <literal>i</literal></para> + </parameter> + <parameter name="context"> + <para>Context in which to match extensions.</para> + </parameter> + <parameter name="option"> + <optionlist> + <option name="s"> + <para>Return immediately if the channel is not answered.</para> + </option> + <option name="i"> + <para>Play <replaceable>filename</replaceable> as an indication tone from your + <filename>indications.conf</filename></para> + </option> + <option name="n"> + <para>Read digits even if the channel is not answered.</para> + </option> + </optionlist> + </parameter> + <parameter name="timeout"> + <para>An integer number of seconds to wait for a digit response. If + greater than <literal>0</literal>, that value will override the default timeout.</para> + </parameter> + </syntax> + <description> + <para>Reads a <literal>#</literal> terminated string of digits from the user into the given variable.</para> + <para>Will set READEXTENSTATUS on exit with one of the following statuses:</para> + <variablelist> + <variable name="READEXTENSTATUS"> + <value name="OK"> + A valid extension exists in ${variable}. + </value> + <value name="TIMEOUT"> + No extension was entered in the specified time. + </value> + <value name="INVALID"> + An invalid extension, ${INVALID_EXTEN}, was entered. + </value> + <value name="SKIP"> + Line was not up and the option 's' was specified. + </value> + <value name="ERROR"> + Invalid arguments were passed. + </value> + </variable> + </variablelist> + </description> + </application> + <function name="VALID_EXTEN" language="en_US"> + <synopsis> + Determine whether an extension exists or not. + </synopsis> + <syntax> + <parameter name="context"> + <para>Defaults to the current context</para> + </parameter> + <parameter name="extension" required="true" /> + <parameter name="priority"> + <para>Priority defaults to <literal>1</literal>.</para> + </parameter> + </syntax> + <description> + <para>Returns a true value if the indicated <replaceable>context</replaceable>, + <replaceable>extension</replaceable>, and <replaceable>priority</replaceable> exist.</para> + </description> + </function> + ***/ + enum { OPT_SKIP = (1 << 0), OPT_INDICATION = (1 << 1), @@ -50,28 +126,6 @@ AST_APP_OPTIONS(readexten_app_options, { static char *app = "ReadExten"; -static char *synopsis = "Read an extension into a variable"; - -static char *descrip = -" ReadExten(<variable>[,[<filename>][,[<context>][,[<option>][,<timeout>]]]])\n\n" -"Reads a #-terminated string of digits from the user into the given variable.\n" -" filename file to play before reading digits or tone with option i\n" -" context context in which to match extensions\n" -" option options are:\n" -" s - Return immediately if the channel is not answered,\n" -" i - Play filename as an indication tone from your\n" -" indications.conf\n" -" n - Read digits even if the channel is not answered.\n" -" timeout An integer number of seconds to wait for a digit response. If\n" -" greater than 0, that value will override the default timeout.\n\n" -"ReadExten will set READEXTENSTATUS on exit with one of the following statuses:\n" -" OK A valid extension exists in ${variable}\n" -" TIMEOUT No extension was entered in the specified time\n" -" INVALID An invalid extension, ${INVALID_EXTEN}, was entered\n" -" SKIP Line was not up and the option 's' was specified\n" -" ERROR Invalid arguments were passed\n"; - - static int readexten_exec(struct ast_channel *chan, void *data) { int res = 0; @@ -232,11 +286,6 @@ static int acf_isexten_exec(struct ast_channel *chan, const char *cmd, char *par static struct ast_custom_function acf_isexten = { .name = "VALID_EXTEN", - .synopsis = "Determine whether an extension exists or not", - .syntax = "VALID_EXTEN([<context>],<extension>[,<priority>])", - .desc = -"Returns a true value if the indicated context, extension, and priority exist.\n" -"Context defaults to the current context, priority defaults to 1.\n", .read = acf_isexten_exec, }; @@ -250,7 +299,7 @@ static int unload_module(void) static int load_module(void) { - int res = ast_register_application(app, readexten_exec, synopsis, descrip); + int res = ast_register_application_xml(app, readexten_exec); res |= ast_custom_function_register(&acf_isexten); return res; } diff --git a/apps/app_readfile.c b/apps/app_readfile.c index 8762ef860..c5234089f 100644 --- a/apps/app_readfile.c +++ b/apps/app_readfile.c @@ -35,16 +35,33 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/app.h" #include "asterisk/module.h" -static char *app_readfile = "ReadFile"; - -static char *readfile_synopsis = "Read the contents of a text file into a channel variable"; - -static char *readfile_descrip = -"ReadFile(varname=file,length)\n" -" varname - Result stored here.\n" -" file - The name of the file to read.\n" -" length - Maximum number of characters to capture.\n"; +/*** DOCUMENTATION + <application name="ReadFile" language="en_US"> + <synopsis> + Read the contents of a text file into a channel variable. + </synopsis> + <syntax argsep="="> + <parameter name="varname" required="true"> + <para>Result stored here.</para> + </parameter> + <parameter name="fileparams" required="true"> + <argument name="file" required="true"> + <para>The name of the file to read.</para> + </argument> + <argument name="length" required="false"> + <para>Maximum number of characters to capture.</para> + <para>If not specified defaults to max.</para> + </argument> + </parameter> + </syntax> + <description> + <para>Read the contents of a text file into channel variable <replaceable>varname</replaceable></para> + <warning><para>ReadFile has been deprecated in favor of Set(varname=${FILE(file,0,length)})</para></warning> + </description> + </application> + ***/ +static char *app_readfile = "ReadFile"; static int readfile_exec(struct ast_channel *chan, void *data) { @@ -101,7 +118,7 @@ static int unload_module(void) static int load_module(void) { - return ast_register_application(app_readfile, readfile_exec, readfile_synopsis, readfile_descrip); + return ast_register_application_xml(app_readfile, readfile_exec); } AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Stores output of file into a variable"); diff --git a/apps/app_record.c b/apps/app_record.c index 8afafc93d..a575efdbe 100644 --- a/apps/app_record.c +++ b/apps/app_record.c @@ -36,35 +36,66 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/channel.h" #include "asterisk/dsp.h" /* use dsp routines for silence detection */ +/*** DOCUMENTATION + <application name="Record" language="en_US"> + <synopsis> + Record to a file. + </synopsis> + <syntax> + <parameter name="filename" required="true" argsep="."> + <argument name="filename" required="true" /> + <argument name="format" required="true"> + <para>Is the format of the file type to be recorded (wav, gsm, etc).</para> + </argument> + </parameter> + <parameter name="silence"> + <para>Is the number of seconds of silence to allow before returning.</para> + </parameter> + <parameter name="maxduration"> + <para>Is the maximum recording duration in seconds. If missing + or 0 there is no maximum.</para> + </parameter> + <parameter name="options"> + <optionlist> + <option name="a"> + <para>Append to existing recording rather than replacing.</para> + </option> + <option name="n"> + <para>Do not answer, but record anyway if line not yet answered.</para> + </option> + <option name="q"> + <para>quiet (do not play a beep tone).</para> + </option> + <option name="s"> + <para>skip recording if the line is not yet answered.</para> + </option> + <option name="t"> + <para>use alternate '*' terminator key (DTMF) instead of default '#'</para> + </option> + <option name="x"> + <para>Ignore all terminator keys (DTMF) and keep recording until hangup.</para> + </option> + </optionlist> + </parameter> + </syntax> + <description> + <para>If filename contains <literal>%d</literal>, these characters will be replaced with a number + incremented by one each time the file is recorded. + Use <astcli>core show file formats</astcli> to see the available formats on your system + User can press <literal>#</literal> to terminate the recording and continue to the next priority. + If the user hangup during a recording, all data will be lost and the application will teminate.</para> + <variablelist> + <variable name="RECORDED_FILE"> + <para>Will be set to the final filename of the recording.</para> + </variable> + </variablelist> + </description> + </application> + + ***/ static char *app = "Record"; -static char *synopsis = "Record to a file"; - -static char *descrip = -" Record(filename.format,silence[,maxduration][,options])\n\n" -"Records from the channel into a given filename. If the file exists it will\n" -"be overwritten.\n" -"- 'format' is the format of the file type to be recorded (wav, gsm, etc).\n" -"- 'silence' is the number of seconds of silence to allow before returning.\n" -"- 'maxduration' is the maximum recording duration in seconds. If missing\n" -"or 0 there is no maximum.\n" -"- 'options' may contain any of the following letters:\n" -" 'a' : append to existing recording rather than replacing\n" -" 'n' : do not answer, but record anyway if line not yet answered\n" -" 'q' : quiet (do not play a beep tone)\n" -" 's' : skip recording if the line is not yet answered\n" -" 't' : use alternate '*' terminator key (DTMF) instead of default '#'\n" -" 'x' : ignore all terminator keys (DTMF) and keep recording until hangup\n" -"\n" -"If filename contains '%d', these characters will be replaced with a number\n" -"incremented by one each time the file is recorded. A channel variable\n" -"named RECORDED_FILE will also be set, which contains the final filemname.\n\n" -"Use 'core show file formats' to see the available formats on your system\n\n" -"User can press '#' to terminate the recording and continue to the next priority.\n\n" -"If the user should hangup during a recording, all data will be lost and the\n" -"application will teminate. \n"; - enum { OPTION_APPEND = (1 << 0), OPTION_NOANSWER = (1 << 1), @@ -359,7 +390,7 @@ static int unload_module(void) static int load_module(void) { - return ast_register_application(app, record_exec, synopsis, descrip); + return ast_register_application_xml(app, record_exec); } AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Trivial Record Application"); diff --git a/apps/app_sayunixtime.c b/apps/app_sayunixtime.c index d0e23449e..f6122e40d 100644 --- a/apps/app_sayunixtime.c +++ b/apps/app_sayunixtime.c @@ -36,29 +36,54 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/say.h" #include "asterisk/app.h" +/*** DOCUMENTATION + <application name="SayUnixTime" language="en_US"> + <synopsis> + Says a specified time in a custom format. + </synopsis> + <syntax> + <parameter name="unixtime"> + <para>time, in seconds since Jan 1, 1970. May be negative. Defaults to now.</para> + </parameter> + <parameter name="timezone"> + <para>timezone, see <directory>/usr/share/zoneinfo</directory> for a list. Defaults to machine default.</para> + </parameter> + <parameter name="format"> + <para>a format the time is to be said in. See <filename>voicemail.conf</filename>. + Defaults to <literal>ABdY "digits/at" IMp</literal></para> + </parameter> + </syntax> + <description> + <para>Uses some of the sound files stored in <directory>/var/lib/asterisk/sounds</directory> to construct a phrase + saying the specified date and/or time in the specified format. </para> + </description> + </application> + <application name="DateTime" language="en_US"> + <synopsis> + Says a specified time in a custom format. + </synopsis> + <syntax> + <parameter name="unixtime"> + <para>time, in seconds since Jan 1, 1970. May be negative. Defaults to now.</para> + </parameter> + <parameter name="timezone"> + <para>timezone, see <filename>/usr/share/zoneinfo</filename> for a list. Defaults to machine default.</para> + </parameter> + <parameter name="format"> + <para>a format the time is to be said in. See <filename>voicemail.conf</filename>. + Defaults to <literal>ABdY "digits/at" IMp</literal></para> + </parameter> + </syntax> + <description> + <para>Say the date and time in a specified format.</para> + </description> + </application> + + ***/ + static char *app_sayunixtime = "SayUnixTime"; static char *app_datetime = "DateTime"; -static char *sayunixtime_synopsis = "Says a specified time in a custom format"; - -static char *sayunixtime_descrip = -"SayUnixTime([unixtime][,[timezone][,format]])\n" -" unixtime - time, in seconds since Jan 1, 1970. May be negative.\n" -" defaults to now.\n" -" timezone - timezone, see /usr/share/zoneinfo for a list.\n" -" defaults to machine default.\n" -" format - a format the time is to be said in. See voicemail.conf.\n" -" defaults to \"ABdY 'digits/at' IMp\"\n"; -static char *datetime_descrip = -"DateTime([unixtime][,[timezone][,format]])\n" -" unixtime - time, in seconds since Jan 1, 1970. May be negative.\n" -" defaults to now.\n" -" timezone - timezone, see /usr/share/zoneinfo for a list.\n" -" defaults to machine default.\n" -" format: - a format the time is to be said in. See voicemail.conf.\n" -" defaults to \"ABdY 'digits/at' IMp\"\n"; - - static int sayunixtime_exec(struct ast_channel *chan, void *data) { AST_DECLARE_APP_ARGS(args, @@ -103,8 +128,8 @@ static int load_module(void) { int res; - res = ast_register_application(app_sayunixtime, sayunixtime_exec, sayunixtime_synopsis, sayunixtime_descrip); - res |= ast_register_application(app_datetime, sayunixtime_exec, sayunixtime_synopsis, datetime_descrip); + res = ast_register_application_xml(app_sayunixtime, sayunixtime_exec); + res |= ast_register_application_xml(app_datetime, sayunixtime_exec); return res; } diff --git a/apps/app_senddtmf.c b/apps/app_senddtmf.c index 9863ce012..bd92230bd 100644 --- a/apps/app_senddtmf.c +++ b/apps/app_senddtmf.c @@ -35,19 +35,30 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/manager.h" #include "asterisk/channel.h" +/*** DOCUMENTATION + <application name="SendDTMF" language="en_US"> + <synopsis> + Sends arbitrary DTMF digits + </synopsis> + <syntax> + <parameter name="digits" required="true"> + <para>List of digits 0-9,*#,abcd</para> + </parameter> + <parameter name="timeout_ms" required="false"> + <para>Amount of time to wait in ms between tones. (defaults to .25s)</para> + </parameter> + <parameter name="duration_ms" required="false"> + <para>Duration of each digit</para> + </parameter> + </syntax> + <description> + <para>DTMF digits sent to a channel with half second pause</para> + <para>It will pass all digits or terminate if it encounters an error.</para> + </description> + </application> + ***/ static char *app = "SendDTMF"; -static char *synopsis = "Sends arbitrary DTMF digits"; - -static char *descrip = -" SendDTMF(digits[,[timeout_ms][,duration_ms]]): Sends DTMF digits on a channel. \n" -" Accepted digits: 0-9, *#abcd, (default .25s pause between digits)\n" -" The application will either pass the assigned digits or terminate if it\n" -" encounters an error.\n" -" Optional Params: \n" -" timeout_ms: pause between digits.\n" -" duration_ms: duration of each digit.\n"; - static int senddtmf_exec(struct ast_channel *chan, void *vdata) { int res = 0; @@ -121,7 +132,7 @@ static int load_module(void) int res; res = ast_manager_register2( "PlayDTMF", EVENT_FLAG_CALL, manager_play_dtmf, "Play DTMF signal on a specific channel.", mandescr_playdtmf ); - res |= ast_register_application(app, senddtmf_exec, synopsis, descrip); + res |= ast_register_application_xml(app, senddtmf_exec); return res; } diff --git a/apps/app_sendtext.c b/apps/app_sendtext.c index e95ff6158..53306aa5a 100644 --- a/apps/app_sendtext.c +++ b/apps/app_sendtext.c @@ -37,19 +37,36 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/module.h" #include "asterisk/app.h" -static const char *app = "SendText"; - -static const char *synopsis = "Send a Text Message"; +/*** DOCUMENTATION + <application name="SendText" language="en_US"> + <synopsis> + Send a Text Message. + </synopsis> + <syntax> + <parameter name="text" required="true" /> + </syntax> + <description> + <para>Sends <replaceable>text</replaceable> to current channel (callee).</para> + <para>Result of transmission will be stored in the <variable>SENDTEXTSTATUS</variable></para> + <variablelist> + <variable name="SENDTEXTSTATUS"> + <value name="SUCCESS"> + Transmission succeeded. + </value> + <value name="FAILURE"> + Transmission failed. + </value> + <value name="UNSUPPORTED"> + Text transmission not supported by channel. + </value> + </variable> + </variablelist> + <note><para>At this moment, text is supposed to be 7 bit ASCII in most channels.</para></note> + </description> + </application> + ***/ -static const char *descrip = -" SendText(text): Sends text to current channel (callee).\n" -"Result of transmission will be stored in the SENDTEXTSTATUS\n" -"channel variable:\n" -" SUCCESS Transmission succeeded\n" -" FAILURE Transmission failed\n" -" UNSUPPORTED Text transmission not supported by channel\n" -"\n" -"At this moment, text is supposed to be 7 bit ASCII in most channels.\n"; +static const char *app = "SendText"; static int sendtext_exec(struct ast_channel *chan, void *data) { @@ -91,7 +108,7 @@ static int unload_module(void) static int load_module(void) { - return ast_register_application(app, sendtext_exec, synopsis, descrip); + return ast_register_application_xml(app, sendtext_exec); } AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Send Text Applications"); diff --git a/apps/app_setcallerid.c b/apps/app_setcallerid.c index f1c9df3cb..6592249b4 100644 --- a/apps/app_setcallerid.c +++ b/apps/app_setcallerid.c @@ -38,26 +38,51 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/image.h" #include "asterisk/callerid.h" -static char *app2 = "SetCallerPres"; - -static char *synopsis2 = "Set CallerID Presentation"; +/*** DOCUMENTATION + <application name="SetCallerPres" language="en_US"> + <synopsis> + Set CallerID Presentation. + </synopsis> + <syntax> + <parameter name="presentation" required="true"> + <enumlist> + <enum name="allowed_not_screened"> + <para>Presentation Allowed, Not Screened.</para> + </enum> + <enum name="allowed_passed_screen"> + <para>Presentation Allowed, Passed Screen.</para> + </enum> + <enum name="allowed_failed_screen"> + <para>Presentation Allowed, Failed Screen.</para> + </enum> + <enum name="allowed"> + <para>Presentation Allowed, Network Number.</para> + </enum> + <enum name="prohib_not_screened"> + <para>Presentation Prohibited, Not Screened.</para> + </enum> + <enum name="prohib_passed_screen"> + <para>Presentation Prohibited, Passed Screen.</para> + </enum> + <enum name="prohib_failed_screen"> + <para>Presentation Prohibited, Failed Screen.</para> + </enum> + <enum name="prohib"> + <para>Presentation Prohibited, Network Number.</para> + </enum> + <enum name="unavailable"> + <para>Number Unavailable.</para> + </enum> + </enumlist> + </parameter> + </syntax> + <description> + <para>Set Caller*ID presentation on a call.</para> + </description> + </application> + ***/ - -static char *descrip2 = -" SetCallerPres(presentation): Set Caller*ID presentation on a call.\n" -" Valid presentations are:\n" -"\n" -" allowed_not_screened : Presentation Allowed, Not Screened\n" -" allowed_passed_screen : Presentation Allowed, Passed Screen\n" -" allowed_failed_screen : Presentation Allowed, Failed Screen\n" -" allowed : Presentation Allowed, Network Number\n" -" prohib_not_screened : Presentation Prohibited, Not Screened\n" -" prohib_passed_screen : Presentation Prohibited, Passed Screen\n" -" prohib_failed_screen : Presentation Prohibited, Failed Screen\n" -" prohib : Presentation Prohibited, Network Number\n" -" unavailable : Number Unavailable\n" -"\n" -; +static char *app2 = "SetCallerPres"; static int setcallerid_pres_exec(struct ast_channel *chan, void *data) { @@ -91,7 +116,7 @@ static int unload_module(void) static int load_module(void) { - return ast_register_application(app2, setcallerid_pres_exec, synopsis2, descrip2); + return ast_register_application_xml(app2, setcallerid_pres_exec); } AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Set CallerID Presentation Application"); diff --git a/apps/app_skel.c b/apps/app_skel.c index 44bf152aa..338a32f8a 100644 --- a/apps/app_skel.c +++ b/apps/app_skel.c @@ -44,11 +44,35 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/lock.h" #include "asterisk/app.h" +/*** DOCUMENTATION + <application name="Skel" language="en_US"> + <synopsis> + Simple one line explaination. + </synopsis> + <syntax> + <parameter name="dummy" required="true"/> + <parameter name="options"> + <optionlist> + <option name="a"> + <para>Option A.</para> + </option> + <option name="b"> + <para>Option B.</para> + </option> + <option name="c"> + <para>Option C.</para> + </option> + </optionlist> + </parameter> + </syntax> + <description> + <para>This application is a template to build other applications from. + It shows you the basic structure to create your own Asterisk applications.</para> + </description> + </application> + ***/ + static char *app = "Skel"; -static char *synopsis = -"Skeleton application."; -static char *descrip = "This application is a template to build other applications from.\n" - " It shows you the basic structure to create your own Asterisk applications.\n"; enum { OPTION_A = (1 << 0), @@ -122,7 +146,7 @@ static int unload_module(void) static int load_module(void) { - return ast_register_application(app, app_exec, synopsis, descrip) ? + return ast_register_application_xml(app, app_exec) ? AST_MODULE_LOAD_DECLINE : AST_MODULE_LOAD_SUCCESS; } diff --git a/apps/app_softhangup.c b/apps/app_softhangup.c index 7af852560..a7ba753fd 100644 --- a/apps/app_softhangup.c +++ b/apps/app_softhangup.c @@ -36,13 +36,28 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/lock.h" #include "asterisk/app.h" -static char *synopsis = "Soft Hangup Application"; - -static char *desc = " SoftHangup(Technology/resource[,options]):\n" -"Hangs up the requested channel. If there are no channels to hangup,\n" -"the application will report it.\n" -" Options:\n" -" 'a' - hang up all channels on a specified device instead of a single resource\n"; +/*** DOCUMENTATION + <application name="SoftHangup" language="en_US"> + <synopsis> + Hangs up the requested channel. + </synopsis> + <syntax> + <parameter name="Technology/Resource" required="true" /> + <parameter name="options"> + <optionlist> + <option name="a"> + <para>Hang up all channels on a specified device instead of a single resource</para> + </option> + </optionlist> + </parameter> + </syntax> + <description> + <para>Hangs up the requested channel. If there are no channels to + hangup, the application will report it.</para> + </description> + </application> + + ***/ static char *app = "SoftHangup"; @@ -114,7 +129,7 @@ static int unload_module(void) static int load_module(void) { - return ast_register_application(app, softhangup_exec, synopsis, desc); + return ast_register_application_xml(app, softhangup_exec); } AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Hangs up the requested channel"); diff --git a/apps/app_stack.c b/apps/app_stack.c index 2e5e6de9e..599c5f1d4 100644 --- a/apps/app_stack.c +++ b/apps/app_stack.c @@ -40,6 +40,70 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/channel.h" #include "asterisk/agi.h" +/*** DOCUMENTATION + <application name="Gosub" language="en_US"> + <synopsis> + Jump to label, saving return address. + </synopsis> + <syntax> + <parameter name="context" /> + <parameter name="exten" /> + <parameter name="priority" required="true" hasparams="optional"> + <argument name="arg1" multiple="true" required="true" /> + <argument name="argN" /> + </parameter> + </syntax> + <description> + <para>Jumps to the label specified, saving the return address.</para> + </description> + </application> + <application name="GosubIf" language="en_US"> + <synopsis> + Conditionally jump to label, saving return address. + </synopsis> + <syntax argsep="?"> + <parameter name="condition" required="true" /> + <parameter name="destination" required="true" argsep=":"> + <argument name="labeliftrue" hasparams="optional"> + <argument name="arg1" required="true" multiple="true" /> + <argument name="argN" /> + </argument> + <argument name="labeliffalse" hasparams="optional"> + <argument name="arg1" required="true" multiple="true" /> + <argument name="argN" /> + </argument> + </parameter> + </syntax> + <description> + <para>If the condition is true, then jump to labeliftrue. If false, jumps to + labeliffalse, if specified. In either case, a jump saves the return point + in the dialplan, to be returned to with a Return.</para> + </description> + </application> + <application name="Return" language="en_US"> + <synopsis> + Return from gosub routine. + </synopsis> + <syntax> + <parameter name="value"> + <para>Return value.</para> + </parameter> + </syntax> + <description> + <para>Jumps to the last label on the stack, removing it. The return <replaceable>value</replaceable>, if + any, is saved in the channel variable <variable>GOSUB_RETVAL</variable>.</para> + </description> + </application> + <application name="StackPop" language="en_US"> + <synopsis> + Remove one address from gosub stack. + </synopsis> + <syntax /> + <description> + <para>Removes last label on the stack, discarding it.</para> + </description> + </application> + ***/ static int agi_loaded = 0; static const char *app_gosub = "Gosub"; @@ -47,27 +111,6 @@ static const char *app_gosubif = "GosubIf"; static const char *app_return = "Return"; static const char *app_pop = "StackPop"; -static const char *gosub_synopsis = "Jump to label, saving return address"; -static const char *gosubif_synopsis = "Conditionally jump to label, saving return address"; -static const char *return_synopsis = "Return from gosub routine"; -static const char *pop_synopsis = "Remove one address from gosub stack"; - -static const char *gosub_descrip = -" Gosub([[context,]exten,]priority[(arg1[,...][,argN])]):\n" -"Jumps to the label specified, saving the return address.\n"; -static const char *gosubif_descrip = -" GosubIf(condition?labeliftrue[(arg1[,...])][:labeliffalse[(arg1[,...])]]):\n" -"If the condition is true, then jump to labeliftrue. If false, jumps to\n" -"labeliffalse, if specified. In either case, a jump saves the return point\n" -"in the dialplan, to be returned to with a Return.\n"; -static const char *return_descrip = -" Return([return-value]):\n" -"Jumps to the last label on the stack, removing it. The return value, if\n" -"any, is saved in the channel variable GOSUB_RETVAL.\n"; -static const char *pop_descrip = -" StackPop():\n" -"Removes last label on the stack, discarding it.\n"; - static void gosub_free(void *data); static struct ast_datastore_info stack_info = { @@ -530,10 +573,10 @@ static int load_module(void) ast_agi_register(ast_module_info->self, &gosub_agi_command); } - ast_register_application(app_pop, pop_exec, pop_synopsis, pop_descrip); - ast_register_application(app_return, return_exec, return_synopsis, return_descrip); - ast_register_application(app_gosubif, gosubif_exec, gosubif_synopsis, gosubif_descrip); - ast_register_application(app_gosub, gosub_exec, gosub_synopsis, gosub_descrip); + ast_register_application_xml(app_pop, pop_exec); + ast_register_application_xml(app_return, return_exec); + ast_register_application_xml(app_gosubif, gosubif_exec); + ast_register_application_xml(app_gosub, gosub_exec); ast_custom_function_register(&local_function); return 0; diff --git a/apps/app_system.c b/apps/app_system.c index 1f39c5a4e..688a649da 100644 --- a/apps/app_system.c +++ b/apps/app_system.c @@ -34,31 +34,68 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/app.h" #include "asterisk/channel.h" /* autoservice */ +/*** DOCUMENTATION + <application name="System" language="en_US"> + <synopsis> + Execute a system command. + </synopsis> + <syntax> + <parameter name="command" required="true"> + <para>Command to execute</para> + </parameter> + </syntax> + <description> + <para>Executes a command by using system(). If the command + fails, the console should report a fallthrough.</para> + <para>Result of execution is returned in the <variable>SYSTEMSTATUS</variable> channel variable:</para> + <variablelist> + <variable name="SYSTEMSTATUS"> + <value name="FAILURE"> + Could not execute the specified command. + </value> + <value name="SUCCESS"> + Specified command successfully executed. + </value> + </variable> + </variablelist> + </description> + </application> + <application name="TrySystem" language="en_US"> + <synopsis> + Try executing a system command. + </synopsis> + <syntax> + <parameter name="command" required="true"> + <para>Command to execute</para> + </parameter> + </syntax> + <description> + <para>Executes a command by using system().</para> + <para>Result of execution is returned in the <variable>SYSTEMSTATUS</variable> channel variable:</para> + <variablelist> + <variable name="SYSTEMSTATUS"> + <value name="FAILURE"> + Could not execute the specified command. + </value> + <value name="SUCCESS"> + Specified command successfully executed. + </value> + <value name="APPERROR"> + Specified command successfully executed, but returned error code. + </value> + </variable> + </variablelist> + </description> + </application> + + ***/ + static char *app = "System"; static char *app2 = "TrySystem"; -static char *synopsis = "Execute a system command"; - -static char *synopsis2 = "Try executing a system command"; - static char *chanvar = "SYSTEMSTATUS"; -static char *descrip = -" System(command): Executes a command by using system(). If the command\n" -"fails, the console should report a fallthrough. \n" -"Result of execution is returned in the SYSTEMSTATUS channel variable:\n" -" FAILURE Could not execute the specified command\n" -" SUCCESS Specified command successfully executed\n"; - -static char *descrip2 = -" TrySystem(command): Executes a command by using system().\n" -"on any situation.\n" -"Result of execution is returned in the SYSTEMSTATUS channel variable:\n" -" FAILURE Could not execute the specified command\n" -" SUCCESS Specified command successfully executed\n" -" APPERROR Specified command successfully executed, but returned error code\n"; - static int system_exec_helper(struct ast_channel *chan, void *data, int failmode) { int res = 0; @@ -120,8 +157,8 @@ static int load_module(void) { int res; - res = ast_register_application(app2, trysystem_exec, synopsis2, descrip2); - res |= ast_register_application(app, system_exec, synopsis, descrip); + res = ast_register_application_xml(app2, trysystem_exec); + res |= ast_register_application_xml(app, system_exec); return res; } diff --git a/apps/app_talkdetect.c b/apps/app_talkdetect.c index 9bc5e84dd..a0236b8fc 100644 --- a/apps/app_talkdetect.c +++ b/apps/app_talkdetect.c @@ -39,21 +39,39 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/dsp.h" #include "asterisk/app.h" -static char *app = "BackgroundDetect"; - -static char *synopsis = "Background a file with talk detect"; - -static char *descrip = -" BackgroundDetect(<filename>[,<sil>[,<min>[,<max>[,<analysistime>]]]]):\n" -"Plays back <filename>, waiting for interruption from a given digit (the digit\n" -"must start the beginning of a valid extension, or it will be ignored). During\n" -"the playback of the file, audio is monitored in the receive direction, and if\n" -"a period of non-silence which is greater than <min> ms yet less than <max> ms\n" -"is followed by silence for at least <sil> ms, which occurs during the first\n" -"<analysistime> ms, then the audio playback is aborted and processing jumps to\n" -"the <talk> extension, if available. If unspecified, <sil>, <min>, <max>, and\n" -"<analysistime> default to 1000, 100, infinity, and infinity respectively.\n"; +/*** DOCUMENTATION + <application name="BackGroundDetect" language="en_US"> + <synopsis> + Background a file with talk detect. + </synopsis> + <syntax> + <parameter name="filename" required="true" /> + <parameter name="sil"> + <para>If not specified, defaults to <literal>1000</literal>.</para> + </parameter> + <parameter name="min"> + <para>If not specified, defaults to <literal>100</literal>.</para> + </parameter> + <parameter name="max"> + <para>If not specified, defaults to <literal>infinity</literal>.</para> + </parameter> + <parameter name="analysistime"> + <para>If not specified, defaults to <literal>infinity</literal>.</para> + </parameter> + </syntax> + <description> + <para>Plays back <replaceable>filename</replaceable>, waiting for interruption from a given digit (the digit + must start the beginning of a valid extension, or it will be ignored). During + the playback of the file, audio is monitored in the receive direction, and if + a period of non-silence which is greater than <replaceable>min</replaceable> ms yet less than + <replaceable>max</replaceable> ms is followed by silence for at least <replaceable>sil</replaceable> ms, + which occurs during the first <replaceable>analysistime</replaceable> ms, then the audio playback is + aborted and processing jumps to the <replaceable>talk</replaceable> extension, if available.</para> + </description> + </application> + ***/ +static char *app = "BackgroundDetect"; static int background_detect_exec(struct ast_channel *chan, void *data) { @@ -227,7 +245,7 @@ static int unload_module(void) static int load_module(void) { - return ast_register_application(app, background_detect_exec, synopsis, descrip); + return ast_register_application_xml(app, background_detect_exec); } AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Playback with Talk Detection"); diff --git a/apps/app_transfer.c b/apps/app_transfer.c index df0c5392b..e1452bb59 100644 --- a/apps/app_transfer.c +++ b/apps/app_transfer.c @@ -36,23 +36,44 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/app.h" #include "asterisk/channel.h" +/*** DOCUMENTATION + <application name="Transfer" language="en_US"> + <synopsis> + Transfer caller to remote extension. + </synopsis> + <syntax> + <parameter name="dest" required="true" argsep="/"> + <argument name="Tech" /> + <argument name="destination" required="true" /> + </parameter> + </syntax> + <description> + <para>Requests the remote caller be transferred + to a given destination. If TECH (SIP, IAX2, LOCAL etc) is used, only + an incoming call with the same channel technology will be transfered. + Note that for SIP, if you transfer before call is setup, a 302 redirect + SIP message will be returned to the caller.</para> + <para>The result of the application will be reported in the <variable>TRANSFERSTATUS</variable> + channel variable:</para> + <variablelist> + <variable name="TRANSFERSTATUS"> + <value name="SUCCESS"> + Transfer succeeded. + </value> + <value name="FAILURE"> + Transfer failed. + </value> + <value name="UNSUPPORTED"> + Transfer unsupported by channel driver. + </value> + </variable> + </variablelist> + </description> + </application> + ***/ static const char *app = "Transfer"; -static const char *synopsis = "Transfer caller to remote extension"; - -static const char *descrip = -" Transfer([Tech/]dest): Requests the remote caller be transferred\n" -"to a given destination. If TECH (SIP, IAX2, LOCAL etc) is used, only\n" -"an incoming call with the same channel technology will be transfered.\n" -"Note that for SIP, if you transfer before call is setup, a 302 redirect\n" -"SIP message will be returned to the caller.\n" -"\nThe result of the application will be reported in the TRANSFERSTATUS\n" -"channel variable:\n" -" SUCCESS Transfer succeeded\n" -" FAILURE Transfer failed\n" -" UNSUPPORTED Transfer unsupported by channel driver\n"; - static int transfer_exec(struct ast_channel *chan, void *data) { int res; @@ -115,7 +136,7 @@ static int unload_module(void) static int load_module(void) { - return ast_register_application(app, transfer_exec, synopsis, descrip); + return ast_register_application_xml(app, transfer_exec); } AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Transfers a caller to another extension"); diff --git a/apps/app_url.c b/apps/app_url.c index f71b32fd0..e20159f5a 100644 --- a/apps/app_url.c +++ b/apps/app_url.c @@ -34,24 +34,49 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/app.h" #include "asterisk/channel.h" -static char *app = "SendURL"; - -static char *synopsis = "Send a URL"; +/*** DOCUMENTATION + <application name="SendURL" language="en_US"> + <synopsis> + Send a URL. + </synopsis> + <syntax> + <parameter name="URL" required="true" /> + <parameter name="option"> + <optionlist> + <option name="w"> + <para>Execution will wait for an acknowledgement that the + URL has been loaded before continuing.</para> + </option> + </optionlist> + </parameter> + </syntax> + <description> + <para>Requests client go to <replaceable>URL</replaceable> (IAX2) or sends the + URL to the client (other channels).</para> + <para>Result is returned in the <variable>SENDURLSTATUS</variable> channel variable:</para> + <variablelist> + <variable name="SENDURLSTATUS"> + <value name="SUCCESS"> + URL successfully sent to client. + </value> + <value name="FAILURE"> + Failed to send URL. + </value> + <value name="NOLOAD"> + Client failed to load URL (wait enabled). + </value> + <value name="UNSUPPORTED"> + Channel does not support URL transport. + </value> + </variable> + </variablelist> + <para>SendURL continues normally if the URL was sent correctly or if the channel + does not support HTML transport. Otherwise, the channel is hung up.</para> + </description> + </application> + ***/ -static char *descrip = -" SendURL(URL[,option]): Requests client go to URL (IAX2) or sends the \n" -"URL to the client (other channels).\n" -"Result is returned in the SENDURLSTATUS channel variable:\n" -" SUCCESS URL successfully sent to client\n" -" FAILURE Failed to send URL\n" -" NOLOAD Client failed to load URL (wait enabled)\n" -" UNSUPPORTED Channel does not support URL transport\n" -"\n" -"If the option 'w' is specified, execution will wait for an\n" -"acknowledgement that the URL has been loaded before continuing\n" -"\n" -"SendURL continues normally if the URL was sent correctly or if the channel\n" -"does not support HTML transport. Otherwise, the channel is hung up.\n"; +static char *app = "SendURL"; enum { OPTION_WAIT = (1 << 0), @@ -143,7 +168,7 @@ static int unload_module(void) static int load_module(void) { - return ast_register_application(app, sendurl_exec, synopsis, descrip); + return ast_register_application_xml(app, sendurl_exec); } AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Send URL Applications"); diff --git a/apps/app_userevent.c b/apps/app_userevent.c index 91d067d54..6d6354af6 100644 --- a/apps/app_userevent.c +++ b/apps/app_userevent.c @@ -30,21 +30,31 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/manager.h" #include "asterisk/app.h" -static char *app = "UserEvent"; - -static char *synopsis = "Send an arbitrary event to the manager interface"; - -static char *descrip = -" UserEvent(eventname[,body]): Sends an arbitrary event to the manager\n" -"interface, with an optional body representing additional arguments. The\n" -"body may be specified as a | delimeted list of headers. Each additional\n" -"argument will be placed on a new line in the event. The format of the\n" -"event will be:\n" -" Event: UserEvent\n" -" UserEvent: <specified event name>\n" -" [body]\n" -"If no body is specified, only Event and UserEvent headers will be present.\n"; +/*** DOCUMENTATION + <application name="UserEvent" language="en_US"> + <synopsis> + Send an arbitrary event to the manager interface. + </synopsis> + <syntax> + <parameter name="eventname" required="true" /> + <parameter name="body" /> + </syntax> + <description> + <para>Sends an arbitrary event to the manager interface, with an optional + <replaceable>body</replaceable> representing additional arguments. The + <replaceable>body</replaceable> may be specified as + a <literal>|</literal> delimeted list of headers. Each additional + argument will be placed on a new line in the event. The format of the + event will be:</para> + <para> Event: UserEvent</para> + <para> UserEvent: <specified event name></para> + <para> [body]</para> + <para>If no <replaceable>body</replaceable> is specified, only Event and UserEvent headers will be present.</para> + </description> + </application> + ***/ +static char *app = "UserEvent"; static int userevent_exec(struct ast_channel *chan, void *data) { @@ -83,7 +93,7 @@ static int unload_module(void) static int load_module(void) { - return ast_register_application(app, userevent_exec, synopsis, descrip); + return ast_register_application_xml(app, userevent_exec); } AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Custom User Event Application"); diff --git a/apps/app_verbose.c b/apps/app_verbose.c index 525cc1c55..b4c6a6384 100644 --- a/apps/app_verbose.c +++ b/apps/app_verbose.c @@ -33,16 +33,43 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/channel.h" static char *app_verbose = "Verbose"; -static char *verbose_synopsis = "Send arbitrary text to verbose output"; -static char *verbose_descrip = -"Verbose([<level>,]<message>)\n" -" level must be an integer value. If not specified, defaults to 0.\n"; - static char *app_log = "Log"; -static char *log_synopsis = "Send arbitrary text to a selected log level"; -static char *log_descrip = -"Log(<level>,<message>)\n" -" level must be one of ERROR, WARNING, NOTICE, DEBUG, VERBOSE, DTMF\n"; + +/*** DOCUMENTATION + <application name="Verbose" language="en_US"> + <synopsis> + Send arbitrary text to verbose output. + </synopsis> + <syntax> + <parameter name="level"> + <para>Must be an integer value. If not specified, defaults to 0.</para> + </parameter> + <parameter name="message" required="true"> + <para>Output text message.</para> + </parameter> + </syntax> + <description> + <para>Sends an arbitrary text message to verbose output.</para> + </description> + </application> + <application name="Log" language="en_US"> + <synopsis> + Send arbitrary text to a selected log level. + </synopsis> + <syntax> + <parameter name="level"> + <para>Level must be one of <literal>ERROR</literal>, <literal>WARNING</literal>, <literal>NOTICE</literal>, + <literal>DEBUG</literal>, <literal>VERBOSE</literal> or <literal>DTMF</literal>.</para> + </parameter> + <parameter name="message" required="true"> + <para>Output text message.</para> + </parameter> + </syntax> + <description> + <para>Sends an arbitrary text message to a selected log level.</para> + </description> + </application> + ***/ static int verbose_exec(struct ast_channel *chan, void *data) @@ -149,8 +176,8 @@ static int load_module(void) { int res; - res = ast_register_application(app_log, log_exec, log_synopsis, log_descrip); - res |= ast_register_application(app_verbose, verbose_exec, verbose_synopsis, verbose_descrip); + res = ast_register_application_xml(app_log, log_exec); + res |= ast_register_application_xml(app_verbose, verbose_exec); return res; } diff --git a/apps/app_waituntil.c b/apps/app_waituntil.c index 8b903b0ba..0b6ccc677 100644 --- a/apps/app_waituntil.c +++ b/apps/app_waituntil.c @@ -34,15 +34,38 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/pbx.h" #include "asterisk/module.h" +/*** DOCUMENTATION + <application name="WaitUntil" language="en_US"> + <synopsis> + Wait (sleep) until the current time is the given epoch. + </synopsis> + <syntax> + <parameter name="epoch" required="true" /> + </syntax> + <description> + <para>Waits until the given <replaceable>epoch</replaceable>.</para> + <para>Sets <variable>WAITUNTILSTATUS</variable> to one of the following values:</para> + <variablelist> + <variable name="WAITUNTILSTATUS"> + <value name="OK"> + Wait succeeded. + </value> + <value name="FAILURE"> + Invalid argument. + </value> + <value name="HANGUP"> + Channel hungup before time elapsed. + </value> + <value name="PAST"> + Time specified had already past. + </value> + </variable> + </variablelist> + </description> + </application> + ***/ + static char *app = "WaitUntil"; -static char *synopsis = "Wait (sleep) until the current time is the given epoch"; -static char *descrip = -" WaitUntil(<epoch>): Waits until the given time. Sets WAITUNTILSTATUS to\n" -"one of the following values:\n" -" OK Wait succeeded\n" -" FAILURE Invalid argument\n" -" HANGUP Channel hung up before time elapsed\n" -" PAST The time specified was already past\n"; static int waituntil_exec(struct ast_channel *chan, void *data) { @@ -89,7 +112,7 @@ static int unload_module(void) static int load_module(void) { - return ast_register_application(app, waituntil_exec, synopsis, descrip); + return ast_register_application_xml(app, waituntil_exec); } AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Wait until specified time"); diff --git a/apps/app_while.c b/apps/app_while.c index 822458663..796244702 100644 --- a/apps/app_while.c +++ b/apps/app_while.c @@ -33,29 +33,72 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/module.h" #include "asterisk/channel.h" -static char *start_app = "While"; -static char *start_desc = -" While(<expr>): Start a While Loop. Execution will return to this\n" -"point when EndWhile() is called until expr is no longer true.\n"; - -static char *start_synopsis = "Start a while loop"; - +/*** DOCUMENTATION + <application name="While" language="en_US"> + <synopsis> + Start a while loop. + </synopsis> + <syntax> + <parameter name="expr" required="true" /> + </syntax> + <description> + <para>Start a While Loop. Execution will return to this point when + <literal>EndWhile()</literal> is called until expr is no longer true.</para> + </description> + <see-also> + <ref type="application">EndWhile</ref> + <ref type="application">ExitWhile</ref> + <ref type="application">ContinueWhile</ref> + </see-also> + </application> + <application name="EndWhile" language="en_US"> + <synopsis> + End a while loop. + </synopsis> + <syntax /> + <description> + <para>Return to the previous called <literal>While()</literal>.</para> + </description> + <see-also> + <ref type="application">While</ref> + <ref type="application">ExitWhile</ref> + <ref type="application">ContinueWhile</ref> + </see-also> + </application> + <application name="ExitWhile" language="en_US"> + <synopsis> + End a While loop. + </synopsis> + <syntax /> + <description> + <para>Exits a <literal>While()</literal> loop, whether or not the conditional has been satisfied.</para> + </description> + <see-also> + <ref type="application">While</ref> + <ref type="application">EndWhile</ref> + <ref type="application">ContinueWhile</ref> + </see-also> + </application> + <application name="ContinueWhile" language="en_US"> + <synopsis> + Restart a While loop. + </synopsis> + <syntax /> + <description> + <para>Returns to the top of the while loop and re-evaluates the conditional.</para> + </description> + <see-also> + <ref type="application">While</ref> + <ref type="application">EndWhile</ref> + <ref type="application">ExitWhile</ref> + </see-also> + </application> + ***/ +static char *start_app = "While"; static char *stop_app = "EndWhile"; -static char *stop_desc = -" EndWhile(): Return to the previous called While()\n"; - -static char *stop_synopsis = "End a while loop"; - static char *exit_app = "ExitWhile"; -static char *exit_desc = -" ExitWhile(): Exits a While() loop, whether or not the conditional has been satisfied.\n"; -static char *exit_synopsis = "End a While loop"; - static char *continue_app = "ContinueWhile"; -static char *continue_desc = -" ContinueWhile(): Returns to the top of the while loop and re-evaluates the conditional.\n"; -static char *continue_synopsis = "Restart a While loop"; #define VAR_SIZE 64 @@ -295,10 +338,10 @@ static int load_module(void) { int res; - res = ast_register_application(start_app, while_start_exec, start_synopsis, start_desc); - res |= ast_register_application(stop_app, while_end_exec, stop_synopsis, stop_desc); - res |= ast_register_application(exit_app, while_exit_exec, exit_synopsis, exit_desc); - res |= ast_register_application(continue_app, while_continue_exec, continue_synopsis, continue_desc); + res = ast_register_application_xml(start_app, while_start_exec); + res |= ast_register_application_xml(stop_app, while_end_exec); + res |= ast_register_application_xml(exit_app, while_exit_exec); + res |= ast_register_application_xml(continue_app, while_continue_exec); return res; } diff --git a/apps/app_zapateller.c b/apps/app_zapateller.c index 2641e69b4..bf9408090 100644 --- a/apps/app_zapateller.c +++ b/apps/app_zapateller.c @@ -37,23 +37,42 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/translate.h" #include "asterisk/app.h" -static char *app = "Zapateller"; - -static char *synopsis = "Block telemarketers with SIT"; - -static char *descrip = -" Zapateller(options): Generates special information tone to block\n" -"telemarketers from calling you. Options is a pipe-delimited list of\n" -"options. The following options are available:\n" -" 'answer' - causes the line to be answered before playing the tone,\n" -" 'nocallerid' - causes Zapateller to only play the tone if there is no\n" -" callerid information available. Options should be\n" -" separated by , characters\n\n" -" This application will set the following channel variable upon completion:\n" -" ZAPATELLERSTATUS - This will contain the last action accomplished by the\n" -" Zapateller application. Possible values include:\n" -" NOTHING | ANSWERED | ZAPPED\n\n"; +/*** DOCUMENTATION + <application name="Zapateller" language="en_US"> + <synopsis> + Block telemarketers with SIT. + </synopsis> + <syntax> + <parameter name="options" required="true"> + <para>Comma delimited list of options.</para> + <optionlist> + <option name="answer"> + <para>Causes the line to be answered before playing the tone.</para> + </option> + <option name="nocallerid"> + <para>Causes Zapateller to only play the tone if there is no + callerid information available.</para> + </option> + </optionlist> + </parameter> + </syntax> + <description> + <para>Generates special information tone to block telemarketers from calling you.</para> + <para>This application will set the following channel variable upon completion:</para> + <variablelist> + <variable name="ZAPATELLERSTATUS"> + <para>This will contain the last action accomplished by the + Zapateller application. Possible values include:</para> + <value name="NOTHING" /> + <value name="ANSWERED" /> + <value name="ZAPPED" /> + </variable> + </variablelist> + </description> + </application> + ***/ +static char *app = "Zapateller"; static int zapateller_exec(struct ast_channel *chan, void *data) { @@ -107,7 +126,7 @@ static int unload_module(void) static int load_module(void) { - return ((ast_register_application(app, zapateller_exec, synopsis, descrip)) ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_SUCCESS); + return ((ast_register_application_xml(app, zapateller_exec)) ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_SUCCESS); } AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Block Telemarketers with Special Information Tone"); diff --git a/build_tools/get_documentation b/build_tools/get_documentation new file mode 100644 index 000000000..7849c522a --- /dev/null +++ b/build_tools/get_documentation @@ -0,0 +1,3 @@ +/\/\*\*\* DOCUMENTATION/ {printit=1; next} +/\*\*\*\// {if (printit) exit} +// {if (printit) print} @@ -1,5 +1,5 @@ #! /bin/sh -# From configure.ac Revision: 150731 . +# From configure.ac Revision: 151252 . # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.61 for asterisk 1.6. # @@ -800,6 +800,10 @@ LDAP_LIB LDAP_INCLUDE LDAP_DIR PBX_LDAP +LIBXML2_LIB +LIBXML2_INCLUDE +LIBXML2_DIR +PBX_LIBXML2 LTDL_LIB LTDL_INCLUDE LTDL_DIR @@ -970,6 +974,7 @@ AST_SHADOW_WARNINGS PBX_RTLD_NOLOAD PBX_IP_MTU_DISCOVER GSM_INTERNAL +CONFIG_LIBXML2 PBX_MISDN_FAC_RESULT PBX_MISDN_FAC_ERROR CONFIG_NETSNMP @@ -1589,6 +1594,7 @@ Optional Features: --enable-dev-mode Turn on developer mode --disable-largefile omit support for large files --enable-internal-poll Use Asterisk's poll implementation + --disable-xmldoc Explicity disable XML documentation Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] @@ -1615,6 +1621,7 @@ Optional Packages: --with-isdnnet=PATH use ISDN4Linux Library files in PATH --with-jack=PATH use Jack Audio Connection Kit files in PATH --with-ldap=PATH use OpenLDAP files in PATH + --with-libxml2=PATH use LibXML2 files in PATH --with-ltdl=PATH use libtool files in PATH --with-lua=PATH use Lua files in PATH --with-misdn=PATH use mISDN User Library files in PATH @@ -8485,6 +8492,34 @@ fi + LIBXML2_DESCRIP="LibXML2" + LIBXML2_OPTION="libxml2" + +# Check whether --with-libxml2 was given. +if test "${with_libxml2+set}" = set; then + withval=$with_libxml2; + case ${withval} in + n|no) + USE_LIBXML2=no + ;; + y|ye|yes) + ac_mandatory_list="${ac_mandatory_list} LIBXML2" + ;; + *) + LIBXML2_DIR="${withval}" + ac_mandatory_list="${ac_mandatory_list} LIBXML2" + ;; + esac + +fi + + PBX_LIBXML2=0 + + + + + + LTDL_DESCRIP="libtool" LTDL_OPTION="ltdl" @@ -34444,6 +34479,212 @@ _ACEOF fi +# Check whether --enable-xmldoc was given. +if test "${enable_xmldoc+set}" = set; then + enableval=$enable_xmldoc; case "${enableval}" in + y|ye|yes) disable_xmldoc=no ;; + n|no) disable_xmldoc=yes ;; + *) { { echo "$as_me:$LINENO: error: bad value ${enableval} for --disable-xmldoc" >&5 +echo "$as_me: error: bad value ${enableval} for --disable-xmldoc" >&2;} + { (exit 1); exit 1; }; } ;; + esac +else + disable_xmldoc=no +fi + + +if test "${disable_xmldoc}" != "yes"; then + + if test "x${PBX_LIBXML2}" != "x1" -a "${USE_LIBXML2}" != "no"; then + PBX_LIBXML2=0 + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}xml2-config", so it can be a program name with args. +set dummy ${ac_tool_prefix}xml2-config; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_CONFIG_LIBXML2+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CONFIG_LIBXML2"; then + ac_cv_prog_CONFIG_LIBXML2="$CONFIG_LIBXML2" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CONFIG_LIBXML2="${ac_tool_prefix}xml2-config" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +CONFIG_LIBXML2=$ac_cv_prog_CONFIG_LIBXML2 +if test -n "$CONFIG_LIBXML2"; then + { echo "$as_me:$LINENO: result: $CONFIG_LIBXML2" >&5 +echo "${ECHO_T}$CONFIG_LIBXML2" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CONFIG_LIBXML2"; then + ac_ct_CONFIG_LIBXML2=$CONFIG_LIBXML2 + # Extract the first word of "xml2-config", so it can be a program name with args. +set dummy xml2-config; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_ac_ct_CONFIG_LIBXML2+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CONFIG_LIBXML2"; then + ac_cv_prog_ac_ct_CONFIG_LIBXML2="$ac_ct_CONFIG_LIBXML2" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CONFIG_LIBXML2="xml2-config" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_CONFIG_LIBXML2=$ac_cv_prog_ac_ct_CONFIG_LIBXML2 +if test -n "$ac_ct_CONFIG_LIBXML2"; then + { echo "$as_me:$LINENO: result: $ac_ct_CONFIG_LIBXML2" >&5 +echo "${ECHO_T}$ac_ct_CONFIG_LIBXML2" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + if test "x$ac_ct_CONFIG_LIBXML2" = x; then + CONFIG_LIBXML2="No" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&5 +echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&2;} +ac_tool_warned=yes ;; +esac + CONFIG_LIBXML2=$ac_ct_CONFIG_LIBXML2 + fi +else + CONFIG_LIBXML2="$ac_cv_prog_CONFIG_LIBXML2" +fi + + if test ! "x${CONFIG_LIBXML2}" = xNo; then + if test x"" = x ; then A=--cflags ; else A="" ; fi + LIBXML2_INCLUDE=$(${CONFIG_LIBXML2} $A) + if test x"" = x ; then A=--libs ; else A="" ; fi + LIBXML2_LIB=$(${CONFIG_LIBXML2} $A) + if test x"#include <libxml/tree.h> + #include <libxml/parser.h>" != x ; then + saved_cppflags="${CPPFLAGS}" + if test "x${LIBXML2_DIR}" != "x"; then + LIBXML2_INCLUDE="-I${LIBXML2_DIR}/include" + fi + CPPFLAGS="${CPPFLAGS} ${LIBXML2_INCLUDE}" + + saved_ldflags="${LDFLAGS}" + LDFLAGS="${LIBXML2_LIB}" + + cat >conftest.$ac_ext <<_ACEOF + /* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + #include <libxml/tree.h> + #include <libxml/parser.h> +int +main () +{ + LIBXML_TEST_VERSION; + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + PBX_LIBXML2=1 + +cat >>confdefs.h <<\_ACEOF +#define HAVE_LIBXML2 1 +_ACEOF + + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext + CPPFLAGS="${saved_cppflags}" + LDFLAGS="${saved_ldflags}" + else + PBX_LIBXML2=1 + +cat >>confdefs.h <<\_ACEOF +#define HAVE_LIBXML2 1 +_ACEOF + + fi + fi + fi + + if test "${PBX_LIBXML2}" != 1; then + { echo "$as_me:$LINENO: *** XML documentation will not be available because the 'libxml2' development package is missing." >&5 +echo "$as_me: *** XML documentation will not be available because the 'libxml2' development package is missing." >&6;} + { echo "$as_me:$LINENO: *** Please run the 'configure' script with the '--disable-xmldoc' parameter option" >&5 +echo "$as_me: *** Please run the 'configure' script with the '--disable-xmldoc' parameter option" >&6;} + { echo "$as_me:$LINENO: *** or install the 'libxml2' development package." >&5 +echo "$as_me: *** or install the 'libxml2' development package." >&6;} + exit 1 + fi +fi + if test "x${PBX_MISDN}" != "x1" -a "${USE_MISDN}" != "no"; then pbxlibdir="" @@ -51281,6 +51522,10 @@ LDAP_LIB!$LDAP_LIB$ac_delim LDAP_INCLUDE!$LDAP_INCLUDE$ac_delim LDAP_DIR!$LDAP_DIR$ac_delim PBX_LDAP!$PBX_LDAP$ac_delim +LIBXML2_LIB!$LIBXML2_LIB$ac_delim +LIBXML2_INCLUDE!$LIBXML2_INCLUDE$ac_delim +LIBXML2_DIR!$LIBXML2_DIR$ac_delim +PBX_LIBXML2!$PBX_LIBXML2$ac_delim LTDL_LIB!$LTDL_LIB$ac_delim LTDL_INCLUDE!$LTDL_INCLUDE$ac_delim LTDL_DIR!$LTDL_DIR$ac_delim @@ -51290,10 +51535,6 @@ LUA_INCLUDE!$LUA_INCLUDE$ac_delim LUA_DIR!$LUA_DIR$ac_delim PBX_LUA!$PBX_LUA$ac_delim MISDN_LIB!$MISDN_LIB$ac_delim -MISDN_INCLUDE!$MISDN_INCLUDE$ac_delim -MISDN_DIR!$MISDN_DIR$ac_delim -PBX_MISDN!$PBX_MISDN$ac_delim -NBS_LIB!$NBS_LIB$ac_delim _ACEOF if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 97; then @@ -51335,6 +51576,10 @@ _ACEOF ac_delim='%!_!# ' for ac_last_try in false false false false false :; do cat >conf$$subs.sed <<_ACEOF +MISDN_INCLUDE!$MISDN_INCLUDE$ac_delim +MISDN_DIR!$MISDN_DIR$ac_delim +PBX_MISDN!$PBX_MISDN$ac_delim +NBS_LIB!$NBS_LIB$ac_delim NBS_INCLUDE!$NBS_INCLUDE$ac_delim NBS_DIR!$NBS_DIR$ac_delim PBX_NBS!$PBX_NBS$ac_delim @@ -51428,10 +51673,6 @@ SQLITE_DIR!$SQLITE_DIR$ac_delim PBX_SQLITE!$PBX_SQLITE$ac_delim SQLITE3_LIB!$SQLITE3_LIB$ac_delim SQLITE3_INCLUDE!$SQLITE3_INCLUDE$ac_delim -SQLITE3_DIR!$SQLITE3_DIR$ac_delim -PBX_SQLITE3!$PBX_SQLITE3$ac_delim -SUPPSERV_LIB!$SUPPSERV_LIB$ac_delim -SUPPSERV_INCLUDE!$SUPPSERV_INCLUDE$ac_delim _ACEOF if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 97; then @@ -51473,6 +51714,10 @@ _ACEOF ac_delim='%!_!# ' for ac_last_try in false false false false false :; do cat >conf$$subs.sed <<_ACEOF +SQLITE3_DIR!$SQLITE3_DIR$ac_delim +PBX_SQLITE3!$PBX_SQLITE3$ac_delim +SUPPSERV_LIB!$SUPPSERV_LIB$ac_delim +SUPPSERV_INCLUDE!$SUPPSERV_INCLUDE$ac_delim SUPPSERV_DIR!$SUPPSERV_DIR$ac_delim PBX_SUPPSERV!$PBX_SUPPSERV$ac_delim OPENSSL_LIB!$OPENSSL_LIB$ac_delim @@ -51533,6 +51778,7 @@ AST_SHADOW_WARNINGS!$AST_SHADOW_WARNINGS$ac_delim PBX_RTLD_NOLOAD!$PBX_RTLD_NOLOAD$ac_delim PBX_IP_MTU_DISCOVER!$PBX_IP_MTU_DISCOVER$ac_delim GSM_INTERNAL!$GSM_INTERNAL$ac_delim +CONFIG_LIBXML2!$CONFIG_LIBXML2$ac_delim PBX_MISDN_FAC_RESULT!$PBX_MISDN_FAC_RESULT$ac_delim PBX_MISDN_FAC_ERROR!$PBX_MISDN_FAC_ERROR$ac_delim CONFIG_NETSNMP!$CONFIG_NETSNMP$ac_delim @@ -51563,7 +51809,7 @@ CURL_CONFIG!$CURL_CONFIG$ac_delim LTLIBOBJS!$LTLIBOBJS$ac_delim _ACEOF - if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 88; then + if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 93; then break elif $ac_last_try; then { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 diff --git a/configure.ac b/configure.ac index 1f0973842..6c69ce63e 100644 --- a/configure.ac +++ b/configure.ac @@ -236,6 +236,7 @@ AST_EXT_LIB_SETUP([IODBC], [iODBC], [iodbc]) AST_EXT_LIB_SETUP([ISDNNET], [ISDN4Linux Library], [isdnnet]) AST_EXT_LIB_SETUP([JACK], [Jack Audio Connection Kit], [jack]) AST_EXT_LIB_SETUP([LDAP], [OpenLDAP], [ldap]) +AST_EXT_LIB_SETUP([LIBXML2], [LibXML2], [libxml2]) AST_EXT_LIB_SETUP([LTDL], [libtool], [ltdl]) AST_EXT_LIB_SETUP([LUA], [Lua], [lua]) AST_EXT_LIB_SETUP([MISDN], [mISDN User Library], [misdn]) @@ -1248,6 +1249,28 @@ AST_EXT_LIB_CHECK([LTDL], [ltdl], [lt_dlinit], [ltdl.h], []) AST_EXT_LIB_CHECK([LDAP], [ldap], [ldap_initialize], [ldap.h]) +AC_ARG_ENABLE([xmldoc], + [AS_HELP_STRING([--disable-xmldoc], + [Explicity disable XML documentation])], + [case "${enableval}" in + y|ye|yes) disable_xmldoc=no ;; + n|no) disable_xmldoc=yes ;; + *) AC_MSG_ERROR(bad value ${enableval} for --disable-xmldoc) ;; + esac], [disable_xmldoc=no]) + +if test "${disable_xmldoc}" != "yes"; then + AST_EXT_TOOL_CHECK([LIBXML2], [xml2], , , + [#include <libxml/tree.h> + #include <libxml/parser.h>], + [LIBXML_TEST_VERSION]) + if test "${PBX_LIBXML2}" != 1; then + AC_MSG_NOTICE(*** XML documentation will not be available because the 'libxml2' development package is missing.) + AC_MSG_NOTICE(*** Please run the 'configure' script with the '--disable-xmldoc' parameter option) + AC_MSG_NOTICE(*** or install the 'libxml2' development package.) + exit 1 + fi +fi + AST_EXT_LIB_CHECK([MISDN], [mISDN], [mISDN_open], [mISDNuser/mISDNlib.h]) if test "${PBX_MISDN}" = 1; then diff --git a/doc/appdocsxml.dtd b/doc/appdocsxml.dtd new file mode 100644 index 000000000..67e86d642 --- /dev/null +++ b/doc/appdocsxml.dtd @@ -0,0 +1,64 @@ + <!ELEMENT docs (application|function)* > + + <!ELEMENT application (synopsis?,syntax?,description?,see-also?)> + <!ATTLIST application name CDATA #REQUIRED> + <!ATTLIST application language CDATA #REQUIRED> + + <!ELEMENT function (synopsis?,syntax?,description?,see-also?)> + <!ATTLIST function name CDATA #REQUIRED> + <!ATTLIST function language CDATA #REQUIRED> + + <!ELEMENT see-also (ref*)> + + <!ELEMENT ref (#PCDATA)*> + <!ATTLIST ref type (application|function|astcli|link|manpage) #REQUIRED> + + <!ELEMENT synopsis (#PCDATA)> + + <!ELEMENT syntax (parameter*)> + <!ATTLIST syntax argsep CDATA ","> + + <!ELEMENT description (para|note|warning|variablelist|enumlist)*> + + <!ELEMENT parameter (optionlist|enumlist|argument|para|note|warning)*> + <!ATTLIST parameter name CDATA #REQUIRED> + <!ATTLIST parameter required (yes|no|true|false) "false"> + <!ATTLIST parameter multiple (yes|no|true|false) "false"> + <!ATTLIST parameter hasparams (yes|no|true|false|optional) "false"> + <!ATTLIST parameter argsep CDATA ","> + + <!ELEMENT optionlist (option+)> + <!ELEMENT option (argument|para|note|warning|variablelist|enumlist)*> + <!ATTLIST option name CDATA #REQUIRED> + <!ATTLIST option argsep CDATA ","> + <!ATTLIST option implies CDATA ""> + + <!ELEMENT enumlist (enum+)> + <!ELEMENT enum (para|note|warning)*> + <!ATTLIST enum name CDATA #REQUIRED> + + <!ELEMENT argument (para|note|warning|variablelist|argument)*> + <!ATTLIST argument name CDATA #REQUIRED> + <!ATTLIST argument multiple (yes|no|true|false) "false"> + <!ATTLIST argument required (yes|no|true|false) "false"> + <!ATTLIST argument hasparams (yes|no|true|false|optional) "false"> + + <!ELEMENT para (#PCDATA|astcli|literal|emphasis|filename|directory|replaceable|variable)*> + <!ELEMENT literal (#PCDATA)> + <!ELEMENT emphasis (#PCDATA)> + <!ELEMENT filename (#PCDATA)> + <!ELEMENT replaceable (#PCDATA)> + <!ELEMENT directory (#PCDATA)> + <!ELEMENT astcli (#PCDATA)> + + <!ELEMENT note (para+)> + <!ELEMENT warning (para+)> + + <!ELEMENT variablelist (variable+)> + <!ELEMENT variable (#PCDATA|value|para)*> + <!ATTLIST variable name CDATA ""> + + <!ELEMENT value (#PCDATA)> + <!ATTLIST value name CDATA #REQUIRED> + <!ATTLIST value default CDATA ""> + diff --git a/doc/tex/asterisk-conf.tex b/doc/tex/asterisk-conf.tex index f39d4dc05..4b08023a6 100644 --- a/doc/tex/asterisk-conf.tex +++ b/doc/tex/asterisk-conf.tex @@ -82,6 +82,9 @@ rungroup = asterisk ; Enable internal timing support (-I) internal_timing = yes | no +; Language Options +documentation_language = en | es | ru + ; These options have no command line equivalent ; Cache record() files in another directory until completion diff --git a/funcs/func_base64.c b/funcs/func_base64.c index 0849e9539..28805b943 100644 --- a/funcs/func_base64.c +++ b/funcs/func_base64.c @@ -30,6 +30,35 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/pbx.h" /* function register/unregister */ #include "asterisk/utils.h" +/*** DOCUMENTATION + <function name="BASE64_ENCODE" language="en_US"> + <synopsis> + Encode a string in base64. + </synopsis> + <syntax> + <parameter name="string" required="true"> + <para>Input string</para> + </parameter> + </syntax> + <description> + <para>Returns the base64 string.</para> + </description> + </function> + <function name="BASE64_DECODE" language="en_US"> + <synopsis> + Decode a base64 string. + </synopsis> + <syntax> + <parameter name="string" required="true"> + <para>Input string.</para> + </parameter> + </syntax> + <description> + <para>Returns the plain text string.</para> + </description> + </function> + ***/ + static int base64_encode(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) { @@ -58,17 +87,11 @@ static int base64_decode(struct ast_channel *chan, const char *cmd, char *data, static struct ast_custom_function base64_encode_function = { .name = "BASE64_ENCODE", - .synopsis = "Encode a string in base64", - .desc = "Returns the base64 string\n", - .syntax = "BASE64_ENCODE(<string>)", .read = base64_encode, }; static struct ast_custom_function base64_decode_function = { .name = "BASE64_DECODE", - .synopsis = "Decode a base64 string", - .desc = "Returns the plain text string\n", - .syntax = "BASE64_DECODE(<base64_string>)", .read = base64_decode, }; diff --git a/funcs/func_blacklist.c b/funcs/func_blacklist.c index 2a2fa78c7..c353b20fd 100644 --- a/funcs/func_blacklist.c +++ b/funcs/func_blacklist.c @@ -35,6 +35,20 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/channel.h" #include "asterisk/astdb.h" +/*** DOCUMENTATION + <function name="BLACKLIST" language="en_US"> + <synopsis> + Check if the callerid is on the blacklist. + </synopsis> + <syntax /> + <description> + <para>Uses astdb to check if the Caller*ID is in family <literal>blacklist</literal>. + Returns <literal>1</literal> or <literal>0</literal>.</para> + </description> + </function> + +***/ + static int blacklist_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) { char blacklist[1]; @@ -55,9 +69,6 @@ static int blacklist_read(struct ast_channel *chan, const char *cmd, char *data, static struct ast_custom_function blacklist_function = { .name = "BLACKLIST", - .synopsis = "Check if the callerid is on the blacklist", - .desc = "Uses astdb to check if the Caller*ID is in family 'blacklist'. Returns 1 or 0.\n", - .syntax = "BLACKLIST()", .read = blacklist_read, }; diff --git a/funcs/func_callerid.c b/funcs/func_callerid.c index c56089ca2..7f066cdaa 100644 --- a/funcs/func_callerid.c +++ b/funcs/func_callerid.c @@ -32,6 +32,74 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/app.h" #include "asterisk/callerid.h" +/*** DOCUMENTATION + <function name="CALLERID" language="en_US"> + <synopsis> + Gets or sets Caller*ID data on the channel. + </synopsis> + <syntax> + <parameter name="datatype" required="true"> + <para>The allowable datatypes are:</para> + <enumlist> + <enum name="all" /> + <enum name="num" /> + <enum name="ANI" /> + <enum name="DNID" /> + <enum name="RDNIS" /> + <enum name="pres" /> + <enum name="ton" /> + </enumlist> + </parameter> + <parameter name="CID"> + <para>Optional Caller*ID</para> + </parameter> + </syntax> + <description> + <para>Gets or sets Caller*ID data on the channel. Uses channel callerid by default or optional + callerid, if specified.</para> + </description> + </function> + <function name="CALLERPRES" language="en_US"> + <synopsis> + Gets or sets Caller*ID presentation on the channel. + </synopsis> + <syntax /> + <description> + <para>Gets or sets Caller*ID presentation on the channel. The following values + are valid:</para> + <enumlist> + <enum name="allowed_not_screened"> + <para>Presentation Allowed, Not Screened.</para> + </enum> + <enum name="allowed_passed_screen"> + <para>Presentation Allowed, Passed Screen.</para> + </enum> + <enum name="allowed_failed_screen"> + <para>Presentation Allowed, Failed Screen.</para> + </enum> + <enum name="allowed"> + <para>Presentation Allowed, Network Number.</para> + </enum> + <enum name="prohib_not_screened"> + <para>Presentation Prohibited, Not Screened.</para> + </enum> + <enum name="prohib_passed_screen"> + <para>Presentation Prohibited, Passed Screen.</para> + </enum> + <enum name="prohib_failed_screen"> + <para>Presentation Prohibited, Failed Screen.</para> + </enum> + <enum name="prohib"> + <para>Presentation Prohibited, Network Number.</para> + </enum> + <enum name="unavailable"> + <para>Number Unavailable.</para> + </enum> + </enumlist> + </description> + </function> + ***/ + static int callerpres_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) { ast_copy_string(buf, ast_named_caller_presentation(chan->cid.cid_pres), len); @@ -184,33 +252,12 @@ static int callerid_write(struct ast_channel *chan, const char *cmd, char *data, static struct ast_custom_function callerid_function = { .name = "CALLERID", - .synopsis = "Gets or sets Caller*ID data on the channel.", - .syntax = "CALLERID(datatype[,<optional-CID>])", - .desc = - "Gets or sets Caller*ID data on the channel. The allowable datatypes\n" - "are \"all\", \"name\", \"num\", \"ANI\", \"DNID\", \"RDNIS\", \"pres\",\n" - "and \"ton\".\n" - "Uses channel callerid by default or optional callerid, if specified.\n", .read = callerid_read, .write = callerid_write, }; static struct ast_custom_function callerpres_function = { .name = "CALLERPRES", - .synopsis = "Gets or sets Caller*ID presentation on the channel.", - .syntax = "CALLERPRES()", - .desc = -"Gets or sets Caller*ID presentation on the channel. The following values\n" -"are valid:\n" -" allowed_not_screened : Presentation Allowed, Not Screened\n" -" allowed_passed_screen : Presentation Allowed, Passed Screen\n" -" allowed_failed_screen : Presentation Allowed, Failed Screen\n" -" allowed : Presentation Allowed, Network Number\n" -" prohib_not_screened : Presentation Prohibited, Not Screened\n" -" prohib_passed_screen : Presentation Prohibited, Passed Screen\n" -" prohib_failed_screen : Presentation Prohibited, Failed Screen\n" -" prohib : Presentation Prohibited, Network Number\n" -" unavailable : Number Unavailable\n", .read = callerpres_read, .write = callerpres_write, }; diff --git a/funcs/func_cdr.c b/funcs/func_cdr.c index 9b73d03f1..6c80e4f93 100644 --- a/funcs/func_cdr.c +++ b/funcs/func_cdr.c @@ -36,6 +36,133 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/app.h" #include "asterisk/cdr.h" +/*** DOCUMENTATION + <function name="CDR" language="en_US"> + <synopsis> + Gets or sets a CDR variable. + </synopsis> + <syntax> + <parameter name="name" required="true"> + <para>CDR field name:</para> + <enumlist> + <enum name="clid"> + <para>Caller ID.</para> + </enum> + <enum name="lastdata"> + <para>Last application arguments.</para> + </enum> + <enum name="disposition"> + <para>ANSWERED, NO ANSWER, BUSY.</para> + </enum> + <enum name="src"> + <para>Source.</para> + </enum> + <enum name="start"> + <para>Time the call started.</para> + </enum> + <enum name="amaflags"> + <para>DOCUMENTATION, BILL, IGNORE, etc.</para> + </enum> + <enum name="dst"> + <para>Destination.</para> + </enum> + <enum name="answer"> + <para>Time the call was answered.</para> + </enum> + <enum name="accountcode"> + <para>The channel's account code.</para> + </enum> + <enum name="dcontext"> + <para>Destination context.</para> + </enum> + <enum name="end"> + <para>Time the call ended.</para> + </enum> + <enum name="uniqueid"> + <para>The channel's unique id.</para> + </enum> + <enum name="dstchannel"> + <para>Destination channel.</para> + </enum> + <enum name="duration"> + <para>Duration of the call.</para> + </enum> + <enum name="userfield"> + <para>The channel's user specified field.</para> + </enum> + <enum name="lastapp"> + <para>Last application.</para> + </enum> + <enum name="billsec"> + <para>Duration of the call once it was answered.</para> + </enum> + <enum name="channel"> + <para>Channel name.</para> + </enum> + </enumlist> + </parameter> + <parameter name="options" required="false"> + <optionlist> + <option name="l"> + <para>Uses the most recent CDR on a channel with multiple records</para> + </option> + <option name="r"> + <para>Searches the entire stack of CDRs on the channel.</para> + </option> + <option name="s"> + <para>Skips any CDR's that are marked 'LOCKED' due to forkCDR() calls. + (on setting/writing CDR vars only)</para> + </option> + <option name="u"> + <para>Retrieves the raw, unprocessed value.</para> + <para>For example, 'start', 'answer', and 'end' will be retrieved as epoch + values, when the <literal>u</literal> option is passed, but formatted as YYYY-MM-DD HH:MM:SS + otherwise. Similarly, disposition and amaflags will return their raw + integral values.</para> + </option> + </optionlist> + </parameter> + </syntax> + <description> + <para>All of the CDR field names are read-only, except for <literal>accountcode</literal>, + <literal>userfield</literal>, and <literal>amaflags</literal>. You may, however, supply + a name not on the above list, and create your own variable, whose value can be changed + with this function, and this variable will be stored on the cdr.</para> + <note><para>For setting CDR values, the <literal>l</literal> flag does not apply to + setting the <literal>accountcode</literal>, <literal>userfield</literal>, or + <literal>amaflags</literal>.</para></note> + <para>Raw values for <literal>disposition</literal>:</para> + <enumlist> + <enum name="1"> + <para>NO ANSWER</para> + </enum> + <enum name="2"> + <para>BUSY</para> + </enum> + <enum name="3"> + <para>FAILED</para> + </enum> + <enum name="4"> + <para>ANSWERED</para> + </enum> + </enumlist> + <para>Raw values for <literal>amaflags</literal>:</para> + <enumlist> + <enum name="1"> + <para>OMIT</para> + </enum> + <enum name="2"> + <para>BILLING</para> + </enum> + <enum name="3"> + <para>DOCUMENTATION</para> + </enum> + </enumlist> + <para>Example: exten => 1,1,Set(CDR(userfield)=test)</para> + </description> + </function> + ***/ + enum { OPT_RECURSIVE = (1 << 0), OPT_UNPARSED = (1 << 1), @@ -128,44 +255,8 @@ static int cdr_write(struct ast_channel *chan, const char *cmd, char *parse, static struct ast_custom_function cdr_function = { .name = "CDR", - .synopsis = "Gets or sets a CDR variable", - .syntax = "CDR(<name>[,options])", .read = cdr_read, .write = cdr_write, - .desc = -"Options:\n" -" 'l' uses the most recent CDR on a channel with multiple records\n" -" 'r' searches the entire stack of CDRs on the channel\n" -" 's' skips any CDR's that are marked 'LOCKED' due to forkCDR() calls.\n" -" (on setting/writing CDR vars only)\n" -" 'u' retrieves the raw, unprocessed value\n" -" For example, 'start', 'answer', and 'end' will be retrieved as epoch\n" -" values, when the 'u' option is passed, but formatted as YYYY-MM-DD HH:MM:SS\n" -" otherwise. Similarly, disposition and amaflags will return their raw\n" -" integral values.\n" -" Here is a list of all the available cdr field names:\n" -" clid lastdata disposition\n" -" src start amaflags\n" -" dst answer accountcode\n" -" dcontext end uniqueid\n" -" dstchannel duration userfield\n" -" lastapp billsec channel\n" -" All of the above variables are read-only, except for accountcode,\n" -" userfield, and amaflags. You may, however, supply\n" -" a name not on the above list, and create your own\n" -" variable, whose value can be changed with this function,\n" -" and this variable will be stored on the cdr.\n" -" For setting CDR values, the 'l' flag does not apply to\n" -" setting the accountcode, userfield, or amaflags.\n" -" raw values for disposition:\n" -" 1 = NO ANSWER\n" -" 2 = BUSY\n" -" 3 = FAILED\n" -" 4 = ANSWERED\n" -" raw values for amaflags:\n" -" 1 = OMIT\n" -" 2 = BILLING\n" -" 3 = DOCUMENTATION\n", }; static int unload_module(void) diff --git a/funcs/func_channel.c b/funcs/func_channel.c index c13c668a3..4393c2e33 100644 --- a/funcs/func_channel.c +++ b/funcs/func_channel.c @@ -38,6 +38,168 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/indications.h" #include "asterisk/stringfields.h" +/*** DOCUMENTATION + <function name="CHANNELS" language="en_US"> + <synopsis> + Gets the list of channels, optionally filtering by a regular expression. + </synopsis> + <syntax> + <parameter name="regular_expression" /> + </syntax> + <description> + <para>Gets the list of channels, optionally filtering by a <replaceable>regular_expression</replaceable>. If + no argument is provided, all known channels are returned. The + <replaceable>regular_expression</replaceable> must correspond to + the POSIX.2 specification, as shown in <emphasis>regex(7)</emphasis>. The list returned + will be space-delimited.</para> + </description> + </function> + <function name="CHANNEL" language="en_US"> + <synopsis> + Gets/sets various pieces of information about the channel. + </synopsis> + <syntax> + <parameter name="item" required="true"> + <para>Standard items (provided by all channel technologies) are:</para> + <enumlist> + <enum name="audioreadformat"> + <para>R/O format currently being read.</para> + </enum> + <enum name="audionativeformat"> + <para>R/O format used natively for audio.</para> + </enum> + <enum name="audiowriteformat"> + <para>R/O format currently being written.</para> + </enum> + <enum name="callgroup"> + <para>R/W call groups for call pickup.</para> + </enum> + <enum name="channeltype"> + <para>R/O technology used for channel.</para> + </enum> + <enum name="language"> + <para>R/W language for sounds played.</para> + </enum> + <enum name="musicclass"> + <para>R/W class (from musiconhold.conf) for hold music.</para> + </enum> + <enum name="parkinglot"> + <para>R/W parkinglot for parking.</para> + </enum> + <enum name="rxgain"> + <para>R/W set rxgain level on channel drivers that support it.</para> + </enum> + <enum name="state"> + <para>R/O state for channel</para> + </enum> + <enum name="tonezone"> + <para>R/W zone for indications played</para> + </enum> + <enum name="txgain"> + <para>R/W set txgain level on channel drivers that support it.</para> + </enum> + <enum name="videonativeformat"> + <para>R/O format used natively for video</para> + </enum> + <enum name="trace"> + <para>R/W whether or not context tracing is enabled, only available + <emphasis>if CHANNEL_TRACE is defined</emphasis>.</para> + </enum> + </enumlist> + <para><emphasis>chan_sip</emphasis> provides the following additional options:</para> + <enumlist> + <enum name="peerip"> + <para>R/O Get the IP address of the peer.</para> + </enum> + <enum name="recvip"> + <para>R/O Get the source IP address of the peer.</para> + </enum> + <enum name="from"> + <para>R/O Get the URI from the From: header.</para> + </enum> + <enum name="uri"> + <para>R/O Get the URI from the Contact: header.</para> + </enum> + <enum name="useragent"> + <para>R/O Get the useragent.</para> + </enum> + <enum name="peername"> + <para>R/O Get the name of the peer.</para> + </enum> + <enum name="t38passthrough"> + <para>R/O <literal>1</literal> if T38 is offered or enabled in this channel, + otherwise <literal>0</literal></para> + </enum> + <enum name="rtpqos"> + <para>R/O Get QOS information about the RTP stream</para> + <para> This option takes two additional arguments:</para> + <para> Argument 1:</para> + <para> <literal>audio</literal> Get data about the audio stream</para> + <para> <literal>video</literal> Get data about the video stream</para> + <para> <literal>text</literal> Get data about the text stream</para> + <para> Argument 2:</para> + <para> <literal>local_ssrc</literal> Local SSRC (stream ID)</para> + <para> <literal>local_lostpackets</literal> Local lost packets</para> + <para> <literal>local_jitter</literal> Local calculated jitter</para> + <para> <literal>local_maxjitter</literal> Local calculated jitter (maximum)</para> + <para> <literal>local_minjitter</literal> Local calculated jitter (minimum)</para> + <para> <literal>local_normdevjitter</literal>Local calculated jitter (normal deviation)</para> + <para> <literal>local_stdevjitter</literal> Local calculated jitter (standard deviation)</para> + <para> <literal>local_count</literal> Number of received packets</para> + <para> <literal>remote_ssrc</literal> Remote SSRC (stream ID)</para> + <para> <literal>remote_lostpackets</literal>Remote lost packets</para> + <para> <literal>remote_jitter</literal> Remote reported jitter</para> + <para> <literal>remote_maxjitter</literal> Remote calculated jitter (maximum)</para> + <para> <literal>remote_minjitter</literal> Remote calculated jitter (minimum)</para> + <para> <literal>remote_normdevjitter</literal>Remote calculated jitter (normal deviation)</para> + <para> <literal>remote_stdevjitter</literal>Remote calculated jitter (standard deviation)</para> + <para> <literal>remote_count</literal> Number of transmitted packets</para> + <para> <literal>remote_ssrc</literal> Remote SSRC (stream ID)</para> + <para> <literal>remote_lostpackets</literal>Remote lost packets</para> + <para> <literal>remote_jitter</literal> Remote reported jitter</para> + <para> <literal>remote_maxjitter</literal> Remote calculated jitter (maximum)</para> + <para> <literal>remote_minjitter</literal> Remote calculated jitter (minimum)</para> + <para> <literal>remote_normdevjitter</literal>Remote calculated jitter (normal deviation)</para> + <para> <literal>remote_stdevjitter</literal>Remote calculated jitter (standard deviation)</para> + <para> <literal>remote_count</literal> Number of transmitted packets</para> + <para> <literal>rtt</literal> Round trip time</para> + <para> <literal>maxrtt</literal> Round trip time (maximum)</para> + <para> <literal>minrtt</literal> Round trip time (minimum)</para> + <para> <literal>normdevrtt</literal> Round trip time (normal deviation)</para> + <para> <literal>stdevrtt</literal> Round trip time (standard deviation)</para> + <para> <literal>all</literal> All statistics (in a form suited to logging, + but not for parsing)</para> + </enum> + <enum name="rtpdest"> + <para>R/O Get remote RTP destination information.</para> + <para> This option takes one additional argument:</para> + <para> Argument 1:</para> + <para> <literal>audio</literal> Get audio destination</para> + <para> <literal>video</literal> Get video destination</para> + </enum> + </enumlist> + <para><emphasis>chan_iax2</emphasis> provides the following additional options:</para> + <enumlist> + <enum name="osptoken"> + <para>R/W Get or set the OSP token information for a call.</para> + </enum> + <enum name="peerip"> + <para>R/O Get the peer's ip address.</para> + </enum> + <enum name="peername"> + <para>R/O Get the peer's username.</para> + </enum> + </enumlist> + </parameter> + </syntax> + <description> + <para>Gets/sets various pieces of information about the channel, additional <replaceable>item</replaceable> may + be available from the channel driver; see its documentation for details. Any <replaceable>item</replaceable> + requested that is not available on the current channel will return an empty string.</para> + </description> + </function> + ***/ + #define locked_copy_string(chan, dest, source, len) \ do { \ ast_channel_lock(chan); \ @@ -168,80 +330,6 @@ static int func_channel_write(struct ast_channel *chan, const char *function, static struct ast_custom_function channel_function = { .name = "CHANNEL", - .synopsis = "Gets/sets various pieces of information about the channel.", - .syntax = "CHANNEL(item)", - .desc = "Gets/set various pieces of information about the channel.\n" - "Standard items (provided by all channel technologies) are:\n" - "R/O audioreadformat format currently being read\n" - "R/O audionativeformat format used natively for audio\n" - "R/O audiowriteformat format currently being written\n" - "R/W callgroup call groups for call pickup\n" - "R/O channeltype technology used for channel\n" - "R/W language language for sounds played\n" - "R/W musicclass class (from musiconhold.conf) for hold music\n" - "R/W parkinglot parkinglot for parking\n" - "R/W rxgain set rxgain level on channel drivers that support it\n" - "R/O state state for channel\n" - "R/W tonezone zone for indications played\n" - "R/W txgain set txgain level on channel drivers that support it\n" - "R/O videonativeformat format used natively for video\n" -#ifdef CHANNEL_TRACE - "R/W trace whether or not context tracing is enabled\n" -#endif - "\n" - "chan_sip provides the following additional options:\n" - "R/O peerip Get the IP address of the peer\n" - "R/O recvip Get the source IP address of the peer\n" - "R/O from Get the URI from the From: header\n" - "R/O uri Get the URI from the Contact: header\n" - "R/O useragent Get the useragent\n" - "R/O peername Get the name of the peer\n" - "R/O t38passthrough 1 if T38 is offered or enabled in this channel, otherwise 0\n" - "R/O rtpqos Get QOS information about the RTP stream\n" - " This option takes two additional arguments:\n" - " Argument 1:\n" - " audio Get data about the audio stream\n" - " video Get data about the video stream\n" - " text Get data about the text stream\n" - " Argument 2:\n" - " local_ssrc Local SSRC (stream ID)\n" - " local_lostpackets Local lost packets\n" - " local_jitter Local calculated jitter\n" - " local_maxjitter Local calculated jitter (maximum)\n" - " local_minjitter Local calculated jitter (minimum)\n" - " local_normdevjitter Local calculated jitter (normal deviation)\n" - " local_stdevjitter Local calculated jitter (standard deviation)\n" - " local_count Number of received packets\n" - " remote_ssrc Remote SSRC (stream ID)\n" - " remote_lostpackets Remote lost packets\n" - " remote_jitter Remote reported jitter\n" - " remote_maxjitter Remote calculated jitter (maximum)\n" - " remote_minjitter Remote calculated jitter (minimum)\n" - " remote_normdevjitter Remote calculated jitter (normal deviation)\n" - " remote_stdevjitter Remote calculated jitter (standard deviation)\n" - " remote_count Number of transmitted packets\n" - " rtt Round trip time\n" - " maxrtt Round trip time (maximum)\n" - " minrtt Round trip time (minimum)\n" - " normdevrtt Round trip time (normal deviation)\n" - " stdevrtt Round trip time (standard deviation)\n" - " all All statistics (in a form suited to logging, but not for parsing)\n" - "R/O rtpdest Get remote RTP destination information\n" - " This option takes one additional argument:\n" - " Argument 1:\n" - " audio Get audio destination\n" - " video Get video destination\n" - "\n" - "chan_iax2 provides the following additional options:\n" - "R/W osptoken Get or set the OSP token information for a call\n" - "R/O peerip Get the peer's ip address\n" - "R/O peername Get the peer's username\n" - "\n" - "Additional items may be available from the channel driver providing\n" - "the channel; see its documentation for details.\n" - "\n" - "Any item requested that is not available on the current channel will\n" - "return an empty string.\n", .read = func_channel_read, .write = func_channel_write, }; @@ -288,13 +376,6 @@ static int func_channels_read(struct ast_channel *chan, const char *function, ch static struct ast_custom_function channels_function = { .name = "CHANNELS", - .synopsis = "Gets the list of channels, optionally filtering by a regular expression.", - .syntax = "CHANNEL([regular expression])", - .desc = -"Gets the list of channels, optionally filtering by a regular expression. If\n" -"no argument is provided, all known channels are returned. The regular\n" -"expression must correspond to the POSIX.2 specification, as shown in\n" -"regex(7). The list returned will be space-delimited.\n", .read = func_channels_read, }; diff --git a/funcs/func_config.c b/funcs/func_config.c index 5669f3655..21d291c2e 100644 --- a/funcs/func_config.c +++ b/funcs/func_config.c @@ -36,6 +36,23 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/pbx.h" #include "asterisk/app.h" +/*** DOCUMENTATION + <function name="AST_CONFIG" language="en_US"> + <synopsis> + Retrieve a variable from a configuration file. + </synopsis> + <syntax> + <parameter name="config_file" required="true" /> + <parameter name="category" required="true" /> + <parameter name="variable_name" required="true" /> + </syntax> + <description> + <para>This function reads a variable from an Asterisk configuration file.</para> + </description> + </function> + +***/ + struct config_item { AST_RWLIST_ENTRY(config_item) entry; struct ast_config *cfg; @@ -160,11 +177,6 @@ static int config_function_read(struct ast_channel *chan, const char *cmd, char static struct ast_custom_function config_function = { .name = "AST_CONFIG", - .syntax = "AST_CONFIG(config_file,category,variable_name)", - .synopsis = "Retrieve a variable from a configuration file", - .desc = - " This function reads a variable from an Asterisk configuration file.\n" - "", .read = config_function_read, }; diff --git a/funcs/func_cut.c b/funcs/func_cut.c index 96779b661..dda907ca2 100644 --- a/funcs/func_cut.c +++ b/funcs/func_cut.c @@ -34,6 +34,49 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/module.h" #include "asterisk/app.h" +/*** DOCUMENTATION + <function name="SORT" language="en_US"> + <synopsis> + Sorts a list of key/vals into a list of keys, based upon the vals. + </synopsis> + <syntax> + <parameter name="keyval" required="true" argsep=":"> + <argument name="key1" required="true" /> + <argument name="val1" required="true" /> + </parameter> + <parameter name="keyvaln" multiple="true" argsep=":"> + <argument name="key2" required="true" /> + <argument name="val2" required="true" /> + </parameter> + </syntax> + <description> + <para>Takes a comma-separated list of keys and values, each separated by a colon, and returns a + comma-separated list of the keys, sorted by their values. Values will be evaluated as + floating-point numbers.</para> + </description> + </function> + <function name="CUT" language="en_US"> + <synopsis> + Slices and dices strings, based upon a named delimiter. + </synopsis> + <syntax> + <parameter name="varname" required="true"> + <para>Variable you want cut</para> + </parameter> + <parameter name="char-delim" required="true"> + <para>Delimiter, defaults to <literal>-</literal></para> + </parameter> + <parameter name="range-spec" required="true"> + <para>Number of the field you want (1-based offset), may also be specified as a range (with <literal>-</literal>) + or group of ranges and fields (with <literal>&</literal>)</para> + </parameter> + </syntax> + <description> + <para>Cut out information from a string (<replaceable>varname</replaceable>), based upon a named delimiter.</para> + </description> + </function> + ***/ + /* Maximum length of any variable */ #define MAXRESULT 1024 @@ -255,25 +298,11 @@ static int acf_cut_exec(struct ast_channel *chan, const char *cmd, char *data, c struct ast_custom_function acf_sort = { .name = "SORT", - .synopsis = "Sorts a list of key/vals into a list of keys, based upon the vals", - .syntax = "SORT(key1:val1[...][,keyN:valN])", - .desc = -"Takes a comma-separated list of keys and values, each separated by a colon, and returns a\n" -"comma-separated list of the keys, sorted by their values. Values will be evaluated as\n" -"floating-point numbers.\n", .read = acf_sort_exec, }; struct ast_custom_function acf_cut = { .name = "CUT", - .synopsis = "Slices and dices strings, based upon a named delimiter.", - .syntax = "CUT(<varname>,<char-delim>,<range-spec>)", - .desc = -" varname - variable you want cut\n" -" char-delim - defaults to '-'\n" -" range-spec - number of the field you want (1-based offset)\n" -" may also be specified as a range (with -)\n" -" or group of ranges and fields (with &)\n", .read = acf_cut_exec, }; diff --git a/funcs/func_db.c b/funcs/func_db.c index 374d4b859..9c8e0bdf9 100644 --- a/funcs/func_db.c +++ b/funcs/func_db.c @@ -40,6 +40,54 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/app.h" #include "asterisk/astdb.h" +/*** DOCUMENTATION + <function name="DB" language="en_US"> + <synopsis> + Read from or write to the Asterisk database. + </synopsis> + <syntax argsep="/"> + <parameter name="family" required="true" /> + <parameter name="key" required="true" /> + </syntax> + <description> + <para>This function will read from or write a value to the Asterisk database. On a + read, this function returns the corresponding value from the database, or blank + if it does not exist. Reading a database value will also set the variable + DB_RESULT. If you wish to find out if an entry exists, use the DB_EXISTS + function.</para> + </description> + </function> + <function name="DB_EXISTS" language="en_US"> + <synopsis> + Check to see if a key exists in the Asterisk database. + </synopsis> + <syntax argsep="/"> + <parameter name="family" required="true" /> + <parameter name="key" required="true" /> + </syntax> + <description> + <para>This function will check to see if a key exists in the Asterisk + database. If it exists, the function will return <literal>1</literal>. If not, + it will return <literal>0</literal>. Checking for existence of a database key will + also set the variable DB_RESULT to the key's value if it exists.</para> + </description> + </function> + <function name="DB_DELETE" language="en_US"> + <synopsis> + Return a value from the database and delete it. + </synopsis> + <syntax argsep="/"> + <parameter name="family" required="true" /> + <parameter name="key" required="true" /> + </syntax> + <description> + <para>This function will retrieve a value from the Asterisk database + and then remove that key from the database. <variable>DB_RESULT</variable> + will be set to the key's value if it exists.</para> + </description> + </function> + ***/ + static int function_db_read(struct ast_channel *chan, const char *cmd, char *parse, char *buf, size_t len) { @@ -100,14 +148,6 @@ static int function_db_write(struct ast_channel *chan, const char *cmd, char *pa static struct ast_custom_function db_function = { .name = "DB", - .synopsis = "Read from or write to the Asterisk database", - .syntax = "DB(<family>/<key>)", - .desc = -"This function will read from or write a value to the Asterisk database. On a\n" -"read, this function returns the corresponding value from the database, or blank\n" -"if it does not exist. Reading a database value will also set the variable\n" -"DB_RESULT. If you wish to find out if an entry exists, use the DB_EXISTS\n" -"function.\n", .read = function_db_read, .write = function_db_write, }; @@ -146,13 +186,6 @@ static int function_db_exists(struct ast_channel *chan, const char *cmd, static struct ast_custom_function db_exists_function = { .name = "DB_EXISTS", - .synopsis = "Check to see if a key exists in the Asterisk database", - .syntax = "DB_EXISTS(<family>/<key>)", - .desc = - "This function will check to see if a key exists in the Asterisk\n" - "database. If it exists, the function will return \"1\". If not,\n" - "it will return \"0\". Checking for existence of a database key will\n" - "also set the variable DB_RESULT to the key's value if it exists.\n", .read = function_db_exists, }; @@ -194,12 +227,6 @@ static int function_db_delete(struct ast_channel *chan, const char *cmd, static struct ast_custom_function db_delete_function = { .name = "DB_DELETE", - .synopsis = "Return a value from the database and delete it", - .syntax = "DB_DELETE(<family>/<key>)", - .desc = - "This function will retrieve a value from the Asterisk database\n" - " and then remove that key from the database. DB_RESULT\n" - "will be set to the key's value if it exists.\n", .read = function_db_delete, }; diff --git a/funcs/func_devstate.c b/funcs/func_devstate.c index 1cedb3e53..f164cb7c1 100644 --- a/funcs/func_devstate.c +++ b/funcs/func_devstate.c @@ -44,6 +44,57 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/astdb.h" #include "asterisk/app.h" +/*** DOCUMENTATION + <function name="DEVICE_STATE" language="en_US"> + <synopsis> + Get or Set a device state. + </synopsis> + <syntax> + <parameter name="device" required="true" /> + </syntax> + <description> + <para>The DEVICE_STATE function can be used to retrieve the device state from any + device state provider. For example:</para> + <para>NoOp(SIP/mypeer has state ${DEVICE_STATE(SIP/mypeer)})</para> + <para>NoOp(Conference number 1234 has state ${DEVICE_STATE(MeetMe:1234)})</para> + <para>The DEVICE_STATE function can also be used to set custom device state from + the dialplan. The <literal>Custom:</literal> prefix must be used. For example:</para> + <para>Set(DEVICE_STATE(Custom:lamp1)=BUSY)</para> + <para>Set(DEVICE_STATE(Custom:lamp2)=NOT_INUSE)</para> + <para>You can subscribe to the status of a custom device state using a hint in + the dialplan:</para> + <para>exten => 1234,hint,Custom:lamp1</para> + <para>The possible values for both uses of this function are:</para> + <para>UNKNOWN | NOT_INUSE | INUSE | BUSY | INVALID | UNAVAILABLE | RINGING | + RINGINUSE | ONHOLD</para> + </description> + </function> + <function name="HINT" language="en_US"> + <synopsis> + Get the devices set for a dialplan hint. + </synopsis> + <syntax> + <parameter name="extension" required="true" argsep="@"> + <argument name="extension" required="true" /> + <argument name="context" /> + </parameter> + <parameter name="options"> + <optionlist> + <option name="n"> + <para>Retrieve name on the hint instead of list of devices.</para> + </option> + </optionlist> + </parameter> + </syntax> + <description> + <para>The HINT function can be used to retrieve the list of devices that are + mapped to a dialplan hint. For example:</para> + <para>NoOp(Hint for Extension 1234 is ${HINT(1234)})</para> + </description> + </function> + ***/ + + static const char astdb_family[] = "CustomDevstate"; static int devstate_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) @@ -296,40 +347,12 @@ static struct ast_cli_entry cli_funcdevstate[] = { static struct ast_custom_function devstate_function = { .name = "DEVICE_STATE", - .synopsis = "Get or Set a device state", - .syntax = "DEVICE_STATE(device)", - .desc = - " The DEVICE_STATE function can be used to retrieve the device state from any\n" - "device state provider. For example:\n" - " NoOp(SIP/mypeer has state ${DEVICE_STATE(SIP/mypeer)})\n" - " NoOp(Conference number 1234 has state ${DEVICE_STATE(MeetMe:1234)})\n" - "\n" - " The DEVICE_STATE function can also be used to set custom device state from\n" - "the dialplan. The \"Custom:\" prefix must be used. For example:\n" - " Set(DEVICE_STATE(Custom:lamp1)=BUSY)\n" - " Set(DEVICE_STATE(Custom:lamp2)=NOT_INUSE)\n" - "You can subscribe to the status of a custom device state using a hint in\n" - "the dialplan:\n" - " exten => 1234,hint,Custom:lamp1\n" - "\n" - " The possible values for both uses of this function are:\n" - "UNKNOWN | NOT_INUSE | INUSE | BUSY | INVALID | UNAVAILABLE | RINGING\n" - "RINGINUSE | ONHOLD\n", .read = devstate_read, .write = devstate_write, }; static struct ast_custom_function hint_function = { .name = "HINT", - .synopsis = "Get the devices set for a dialplan hint", - .syntax = "HINT(extension[@context][|options])", - .desc = - " The HINT function can be used to retrieve the list of devices that are\n" - "mapped to a dialplan hint. For example:\n" - " NoOp(Hint for Extension 1234 is ${HINT(1234)})\n" - "Options:\n" - " 'n' - Retrieve name on the hint instead of list of devices\n" - "", .read = hint_read, }; diff --git a/funcs/func_dialgroup.c b/funcs/func_dialgroup.c index c3674beb9..4e4f63389 100644 --- a/funcs/func_dialgroup.c +++ b/funcs/func_dialgroup.c @@ -39,6 +39,40 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/astobj2.h" #include "asterisk/astdb.h" +/*** DOCUMENTATION + <function name="DIALGROUP" language="en_US"> + <synopsis> + Manages a group of users for dialing. + </synopsis> + <syntax> + <parameter name="group" required="true" /> + <parameter name="op"> + <para>The operation name, possible values are:</para> + <para><literal>add</literal> - add a channel name or interface (write-only)</para> + <para><literal>del</literal> - remove a channel name or interface (write-only)</para> + </parameter> + </syntax> + <description> + <para>Presents an interface meant to be used in concert with the Dial + application, by presenting a list of channels which should be dialled when + referenced.</para> + <para>When DIALGROUP is read from, the argument is interpreted as the particular + <replaceable>group</replaceable> for which a dial should be attempted. When DIALGROUP is written to + with no arguments, the entire list is replaced with the argument specified.</para> + <para>Functionality is similar to a queue, except that when no interfaces are + available, execution may continue in the dialplan. This is useful when + you want certain people to be the first to answer any calls, with immediate + fallback to a queue when the front line people are busy or unavailable, but + you still want front line people to log in and out of that group, just like + a queue.</para> + <para>Example:</para> + <para>exten => 1,1,Set(DIALGROUP(mygroup,add)=SIP/10)</para> + <para>exten => 1,n,Set(DIALGROUP(mygroup,add)=SIP/20)</para> + <para>exten => 1,n,Dial(${DIALGROUP(mygroup)})</para> + </description> + </function> + ***/ + static struct ao2_container *group_container = NULL; struct group_entry { @@ -232,24 +266,6 @@ static int dialgroup_write(struct ast_channel *chan, const char *cmd, char *data static struct ast_custom_function dialgroup_function = { .name = "DIALGROUP", - .synopsis = "Manages a group of users for dialing", - .syntax = "DIALGROUP(<group>[,op])", - .desc = -" DIALGROUP presents an interface meant to be used in concert with the Dial\n" -"application, by presenting a list of channels which should be dialled when\n" -"referenced.\n" -" When DIALGROUP is read from, the argument is interpreted as the particular\n" -"group for which a dial should be attempted. When DIALGROUP is written to\n" -"with no arguments, the entire list is replaced with the argument specified.\n" -"Other operations are as follows:\n" -" add - add a channel name or interface (write-only)\n" -" del - remove a channel name or interface (write-only)\n\n" -"Functionality is similar to a queue, except that when no interfaces are\n" -"available, execution may continue in the dialplan. This is useful when\n" -"you want certain people to be the first to answer any calls, with immediate\n" -"fallback to a queue when the front line people are busy or unavailable, but\n" -"you still want front line people to log in and out of that group, just like\n" -"a queue.\n", .read = dialgroup_read, .write = dialgroup_write, }; diff --git a/funcs/func_dialplan.c b/funcs/func_dialplan.c index 6d4c488f6..0e371d2c8 100644 --- a/funcs/func_dialplan.c +++ b/funcs/func_dialplan.c @@ -33,6 +33,23 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/pbx.h" #include "asterisk/app.h" +/*** DOCUMENTATION + <function name="DIALPLAN_EXISTS" language="en_US"> + <synopsis> + Checks the existence of a dialplan target. + </synopsis> + <syntax> + <parameter name="context" required="true" /> + <parameter name="extension" /> + <parameter name="priority" /> + </syntax> + <description> + <para>This function returns <literal>1</literal> if the target exits. Otherwise, it returns <literal>0</literal>.</para> + </description> + </function> + + ***/ + static int isexten_function_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) { @@ -87,9 +104,6 @@ static int isexten_function_read(struct ast_channel *chan, const char *cmd, char static struct ast_custom_function isexten_function = { .name = "DIALPLAN_EXISTS", - .syntax = "DIALPLAN_EXISTS(context[,extension[,priority]])", - .synopsis = "Checks the existence of a dialplan target.", - .desc = "This function returns 1 if the target exits. Otherwise, it returns 0.\n", .read = isexten_function_read, }; diff --git a/funcs/func_enum.c b/funcs/func_enum.c index 54893a9bf..525c935f6 100644 --- a/funcs/func_enum.c +++ b/funcs/func_enum.c @@ -46,6 +46,109 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/enum.h" #include "asterisk/app.h" +/*** DOCUMENTATION + <function name="ENUMQUERY" language="en_US"> + <synopsis> + Initiate an ENUM query. + </synopsis> + <syntax> + <parameter name="number" required="true" /> + <parameter name="method-type"> + <para>If no <replaceable>method-type</replaceable> is given, the default will be + <literal>sip</literal>.</para> + </parameter> + <parameter name="zone-suffix"> + <para>If no <replaceable>zone-suffix</replaceable> is given, the default will be + <literal>e164.arpa</literal></para> + </parameter> + </syntax> + <description> + <para>This will do a ENUM lookup of the given phone number.</para> + </description> + </function> + <function name="ENUMRESULT" language="en_US"> + <synopsis> + Retrieve results from a ENUMQUERY. + </synopsis> + <syntax> + <parameter name="id" required="true"> + <para>The identifier returned by the ENUMQUERY function.</para> + </parameter> + <parameter name="resultnum" required="true"> + <para>The number of the result that you want to retrieve.</para> + <para>Results start at <literal>1</literal>. If this argument is specified + as <literal>getnum</literal>, then it will return the total number of results + that are available.</para> + </parameter> + </syntax> + <description> + <para>This function will retrieve results from a previous use + of the ENUMQUERY function.</para> + </description> + </function> + <function name="ENUMLOOKUP" language="en_US"> + <synopsis> + General or specific querying of NAPTR records for ENUM or ENUM-like DNS pointers. + </synopsis> + <syntax> + <parameter name="number" required="true" /> + <parameter name="method-type"> + <para>If no <replaceable>method-type</replaceable> is given, the default will be + <literal>sip</literal>.</para> + </parameter> + <parameter name="options"> + <optionlist> + <option name="c"> + <para>Returns an integer count of the number of NAPTRs of a certain RR type.</para> + <para>Combination of <literal>c</literal> and Method-type of <literal>ALL</literal> will + return a count of all NAPTRs for the record.</para> + </option> + <option name="u"> + <para>Returns the full URI and does not strip off the URI-scheme.</para> + </option> + <option name="s"> + <para>Triggers ISN specific rewriting.</para> + </option> + <option name="i"> + <para>Looks for branches into an Infrastructure ENUM tree.</para> + </option> + <option name="d"> + <para>for a direct DNS lookup without any flipping of digits.</para> + </option> + </optionlist> + </parameter> + <parameter name="record#"> + <para>If no <replaceable>record#</replaceable> is given, + defaults to <literal>1</literal>.</para> + </parameter> + <parameter name="zone-suffix"> + <para>If no <replaceable>zone-suffix</replaceable> is given, the default will be + <literal>e164.arpa</literal></para> + </parameter> + </syntax> + <description> + <para>For more information see <filename>doc/asterisk.pdf</filename>.</para> + </description> + </function> + <function name="TXTCIDNAME" language="en_US"> + <synopsis> + TXTCIDNAME looks up a caller name via DNS. + </synopsis> + <syntax> + <parameter name="number" required="true" /> + <parameter name="zone-suffix"> + <para>If no <replaceable>zone-suffix</replaceable> is given, the default will be + <literal>e164.arpa</literal></para> + </parameter> + </syntax> + <description> + <para>This function looks up the given phone number in DNS to retrieve + the caller id name. The result will either be blank or be the value + found in the TXT record in DNS.</para> + </description> + </function> + ***/ + static char *synopsis = "Syntax: ENUMLOOKUP(number[,Method-type[,options[,record#[,zone-suffix]]]])\n"; static int function_enum(struct ast_channel *chan, const char *cmd, char *data, @@ -295,44 +398,16 @@ finish: static struct ast_custom_function enum_query_function = { .name = "ENUMQUERY", - .synopsis = "Initiate an ENUM query", - .syntax = "ENUMQUERY(number[,Method-type[,zone-suffix]])", - .desc = "This will do a ENUM lookup of the given phone number.\n" - "If no method-tpye is given, the default will be sip. If no\n" - "zone-suffix is given, the default will be \"e164.arpa\".\n" - "The result of this function will be a numeric ID that can\n" - "be used to retrieve the results using the ENUMRESULT function.\n", .read = enum_query_read, }; static struct ast_custom_function enum_result_function = { .name = "ENUMRESULT", - .synopsis = "Retrieve results from a ENUMQUERY", - .syntax = "ENUMRESULT(id,resultnum)", - .desc = "This function will retrieve results from a previous use\n" - "of the ENUMQUERY function.\n" - " id - This argument is the identifier returned by the ENUMQUERY function.\n" - " resultnum - This is the number of the result that you want to retrieve.\n" - " Results start at 1. If this argument is specified as \"getnum\",\n" - " then it will return the total number of results that are available.\n", .read = enum_result_read, }; static struct ast_custom_function enum_function = { .name = "ENUMLOOKUP", - .synopsis = - "General or specific querying of NAPTR records for ENUM or ENUM-like DNS pointers", - .syntax = - "ENUMLOOKUP(number[,Method-type[,options[,record#[,zone-suffix]]]])", - .desc = - "Option 'c' returns an integer count of the number of NAPTRs of a certain RR type.\n" - "Combination of 'c' and Method-type of 'ALL' will return a count of all NAPTRs for the record.\n" - "Option 'u' returns the full URI and does not strip off the URI-scheme.\n" - "Option 's' triggers ISN specific rewriting\n" - "Option 'i' looks for branches into an Infrastructure ENUM tree\n" - "Option 'd' for a direct DNS lookup without any flipping of digits\n" - "Defaults are: Method-type=sip, no options, record=1, zone-suffix=e164.arpa\n\n" - "For more information, see doc/asterisk.pdf", .read = function_enum, }; @@ -370,12 +445,6 @@ static int function_txtcidname(struct ast_channel *chan, const char *cmd, static struct ast_custom_function txtcidname_function = { .name = "TXTCIDNAME", - .synopsis = "TXTCIDNAME looks up a caller name via DNS", - .syntax = "TXTCIDNAME(<number>[,zone-suffix])", - .desc = - "This function looks up the given phone number in DNS to retrieve\n" - "the caller id name. The result will either be blank or be the value\n" - "found in the TXT record in DNS. The default zone-suffix is e164.arpa.\n", .read = function_txtcidname, }; diff --git a/funcs/func_env.c b/funcs/func_env.c index 4eba211bb..401dc28e3 100644 --- a/funcs/func_env.c +++ b/funcs/func_env.c @@ -33,6 +33,59 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/utils.h" #include "asterisk/app.h" +/*** DOCUMENTATION + <function name="ENV" language="en_US"> + <synopsis> + Gets or sets the environment variable specified. + </synopsis> + <syntax> + <parameter name="varname" required="true"> + <para>Enviroment variable name</para> + </parameter> + </syntax> + <description> + </description> + </function> + <function name="STAT" language="en_US"> + <synopsis> + Does a check on the specified file. + </synopsis> + <syntax> + <parameter name="flag" required="true"> + <para>Flag may be one of the following:</para> + <para>d - Checks if the file is a directory.</para> + <para>e - Checks if the file exists.</para> + <para>f - Checks if the file is a regular file.</para> + <para>m - Returns the file mode (in octal)</para> + <para>s - Returns the size (in bytes) of the file</para> + <para>A - Returns the epoch at which the file was last accessed.</para> + <para>C - Returns the epoch at which the inode was last changed.</para> + <para>M - Returns the epoch at which the file was last modified.</para> + </parameter> + <parameter name="filename" required="true" /> + </syntax> + <description> + </description> + </function> + <function name="FILE" language="en_US"> + <synopsis> + Obtains the contents of a file. + </synopsis> + <syntax> + <parameter name="filename" required="true" /> + <parameter name="offset" required="true"> + <para>Maybe specified as any number. if negative <replaceable>offset</replaceable> specifies the number + of bytes back from the end of the file.</para> + </parameter> + <parameter name="length" required="true"> + <para>If specified, will limit the length of the data read to that size.</para> + </parameter> + </syntax> + <description> + </description> + </function> + ***/ + static int env_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) { @@ -151,43 +204,23 @@ static int file_read(struct ast_channel *chan, const char *cmd, char *data, char static struct ast_custom_function env_function = { .name = "ENV", - .synopsis = "Gets or sets the environment variable specified", - .syntax = "ENV(<envname>)", .read = env_read, - .write = env_write, + .write = env_write }; static struct ast_custom_function stat_function = { .name = "STAT", - .synopsis = "Does a check on the specified file", - .syntax = "STAT(<flag>,<filename>)", - .read = stat_read, - .desc = - "flag may be one of the following:\n" - " d - Checks if the file is a directory\n" - " e - Checks if the file exists\n" - " f - Checks if the file is a regular file\n" - " m - Returns the file mode (in octal)\n" - " s - Returns the size (in bytes) of the file\n" - " A - Returns the epoch at which the file was last accessed\n" - " C - Returns the epoch at which the inode was last changed\n" - " M - Returns the epoch at which the file was last modified\n", + .read = stat_read }; static struct ast_custom_function file_function = { .name = "FILE", - .synopsis = "Obtains the contents of a file", - .syntax = "FILE(<filename>,<offset>,<length>)", - .read = file_read, + .read = file_read /* * Some enterprising programmer could probably add write functionality * to FILE(), although I'm not sure how useful it would be. Hence why * it's called FILE and not READFILE (like the app was). */ - .desc = -"<offset> may be specified as any number. If negative, <offset> specifies\n" -" the number of bytes back from the end of the file.\n" -"<length>, if specified, will limit the length of the data read to that size.\n", }; static int unload_module(void) diff --git a/funcs/func_extstate.c b/funcs/func_extstate.c index 8866d89b9..7f2288560 100644 --- a/funcs/func_extstate.c +++ b/funcs/func_extstate.c @@ -36,6 +36,29 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/utils.h" #include "asterisk/devicestate.h" +/*** DOCUMENTATION + <function name="EXTENSION_STATE" language="en_US"> + <synopsis> + Get an extension's state. + </synopsis> + <syntax argsep="@"> + <parameter name="extension" required="true" /> + <parameter name="context"> + <para>If it is not specified defaults to <literal>default</literal>.</para> + </parameter> + </syntax> + <description> + <para>The EXTENSION_STATE function can be used to retrieve the state from any + hinted extension. For example:</para> + <para>NoOp(1234@default has state ${EXTENSION_STATE(1234)})</para> + <para>NoOp(4567@home has state ${EXTENSION_STATE(4567@home)})</para> + <para>The possible values returned by this function are:</para> + <para>UNKNOWN | NOT_INUSE | INUSE | BUSY | INVALID | UNAVAILABLE | RINGING | + RINGINUSE | HOLDINUSE | ONHOLD</para> + </description> + </function> + ***/ + static const char *ast_extstate_str(int state) { const char *res = "UNKNOWN"; @@ -98,17 +121,6 @@ static int extstate_read(struct ast_channel *chan, const char *cmd, char *data, static struct ast_custom_function extstate_function = { .name = "EXTENSION_STATE", - .synopsis = "Get an extension's state", - .syntax = "EXTENSION_STATE(extension[@context])", - .desc = - " The EXTENSION_STATE function can be used to retrieve the state from any\n" - "hinted extension. For example:\n" - " NoOp(1234@default has state ${EXTENSION_STATE(1234)})\n" - " NoOp(4567@home has state ${EXTENSION_STATE(4567@home)})\n" - "\n" - " The possible values returned by this function are:\n" - "UNKNOWN | NOT_INUSE | INUSE | BUSY | INVALID | UNAVAILABLE | RINGING\n" - "RINGINUSE | HOLDINUSE | ONHOLD\n", .read = extstate_read, }; diff --git a/funcs/func_global.c b/funcs/func_global.c index 3380cef12..74df1757c 100644 --- a/funcs/func_global.c +++ b/funcs/func_global.c @@ -37,6 +37,51 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/app.h" #include "asterisk/manager.h" +/*** DOCUMENTATION + <function name="GLOBAL" language="en_US"> + <synopsis> + Gets or sets the global variable specified. + </synopsis> + <syntax> + <parameter name="varname" required="true"> + <para>Global variable name</para> + </parameter> + </syntax> + <description> + <para>Set or get the value of a global variable specified in <replaceable>varname</replaceable></para> + </description> + </function> + <function name="SHARED" language="en_US"> + <synopsis> + Gets or sets the shared variable specified. + </synopsis> + <syntax> + <parameter name="varname" required="true"> + <para>Variable name</para> + </parameter> + <parameter name="channel"> + <para>If not specified will default to current channel. It is the complete + channel name: <literal>SIP/12-abcd1234</literal> or the prefix only <literal>SIP/12</literal>.</para> + </parameter> + </syntax> + <description> + <para>Implements a shared variable area, in which you may share variables between + channels.</para> + <para>The variables used in this space are separate from the general namespace of + the channel and thus <variable>SHARED(foo)</variable> and <variable>foo</variable> + represent two completely different variables, despite sharing the same name.</para> + <para>Finally, realize that there is an inherent race between channels operating + at the same time, fiddling with each others' internal variables, which is why + this special variable namespace exists; it is to remind you that variables in + the SHARED namespace may change at any time, without warning. You should + therefore take special care to ensure that when using the SHARED namespace, + you retrieve the variable and store it in a regular channel variable before + using it in a set of calculations (or you might be surprised by the result).</para> + </description> + </function> + + ***/ + static void shared_variable_free(void *data); static struct ast_datastore_info shared_variable_info = { @@ -76,8 +121,6 @@ static int global_write(struct ast_channel *chan, const char *cmd, char *data, c static struct ast_custom_function global_function = { .name = "GLOBAL", - .synopsis = "Gets or sets the global variable specified", - .syntax = "GLOBAL(<varname>)", .read = global_read, .write = global_write, }; @@ -203,25 +246,6 @@ static int shared_write(struct ast_channel *chan, const char *cmd, char *data, c static struct ast_custom_function shared_function = { .name = "SHARED", - .synopsis = "Gets or sets the shared variable specified", - .syntax = "SHARED(<varname>[,<channel>])", - .desc = -"Implements a shared variable area, in which you may share variables between\n" -"channels. If channel is unspecified, defaults to the current channel. Note\n" -"that the channel name may be the complete name (i.e. SIP/12-abcd1234) or the\n" -"prefix only (i.e. SIP/12).\n" -"\n" -"The variables used in this space are separate from the general namespace of\n" -"the channel and thus ${SHARED(foo)} and ${foo} represent two completely\n" -"different variables, despite sharing the same name.\n" -"\n" -"Finally, realize that there is an inherent race between channels operating\n" -"at the same time, fiddling with each others' internal variables, which is why\n" -"this special variable namespace exists; it is to remind you that variables in\n" -"the SHARED namespace may change at any time, without warning. You should\n" -"therefore take special care to ensure that when using the SHARED namespace,\n" -"you retrieve the variable and store it in a regular channel variable before\n" -"using it in a set of calculations (or you might be surprised by the result).\n", .read = shared_read, .write = shared_write, }; diff --git a/funcs/func_groupcount.c b/funcs/func_groupcount.c index b70a42e94..181855015 100644 --- a/funcs/func_groupcount.c +++ b/funcs/func_groupcount.c @@ -31,6 +31,67 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/utils.h" #include "asterisk/app.h" +/*** DOCUMENTATION + <function name="GROUP_COUNT" language="en_US"> + <synopsis> + Counts the number of channels in the specified group. + </synopsis> + <syntax argsep="@"> + <parameter name="groupname"> + <para>Group name.</para> + </parameter> + <parameter name="category"> + <para>Category name</para> + </parameter> + </syntax> + <description> + <para>Calculates the group count for the specified group, or uses the + channel's current group if not specifed (and non-empty).</para> + </description> + </function> + <function name="GROUP_MATCH_COUNT" language="en_US"> + <synopsis> + Counts the number of channels in the groups matching the specified pattern. + </synopsis> + <syntax argsep="@"> + <parameter name="groupmatch" required="true"> + <para>A standard regular expression used to match a group name.</para> + </parameter> + <parameter name="category"> + <para>Category name.</para> + </parameter> + </syntax> + <description> + <para>Calculates the group count for all groups that match the specified pattern. + Uses standard regular expression matching (see regex(7)).</para> + </description> + </function> + <function name="GROUP" language="en_US"> + <synopsis> + Gets or sets the channel group. + </synopsis> + <syntax> + <parameter name="category"> + <para>Category name.</para> + </parameter> + </syntax> + <description> + <para><replaceable>category</replaceable> can be employed for more fine grained group management. Each channel + can only be member of exactly one group per <replaceable>category</replaceable>.</para> + </description> + </function> + <function name="GROUP_LIST" language="en_US"> + <synopsis> + Gets a list of the groups set on a channel. + </synopsis> + <syntax /> + <description> + <para>Gets a list of the groups set on a channel.</para> + </description> + </function> + + ***/ + static int group_count_function_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) { @@ -72,11 +133,6 @@ static int group_count_function_read(struct ast_channel *chan, const char *cmd, static struct ast_custom_function group_count_function = { .name = "GROUP_COUNT", - .syntax = "GROUP_COUNT([groupname][@category])", - .synopsis = "Counts the number of channels in the specified group", - .desc = - "Calculates the group count for the specified group, or uses the\n" - "channel's current group if not specifed (and non-empty).\n", .read = group_count_function_read, }; @@ -102,12 +158,6 @@ static int group_match_count_function_read(struct ast_channel *chan, static struct ast_custom_function group_match_count_function = { .name = "GROUP_MATCH_COUNT", - .syntax = "GROUP_MATCH_COUNT(groupmatch[@category])", - .synopsis = - "Counts the number of channels in the groups matching the specified pattern", - .desc = - "Calculates the group count for all groups that match the specified pattern.\n" - "Uses standard regular expression matching (see regex(7)).\n", .read = group_match_count_function_read, .write = NULL, }; @@ -159,9 +209,6 @@ static int group_function_write(struct ast_channel *chan, const char *cmd, static struct ast_custom_function group_function = { .name = "GROUP", - .syntax = "GROUP([category])", - .synopsis = "Gets or sets the channel group.", - .desc = "Gets or sets the channel group.\n", .read = group_function_read, .write = group_function_write, }; @@ -204,9 +251,6 @@ static int group_list_function_read(struct ast_channel *chan, const char *cmd, static struct ast_custom_function group_list_function = { .name = "GROUP_LIST", - .syntax = "GROUP_LIST()", - .synopsis = "Gets a list of the groups set on a channel.", - .desc = "Gets a list of the groups set on a channel.\n", .read = group_list_function_read, .write = NULL, }; diff --git a/funcs/func_iconv.c b/funcs/func_iconv.c index 74f32412b..231b4880f 100644 --- a/funcs/func_iconv.c +++ b/funcs/func_iconv.c @@ -41,6 +41,32 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/utils.h" #include "asterisk/app.h" +/*** DOCUMENTATION + <function name="ICONV" language="en_US"> + <synopsis> + Converts charsets of strings. + </synopsis> + <syntax> + <parameter name="in-charset" required="true"> + <para>Input charset</para> + </parameter> + <parameter name="out-charset" required="true"> + <para>Output charset</para> + </parameter> + <parameter name="string" required="true"> + <para>String to convert, from <replaceable>in-charset</replaceable> to <replaceable>out-charset</replaceable></para> + </parameter> + </syntax> + <description> + <para>Converts string from <replaceable>in-charset</replaceable> into <replaceable>out-charset</replaceable>. + For available charsets, use <literal>iconv -l</literal> on your shell command line.</para> + <note><para>Due to limitations within the API, ICONV will not currently work with + charsets with embedded NULLs. If found, the string will terminate.</para></note> + </description> + </function> + ***/ + + /*! * Some systems define the second arg to iconv() as (const char *), * while others define it as (char *). Cast it to a (void *) to @@ -101,14 +127,7 @@ static int iconv_read(struct ast_channel *chan, const char *cmd, char *arguments static struct ast_custom_function iconv_function = { .name = "ICONV", - .synopsis = "Converts charsets of strings.", - .desc = -"Converts string from in-charset into out-charset. For available charsets,\n" -"use 'iconv -l' on your shell command line.\n" -"Note: due to limitations within the API, ICONV will not currently work with\n" -"charsets with embedded NULLs. If found, the string will terminate.\n", - .syntax = "ICONV(in-charset,out-charset,string)", - .read = iconv_read, + .read = iconv_read }; static int unload_module(void) diff --git a/funcs/func_lock.c b/funcs/func_lock.c index 133ea3e22..d6df6d0ef 100644 --- a/funcs/func_lock.c +++ b/funcs/func_lock.c @@ -37,6 +37,53 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/module.h" #include "asterisk/linkedlists.h" +/*** DOCUMENTATION + <function name="LOCK" language="en_US"> + <synopsis> + Attempt to obtain a named mutex. + </synopsis> + <syntax> + <parameter name="lockname" required="true" /> + </syntax> + <description> + <para>Attempts to grab a named lock exclusively, and prevents other channels from + obtaining the same lock. LOCK will wait for the lock to become available. + Returns <literal>1</literal> if the lock was obtained or <literal>0</literal> on error.</para> + <note><para>To avoid the possibility of a deadlock, LOCK will only attempt to + obtain the lock for 3 seconds if the channel already has another lock.</para></note> + </description> + </function> + <function name="TRYLOCK" language="en_US"> + <synopsis> + Attempt to obtain a named mutex. + </synopsis> + <syntax> + <parameter name="lockname" required="true" /> + </syntax> + <description> + <para>Attempts to grab a named lock exclusively, and prevents other channels + from obtaining the same lock. Returns <literal>1</literal> if the lock was + available or <literal>0</literal> otherwise.</para> + </description> + </function> + <function name="UNLOCK" language="en_US"> + <synopsis> + Unlocks a named mutex. + </synopsis> + <syntax> + <parameter name="lockname" required="true" /> + </syntax> + <description> + <para>Unlocks a previously locked mutex. Returns <literal>1</literal> if the channel + had a lock or <literal>0</literal> otherwise.</para> + <note><para>It is generally unnecessary to unlock in a hangup routine, as any locks + held are automatically freed when the channel is destroyed.</para></note> + </description> + </function> + ***/ + + + AST_LIST_HEAD_STATIC(locklist, lock_frame); static void lock_free(void *data); @@ -276,36 +323,16 @@ static int trylock_read(struct ast_channel *chan, const char *cmd, char *data, c static struct ast_custom_function lock_function = { .name = "LOCK", - .synopsis = "Attempt to obtain a named mutex", - .desc = -"Attempts to grab a named lock exclusively, and prevents other channels from\n" -"obtaining the same lock. LOCK will wait for the lock to become available.\n" -"Returns 1 if the lock was obtained or 0 on error.\n\n" -"Note: to avoid the possibility of a deadlock, LOCK will only attempt to\n" -"obtain the lock for 3 seconds if the channel already has another lock.\n", - .syntax = "LOCK(<lockname>)", .read = lock_read, }; static struct ast_custom_function trylock_function = { .name = "TRYLOCK", - .synopsis = "Attempt to obtain a named mutex", - .desc = -"Attempts to grab a named lock exclusively, and prevents other channels\n" -"from obtaining the same lock. Returns 1 if the lock was available or 0\n" -"otherwise.\n", - .syntax = "TRYLOCK(<lockname>)", .read = trylock_read, }; static struct ast_custom_function unlock_function = { .name = "UNLOCK", - .synopsis = "Unlocks a named mutex", - .desc = -"Unlocks a previously locked mutex. Note that it is generally unnecessary to\n" -"unlock in a hangup routine, as any locks held are automatically freed when the\n" -"channel is destroyed. Returns 1 if the channel had a lock or 0 otherwise.\n", - .syntax = "UNLOCK(<lockname>)", .read = unlock_read, }; diff --git a/funcs/func_logic.c b/funcs/func_logic.c index 7fca070aa..ef644f43f 100644 --- a/funcs/func_logic.c +++ b/funcs/func_logic.c @@ -34,6 +34,83 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/utils.h" #include "asterisk/app.h" +/*** DOCUMENTATION + <function name="ISNULL" language="en_US"> + <synopsis> + Check if a value is NULL. + </synopsis> + <syntax> + <parameter name="data" required="true" /> + </syntax> + <description> + <para>Returns <literal>1</literal> if NULL or <literal>0</literal> otherwise.</para> + </description> + </function> + <function name="SET" language="en_US"> + <synopsis> + SET assigns a value to a channel variable. + </synopsis> + <syntax argsep="="> + <parameter name="varname" required="true" /> + <parameter name="value" /> + </syntax> + <description> + </description> + </function> + <function name="EXISTS" language="en_US"> + <synopsis> + Test the existence of a value. + </synopsis> + <syntax> + <parameter name="data" required="true" /> + </syntax> + <description> + <para>Returns <literal>1</literal> if exists, <literal>0</literal> otherwise.</para> + </description> + </function> + <function name="IF" language="en_US"> + <synopsis> + Check for an expresion. + </synopsis> + <syntax argsep="?"> + <parameter name="expresion" required="true" /> + <parameter name="retvalue" argsep=":" required="true"> + <argument name="true" /> + <argument name="false" /> + </parameter> + </syntax> + <description> + <para>Returns the data following <literal>?</literal> if true, else the data following <literal>:</literal></para> + </description> + </function> + <function name="IFTIME" language="en_US"> + <synopsis> + Temporal Conditional. + </synopsis> + <syntax argsep="?"> + <parameter name="timespec" required="true" /> + <parameter name="retvalue" required="true" argsep=":"> + <argument name="true" /> + <argument name="false" /> + </parameter> + </syntax> + <description> + <para>Returns the data following <literal>?</literal> if true, else the data following <literal>:</literal></para> + </description> + </function> + <function name="IMPORT" language="en_US"> + <synopsis> + Retrieve the value of a variable from another channel. + </synopsis> + <syntax> + <parameter name="channel" required="true" /> + <parameter name="variable" required="true" /> + </syntax> + <description> + </description> + </function> + ***/ + static int isnull(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) { @@ -168,46 +245,31 @@ static int acf_import(struct ast_channel *chan, const char *cmd, char *data, cha static struct ast_custom_function isnull_function = { .name = "ISNULL", - .synopsis = "NULL Test: Returns 1 if NULL or 0 otherwise", - .syntax = "ISNULL(<data>)", .read = isnull, }; static struct ast_custom_function set_function = { .name = "SET", - .synopsis = "SET assigns a value to a channel variable", - .syntax = "SET(<varname>=[<value>])", .read = set, }; static struct ast_custom_function exists_function = { .name = "EXISTS", - .synopsis = "Existence Test: Returns 1 if exists, 0 otherwise", - .syntax = "EXISTS(<data>)", .read = exists, }; static struct ast_custom_function if_function = { .name = "IF", - .synopsis = - "Conditional: Returns the data following '?' if true, else the data following ':'", - .syntax = "IF(<expr>?[<true>][:<false>])", .read = acf_if, }; static struct ast_custom_function if_time_function = { .name = "IFTIME", - .synopsis = - "Temporal Conditional: Returns the data following '?' if true, else the data following ':'", - .syntax = "IFTIME(<timespec>?[<true>][:<false>])", .read = iftime, }; static struct ast_custom_function import_function = { .name = "IMPORT", - .synopsis = - "Retrieve the value of a variable from another channel\n", - .syntax = "IMPORT(channel,variable)", .read = acf_import, }; diff --git a/funcs/func_math.c b/funcs/func_math.c index 3517b16ed..627cf860a 100644 --- a/funcs/func_math.c +++ b/funcs/func_math.c @@ -39,6 +39,35 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/app.h" #include "asterisk/config.h" +/*** DOCUMENTATION + <function name="MATH" language="en_US"> + <synopsis> + Performs Mathematical Functions. + </synopsis> + <syntax> + <parameter name="expression" required="true"> + <para>Is of the form: + <replaceable>number1</replaceable><replaceable>op</replaceable><replaceable>number2</replaceable> + where the possible values for <replaceable>op</replaceable> + are:</para> + <para>+,-,/,*,%,<<,>>,^,AND,OR,XOR,<,%gt;,>=,<=,== (and behave as their C equivalents)</para> + </parameter> + <parameter name="type"> + <para>Wanted type of result:</para> + <para>f, float - float(default)</para> + <para>i, int - integer</para> + <para>h, hex - hex</para> + <para>c, char - char</para> + </parameter> + </syntax> + <description> + <para>Performs mathematicas functions based on two parameters and a operator, the returned + value type is <replaceable>type</replaceable></para> + <para>Example: Set(i=${MATH(123%16,int)}) - sets var i=11</para> + </description> + </function> + ***/ + enum TypeOfFunctions { ADDFUNCTION, DIVIDEFUNCTION, @@ -306,17 +335,6 @@ static int math(struct ast_channel *chan, const char *cmd, char *parse, static struct ast_custom_function math_function = { .name = "MATH", - .synopsis = "Performs Mathematical Functions", - .syntax = "MATH(<number1><op><number2>[,<type_of_result>])", - .desc = "Perform calculation on number1 to number2. Valid ops are: \n" - " +,-,/,*,%,<<,>>,^,AND,OR,XOR,<,>,>=,<=,==\n" - "and behave as their C equivalents.\n" - "<type_of_result> - wanted type of result:\n" - " f, float - float(default)\n" - " i, int - integer,\n" - " h, hex - hex,\n" - " c, char - char\n" - "Example: Set(i=${MATH(123%16,int)}) - sets var i=11", .read = math }; diff --git a/funcs/func_md5.c b/funcs/func_md5.c index b376e8ae3..23b35489a 100644 --- a/funcs/func_md5.c +++ b/funcs/func_md5.c @@ -33,6 +33,20 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/module.h" #include "asterisk/pbx.h" +/*** DOCUMENTATION + <function name="MD5" language="en_US"> + <synopsis> + Computes an MD5 digest. + </synopsis> + <syntax> + <parameter name="data" required="true" /> + </syntax> + <description> + <para>Computes an MD5 digest.</para> + </description> + </function> + ***/ + static int md5(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) { @@ -49,8 +63,6 @@ static int md5(struct ast_channel *chan, const char *cmd, char *data, static struct ast_custom_function md5_function = { .name = "MD5", - .synopsis = "Computes an MD5 digest", - .syntax = "MD5(<data>)", .read = md5, }; diff --git a/funcs/func_module.c b/funcs/func_module.c index 8b2326386..a7cf73164 100644 --- a/funcs/func_module.c +++ b/funcs/func_module.c @@ -28,6 +28,24 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/module.h" #include "asterisk/pbx.h" +/*** DOCUMENTATION + <function name="IFMODULE" language="en_US"> + <synopsis> + Checks if an Asterisk module is loaded in memory. + </synopsis> + <syntax> + <parameter name="modulename.so" required="true"> + <para>Module name complete with <literal>.so</literal></para> + </parameter> + </syntax> + <description> + <para>Checks if a module is loaded. Use the full module name + as shown by the list in <literal>module list</literal>. + Returns <literal>1</literal> if module exists in memory, otherwise <literal>0</literal></para> + </description> + </function> + ***/ + static int ifmodule_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) { @@ -46,12 +64,7 @@ static int ifmodule_read(struct ast_channel *chan, const char *cmd, char *data, static struct ast_custom_function ifmodule_function = { .name = "IFMODULE", - .synopsis = "Checks if an Asterisk module is loaded in memory", - .syntax = "IFMODULE(<modulename.so>)", .read = ifmodule_read, - .desc = "Checks if a module is loaded. Use the full module name\n" - "as shown by the list in \"module list\". \n" - "Returns \"1\" if module exists in memory, otherwise \"0\".\n", }; diff --git a/funcs/func_odbc.c b/funcs/func_odbc.c index 85f7e2395..135dd9819 100644 --- a/funcs/func_odbc.c +++ b/funcs/func_odbc.c @@ -47,6 +47,58 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/app.h" #include "asterisk/cli.h" +/*** DOCUMENTATION + <function name="ODBC_FETCH" language="en_US"> + <synopsis> + Fetch a row from a multirow query. + </synopsis> + <syntax> + <parameter name="result-id" required="true" /> + </syntax> + <description> + <para>For queries which are marked as mode=multirow, the original + query returns a <replaceable>result-id</replaceable> from which results + may be fetched. This function implements the actual fetch of the results.</para> + <para>This also sets <variable>ODBC_FETCH_STATUS</variable>.</para> + <variablelist> + <variable name="ODBC_FETCH_STATUS"> + <value name="SUCESS"> + If rows are available. + </value> + <value name="FAILURE"> + If no rows are available. + </value> + </variable> + </variablelist> + </description> + </function> + <application name="ODBCFinish" language="en_US"> + <synopsis> + Clear the resultset of a sucessful multirow query. + </synopsis> + <syntax> + <parameter name="result-id" required="true" /> + </syntax> + <description> + <para>For queries which are marked as mode=multirow, this will clear + any remaining rows of the specified resultset.</para> + </description> + </application> + <function name="SQL_ESC" language="en_US"> + <synopsis> + Escapes single ticks for use in SQL statements. + </synopsis> + <syntax> + <parameter name="string" required="true" /> + </syntax> + <description> + <para>Used in SQL templates to escape data which may contain single ticks + <literal>'</literal> which are otherwise used to delimit data.</para> + <para>Example: SELECT foo FROM bar WHERE baz='${SQL_ESC(${ARG1})}'</para> + </description> + </function> + ***/ + static char *config = "func_odbc.conf"; enum { @@ -620,12 +672,6 @@ static int acf_escape(struct ast_channel *chan, const char *cmd, char *data, cha static struct ast_custom_function escape_function = { .name = "SQL_ESC", - .synopsis = "Escapes single ticks for use in SQL statements", - .syntax = "SQL_ESC(<string>)", - .desc = -"Used in SQL templates to escape data which may contain single ticks (') which\n" -"are otherwise used to delimit data. For example:\n" -"SELECT foo FROM bar WHERE baz='${SQL_ESC(${ARG1})}'\n", .read = acf_escape, .write = NULL, }; @@ -660,24 +706,11 @@ static int acf_fetch(struct ast_channel *chan, const char *cmd, char *data, char static struct ast_custom_function fetch_function = { .name = "ODBC_FETCH", - .synopsis = "Fetch a row from a multirow query", - .syntax = "ODBC_FETCH(<result-id>)", - .desc = -"For queries which are marked as mode=multirow, the original query returns a\n" -"result-id from which results may be fetched. This function implements the\n" -"actual fetch of the results.\n" -"This function also sets ODBC_FETCH_STATUS to one of \"SUCCESS\" or \"FAILURE\",\n" -"depending upon whether there were rows available or not.\n", .read = acf_fetch, .write = NULL, }; static char *app_odbcfinish = "ODBCFinish"; -static char *syn_odbcfinish = "Clear the resultset of a successful multirow query"; -static char *desc_odbcfinish = -"ODBCFinish(<result-id>)\n" -" Clears any remaining rows of the specified resultset\n"; - static int exec_odbcfinish(struct ast_channel *chan, void *data) { @@ -784,6 +817,12 @@ static int init_acf_query(struct ast_config *cfg, char *catg, struct acf_odbc_qu *query = NULL; return ENOMEM; } + if (ast_string_field_init((*query)->acf, 128)) { + ast_free((*query)->acf); + ast_free(*query); + *query = NULL; + return ENOMEM; + } if ((tmp = ast_variable_retrieve(cfg, catg, "prefix")) && !ast_strlen_zero(tmp)) { asprintf((char **)&((*query)->acf->name), "%s_%s", tmp, catg); @@ -792,6 +831,7 @@ static int init_acf_query(struct ast_config *cfg, char *catg, struct acf_odbc_qu } if (!((*query)->acf->name)) { + ast_string_field_free_memory((*query)->acf); ast_free((*query)->acf); ast_free(*query); *query = NULL; @@ -799,13 +839,14 @@ static int init_acf_query(struct ast_config *cfg, char *catg, struct acf_odbc_qu } if ((tmp = ast_variable_retrieve(cfg, catg, "syntax")) && !ast_strlen_zero(tmp)) { - asprintf((char **)&((*query)->acf->syntax), "%s(%s)", (*query)->acf->name, tmp); + ast_string_field_build((*query)->acf, syntax, "%s(%s)", (*query)->acf->name, tmp); } else { - asprintf((char **)&((*query)->acf->syntax), "%s(<arg1>[...[,<argN>]])", (*query)->acf->name); + ast_string_field_build((*query)->acf, syntax, "%s(<arg1>[...[,<argN>]])", (*query)->acf->name); } - if (!((*query)->acf->syntax)) { + if (ast_strlen_zero((*query)->acf->syntax)) { ast_free((char *)(*query)->acf->name); + ast_string_field_free_memory((*query)->acf); ast_free((*query)->acf); ast_free(*query); *query = NULL; @@ -813,14 +854,14 @@ static int init_acf_query(struct ast_config *cfg, char *catg, struct acf_odbc_qu } if ((tmp = ast_variable_retrieve(cfg, catg, "synopsis")) && !ast_strlen_zero(tmp)) { - (*query)->acf->synopsis = ast_strdup(tmp); + ast_string_field_set((*query)->acf, synopsis, tmp); } else { - (*query)->acf->synopsis = ast_strdup("Runs the referenced query with the specified arguments"); + ast_string_field_set((*query)->acf, synopsis, "Runs the referenced query with the specified arguments"); } - if (!((*query)->acf->synopsis)) { + if (ast_strlen_zero((*query)->acf->synopsis)) { ast_free((char *)(*query)->acf->name); - ast_free((char *)(*query)->acf->syntax); + ast_string_field_free_memory((*query)->acf); ast_free((*query)->acf); ast_free(*query); *query = NULL; @@ -828,7 +869,7 @@ static int init_acf_query(struct ast_config *cfg, char *catg, struct acf_odbc_qu } if (!ast_strlen_zero((*query)->sql_read) && !ast_strlen_zero((*query)->sql_write)) { - asprintf((char **)&((*query)->acf->desc), + ast_string_field_build((*query)->acf, desc, "Runs the following query, as defined in func_odbc.conf, performing\n" "substitution of the arguments into the query as specified by ${ARG1},\n" "${ARG2}, ... ${ARGn}. When setting the function, the values are provided\n" @@ -844,13 +885,13 @@ static int init_acf_query(struct ast_config *cfg, char *catg, struct acf_odbc_qu ast_strlen_zero((*query)->sql_insert) ? "" : (*query)->sql_insert, ast_strlen_zero((*query)->sql_insert) ? "" : "\n"); } else if (!ast_strlen_zero((*query)->sql_read)) { - asprintf((char **)&((*query)->acf->desc), - "Runs the following query, as defined in func_odbc.conf, performing\n" - "substitution of the arguments into the query as specified by ${ARG1},\n" - "${ARG2}, ... ${ARGn}. This function may only be read, not set.\n\nSQL:\n%s\n", - (*query)->sql_read); + ast_string_field_build((*query)->acf, desc, + "Runs the following query, as defined in func_odbc.conf, performing\n" + "substitution of the arguments into the query as specified by ${ARG1},\n" + "${ARG2}, ... ${ARGn}. This function may only be read, not set.\n\nSQL:\n%s\n", + (*query)->sql_read); } else if (!ast_strlen_zero((*query)->sql_write)) { - asprintf((char **)&((*query)->acf->desc), + ast_string_field_build((*query)->acf, desc, "Runs the following query, as defined in func_odbc.conf, performing\n" "substitution of the arguments into the query as specified by ${ARG1},\n" "${ARG2}, ... ${ARGn}. The values are provided either in whole as\n" @@ -864,8 +905,7 @@ static int init_acf_query(struct ast_config *cfg, char *catg, struct acf_odbc_qu ast_strlen_zero((*query)->sql_insert) ? "" : (*query)->sql_insert, ast_strlen_zero((*query)->sql_insert) ? "" : "\n"); } else { - ast_free((char *)(*query)->acf->synopsis); - ast_free((char *)(*query)->acf->syntax); + ast_string_field_free_memory((*query)->acf); ast_free((char *)(*query)->acf->name); ast_free((*query)->acf); ast_free(*query); @@ -873,9 +913,8 @@ static int init_acf_query(struct ast_config *cfg, char *catg, struct acf_odbc_qu return EINVAL; } - if (! ((*query)->acf->desc)) { - ast_free((char *)(*query)->acf->synopsis); - ast_free((char *)(*query)->acf->syntax); + if (ast_strlen_zero((*query)->acf->desc)) { + ast_string_field_free_memory((*query)->acf); ast_free((char *)(*query)->acf->name); ast_free((*query)->acf); ast_free(*query); @@ -904,12 +943,7 @@ static int free_acf_query(struct acf_odbc_query *query) if (query->acf) { if (query->acf->name) ast_free((char *)query->acf->name); - if (query->acf->syntax) - ast_free((char *)query->acf->syntax); - if (query->acf->synopsis) - ast_free((char *)query->acf->synopsis); - if (query->acf->desc) - ast_free((char *)query->acf->desc); + ast_string_field_free_memory(query->acf); ast_free(query->acf); } ast_free(query); @@ -1254,7 +1288,7 @@ static int load_module(void) struct ast_flags config_flags = { 0 }; res |= ast_custom_function_register(&fetch_function); - res |= ast_register_application(app_odbcfinish, exec_odbcfinish, syn_odbcfinish, desc_odbcfinish); + res |= ast_register_application_xml(app_odbcfinish, exec_odbcfinish); AST_RWLIST_WRLOCK(&queries); cfg = ast_config_load(config, config_flags); diff --git a/funcs/func_rand.c b/funcs/func_rand.c index a3db21d26..079723686 100644 --- a/funcs/func_rand.c +++ b/funcs/func_rand.c @@ -34,6 +34,24 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/utils.h" #include "asterisk/app.h" +/*** DOCUMENTATION + <function name="RAND" language="en_US"> + <synopsis> + Choose a random number in a range. + </synopsis> + <syntax> + <parameter name="min" /> + <parameter name="max" /> + </syntax> + <description> + <para>Choose a random number between <replaceable>min</replaceable> and <replaceable>max</replaceable>. + <replaceable>min</replaceable> defaults to <literal>0</literal>, if not specified, while <replaceable>max</replaceable> defaults + to <literal>RAND_MAX</literal> (2147483647 on many systems).</para> + <para>Example: Set(junky=${RAND(1,8)}); + Sets junky to a random number between 1 and 8, inclusive.</para> + </description> + </function> + ***/ static int acf_rand_exec(struct ast_channel *chan, const char *cmd, char *parse, char *buffer, size_t buflen) { @@ -68,13 +86,6 @@ static int acf_rand_exec(struct ast_channel *chan, const char *cmd, static struct ast_custom_function acf_rand = { .name = "RAND", - .synopsis = "Choose a random number in a range", - .syntax = "RAND([min][,max])", - .desc = - "Choose a random number between min and max. Min defaults to 0, if not\n" - "specified, while max defaults to RAND_MAX (2147483647 on many systems).\n" - " Example: Set(junky=${RAND(1,8)}); \n" - " Sets junky to a random number between 1 and 8, inclusive.\n", .read = acf_rand_exec, }; diff --git a/funcs/func_realtime.c b/funcs/func_realtime.c index f3dd14be6..31989c425 100644 --- a/funcs/func_realtime.c +++ b/funcs/func_realtime.c @@ -37,6 +37,72 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/utils.h" #include "asterisk/app.h" +/*** DOCUMENTATION + <function name="REALTIME" language="en_US"> + <synopsis> + RealTime Read/Write Functions. + </synopsis> + <syntax> + <parameter name="family" required="true" /> + <parameter name="fieldmatch" required="true" /> + <parameter name="value" /> + <parameter name="delim1|field"> + <para>Use <replaceable>delim1</replaceable> with <replaceable>delim2</replaceable> on + read and <replaceable>field</replaceable> without <replaceable>delim2</replaceable> on + write</para> + <para>If we are reading and <replaceable>delim1</replaceable> is not specified, defaults + to <literal>,</literal></para> + </parameter> + <parameter name="delim2"> + <para>Parameter only used when reading, if not specified defaults to <literal>=</literal></para> + </parameter> + </syntax> + <description> + <para>This function will read or write values from/to a RealTime repository. + REALTIME(....) will read names/values from the repository, and + REALTIME(....)= will write a new value/field to the repository. On a + read, this function returns a delimited text string. The name/value + pairs are delimited by <replaceable>delim1</replaceable>, and the name and value are delimited + between each other with delim2. + If there is no match, NULL will be returned by the function. + On a write, this function will always return NULL.</para> + </description> + </function> + <function name="REALTIME_STORE" language="en_US"> + <synopsis> + RealTime Store Function. + </synopsis> + <syntax> + <parameter name="family" required="true" /> + <parameter name="field1" required="true" /> + <parameter name="fieldN" required="true" multiple="true" /> + <parameter name="field30" required="true" /> + </syntax> + <description> + <para>This function will insert a new set of values into the RealTime repository. + If RT engine provides an unique ID of the stored record, REALTIME_STORE(...)=.. + creates channel variable named RTSTOREID, which contains value of unique ID. + Currently, a maximum of 30 field/value pairs is supported.</para> + </description> + </function> + <function name="REALTIME_DESTROY" language="en_US"> + <synopsis> + RealTime Destroy Function. + </synopsis> + <syntax> + <parameter name="family" required="true" /> + <parameter name="fieldmatch" required="true" /> + <parameter name="value" /> + <parameter name="delim1" /> + <parameter name="delim2" /> + </syntax> + <description> + <para>This function acts in the same way as REALTIME(....) does, except that + it destroys matched record in RT engine.</para> + </description> + </function> + ***/ + static int function_realtime_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) { struct ast_variable *var, *head; @@ -232,39 +298,17 @@ static int function_realtime_readdestroy(struct ast_channel *chan, const char *c struct ast_custom_function realtime_function = { .name = "REALTIME", - .synopsis = "RealTime Read/Write Functions", - .syntax = "REALTIME(family,fieldmatch[,value[,delim1[,delim2]]]) on read\n" - "REALTIME(family,fieldmatch,value,field) on write", - .desc = "This function will read or write values from/to a RealTime repository.\n" - "REALTIME(....) will read names/values from the repository, and \n" - "REALTIME(....)= will write a new value/field to the repository. On a\n" - "read, this function returns a delimited text string. The name/value \n" - "pairs are delimited by delim1, and the name and value are delimited \n" - "between each other with delim2. The default for delim1 is ',' and \n" - "the default for delim2 is '='. If there is no match, NULL will be \n" - "returned by the function. On a write, this function will always \n" - "return NULL. \n", .read = function_realtime_read, .write = function_realtime_write, }; struct ast_custom_function realtime_store_function = { .name = "REALTIME_STORE", - .synopsis = "RealTime Store Function", - .syntax = "REALTIME_STORE(family,field1,field2,...,field30) = value1,value2,...,value30", - .desc = "This function will insert a new set of values into the RealTime repository.\n" - "If RT engine provides an unique ID of the stored record, REALTIME_STORE(...)=..\n" - "creates channel variable named RTSTOREID, which contains value of unique ID.\n" - "Currently, a maximum of 30 field/value pairs is supported.\n", .write = function_realtime_store, }; struct ast_custom_function realtime_destroy_function = { .name = "REALTIME_DESTROY", - .synopsis = "RealTime Destroy Function", - .syntax = "REALTIME_DESTROY(family,fieldmatch[,value[,delim1[,delim2]]])\n", - .desc = "This function acts in the same way as REALTIME(....) does, except that\n" - "it destroys matched record in RT engine.\n", .read = function_realtime_readdestroy, }; diff --git a/funcs/func_sha1.c b/funcs/func_sha1.c index 6474140dd..973bc5c07 100644 --- a/funcs/func_sha1.c +++ b/funcs/func_sha1.c @@ -31,6 +31,25 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/module.h" #include "asterisk/pbx.h" +/*** DOCUMENTATION + <function name="SHA1" language="en_US"> + <synopsis> + Computes a SHA1 digest. + </synopsis> + <syntax> + <parameter name="data" required="true"> + <para>Input string</para> + </parameter> + </syntax> + <description> + <para>Generate a SHA1 digest via the SHA1 algorythm.</para> + <para>Example: Set(sha1hash=${SHA1(junky)})</para> + <para>Sets the asterisk variable sha1hash to the string <literal>60fa5675b9303eb62f99a9cd47f9f5837d18f9a0</literal> + which is known as his hash</para> + </description> + </function> + ***/ + static int sha1(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) { @@ -54,13 +73,7 @@ static int sha1(struct ast_channel *chan, const char *cmd, char *data, static struct ast_custom_function sha1_function = { .name = "SHA1", - .synopsis = "Computes a SHA1 digest", - .syntax = "SHA1(<data>)", .read = sha1, - .desc = "Generate a SHA1 digest via the SHA1 algorythm.\n" - " Example: Set(sha1hash=${SHA1(junky)})\n" - " Sets the asterisk variable sha1hash to the string '60fa5675b9303eb62f99a9cd47f9f5837d18f9a0'\n" - " which is known as his hash\n", }; static int unload_module(void) diff --git a/funcs/func_shell.c b/funcs/func_shell.c index 57a9819cd..df7164d5f 100644 --- a/funcs/func_shell.c +++ b/funcs/func_shell.c @@ -63,19 +63,31 @@ static int shell_helper(struct ast_channel *chan, const char *cmd, char *data, return 0; } +/*** DOCUMENTATION + <function name="SHELL" language="en_US"> + <synopsis> + Executes a command as if you were at a shell. + </synopsis> + <syntax> + <parameter name="command" required="true"> + <para>This is the argument to the function, the command you want to pass to the shell.</para> + </parameter> + </syntax> + <description> + <para>Returns the value from a system command</para> + <para>Example: <literal>Set(foo=${SHELL(echo \bar\)})</literal></para> + <note><para>When using the SHELL() dialplan function, your \SHELL\ is /bin/sh, + which may differ as to the underlying shell, depending upon your production + platform. Also keep in mind that if you are using a common path, you should + be mindful of race conditions that could result from two calls running + SHELL() simultaneously.</para></note> + </description> + + </function> + ***/ static struct ast_custom_function shell_function = { .name = "SHELL", - .synopsis = "Executes a command as if you were at a shell.", - .syntax = "SHELL(<command>)", .read = shell_helper, - .desc = -"Returns the value from a system command\n" -" Example: Set(foo=${SHELL(echo \"bar\")})\n" -" Note: When using the SHELL() dialplan function, your \"SHELL\" is /bin/sh,\n" -" which may differ as to the underlying shell, depending upon your production\n" -" platform. Also keep in mind that if you are using a common path, you should\n" -" be mindful of race conditions that could result from two calls running\n" -" SHELL() simultaneously.\n", }; static int unload_module(void) diff --git a/funcs/func_speex.c b/funcs/func_speex.c index 4ddfab80b..6858cf7a3 100644 --- a/funcs/func_speex.c +++ b/funcs/func_speex.c @@ -48,6 +48,52 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #define DEFAULT_AGC_LEVEL 8000.0 +/*** DOCUMENTATION + <function name="AGC" language="en_US"> + <synopsis> + Apply automatic gain control to audio on a channel. + </synopsis> + <syntax> + <parameter name="channeldirection" required="true"> + <para>This can be either <literal>rx</literal> or <literal>tx</literal></para> + </parameter> + </syntax> + <description> + <para>The AGC function will apply automatic gain control to the audio on the + channel that it is executed on. Using <literal>rx</literal> for audio recieved + and <literal>tx</literal> for audio transmitted to the channel. When using this + function you set a target audio level. It is primarly intended for use with + analog lines, but could be useful for other channels as well. The target volume + is set with a number between <literal>1-32768</literal>. The larger the number + the louder (more gain) the channel will recieve.</para> + <para>Examples:</para> + <para>exten => 1,1,Set(AGC(rx)=8000)</para> + <para>exten => 1,2,Set(AGC(tx)=off)</para> + </description> + </function> + <function name="DENOISE" language="en_US"> + <synopsis> + Apply noise reduction to audio on a channel. + </synopsis> + <syntax> + <parameter name="channeldirection" required="true"> + <para>This can be either <literal>rx</literal> or <literal>tx</literal> + the values that can be set to this are either <literal>on</literal> and + <literal>off</literal></para> + </parameter> + </syntax> + <description> + <para>The DENOISE function will apply noise reduction to audio on the channel + that it is executed on. It is very useful for noisy analog lines, especially + when adjusting gains or using AGC. Use <literal>rx</literal> for audio received from the channel + and <literal>tx</literal> to apply the filter to the audio being sent to the channel.</para> + <para>Examples:</para> + <para>exten => 1,1,Set(DENOISE(rx)=on)</para> + <para>exten => 1,2,Set(DENOISE(tx)=off)</para> + </description> + </function> + ***/ + struct speex_direction_info { SpeexPreprocessState *state; /*!< speex preprocess state object */ int agc; /*!< audio gain control is enabled or not */ @@ -290,39 +336,12 @@ static int speex_read(struct ast_channel *chan, const char *cmd, char *data, cha static struct ast_custom_function agc_function = { .name = "AGC", - .synopsis = "Apply automatic gain control to audio on a channel", - .desc = - " The AGC function will apply automatic gain control to audio on the channel\n" - "that this function is executed on. Use rx for audio received from the channel\n" - "and tx to apply AGC to the audio being sent to the channel. When using this\n" - "function, you set a target audio level. It is primarily intended for use with\n" - "analog lines, but could be useful for other channels, as well. The target volume\n" - "is set with a number between 1 and 32768. Larger numbers are louder.\n" - " Example Usage:\n" - " Set(AGC(rx)=8000)\n" - " Set(AGC(tx)=8000)\n" - " Set(AGC(rx)=off)\n" - " Set(AGC(tx)=off)\n" - "", .write = speex_write, .read = speex_read }; static struct ast_custom_function denoise_function = { .name = "DENOISE", - .synopsis = "Apply noise reduction to audio on a channel", - .desc = - " The DENOISE function will apply noise reduction to audio on the channel\n" - "that this function is executed on. It is especially useful for noisy analog\n" - "lines, especially when adjusting gains or using AGC. Use rx for audio\n" - "received from the channel and tx to apply the filter to the audio being sent\n" - "to the channel.\n" - " Example Usage:\n" - " Set(DENOISE(rx)=on)\n" - " Set(DENOISE(tx)=on)\n" - " Set(DENOISE(rx)=off)\n" - " Set(DENOISE(tx)=off)\n" - "", .write = speex_write, .read = speex_read }; diff --git a/funcs/func_strings.c b/funcs/func_strings.c index 2494518e3..c45638564 100644 --- a/funcs/func_strings.c +++ b/funcs/func_strings.c @@ -39,6 +39,244 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/app.h" #include "asterisk/localtime.h" +/*** DOCUMENTATION + <function name="FIELDQTY" language="en_US"> + <synopsis> + Count the fields with an arbitrary delimiter + </synopsis> + <syntax> + <parameter name="varname" required="true" /> + <parameter name="delim" required="true" /> + </syntax> + <description> + <para>Example: ${FIELDQTY(ex-amp-le,-)} returns 3</para> + </description> + </function> + <function name="FILTER" language="en_US"> + <synopsis> + Filter the string to include only the allowed characters + </synopsis> + <syntax> + <parameter name="allowed-chars" required="true" /> + <parameter name="string" required="true" /> + </syntax> + <description> + <para>Permits all characters listed in <replaceable>allowed-chars</replaceable>, + filtering all others outs. In addition to literally listing the characters, + you may also use ranges of characters (delimited by a <literal>-</literal></para> + <para>Hexadecimal characters started with a <literal>\x</literal>(i.e. \x20)</para> + <para>Octal characters started with a <literal>\0</literal> (i.e. \040)</para> + <para>Also <literal>\t</literal>,<literal>\n</literal> and <literal>\r</literal> are recognized.</para> + <note><para>If you want the <literal>-</literal> character it needs to be prefixed with a + <literal>\</literal></para></note> + </description> + </function> + <function name="REGEX" language="en_US"> + <synopsis> + Check string against a regular expression. + </synopsis> + <syntax argsep=" "> + <parameter name=""regular expression"" required="true" /> + <parameter name="string" required="true" /> + </syntax> + <description> + <para>Return <literal>1</literal> on regular expression match or <literal>0</literal> otherwise</para> + <para>Please note that the space following the double quotes separating the + regex from the data is optional and if present, is skipped. If a space is + desired at the beginning of the data, then put two spaces there; the second + will not be skipped.</para> + </description> + </function> + <application name="ClearHash" language="en_US"> + <synopsis> + Clear the keys from a specified hashname. + </synopsis> + <syntax> + <parameter name="hashname" required="true" /> + </syntax> + <description> + <para>Clears all keys out of the specified <replaceable>hashname</replaceable>.</para> + </description> + </application> + <function name="HASH" language="en_US"> + <synopsis> + Implementation of a dialplan associative array + </synopsis> + <syntax> + <parameter name="hashname" required="true" /> + <parameter name="hashkey" /> + </syntax> + <description> + <para>In two arguments mode, gets and sets values to corresponding keys within + a named associative array. The single-argument mode will only work when assigned + to from a function defined by func_odbc</para> + </description> + </function> + <function name="HASHKEYS" language="en_US"> + <synopsis> + Retrieve the keys of the HASH() function. + </synopsis> + <syntax> + <parameter name="hashname" required="true" /> + </syntax> + <description> + <para>Returns a comma-delimited list of the current keys of the associative array + defined by the HASH() function. Note that if you iterate over the keys of + the result, adding keys during iteration will cause the result of the HASHKEYS() + function to change.</para> + </description> + </function> + <function name="KEYPADHASH" language="en_US"> + <synopsis> + Hash the letters in string into equivalent keypad numbers. + </synopsis> + <syntax> + <parameter name="string" required="true" /> + </syntax> + <description> + <para>Example: ${KEYPADHASH(Les)} returns "537"</para> + </description> + </function> + <function name="ARRAY" language="en_US"> + <synopsis> + Allows setting multiple variables at once. + </synopsis> + <syntax> + <parameter name="var1" required="true" /> + <parameter name="var2" required="false" multiple="true" /> + <parameter name="varN" required="false" /> + </syntax> + <description> + <para>The comma-delimited list passed as a value to which the function is set will + be interpreted as a set of values to which the comma-delimited list of + variable names in the arguement should be set.</para> + <para>Example: Set(ARRAY(var1,var2)=1,2) will set var1 to 1 and var2 to 2</para> + </description> + </function> + <function name="STRPTIME" language="en_US"> + <synopsis> + Returns the epoch of the arbitrary date/time string structured as described by the format. + </synopsis> + <syntax> + <parameter name="datetime" required="true" /> + <parameter name="timezone" required="true" /> + <parameter name="format" required="true" /> + </syntax> + <description> + <para>This is useful for converting a date into <literal>EPOCH</literal> time, + possibly to pass to an application like SayUnixTime or to calculate the difference + between the two date strings</para> + <para>Example: ${STRPTIME(2006-03-01 07:30:35,America/Chicago,%Y-%m-%d %H:%M:%S)} returns 1141219835</para> + </description> + </function> + <function name="STRFTIME" language="en_US"> + <synopsis> + Returns the current date/time in the specified format. + </synopsis> + <syntax> + <parameter name="epoch" /> + <parameter name="timezone" /> + <parameter name="format" /> + </syntax> + <description> + <para>STRFTIME supports all of the same formats as the underlying C function + <emphasis>strftime(3)</emphasis>. + It also supports the following format: <literal>%[n]q</literal> - fractions of a second, + with leading zeros.</para> + <para>Example: <literal>%3q</literal> will give milliseconds and <literal>%1q</literal> + will give tenths of a second. The default is set at milliseconds (n=3). + The common case is to use it in combination with %S, as in <literal>%S.%3q</literal>.</para> + </description> + <see-also> + <ref type="manpage">strftime(3)</ref> + </see-also> + </function> + <function name="EVAL" language="en_US"> + <synopsis> + Evaluate stored variables + </synopsis> + <syntax> + <parameter name="variable" required="true" /> + </syntax> + <description> + <para>Using EVAL basically causes a string to be evaluated twice. + When a variable or expression is in the dialplan, it will be + evaluated at runtime. However, if the results of the evaluation + is in fact another variable or expression, using EVAL will have it + evaluated a second time.</para> + <para>Example: If the <variable>MYVAR</variable> contains + <variable>OTHERVAR</variable>, then the result of ${EVAL( + <variable>MYVAR</variable>)} in the dialplan will be the + contents of <variable>OTHERVAR</variable>. Normally just + putting <variable>MYVAR</variable> in the dialplan the result + would be <variable>OTHERVAR</variable>.</para> + </description> + </function> + <function name="TOUPPER" language="en_US"> + <synopsis> + Convert string to all uppercase letters. + </synopsis> + <syntax> + <parameter name="string" required="true" /> + </syntax> + <description> + <para>Example: ${TOUPPER(Example)} returns "EXAMPLE"</para> + </description> + </function> + <function name="TOLOWER" language="en_US"> + <synopsis> + Convert string to all lowercase letters. + </synopsis> + <syntax> + <parameter name="string" required="true" /> + </syntax> + <description> + <para>Example: ${TOLOWER(Example)} returns "example"</para> + </description> + </function> + <function name="LEN" language="en_US"> + <synopsis> + Return the length of the string given. + </synopsis> + <syntax> + <parameter name="string" required="true" /> + </syntax> + <description> + <para>Example: ${LEN(example)} returns 7</para> + </description> + </function> + <function name="SPRINTF" language="en_US"> + <synopsis> + Format a variable according to a format string. + </synopsis> + <syntax> + <parameter name="format" required="true" /> + <parameter name="arg1" required="true" /> + <parameter name="arg2" multiple="true" /> + <parameter name="argN" /> + </syntax> + <description> + <para>Parses the format string specified and returns a string matching + that format. Supports most options found in <emphasis>sprintf(3)</emphasis>. + Returns a shortened string if a format specifier is not recognized.</para> + </description> + <see-also> + <ref type="manpage">sprintf(3)</ref> + </see-also> + </function> + <function name="QUOTE" language="en_US"> + <synopsis> + Quotes a given string, escaping embedded quotes as necessary + </synopsis> + <syntax> + <parameter name="string" required="true" /> + </syntax> + <description> + <para>Example: ${QUOTE(ab"c"de)} will return "abcde"</para> + </description> + </function> + ***/ + static int function_fieldqty(struct ast_channel *chan, const char *cmd, char *parse, char *buf, size_t len) { @@ -81,8 +319,6 @@ static int function_fieldqty(struct ast_channel *chan, const char *cmd, static struct ast_custom_function fieldqty_function = { .name = "FIELDQTY", - .synopsis = "Count the fields, with an arbitrary delimiter", - .syntax = "FIELDQTY(<varname>,<delim>)", .read = function_fieldqty, }; @@ -147,16 +383,7 @@ static int filter(struct ast_channel *chan, const char *cmd, char *parse, char * static struct ast_custom_function filter_function = { .name = "FILTER", - .synopsis = "Filter the string to include only the allowed characters", - .syntax = "FILTER(<allowed-chars>,<string>)", .read = filter, - .desc = -"Permits all characters listed in <allowed-chars>, filtering all others out.\n" -"In addition to literally listing the characters, you may also use ranges of\n" -"characters (delimited by a '-'), as well as hexadecimal characters started\n" -"with a \\x (i.e. \\x20) and octal characters started with \\0 (i.e. \\040).\n" -"Also, \\t, \\n, and \\r are recognized. If you want a literal '-' character,\n" -"simply prefix it with a '\\'\n", }; static int regex(struct ast_channel *chan, const char *cmd, char *parse, char *buf, @@ -198,13 +425,6 @@ static int regex(struct ast_channel *chan, const char *cmd, char *parse, char *b static struct ast_custom_function regex_function = { .name = "REGEX", - .synopsis = "Regular Expression", - .desc = - "Returns 1 if data matches regular expression, or 0 otherwise.\n" - "Please note that the space following the double quotes separating the regex from the data\n" - "is optional and if present, is skipped. If a space is desired at the beginning of the data,\n" - "then put two spaces there; the second will not be skipped.\n", - .syntax = "REGEX(\"<regular expression>\" <data>)", .read = regex, }; @@ -212,10 +432,6 @@ static struct ast_custom_function regex_function = { #define HASH_FORMAT HASH_PREFIX "%s~" static char *app_clearhash = "ClearHash"; -static char *syn_clearhash = "Clear the keys from a specified hashname"; -static char *desc_clearhash = -"ClearHash(<hashname>)\n" -" Clears all keys out of the specified hashname\n"; /* This function probably should migrate to main/pbx.c, as pbx_builtin_clearvar_prefix() */ static void clearvar_prefix(struct ast_channel *chan, const char *prefix) @@ -400,38 +616,18 @@ static int hash_read(struct ast_channel *chan, const char *cmd, char *data, char static struct ast_custom_function hash_function = { .name = "HASH", - .synopsis = "Implementation of a dialplan associative array", - .syntax = "HASH(hashname[,hashkey])", .write = hash_write, .read = hash_read, - .desc = - "In two argument mode, gets and sets values to corresponding keys within a named\n" - "associative array. The single-argument mode will only work when assigned to from\n" - "a function defined by func_odbc.so.\n", }; static struct ast_custom_function hashkeys_function = { .name = "HASHKEYS", - .synopsis = "Retrieve the keys of a HASH()", - .syntax = "HASHKEYS(<hashname>)", .read = hashkeys_read, - .desc = - "Returns a comma-delimited list of the current keys of an associative array\n" - "defined by the HASH() function. Note that if you iterate over the keys of\n" - "the result, adding keys during iteration will cause the result of the HASHKEYS\n" - "function to change.\n", }; static struct ast_custom_function array_function = { .name = "ARRAY", - .synopsis = "Allows setting multiple variables at once", - .syntax = "ARRAY(var1[,var2[...][,varN]])", .write = array, - .desc = - "The comma-separated list passed as a value to which the function is set will\n" - "be interpreted as a set of values to which the comma-separated list of\n" - "variable names in the argument should be set.\n" - "Hence, Set(ARRAY(var1,var2)=1,2) will set var1 to 1 and var2 to 2.\n", }; static int acf_sprintf(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) @@ -580,13 +776,7 @@ sprintf_fail: static struct ast_custom_function sprintf_function = { .name = "SPRINTF", - .synopsis = "Format a variable according to a format string", - .syntax = "SPRINTF(<format>,<arg1>[,...<argN>])", .read = acf_sprintf, - .desc = -"Parses the format string specified and returns a string matching that format.\n" -"Supports most options supported by sprintf(3). Returns a shortened string if\n" -"a format specifier is not recognized.\n", }; static int quote(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) @@ -613,8 +803,6 @@ static int quote(struct ast_channel *chan, const char *cmd, char *data, char *bu static struct ast_custom_function quote_function = { .name = "QUOTE", - .synopsis = "Quotes a given string, escaping embedded quotes as necessary", - .syntax = "QUOTE(<string>)", .read = quote, }; @@ -634,8 +822,6 @@ static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, static struct ast_custom_function len_function = { .name = "LEN", - .synopsis = "Returns the length of the argument given", - .syntax = "LEN(<string>)", .read = len, }; @@ -670,16 +856,6 @@ static int acf_strftime(struct ast_channel *chan, const char *cmd, char *parse, static struct ast_custom_function strftime_function = { .name = "STRFTIME", - .synopsis = "Returns the current date/time in a specified format.", - .syntax = "STRFTIME([<epoch>][,[timezone][,format]])", - .desc = -"STRFTIME sports all of the same formats as the underlying C function\n" -"strftime(3) - see the man page for details. It also supports the\n" -"following format:\n" -" %[n]q - fractions of a second, with leading zeroes. For example, %3q will\n" -" give milliseconds and %1q will give tenths of a second. The default\n" -" is to output milliseconds (n=3). The common case is to use it in\n" -" combination with %S, as in \"%S.%3q\".\n", .read = acf_strftime, }; @@ -722,16 +898,6 @@ static int acf_strptime(struct ast_channel *chan, const char *cmd, char *data, static struct ast_custom_function strptime_function = { .name = "STRPTIME", - .synopsis = - "Returns the epoch of the arbitrary date/time string structured as described in the format.", - .syntax = "STRPTIME(<datetime>,<timezone>,<format>)", - .desc = - "This is useful for converting a date into an EPOCH time, possibly to pass to\n" - "an application like SayUnixTime or to calculate the difference between two\n" - "date strings.\n" - "\n" - "Example:\n" - " ${STRPTIME(2006-03-01 07:30:35,America/Chicago,%Y-%m-%d %H:%M:%S)} returns 1141219835\n", .read = acf_strptime, }; @@ -754,17 +920,6 @@ static int function_eval(struct ast_channel *chan, const char *cmd, char *data, static struct ast_custom_function eval_function = { .name = "EVAL", - .synopsis = "Evaluate stored variables.", - .syntax = "EVAL(<variable>)", - .desc = "Using EVAL basically causes a string to be evaluated twice.\n" - "When a variable or expression is in the dialplan, it will be\n" - "evaluated at runtime. However, if the result of the evaluation\n" - "is in fact a variable or expression, using EVAL will have it\n" - "evaluated a second time. For example, if the variable ${MYVAR}\n" - "contains \"${OTHERVAR}\", then the result of putting ${EVAL(${MYVAR})}\n" - "in the dialplan will be the contents of the variable, OTHERVAR.\n" - "Normally, by just putting ${MYVAR} in the dialplan, you would be\n" - "left with \"${OTHERVAR}\".\n", .read = function_eval, }; @@ -805,10 +960,7 @@ static int keypadhash(struct ast_channel *chan, const char *cmd, char *data, cha static struct ast_custom_function keypadhash_function = { .name = "KEYPADHASH", - .synopsis = "Hash the letters in the string into the equivalent keypad numbers.", - .syntax = "KEYPADHASH(<string>)", .read = keypadhash, - .desc = "Example: ${KEYPADHASH(Les)} returns \"537\"\n", }; static int string_toupper(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen) @@ -822,10 +974,7 @@ static int string_toupper(struct ast_channel *chan, const char *cmd, char *data, static struct ast_custom_function toupper_function = { .name = "TOUPPER", - .synopsis = "Convert the string to upper case.", - .syntax = "TOUPPER(<string>)", .read = string_toupper, - .desc = "Example: ${TOUPPER(Example)} returns \"EXAMPLE\"\n", }; static int string_tolower(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen) @@ -839,10 +988,7 @@ static int string_tolower(struct ast_channel *chan, const char *cmd, char *data, static struct ast_custom_function tolower_function = { .name = "TOLOWER", - .synopsis = "Convert the string to lower case.", - .syntax = "TOLOWER(<string>)", .read = string_tolower, - .desc = "Example: ${TOLOWER(Example)} returns \"example\"\n", }; static int unload_module(void) @@ -886,7 +1032,7 @@ static int load_module(void) res |= ast_custom_function_register(&sprintf_function); res |= ast_custom_function_register(&hashkeys_function); res |= ast_custom_function_register(&hash_function); - res |= ast_register_application(app_clearhash, exec_clearhash, syn_clearhash, desc_clearhash); + res |= ast_register_application_xml(app_clearhash, exec_clearhash); res |= ast_custom_function_register(&toupper_function); res |= ast_custom_function_register(&tolower_function); diff --git a/funcs/func_timeout.c b/funcs/func_timeout.c index 625070217..a035a0563 100644 --- a/funcs/func_timeout.c +++ b/funcs/func_timeout.c @@ -34,6 +34,42 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/utils.h" #include "asterisk/app.h" +/*** DOCUMENTATION + <function name="TIMEOUT" language="en_US"> + <synopsis> + Gets or sets timeouts on the channel. Timeout values are in seconds. + </synopsis> + <syntax> + <parameter name="timeouttype" required="true"> + <para>The timeout that will be manipulated. The possible timeout types + are: <literal>absolute</literal>, <literal>digit</literal> or + <literal>response</literal></para> + </parameter> + </syntax> + <description> + <para>The timeouts that can be manipulated are:</para> + <para><literal>absolute</literal>: The absolute maximum amount of time permitted for a call. + Setting of 0 disables the timeout.</para> + <para><literal>digit</literal>: The maximum amount of time permitted between digits when the + user is typing in an extension. When this timeout expires, + after the user has started to type in an extension, the + extension will be considered complete, and will be + interpreted. Note that if an extension typed in is valid, + it will not have to timeout to be tested, so typically at + the expiry of this timeout, the extension will be considered + invalid (and thus control would be passed to the <literal>i</literal> + extension, or if it doesn't exist the call would be + terminated). The default timeout is 5 seconds.</para> + <para><literal>response</literal>: The maximum amount of time permitted after falling through a + series of priorities for a channel in which the user may + begin typing an extension. If the user does not type an + extension in this amount of time, control will pass to the + <literal>t</literal> extension if it exists, and if not the call would be + terminated. The default timeout is 10 seconds.</para> + </description> + </function> + ***/ + static int timeout_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) { @@ -149,29 +185,6 @@ static int timeout_write(struct ast_channel *chan, const char *cmd, char *data, static struct ast_custom_function timeout_function = { .name = "TIMEOUT", - .synopsis = "Gets or sets timeouts on the channel. Timeout values are in seconds.", - .syntax = "TIMEOUT(timeouttype)", - .desc = - "Gets or sets various channel timeouts. The timeouts that can be\n" - "manipulated are:\n" "\n" - "absolute: The absolute maximum amount of time permitted for a call. A\n" - " setting of 0 disables the timeout.\n" "\n" - "digit: The maximum amount of time permitted between digits when the\n" - " user is typing in an extension. When this timeout expires,\n" - " after the user has started to type in an extension, the\n" - " extension will be considered complete, and will be\n" - " interpreted. Note that if an extension typed in is valid,\n" - " it will not have to timeout to be tested, so typically at\n" - " the expiry of this timeout, the extension will be considered\n" - " invalid (and thus control would be passed to the 'i'\n" - " extension, or if it doesn't exist the call would be\n" - " terminated). The default timeout is 5 seconds.\n" "\n" - "response: The maximum amount of time permitted after falling through a\n" - " series of priorities for a channel in which the user may\n" - " begin typing an extension. If the user does not type an\n" - " extension in this amount of time, control will pass to the\n" - " 't' extension if it exists, and if not the call would be\n" - " terminated. The default timeout is 10 seconds.\n", .read = timeout_read, .write = timeout_write, }; diff --git a/funcs/func_uri.c b/funcs/func_uri.c index 94ae220b6..5efa6ea38 100644 --- a/funcs/func_uri.c +++ b/funcs/func_uri.c @@ -38,6 +38,35 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/utils.h" #include "asterisk/app.h" +/*** DOCUMENTATION + <function name="URIENCODE" language="en_US"> + <synopsis> + Encodes a string to URI-safe encoding according to RFC 2396. + </synopsis> + <syntax> + <parameter name="data" required="true"> + <para>Input string to be encoded.</para> + </parameter> + </syntax> + <description> + <para>Returns the encoded string defined in <replaceable>data</replaceable>.</para> + </description> + </function> + <function name="URIDECODE" language="en_US"> + <synopsis> + Decodes a URI-encoded string according to RFC 2396. + </synopsis> + <syntax> + <parameter name="data" required="true"> + <para>Input string to be decoded.</para> + </parameter> + </syntax> + <description> + <para>Returns the decoded URI-encoded <replaceable>data</replaceable> string.</para> + </description> + </function> + ***/ + /*! \brief uriencode: Encode URL according to RFC 2396 */ static int uriencode(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) @@ -69,15 +98,11 @@ static int uridecode(struct ast_channel *chan, const char *cmd, char *data, static struct ast_custom_function urldecode_function = { .name = "URIDECODE", - .synopsis = "Decodes a URI-encoded string according to RFC 2396.", - .syntax = "URIDECODE(<data>)", .read = uridecode, }; static struct ast_custom_function urlencode_function = { .name = "URIENCODE", - .synopsis = "Encodes a string to URI-safe encoding according to RFC 2396.", - .syntax = "URIENCODE(<data>)", .read = uriencode, }; diff --git a/funcs/func_version.c b/funcs/func_version.c index 973f866c6..8ed6c218f 100644 --- a/funcs/func_version.c +++ b/funcs/func_version.c @@ -34,6 +34,49 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/ast_version.h" #include "asterisk/build.h" +/*** DOCUMENTATION + <function name="VERSION" language="en_US"> + <synopsis> + Return the Version info for this Asterisk. + </synopsis> + <syntax> + <parameter name="info"> + <para>The possible values are:</para> + <enumlist> + <enum name="ASTERISK_VERSION_NUM"> + <para>A string of digits is returned (right now fixed at 999999).</para> + </enum> + <enum name="BUILD_USER"> + <para>The string representing the user's name whose account + was used to configure Asterisk, is returned.</para> + </enum> + <enum name="BUILD_HOSTNAME"> + <para>The string representing the name of the host on which Asterisk was configured, is returned.</para> + </enum> + <enum name="BUILD_MACHINE"> + <para>The string representing the type of machine on which Asterisk was configured, is returned.</para> + </enum> + <enum name="BUILD_OS"> + <para>The string representing the OS of the machine on which Asterisk was configured, is returned.</para> + </enum> + <enum name="BUILD_DATE"> + <para>The string representing the date on which Asterisk was configured, is returned.</para> + </enum> + <enum name="BUILD_KERNEL"> + <para>The string representing the kernel version of the machine on which Asterisk + was configured, is returned.</para> + </enum> + </enumlist> + </parameter> + </syntax> + <description> + <para>If there are no arguments, return the version of Asterisk in this format: SVN-branch-1.4-r44830M</para> + <para>Example: Set(junky=${VERSION()};</para> + <para>Sets junky to the string <literal>SVN-branch-1.6-r74830M</literal>, or possibly, <literal>SVN-trunk-r45126M</literal>.</para> + </description> + </function> + ***/ + static int acf_version_exec(struct ast_channel *chan, const char *cmd, char *parse, char *buffer, size_t buflen) { @@ -70,19 +113,6 @@ static int acf_version_exec(struct ast_channel *chan, const char *cmd, static struct ast_custom_function acf_version = { .name = "VERSION", - .synopsis = "Return the Version info for this Asterisk", - .syntax = "VERSION([info])", - .desc = - "If there are no arguments, return the version of Asterisk in this format: SVN-branch-1.4-r44830M\n" - "If the argument is 'ASTERISK_VERSION_NUM', a string of digits is returned (right now fixed at 999999).\n" - "If the argument is 'BUILD_USER', the string representing the user's name whose account was used to configure Asterisk, is returned.\n" - "If the argument is 'BUILD_HOSTNAME', the string representing the name of the host on which Asterisk was configured, is returned.\n" - "If the argument is 'BUILD_MACHINE', the string representing the type of machine on which Asterisk was configured, is returned.\n" - "If the argument is 'BUILD_OS', the string representing the OS of the machine on which Asterisk was configured, is returned.\n" - "If the argument is 'BUILD_DATE', the string representing the date on which Asterisk was configured, is returned.\n" - "If the argument is 'BUILD_KERNEL', the string representing the kernel version of the machine on which Asterisk was configured, is returned .\n" - " Example: Set(junky=${VERSION()}; \n" - " Sets junky to the string 'SVN-branch-1.6-r74830M', or possibly, 'SVN-trunk-r45126M'.\n", .read = acf_version_exec, }; diff --git a/funcs/func_vmcount.c b/funcs/func_vmcount.c index 24d83140d..f79669b6d 100644 --- a/funcs/func_vmcount.c +++ b/funcs/func_vmcount.c @@ -39,6 +39,30 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/utils.h" #include "asterisk/app.h" +/*** DOCUMENTATION + <function name="VMCOUNT" language="en_US"> + <synopsis> + Count the voicemails in a specified mailbox. + </synopsis> + <syntax> + <parameter name="vmbox" required="true" argsep="@"> + <argument name="vmbox" required="true" /> + <argument name="context" required="false"> + <para>If not specified, defaults to <literal>default</literal>.</para> + </argument> + </parameter> + <parameter name="folder" required="false"> + <para>If not specified, defaults to <literal>INBOX</literal></para> + </parameter> + </syntax> + <description> + <para>Count the number of voicemails in a specified mailbox, you could also specify + the <replaceable>context</replaceable> and the mailbox <replaceable>folder</replaceable>.</para> + <para>Example: <literal>exten => s,1,Set(foo=${VMCOUNT(125)})</literal></para> + </description> + </function> + ***/ + static int acf_vmcount_exec(struct ast_channel *chan, const char *cmd, char *argsstr, char *buf, size_t len) { char *context; @@ -72,11 +96,6 @@ static int acf_vmcount_exec(struct ast_channel *chan, const char *cmd, char *arg struct ast_custom_function acf_vmcount = { .name = "VMCOUNT", - .synopsis = "Counts the voicemail in a specified mailbox", - .syntax = "VMCOUNT(vmbox[@context][,folder])", - .desc = - " context - defaults to \"default\"\n" - " folder - defaults to \"INBOX\"\n", .read = acf_vmcount_exec, }; diff --git a/funcs/func_volume.c b/funcs/func_volume.c index 530f9b876..9c8b92b20 100644 --- a/funcs/func_volume.c +++ b/funcs/func_volume.c @@ -36,6 +36,26 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/utils.h" #include "asterisk/audiohook.h" +/*** DOCUMENTATION + <function name="VOLUME" language="en_US"> + <synopsis> + Set the TX or RX volume of a channel. + </synopsis> + <syntax> + <parameter name="direction" required="true"> + <para>Must be <literal>TX</literal> or <literal>RX</literal>.</para> + </parameter> + </syntax> + <description> + <para>The VOLUME function can be used to increase or decrease the <literal>tx</literal> or + <literal>rx</literal> gain of any channel.</para> + <para>For example:</para> + <para>Set(VOLUME(TX)=3)</para> + <para>Set(VOLUME(RX)=2)</para> + </description> + </function> + ***/ + struct volume_information { struct ast_audiohook audiohook; int tx_gain; @@ -137,13 +157,6 @@ static int volume_write(struct ast_channel *chan, const char *cmd, char *data, c static struct ast_custom_function volume_function = { .name = "VOLUME", - .synopsis = "Set the TX or RX volume of a channel", - .syntax = "VOLUME(TX|RX)", - .desc = - " The VOLUME function can be used to increase or decrease the tx or\n" - "rx gain of any channel. For example:\n" - " Set(VOLUME(TX)=3)\n" - " Set(VOLUME(RX)=2)\n", .write = volume_write, }; diff --git a/include/asterisk/_private.h b/include/asterisk/_private.h index fe9aa2c04..be4542d7a 100644 --- a/include/asterisk/_private.h +++ b/include/asterisk/_private.h @@ -56,4 +56,10 @@ int ast_timing_init(void); /*!< Provided by timing.c */ */ int ast_module_reload(const char *name); +/*! \brief Load XML documentation. Provided by pbx.c + * \retval 1 on error. + * \retval 0 on success. + */ +int ast_load_documentation(void); + #endif /* _ASTERISK__PRIVATE_H */ diff --git a/include/asterisk/autoconfig.h.in b/include/asterisk/autoconfig.h.in index 3417c738e..79134bd3c 100644 --- a/include/asterisk/autoconfig.h.in +++ b/include/asterisk/autoconfig.h.in @@ -410,6 +410,9 @@ /* Define to 1 if you have the <libintl.h> header file. */ #undef HAVE_LIBINTL_H +/* Define if your system has the LIBXML2 libraries. */ +#undef HAVE_LIBXML2 + /* Define to 1 if you have the <limits.h> header file. */ #undef HAVE_LIMITS_H diff --git a/include/asterisk/compat.h b/include/asterisk/compat.h index e481fbec4..0b431f5e0 100644 --- a/include/asterisk/compat.h +++ b/include/asterisk/compat.h @@ -182,4 +182,15 @@ typedef unsigned int uint; typedef unsigned long long uint64_t; #endif +/* glob compat stuff */ +#if defined(__Darwin__) || defined(__CYGWIN__) +#define GLOB_ABORTED GLOB_ABEND +#endif +#include <glob.h> +#ifdef SOLARIS +#define MY_GLOB_FLAGS GLOB_NOCHECK +#else +#define MY_GLOB_FLAGS (GLOB_NOMAGIC|GLOB_BRACE) +#endif + #endif diff --git a/include/asterisk/extconf.h b/include/asterisk/extconf.h index 086271ce5..7527c579f 100644 --- a/include/asterisk/extconf.h +++ b/include/asterisk/extconf.h @@ -76,8 +76,14 @@ struct ast_config { /*! \brief A registered application */ struct ast_app { int (*execute)(struct ast_channel *chan, void *data); - const char *synopsis; /*!< Synopsis text for 'show applications' */ - const char *description; /*!< Description (help text) for 'show application <name>' */ + AST_DECLARE_STRING_FIELDS( + AST_STRING_FIELD(synopsis); /*!< Synopsis text for 'show applications' */ + AST_STRING_FIELD(description); /*!< Description (help text) for 'show application <name>' */ + AST_STRING_FIELD(syntax); /*!< Syntax text for 'core show applications' */ + AST_STRING_FIELD(arguments); /*!< Arguments description */ + AST_STRING_FIELD(seealso); /*!< See also */ + ); + enum ast_xmldoc_src docsrc; /*!< Where the documentation come from. */ AST_RWLIST_ENTRY(ast_app) list; /*!< Next app in list */ void *module; /*!< Module this app belongs to */ char name[0]; /*!< Name of the application */ diff --git a/include/asterisk/module.h b/include/asterisk/module.h index f466395c0..640c5af32 100644 --- a/include/asterisk/module.h +++ b/include/asterisk/module.h @@ -380,6 +380,23 @@ static void __restore_globals(void) */ #define ast_register_application(app, execute, synopsis, description) ast_register_application2(app, execute, synopsis, description, ast_module_info->self) +/*! + * \brief Register an application using XML documentation. + * + * \param app Short name of the application + * \param execute a function callback to execute the application. It should return + * non-zero if the channel needs to be hung up. + * + * This registers an application with Asterisk's internal application list. + * \note The individual applications themselves are responsible for registering and unregistering + * and unregistering their own CLI commands. + * + * \retval 0 success + * \retval -1 failure. + */ +#define ast_register_application_xml(app, execute) ast_register_application(app, execute, NULL, NULL) + + /*! * \brief Register an application. * diff --git a/include/asterisk/pbx.h b/include/asterisk/pbx.h index d2d95acca..3348bb8d7 100644 --- a/include/asterisk/pbx.h +++ b/include/asterisk/pbx.h @@ -26,6 +26,7 @@ #include "asterisk/sched.h" #include "asterisk/chanvars.h" #include "asterisk/hashtab.h" +#include "asterisk/stringfields.h" #if defined(__cplusplus) || defined(c_plusplus) extern "C" { @@ -73,12 +74,23 @@ struct ast_sw; /*! \brief Typedef for devicestate and hint callbacks */ typedef int (*ast_state_cb_type)(char *context, char* id, enum ast_extension_states state, void *data); +/*! \brief From where the documentation come from */ +enum ast_doc_src { + AST_XML_DOC, /*!< From XML documentation */ + AST_STATIC_DOC /*!< From application/function registration */ +}; + /*! \brief Data structure associated with a custom dialplan function */ struct ast_custom_function { - const char *name; /*!< Name */ - const char *synopsis; /*!< Short description for "show functions" */ - const char *desc; /*!< Help text that explains it all */ - const char *syntax; /*!< Syntax description */ + const char *name; /*!< Name */ + AST_DECLARE_STRING_FIELDS( + AST_STRING_FIELD(synopsis); /*!< Synopsis text for 'show functions' */ + AST_STRING_FIELD(desc); /*!< Description (help text) for 'show functions <name>' */ + AST_STRING_FIELD(syntax); /*!< Syntax text for 'core show functions' */ + AST_STRING_FIELD(arguments); /*!< Arguments description */ + AST_STRING_FIELD(seealso); /*!< See also */ + ); + enum ast_doc_src docsrc; /*!< Where the documentation come from */ int (*read)(struct ast_channel *, const char *, char *, char *, size_t); /*!< Read function, if read is supported */ int (*write)(struct ast_channel *, const char *, char *, const char *); /*!< Write function, if write is supported */ struct ast_module *mod; /*!< Module this custom function belongs to */ diff --git a/include/asterisk/strings.h b/include/asterisk/strings.h index 19315b02f..16a60c38a 100644 --- a/include/asterisk/strings.h +++ b/include/asterisk/strings.h @@ -387,6 +387,21 @@ void ast_str_reset(struct ast_str *buf), } ) +/*! \brief Trims trailing whitespace characters from an ast_str string. + * \param buf A pointer to the ast_str string. + */ +AST_INLINE_API( +void ast_str_trim_blanks(struct ast_str *buf), +{ + if (!buf) { + return; + } + while (buf->used && buf->str[buf->used - 1] < 33) { + buf->str[--(buf->used)] = '\0'; + } +} +) + /* * AST_INLINE_API() is a macro that takes a block of code as an argument. * Using preprocessor #directives in the argument is not supported by all diff --git a/include/asterisk/term.h b/include/asterisk/term.h index 3277f0042..8c6cab43e 100644 --- a/include/asterisk/term.h +++ b/include/asterisk/term.h @@ -64,6 +64,28 @@ extern "C" { char *term_color(char *outbuf, const char *inbuf, int fgcolor, int bgcolor, int maxout); +/*! + * \brief Append a color sequence to an ast_str + * + * \param str The string to append to + * \param fgcolor foreground color + * \param bgcolor background color + * + * \retval 0 success + * \retval -1 failure + */ +int ast_term_color_code(struct ast_str **str, int fgcolor, int bgcolor); + +/*! + * \brief Write a color sequence to a string + * + * \param outbuf the location to write to + * \param fgcolor foreground color + * \param bgcolor background color + * \param maxout maximum number of characters to write + * + * \return outbuf + */ char *term_color_code(char *outbuf, int fgcolor, int bgcolor, int maxout); char *term_strip(char *outbuf, char *inbuf, int maxout); diff --git a/include/asterisk/xml.h b/include/asterisk/xml.h new file mode 100644 index 000000000..8ed9ffdfd --- /dev/null +++ b/include/asterisk/xml.h @@ -0,0 +1,122 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2008, Eliel C. Sardanons (LU1ALY) <eliels@gmail.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. + */ + +#ifndef _ASTERISK_XML_H +#define _ASTERISK_XML_H + +/*! \file + * \brief Asterisk XML abstraction layer + */ + +struct ast_xml_node; +struct ast_xml_doc; + +/*! \brief Initialize the XML library implementation. + * This function is used to setup everything needed + * to start working with the xml implementation. + * \retval 0 On success. + * \retval 1 On error. + */ +int ast_xml_init(void); + +/*! \brief Cleanup library allocated global data. + * \retval 0 On success. + * \retval 1 On error. + */ +int ast_xml_finish(void); + +/*! \brief Open an XML document. + * \param filename Document path. + * \retval NULL on error. + * \retval The ast_xml_doc reference to the open document. + */ +struct ast_xml_doc *ast_xml_open(char *filename); + +/*! \brief Close an already open document and free the used + * structure. + * \retval doc The document reference. + */ +void ast_xml_close(struct ast_xml_doc *doc); + +/*! \brief Get the document root node. + * \param doc Document reference + * \retval NULL on error + * \retval The root node on success. + */ +struct ast_xml_node *ast_xml_get_root(struct ast_xml_doc *doc); + +/*! \brief Free node + * \param node Node to be released. + */ +void ast_xml_free_node(struct ast_xml_node *node); + +/*! \brief Free an attribute returned by ast_xml_get_attribute() + * \param data pointer to be freed. + */ +void ast_xml_free_attr(const char *attribute); + +/*! \brief Free a content element that was returned by ast_xml_get_text() + * \param text text to be freed. + */ +void ast_xml_free_text(const char *text); + +/*! \brief Get a node attribute by name + * \param node Node where to search the attribute. + * \param attrname Attribute name. + * \retval NULL on error + * \retval The attribute value on success. + */ +const char *ast_xml_get_attribute(struct ast_xml_node *node, const char *attrname); + +/*! \brief Find a node element by name. + * \param node This is the node starting point. + * \param name Node name to find. + * \param attrname attribute name to match (if NULL it won't be matched). + * \param attrvalue attribute value to match (if NULL it won't be matched). + * \retval NULL if not found + * \retval The node on success. + */ +struct ast_xml_node *ast_xml_find_element(struct ast_xml_node *root_node, const char *name, const char *attrname, const char *attrvalue); + +/*! \brief Get an element content string. + * \param node Node from where to get the string. + * \retval NULL on error. + * \retval The text content of node. + */ +const char *ast_xml_get_text(struct ast_xml_node *node); + +/*! \brief Get the name of a node. */ +const char *ast_xml_node_get_name(struct ast_xml_node *node); + +/*! \brief Get the node's children. */ +struct ast_xml_node *ast_xml_node_get_children(struct ast_xml_node *node); + +/*! \brief Get the next node in the same level. */ +struct ast_xml_node *ast_xml_node_get_next(struct ast_xml_node *node); + +/*! \brief Get the previous node in the same leve. */ +struct ast_xml_node *ast_xml_node_get_prev(struct ast_xml_node *node); + +/*! \brief Get the parent of a specified node. */ +struct ast_xml_node *ast_xml_node_get_parent(struct ast_xml_node *node); + +/* Features using ast_xml_ */ +#ifdef HAVE_LIBXML2 +#define AST_XML_DOCS +#endif + +#endif /* _ASTERISK_XML_H */ + diff --git a/main/Makefile b/main/Makefile index b1ef7ef77..cab6f9b9a 100644 --- a/main/Makefile +++ b/main/Makefile @@ -28,7 +28,7 @@ OBJS= tcptls.o io.o sched.o logger.o frame.o loader.o config.o channel.o \ cryptostub.o sha1.o http.o fixedjitterbuf.o abstract_jb.o \ strcompat.o threadstorage.o dial.o event.o adsistub.o audiohook.o \ astobj2.o hashtab.o global_datastores.o version.o \ - features.o taskprocessor.o timing.o datastore.o + features.o taskprocessor.o timing.o datastore.o xml.o # we need to link in the objects statically, not as a library, because # otherwise modules will not have them available if none of the static @@ -41,7 +41,7 @@ OBJS+=say.o AST_LIBS += $(SSL_LIB) AST_LIBS += $(BKTR_LIB) - +AST_LIBS += $(LIBXML2_LIB) ifeq ($(POLL_AVAILABLE),) OBJS+=poll.o diff --git a/main/asterisk.c b/main/asterisk.c index 73e27c229..239acd7ff 100644 --- a/main/asterisk.c +++ b/main/asterisk.c @@ -117,6 +117,7 @@ int daemon(int, int); /* defined in libresolv of all places */ #include "asterisk/devicestate.h" #include "asterisk/module.h" #include "asterisk/dsp.h" +#include "asterisk/xml.h" #include "asterisk/buildinfo.h" #include "asterisk/doxyref.h" /* Doxygen documentation */ @@ -3322,6 +3323,11 @@ int main(int argc, char *argv[]) exit(1); } +#ifdef AST_XML_DOCS + /* Load XML documentation. */ + ast_load_documentation(); +#endif + if (load_modules(1)) { /* Load modules, pre-load only */ printf("%s", term_quit()); exit(1); diff --git a/main/config.c b/main/config.c index a382a7a80..b3abe2730 100644 --- a/main/config.c +++ b/main/config.c @@ -39,24 +39,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #define AST_INCLUDE_GLOB 1 -#ifdef AST_INCLUDE_GLOB -/* glob compat stuff - eventually this should go in compat.h or some - * header in include/asterisk/ - */ -#if defined(__Darwin__) || defined(__CYGWIN__) -#define GLOB_ABORTED GLOB_ABEND -#endif - -#include <glob.h> - -#ifdef SOLARIS -#define MY_GLOB_FLAGS GLOB_NOCHECK -#else -#define MY_GLOB_FLAGS (GLOB_NOMAGIC|GLOB_BRACE) -#endif - -#endif - #include "asterisk/config.h" #include "asterisk/cli.h" #include "asterisk/lock.h" diff --git a/main/features.c b/main/features.c index 82b85669c..adf5086aa 100644 --- a/main/features.c +++ b/main/features.c @@ -56,6 +56,98 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/global_datastores.h" #include "asterisk/astobj2.h" +/*** DOCUMENTATION + <application name="Bridge" language="en_US"> + <synopsis> + Bridge two channels. + </synopsis> + <syntax> + <parameter name="channel" required="true"> + <para>The current channel is bridged to the specified <replaceable>channel</replaceable>.</para> + </parameter> + <parameter name="options"> + <optionlist> + <option name="p"> + <para>Play a courtesy tone to <replaceable>channel</replaceable>.</para> + </option> + </optionlist> + </parameter> + </syntax> + <description> + <para>Allows the ability to bridge two channels via the dialplan.</para> + <para>This application sets the following channel variable upon completion:</para> + <variablelist> + <variable name="BRIDGERESULT"> + <para>The result of the bridge attempt as a text string.</para> + <value name="SUCCESS" /> + <value name="FAILURE" /> + <value name="LOOP" /> + <value name="NONEXISTENT" /> + <value name="INCOMPATIBLE" /> + </variable> + </variablelist> + </description> + </application> + <application name="ParkedCall" language="en_US"> + <synopsis> + Answer a parked call. + </synopsis> + <syntax> + <parameter name="exten" required="true" /> + </syntax> + <description> + <para>Used to connect to a parked call. This application is always + registered internally and does not need to be explicitly added + into the dialplan, although you should include the <literal>parkedcalls</literal> + context. If no extension is provided, then the first available + parked call will be acquired.</para> + </description> + </application> + <application name="Park" language="en_US"> + <synopsis> + Park yourself. + </synopsis> + <syntax> + <parameter name="timeout"> + <para>A custom parking timeout for this parked call.</para> + </parameter> + <parameter name="return_context"> + <para>The context to return the call to after it times out.</para> + </parameter> + <parameter name="return_exten"> + <para>The extension to return the call to after it times out.</para> + </parameter> + <parameter name="return_priority"> + <para>The priority to return the call to after it times out.</para> + </parameter> + <parameter name="options"> + <para>A list of options for this parked call.</para> + <optionlist> + <option name="r"> + <para>Send ringing instead of MOH to the parked call.</para> + </option> + <option name="R"> + <para>Randomize the selection of a parking space.</para> + </option> + <option name="s"> + <para>Silence announcement of the parking space number.</para> + </option> + </optionlist> + </parameter> + </syntax> + <description> + <para>Used to park yourself (typically in combination with a supervised + transfer to know the parking space). This application is always + registered internally and does not need to be explicitly added + into the dialplan, although you should include the <literal>parkedcalls</literal> + context (or the context specified in <filename>features.conf</filename>).</para> + <para>If you set the <variable>PARKINGEXTEN</variable> variable to an extension in your + parking context, Park() will park the call on that extension, unless + it already exists. In that case, execution will continue at next priority.</para> + </description> + </application> + ***/ + #define DEFAULT_PARK_TIME 45000 #define DEFAULT_TRANSFER_DIGIT_TIMEOUT 3000 #define DEFAULT_FEATURE_DIGIT_TIMEOUT 2000 @@ -150,41 +242,8 @@ static unsigned int atxfercallbackretries; static char *registrar = "features"; /*!< Registrar for operations */ /* module and CLI command definitions */ -static char *synopsis = "Answer a parked call"; - -static char *descrip = "ParkedCall(exten): " -"Used to connect to a parked call. This application is always\n" -"registered internally and does not need to be explicitly added\n" -"into the dialplan, although you should include the 'parkedcalls'\n" -"context. If no extension is provided, then the first available\n" -"parked call will be acquired.\n"; - static char *parkcall = PARK_APP_NAME; -static char *synopsis2 = "Park yourself"; - -static char *descrip2 = -" Park([timeout,[return_context,[return_exten,[return_priority,[options]]]]]):" -"Used to park yourself (typically in combination with a supervised\n" -"transfer to know the parking space). This application is always\n" -"registered internally and does not need to be explicitly added\n" -"into the dialplan, although you should include the 'parkedcalls'\n" -"context (or the context specified in features.conf).\n\n" -"If you set the PARKINGEXTEN variable to an extension in your\n" -"parking context, Park() will park the call on that extension, unless\n" -"it already exists. In that case, execution will continue at next\n" -"priority.\n" -" This application can accept arguments as well.\n" -" timeout - A custom parking timeout for this parked call.\n" -" return_context - The context to return the call to after it times out.\n" -" return_exten - The extension to return the call to after it times out.\n" -" return_priority - The priority to return the call to after it times out.\n" -" options - A list of options for this parked call. Valid options are:\n" -" 'r' - Send ringing instead of MOH to the parked call.\n" -" 'R' - Randomize the selection of a parking space.\n" -" 's' - Silence announcement of the parking space number.\n" -""; - static struct ast_app *monitor_app = NULL; static int monitor_ok = 1; @@ -3962,16 +4021,6 @@ int ast_pickup_call(struct ast_channel *chan) } static char *app_bridge = "Bridge"; -static char *bridge_synopsis = "Bridge two channels"; -static char *bridge_descrip = -"Usage: Bridge(channel[,options])\n" -" Allows the ability to bridge two channels via the dialplan.\n" -"The current channel is bridged to the specified 'channel'.\n" -" Options:\n" -" p - Play a courtesy tone to 'channel'.\n" -"This application sets the following channel variable upon completion:\n" -" BRIDGERESULT The result of the bridge attempt as a text string, one of\n" -" SUCCESS | FAILURE | LOOP | NONEXISTENT | INCOMPATIBLE\n"; enum { BRIDGE_OPT_PLAYTONE = (1 << 0), @@ -4113,7 +4162,7 @@ int ast_features_init(void) { int res; - ast_register_application2(app_bridge, bridge_exec, bridge_synopsis, bridge_descrip, NULL); + ast_register_application2(app_bridge, bridge_exec, NULL, NULL, NULL); parkinglots = ao2_container_alloc(7, parkinglot_hash_cb, parkinglot_cmp_cb); @@ -4121,9 +4170,9 @@ int ast_features_init(void) return res; ast_cli_register_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry)); ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL); - res = ast_register_application2(parkedcall, park_exec, synopsis, descrip, NULL); + res = ast_register_application2(parkedcall, park_exec, NULL, NULL, NULL); if (!res) - res = ast_register_application2(parkcall, park_call_exec, synopsis2, descrip2, NULL); + res = ast_register_application2(parkcall, park_call_exec, NULL, NULL, NULL); if (!res) { ast_manager_register("ParkedCalls", 0, manager_parking_status, "List parked calls"); ast_manager_register2("Park", EVENT_FLAG_CALL, manager_park, "Park a channel", mandescr_park); diff --git a/main/pbx.c b/main/pbx.c index b86cb38ce..0df8b1377 100644 --- a/main/pbx.c +++ b/main/pbx.c @@ -12,7 +12,7 @@ * 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 +* the GNU General Public License Version 2. See the LICENSE file * at the top of the source tree. */ @@ -59,12 +59,12 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/musiconhold.h" #include "asterisk/app.h" #include "asterisk/devicestate.h" -#include "asterisk/stringfields.h" #include "asterisk/event.h" #include "asterisk/hashtab.h" #include "asterisk/module.h" #include "asterisk/indications.h" #include "asterisk/taskprocessor.h" +#include "asterisk/xml.h" /*! * \note I M P O R T A N T : @@ -87,6 +87,541 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") * */ +/*** DOCUMENTATION + <application name="Answer" language="en_US"> + <synopsis> + Answer a channel if ringing. + </synopsis> + <syntax> + <parameter name="delay"> + <para>Asterisk will wait this number of milliseconds before returning to + the dialplan after answering the call.</para> + </parameter> + </syntax> + <description> + <para>If the call has not been answered, this application will + answer it. Otherwise, it has no effect on the call.</para> + </description> + </application> + <application name="BackGround" language="en_US"> + <synopsis> + Play an audio file while waiting for digits of an extension to go to. + </synopsis> + <syntax> + <parameter name="filenames" required="true" argsep="&"> + <argument name="filename1" required="true" /> + <argument name="filename2" multiple="true" /> + </parameter> + <parameter name="options"> + <optionlist> + <option name="s"> + <para>Causes the playback of the message to be skipped + if the channel is not in the <literal>up</literal> state (i.e. it + hasn't been answered yet). If this happens, the + application will return immediately.</para> + </option> + <option name="n"> + <para>Don't answer the channel before playing the files.</para> + </option> + <option name="m"> + <para>Only break if a digit hit matches a one digit + extension in the destination context.</para> + </option> + </optionlist> + </parameter> + <parameter name="langoverride"> + <para>Explicitly specifies which language to attempt to use for the requested sound files.</para> + </parameter> + <parameter name="context"> + <para>This is the dialplan context that this application will use when exiting + to a dialed extension.</para> + </parameter> + </syntax> + <description> + <para>This application will play the given list of files <emphasis>(do not put extension)</emphasis> + while waiting for an extension to be dialed by the calling channel. To continue waiting + for digits after this application has finished playing files, the <literal>WaitExten</literal> + application should be used.</para> + <para>If one of the requested sound files does not exist, call processing will be terminated.</para> + <para>This application sets the following channel variable upon completion:</para> + <variablelist> + <variable name="BACKGROUNDSTATUS"> + <para>The status of the background attempt as a text string.</para> + <value name="SUCCESS" /> + <value name="FAILED" /> + </variable> + </variablelist> + </description> + <see-also> + <ref type="application">Playback</ref> + </see-also> + </application> + <application name="Busy" language="en_US"> + <synopsis> + Indicate the Busy condition. + </synopsis> + <syntax> + <parameter name="timeout"> + <para>If specified, the calling channel will be hung up after the specified number of seconds. + Otherwise, this application will wait until the calling channel hangs up.</para> + </parameter> + </syntax> + <description> + <para>This application will indicate the busy condition to the calling channel.</para> + </description> + </application> + <application name="Congestion" language="en_US"> + <synopsis> + Indicate the Congestion condition. + </synopsis> + <syntax> + <parameter name="timeout"> + <para>If specified, the calling channel will be hung up after the specified number of seconds. + Otherwise, this application will wait until the calling channel hangs up.</para> + </parameter> + </syntax> + <description> + <para>This application will indicate the congestion condition to the calling channel.</para> + </description> + </application> + <application name="ExecIfTime" language="en_US"> + <synopsis> + Conditional application execution based on the current time. + </synopsis> + <syntax argsep="?"> + <parameter name="day_condition" required="true"> + <argument name="times" required="true" /> + <argument name="weekdays" required="true" /> + <argument name="mdays" required="true" /> + <argument name="months" required="true" /> + </parameter> + <parameter name="appname" required="true" hasparams="optional"> + <argument name="appargs" required="true" /> + </parameter> + </syntax> + <description> + <para>This application will execute the specified dialplan application, with optional + arguments, if the current time matches the given time specification.</para> + </description> + </application> + <application name="Goto" language="en_US"> + <synopsis> + Jump to a particular priority, extension, or context. + </synopsis> + <syntax> + <parameter name="context" /> + <parameter name="extensions" /> + <parameter name="priority" required="true" /> + </syntax> + <description> + <para>This application will set the current context, extension, and priority in the channel structure. + After it completes, the pbx engine will continue dialplan execution at the specified location. + If no specific <replaceable>extension</replaceable>, or <replaceable>extension</replaceable> and + <replaceable>context</replaceable>, are specified, then this application will + just set the specified <replaceable>priority</replaceable> of the current extension.</para> + <para>At least a <replaceable>priority</replaceable> is required as an argument, or the goto will + return a <literal>-1</literal>, and the channel and call will be terminated.</para> + <para>If the location that is put into the channel information is bogus, and asterisk cannot + find that location in the dialplan, then the execution engine will try to find and execute the code in + the <literal>i</literal> (invalid) extension in the current context. If that does not exist, it will try to execute the + <literal>h</literal> extension. If either or neither the <literal>h</literal> or <literal>i</literal> extensions + have been defined, the channel is hung up, and the execution of instructions on the channel is terminated. + What this means is that, for example, you specify a context that does not exist, then + it will not be possible to find the <literal>h</literal> or <literal>i</literal> extensions, + and the call will terminate!</para> + </description> + </application> + <application name="GotoIf" language="en_US"> + <synopsis> + Conditional goto. + </synopsis> + <syntax argsep="?"> + <parameter name="condition" required="true" /> + <parameter name="destination" required="true" argsep=":"> + <argument name="labeliftrue"> + <para>Continue at <replaceable>labeliftrue</replaceable> if the condition is true.</para> + </argument> + <argument name="labeliffalse"> + <para>Continue at <replaceable>labeliffalse</replaceable> if the condition is false.</para> + </argument> + </parameter> + </syntax> + <description> + <para>This application will set the current context, extension, and priority in the channel structure + based on the evaluation of the given condition. After this application completes, the + pbx engine will continue dialplan execution at the specified location in the dialplan. + The labels are specified with the same syntax as used within the Goto application. + If the label chosen by the condition is omitted, no jump is performed, and the execution passes to the + next instruction. If the target location is bogus, and does not exist, the execution engine will try + to find and execute the code in the <literal>i</literal> (invalid) extension in the current context. + If that does not exist, it will try to execute the <literal>h</literal> extension. + If either or neither the <literal>h</literal> or <literal>i</literal> extensions have been defined, + the channel is hung up, and the execution of instructions on the channel is terminated. + Remember that this command can set the current context, and if the context specified + does not exist, then it will not be able to find any 'h' or 'i' extensions there, and + the channel and call will both be terminated!.</para> + </description> + </application> + <application name="GotoIfTime" language="en_US"> + <synopsis> + Conditional Goto based on the current time. + </synopsis> + <syntax argsep="?"> + <parameter name="condition" required="true"> + <argument name="times" required="true" /> + <argument name="weekdays" required="true" /> + <argument name="mdays" required="true" /> + <argument name="months" required="true" /> + </parameter> + <parameter name="destination" required="true" argsep=":"> + <argument name="labeliftrue" /> + <argument name="labeliffalse" /> + </parameter> + </syntax> + <description> + <para>This application will set the context, extension, and priority in the channel structure + based on the evaluation of the given time specification. After this application completes, + the pbx engine will continue dialplan execution at the specified location in the dialplan. + If the current time is within the given time specification, the channel will continue at + <replaceable>labeliftrue</replaceable>. Otherwise the channel will continue at <replaceable>labeliffalse</replaceable>. + If the label chosen by the condition is omitted, no jump is performed, and execution passes to the next + instruction. If the target jump location is bogus, the same actions would be taken as for <literal>Goto</literal>. + Further information on the time specification can be found in examples + illustrating how to do time-based context includes in the dialplan.</para> + </description> + </application> + <application name="ImportVar" language="en_US"> + <synopsis> + Import a variable from a channel into a new variable. + </synopsis> + <syntax argsep="="> + <parameter name="newvar" required="true" /> + <parameter name="vardata" required="true"> + <argument name="channelname" required="true" /> + <argument name="variable" required="true" /> + </parameter> + </syntax> + <description> + <para>This application imports a <replaceable>variable</replaceable> from the specified + <replaceable>channel</replaceable> (as opposed to the current one) and stores it as a variable + (<replaceable>newvar</replaceable>) in the current channel (the channel that is calling this + application). Variables created by this application have the same inheritance properties as those + created with the <literal>Set</literal> application.</para> + </description> + <see-also> + <ref type="application">Set</ref> + </see-also> + </application> + <application name="Hangup" language="en_US"> + <synopsis> + Hang up the calling channel. + </synopsis> + <syntax> + <parameter name="causecode"> + <para>If a <replaceable>causecode</replaceable> is given the channel's + hangup cause will be set to the given value.</para> + </parameter> + </syntax> + <description> + <para>This application will hang up the calling channel.</para> + </description> + </application> + <application name="Incomplete" language="en_US"> + <synopsis> + Returns AST_PBX_INCOMPLETE value. + </synopsis> + <syntax> + <parameter name="n"> + <para>If specified, then Incomplete will not attempt to answer the channel first.</para> + <note><para>Most channel types need to be in Answer state in order to receive DTMF.</para></note> + </parameter> + </syntax> + <description> + <para>Signals the PBX routines that the previous matched extension is incomplete + and that further input should be allowed before matching can be considered + to be complete. Can be used within a pattern match when certain criteria warrants + a longer match.</para> + + </description> + </application> + <application name="KeepAlive" language="en_US"> + <synopsis> + Returns AST_PBX_KEEPALIVE value. + </synopsis> + <syntax /> + <description> + <para>This application is chiefly meant for internal use with Gosubs. Please do not run + it alone from the dialplan!</para> + </description> + </application> + <application name="NoOp" language="en_US"> + <synopsis> + Do Nothing (No Operation). + </synopsis> + <syntax> + <parameter name="text"> + <para>Any text provided can be viewed at the Asterisk CLI.</para> + </parameter> + </syntax> + <description> + <para>This application does nothing. However, it is useful for debugging purposes.</para> + <para>This method can be used to see the evaluations of variables or functions without having any effect.</para> + </description> + <see-also> + <ref type="application">Verbose</ref> + </see-also> + </application> + <application name="Proceeding" language="en_US"> + <synopsis> + Indicate proceeding. + </synopsis> + <syntax /> + <description> + <para>This application will request that a proceeding message be provided to the calling channel.</para> + </description> + </application> + <application name="Progress" language="en_US"> + <synopsis> + Indicate progress. + </synopsis> + <syntax /> + <description> + <para>This application will request that in-band progress information be provided to the calling channel.</para> + </description> + </application> + <application name="RaiseException" language="en_US"> + <synopsis> + Handle an exceptional condition. + </synopsis> + <syntax> + <parameter name="reason" required="true" /> + </syntax> + <description> + <para>This application will jump to the <literal>e</literal> extension in the current context, setting the + dialplan function EXCEPTION(). If the <literal>e</literal> extension does not exist, the call will hangup.</para> + </description> + </application> + <application name="ResetCDR" language="en_US"> + <synopsis> + Resets the Call Data Record. + </synopsis> + <syntax> + <parameter name="options"> + <optionlist> + <option name="w"> + <para>Store the current CDR record before resetting it.</para> + </option> + <option name="a"> + <para>Store any stacked records.</para> + </option> + <option name="v"> + <para>Save CDR variables.</para> + </option> + <option name="e"> + <para>Enable CDR only (negate effects of NoCDR).</para> + </option> + </optionlist> + </parameter> + </syntax> + <description> + <para>This application causes the Call Data Record to be reset.</para> + </description> + </application> + <application name="Ringing" language="en_US"> + <synopsis> + Indicate ringing tone. + </synopsis> + <syntax /> + <description> + <para>This application will request that the channel indicate a ringing tone to the user.</para> + </description> + </application> + <application name="SayAlpha" language="en_US"> + <synopsis> + Say Alpha. + </synopsis> + <syntax> + <parameter name="string" required="true" /> + </syntax> + <description> + <para>This application will play the sounds that correspond to the letters of the + given <replaceable>string</replaceable>.</para> + </description> + </application> + <application name="SayDigits" language="en_US"> + <synopsis> + Say Digits. + </synopsis> + <syntax> + <parameter name="digits" required="true" /> + </syntax> + <description> + <para>This application will play the sounds that correspond to the digits of + the given number. This will use the language that is currently set for the channel.</para> + </description> + </application> + <application name="SayNumber" language="en_US"> + <synopsis> + Say Number. + </synopsis> + <syntax> + <parameter name="digits" required="true" /> + <parameter name="gender" /> + </syntax> + <description> + <para>This application will play the sounds that correspond to the given <replaceable>digits</replaceable>. + Optionally, a <replaceable>gender</replaceable> may be specified. This will use the language that is currently + set for the channel. See the LANGUAGE() function for more information on setting the language for the channel.</para> + </description> + </application> + <application name="SayPhonetic" language="en_US"> + <synopsis> + Say Phonetic. + </synopsis> + <syntax> + <parameter name="string" required="true" /> + </syntax> + <description> + <para>This application will play the sounds from the phonetic alphabet that correspond to the + letters in the given <replaceable>string</replaceable>.</para> + </description> + </application> + <application name="Set" language="en_US"> + <synopsis> + Set channel variable or function value. + </synopsis> + <syntax argsep="="> + <parameter name="name" required="true" /> + <parameter name="value" required="true" /> + </syntax> + <description> + <para>This function can be used to set the value of channel variables or dialplan functions. + When setting variables, if the variable name is prefixed with <literal>_</literal>, + the variable will be inherited into channels created from the current channel. + If the variable name is prefixed with <literal>__</literal>, the variable will be + inherited into channels created from the current channel and all children channels.</para> + <note><para>If (and only if), in <filename>/etc/asterisk/asterisk.conf</filename>, you have + a <literal>[compat]</literal> category, and you have <literal>app_set = 1.6</literal> under that,then + the behavior of this app changes, and does not strip surrounding quotes from the right hand side as + it did previously in 1.4. The <literal>app_set = 1.6</literal> is only inserted if <literal>make samples</literal> + is executed, or if users insert this by hand into the <filename>asterisk.conf</filename> file. + The advantages of not stripping out quoting, and not caring about the separator characters (comma and vertical bar) + were sufficient to make these changes in 1.6. Confusion about how many backslashes would be needed to properly + protect separators and quotes in various database access strings has been greatly + reduced by these changes.</para></note> + </description> + </application> + <application name="MSet" language="en_US"> + <synopsis> + Set channel variable(s) or function value(s). + </synopsis> + <syntax> + <parameter name="set1" required="true" argsep="="> + <argument name="name1" required="true" /> + <argument name="value1" required="true" /> + </parameter> + <parameter name="set2" multiple="true" argsep="="> + <argument name="name2" required="true" /> + <argument name="value2" required="true" /> + </parameter> + </syntax> + <description> + <para>This function can be used to set the value of channel variables or dialplan functions. + When setting variables, if the variable name is prefixed with <literal>_</literal>, + the variable will be inherited into channels created from the current channel + If the variable name is prefixed with <literal>__</literal>, the variable will be + inherited into channels created from the current channel and all children channels. + MSet behaves in a similar fashion to the way Set worked in 1.2/1.4 and is thus + prone to doing things that you may not expect. For example, it strips surrounding + double-quotes from the right-hand side (value). If you need to put a separator + character (comma or vert-bar), you will need to escape them by inserting a backslash + before them. Avoid its use if possible.</para> + </description> + </application> + <application name="SetAMAFlags" language="en_US"> + <synopsis> + Set the AMA Flags. + </synopsis> + <syntax> + <parameter name="flag" /> + </syntax> + <description> + <para>This application will set the channel's AMA Flags for billing purposes.</para> + </description> + </application> + <application name="Wait" language="en_US"> + <synopsis> + Waits for some time. + </synopsis> + <syntax> + <parameter name="seconds" required="true"> + <para>Can be passed with fractions of a second. For example, <literal>1.5</literal> will ask the + application to wait for 1.5 seconds.</para> + </parameter> + </syntax> + <description> + <para>This application waits for a specified number of <replaceable>seconds</replaceable>.</para> + </description> + </application> + <application name="WaitExten" language="en_US"> + <synopsis> + Waits for an extension to be entered. + </synopsis> + <syntax> + <parameter name="seconds"> + <para>Can be passed with fractions of a second. For example, <literal>1.5</literal> will ask the + application to wait for 1.5 seconds.</para> + </parameter> + <parameter name="options"> + <optionlist> + <option name="m"> + <para>Provide music on hold to the caller while waiting for an extension.</para> + <argument name="x"> + <para>Specify the class for music on hold.</para> + </argument> + </option> + </optionlist> + </parameter> + </syntax> + <description> + <para>This application waits for the user to enter a new extension for a specified number + of <replaceable>seconds</replaceable>.</para> + </description> + <see-also> + <ref type="application">Playback</ref> + <ref type="application">Background</ref> + </see-also> + </application> + <function name="EXCEPTION" language="en_US"> + <synopsis> + Retrieve the details of the current dialplan exception. + </synopsis> + <syntax> + <parameter name="field" required="true"> + <para>The following fields are available for retrieval:</para> + <enumlist> + <enum name="reason"> + <para>INVALID, ERROR, RESPONSETIMEOUT, ABSOLUTETIMEOUT, or custom + value set by the RaiseException() application</para> + </enum> + <enum name="context"> + <para>The context executing when the exception occurred.</para> + </enum> + <enum name="exten"> + <para>The extension executing when the exception occurred.</para> + </enum> + <enum name="priority"> + <para>The numeric priority executing when the exception occurred.</para> + </enum> + </enumlist> + </parameter> + </syntax> + <description> + <para>Retrieve the details (specified <replaceable>field</replaceable>) of the current dialplan exception.</para> + </description> + </function> + ***/ + #ifdef LOW_MEMORY #define EXT_DATA_SIZE 256 #else @@ -220,12 +755,17 @@ struct ast_context { char name[0]; /*!< Name of the context */ }; - /*! \brief ast_app: A registered application */ struct ast_app { int (*execute)(struct ast_channel *chan, void *data); - const char *synopsis; /*!< Synopsis text for 'show applications' */ - const char *description; /*!< Description (help text) for 'show application <name>' */ + AST_DECLARE_STRING_FIELDS( + AST_STRING_FIELD(synopsis); /*!< Synopsis text for 'show applications' */ + AST_STRING_FIELD(description); /*!< Description (help text) for 'show application <name>' */ + AST_STRING_FIELD(syntax); /*!< Syntax text for 'core show applications' */ + AST_STRING_FIELD(arguments); /*!< Arguments description */ + AST_STRING_FIELD(seealso); /*!< See also */ + ); + enum ast_doc_src docsrc;/*!< Where the documentation come from. */ AST_RWLIST_ENTRY(ast_app) list; /*!< Next app in list */ struct ast_module *module; /*!< Module this app belongs to */ char name[0]; /*!< Name of the application */ @@ -281,6 +821,42 @@ struct pbx_exception { int priority; /*!< Priority associated with this exception */ }; +#ifdef AST_XML_DOCS +/*! \brief Default documentation language. */ +static const char default_documentation_language[] = "en_US"; + +/*! \brief Number of columns to print when showing the XML documentation with a + * 'core show application/function *' CLI command. Used in text wrapping.*/ +static const int xmldoc_text_columns = 74; + +/*! \brief This is a value that we will use to let the wrapping mechanism move the cursor + * backward and forward xmldoc_max_diff positions before cutting the middle of a + * word, trying to find a space or a \n. */ +static const int xmldoc_max_diff = 5; + +/*! \brief XML documentation language. */ +static char documentation_language[6]; + +/*! \brief XML documentation tree */ +struct documentation_tree { + char *filename; /*!< XML document filename. */ + struct ast_xml_doc *doc; /*!< Open document pointer. */ + AST_RWLIST_ENTRY(documentation_tree) entry; +}; + +/*! + * \brief Container of documentation trees + * + * \note A RWLIST is a sufficient container type to use here for now. + * However, some changes will need to be made to implement ref counting + * if reload support is added in the future. + */ +static AST_RWLIST_HEAD_STATIC(xmldoc_tree, documentation_tree); +#endif + +/*! \brief Maximum number of characters needed for a color escape sequence, plus a null char */ +#define MAX_ESCAPE_CHARS 23 + static int pbx_builtin_answer(struct ast_channel *, void *); static int pbx_builtin_goto(struct ast_channel *, void *); static int pbx_builtin_hangup(struct ast_channel *, void *); @@ -326,6 +902,9 @@ static unsigned int hashtab_hash_extens(const void *obj); static unsigned int hashtab_hash_priority(const void *obj); static unsigned int hashtab_hash_labels(const void *obj); static void __ast_internal_context_destroy( struct ast_context *con); +#ifdef AST_XML_DOCS +static char *xmldoc_colorization(const char *bwinput); +#endif /* a func for qsort to use to sort a char array */ static int compare_char(const void *a, const void *b) @@ -433,296 +1012,38 @@ static AST_RWLIST_HEAD_STATIC(acf_root, ast_custom_function); static struct pbx_builtin { char name[AST_MAX_APP]; int (*execute)(struct ast_channel *chan, void *data); - char *synopsis; - char *description; } builtins[] = { /* These applications are built into the PBX core and do not need separate modules */ - { "Answer", pbx_builtin_answer, - "Answer a channel if ringing", - " Answer([delay]): If the call has not been answered, this application will\n" - "answer it. Otherwise, it has no effect on the call. If a delay is specified,\n" - "Asterisk will wait this number of milliseconds before returning to\n" - "the dialplan after answering the call.\n" - }, - - { "BackGround", pbx_builtin_background, - "Play an audio file while waiting for digits of an extension to go to.", - " Background(filename1[&filename2...][,options[,langoverride][,context]]):\n" - "This application will play the given list of files (do not put extension)\n" - "while waiting for an extension to be dialed by the calling channel. To\n" - "continue waiting for digits after this application has finished playing\n" - "files, the WaitExten application should be used. The 'langoverride' option\n" - "explicitly specifies which language to attempt to use for the requested sound\n" - "files. If a 'context' is specified, this is the dialplan context that this\n" - "application will use when exiting to a dialed extension." - " If one of the requested sound files does not exist, call processing will be\n" - "terminated.\n" - " Options:\n" - " s - Causes the playback of the message to be skipped\n" - " if the channel is not in the 'up' state (i.e. it\n" - " hasn't been answered yet). If this happens, the\n" - " application will return immediately.\n" - " n - Don't answer the channel before playing the files.\n" - " m - Only break if a digit hit matches a one digit\n" - " extension in the destination context.\n" - "This application sets the following channel variable upon completion:\n" - " BACKGROUNDSTATUS The status of the background attempt as a text string, one of\n" - " SUCCESS | FAILED\n" - "See Also: Playback (application) -- Play sound file(s) to the channel,\n" - " that cannot be interrupted\n" - }, - - { "Busy", pbx_builtin_busy, - "Indicate the Busy condition", - " Busy([timeout]): This application will indicate the busy condition to\n" - "the calling channel. If the optional timeout is specified, the calling channel\n" - "will be hung up after the specified number of seconds. Otherwise, this\n" - "application will wait until the calling channel hangs up.\n" - }, - - { "Congestion", pbx_builtin_congestion, - "Indicate the Congestion condition", - " Congestion([timeout]): This application will indicate the congestion\n" - "condition to the calling channel. If the optional timeout is specified, the\n" - "calling channel will be hung up after the specified number of seconds.\n" - "Otherwise, this application will wait until the calling channel hangs up.\n" - }, - - { "ExecIfTime", pbx_builtin_execiftime, - "Conditional application execution based on the current time", - " ExecIfTime(<times>,<weekdays>,<mdays>,<months>?appname[(appargs)]):\n" - "This application will execute the specified dialplan application, with optional\n" - "arguments, if the current time matches the given time specification.\n" - }, - - { "Goto", pbx_builtin_goto, - "Jump to a particular priority, extension, or context", - " Goto([[context,]extension,]priority): This application will set the current\n" - "context, extension, and priority in the channel structure. After it completes, the\n" - "pbx engine will continue dialplan execution at the specified location.\n" - "If no specific extension, or extension and context, are specified, then this\n" - "application will just set the specified priority of the current extension.\n" - " At least a priority is required as an argument, or the goto will return a -1,\n" - "and the channel and call will be terminated.\n" - " If the location that is put into the channel information is bogus, and asterisk cannot\n" - "find that location in the dialplan,\n" - "then the execution engine will try to find and execute the code in the 'i' (invalid)\n" - "extension in the current context. If that does not exist, it will try to execute the\n" - "'h' extension. If either or neither the 'h' or 'i' extensions have been defined, the\n" - "channel is hung up, and the execution of instructions on the channel is terminated.\n" - "What this means is that, for example, you specify a context that does not exist, then\n" - "it will not be possible to find the 'h' or 'i' extensions, and the call will terminate!\n" - }, - - { "GotoIf", pbx_builtin_gotoif, - "Conditional goto", - " GotoIf(condition?[labeliftrue]:[labeliffalse]): This application will set the current\n" - "context, extension, and priority in the channel structure based on the evaluation of\n" - "the given condition. After this application completes, the\n" - "pbx engine will continue dialplan execution at the specified location in the dialplan.\n" - "The channel will continue at\n" - "'labeliftrue' if the condition is true, or 'labeliffalse' if the condition is\n" - "false. The labels are specified with the same syntax as used within the Goto\n" - "application. If the label chosen by the condition is omitted, no jump is\n" - "performed, and the execution passes to the next instruction.\n" - "If the target location is bogus, and does not exist, the execution engine will try \n" - "to find and execute the code in the 'i' (invalid)\n" - "extension in the current context. If that does not exist, it will try to execute the\n" - "'h' extension. If either or neither the 'h' or 'i' extensions have been defined, the\n" - "channel is hung up, and the execution of instructions on the channel is terminated.\n" - "Remember that this command can set the current context, and if the context specified\n" - "does not exist, then it will not be able to find any 'h' or 'i' extensions there, and\n" - "the channel and call will both be terminated!\n" - }, - - { "GotoIfTime", pbx_builtin_gotoiftime, - "Conditional Goto based on the current time", - " GotoIfTime(<times>,<weekdays>,<mdays>,<months>?[labeliftrue]:[labeliffalse]):\n" - "This application will set the context, extension, and priority in the channel structure\n" - "based on the evaluation of the given time specification. After this application completes,\n" - "the pbx engine will continue dialplan execution at the specified location in the dialplan.\n" - "If the current time is within the given time specification, the channel will continue at\n" - "'labeliftrue'. Otherwise the channel will continue at 'labeliffalse'. If the label chosen\n" - "by the condition is omitted, no jump is performed, and execution passes to the next\n" - "instruction. If the target jump location is bogus, the same actions would be taken as for\n" - "Goto.\n" - "Further information on the time specification can be found in examples\n" - "illustrating how to do time-based context includes in the dialplan.\n" - }, - - { "ImportVar", pbx_builtin_importvar, - "Import a variable from a channel into a new variable", - " ImportVar(newvar=channelname,variable): This application imports a variable\n" - "from the specified channel (as opposed to the current one) and stores it as\n" - "a variable in the current channel (the channel that is calling this\n" - "application). Variables created by this application have the same inheritance\n" - "properties as those created with the Set application. See the documentation for\n" - "Set for more information.\n" - }, - - { "Hangup", pbx_builtin_hangup, - "Hang up the calling channel", - " Hangup([causecode]): This application will hang up the calling channel.\n" - "If a causecode is given the channel's hangup cause will be set to the given\n" - "value.\n" - }, - - { "Incomplete", pbx_builtin_incomplete, - "returns AST_PBX_INCOMPLETE value", - " Incomplete([n]): Signals the PBX routines that the previous matched extension\n" - "is incomplete and that further input should be allowed before matching can\n" - "be considered to be complete. Can be used within a pattern match when\n" - "certain criteria warrants a longer match.\n" - " If the 'n' option is specified, then Incomplete will not attempt to answer\n" - "the channel first. Note that most channel types need to be in Answer state\n" - "in order to receive DTMF.\n" - }, - - { "KeepAlive", pbx_builtin_keepalive, - "returns AST_PBX_KEEPALIVE value", - " KeepAlive(): This application is chiefly meant for internal use with Gosubs.\n" - "Please do not run it alone from the dialplan!\n" - }, - - { "NoOp", pbx_builtin_noop, - "Do Nothing (No Operation)", - " NoOp(): This application does nothing. However, it is useful for debugging\n" - "purposes. Any text that is provided as arguments to this application can be\n" - "viewed at the Asterisk CLI. This method can be used to see the evaluations of\n" - "variables or functions without having any effect. Alternatively, see the\n" - "Verbose() application for finer grain control of output at custom verbose levels.\n" - }, - - { "Proceeding", pbx_builtin_proceeding, - "Indicate proceeding", - " Proceeding(): This application will request that a proceeding message\n" - "be provided to the calling channel.\n" - }, - - { "Progress", pbx_builtin_progress, - "Indicate progress", - " Progress(): This application will request that in-band progress information\n" - "be provided to the calling channel.\n" - }, - - { "RaiseException", pbx_builtin_raise_exception, - "Handle an exceptional condition", - " RaiseException(<reason>): This application will jump to the \"e\" extension\n" - "in the current context, setting the dialplan function EXCEPTION(). If the \"e\"\n" - "extension does not exist, the call will hangup.\n" - }, - - { "ResetCDR", pbx_builtin_resetcdr, - "Resets the Call Data Record", - " ResetCDR([options]): This application causes the Call Data Record to be\n" - "reset.\n" - " Options:\n" - " w -- Store the current CDR record before resetting it.\n" - " a -- Store any stacked records.\n" - " v -- Save CDR variables.\n" - " e -- Enable CDR only (negate effects of NoCDR).\n" - }, - - { "Ringing", pbx_builtin_ringing, - "Indicate ringing tone", - " Ringing(): This application will request that the channel indicate a ringing\n" - "tone to the user.\n" - }, - - { "SayAlpha", pbx_builtin_saycharacters, - "Say Alpha", - " SayAlpha(string): This application will play the sounds that correspond to\n" - "the letters of the given string.\n" - }, - - { "SayDigits", pbx_builtin_saydigits, - "Say Digits", - " SayDigits(digits): This application will play the sounds that correspond\n" - "to the digits of the given number. This will use the language that is currently\n" - "set for the channel. See the LANGUAGE function for more information on setting\n" - "the language for the channel.\n" - }, - - { "SayNumber", pbx_builtin_saynumber, - "Say Number", - " SayNumber(digits[,gender]): This application will play the sounds that\n" - "correspond to the given number. Optionally, a gender may be specified.\n" - "This will use the language that is currently set for the channel. See the\n" - "LANGUAGE function for more information on setting the language for the channel.\n" - }, - - { "SayPhonetic", pbx_builtin_sayphonetic, - "Say Phonetic", - " SayPhonetic(string): This application will play the sounds from the phonetic\n" - "alphabet that correspond to the letters in the given string.\n" - }, - - { "Set", pbx_builtin_setvar, - "Set channel variable or function value", - " Set(name=value)\n" - "This function can be used to set the value of channel variables or dialplan\n" - "functions. When setting variables, if the variable name is prefixed with _,\n" - "the variable will be inherited into channels created from the current\n" - "channel. If the variable name is prefixed with __, the variable will be\n" - "inherited into channels created from the current channel and all children\n" - "channels.\n" - "Compatibility note: If (and only if), in /etc/asterisk/asterisk.conf, you have a [compat]\n" - "category, and you have app_set = 1.6 under that, then the behavior of this\n" - "app changes, and does not strip surrounding quotes from the right hand side\n" - "as it did previously in 1.4. The app_set = 1.6 is only inserted if 'make samples'\n" - "is executed, or if users insert this by hand into the asterisk.conf file.\n" - "/nThe advantages of not stripping out quoting, and not caring about the\n" - "separator characters (comma and vertical bar) were sufficient to make these\n" - "changes in 1.6. Confusion about how many backslashes would be needed to properly\n" - "protect separators and quotes in various database access strings has been greatly\n" - "reduced by these changes.\n" - }, - - { "MSet", pbx_builtin_setvar_multiple, - "Set channel variable(s) or function value(s)", - " MSet(name1=value1,name2=value2,...)\n" - "This function can be used to set the value of channel variables or dialplan\n" - "functions. When setting variables, if the variable name is prefixed with _,\n" - "the variable will be inherited into channels created from the current\n" - "channel. If the variable name is prefixed with __, the variable will be\n" - "inherited into channels created from the current channel and all children\n" - "channels.\n\n" - "MSet behaves in a similar fashion to the way Set worked in 1.2/1.4 and is thus\n" - "prone to doing things that you may not expect. For example, it strips surrounding\n" - "double-quotes from the right-hand side (value). If you need to put a separator\n" - "character (comma or vert-bar), you will need to escape them by inserting a backslash\n" - "before them. Avoid its use if possible.\n" - }, - - { "SetAMAFlags", pbx_builtin_setamaflags, - "Set the AMA Flags", - " SetAMAFlags([flag]): This application will set the channel's AMA Flags for\n" - " billing purposes.\n" - }, - - { "Wait", pbx_builtin_wait, - "Waits for some time", - " Wait(seconds): This application waits for a specified number of seconds.\n" - "Then, dialplan execution will continue at the next priority.\n" - " Note that the seconds can be passed with fractions of a second. For example,\n" - "'1.5' will ask the application to wait for 1.5 seconds.\n" - }, - - { "WaitExten", pbx_builtin_waitexten, - "Waits for an extension to be entered", - " WaitExten([seconds][,options]): This application waits for the user to enter\n" - "a new extension for a specified number of seconds.\n" - " Note that the seconds can be passed with fractions of a second. For example,\n" - "'1.5' will ask the application to wait for 1.5 seconds.\n" - " Options:\n" - " m[(x)] - Provide music on hold to the caller while waiting for an extension.\n" - " Optionally, specify the class for music on hold within parenthesis.\n" - "See Also: Playback(application), Background(application).\n" - }, - + { "Answer", pbx_builtin_answer }, + { "BackGround", pbx_builtin_background }, + { "Busy", pbx_builtin_busy }, + { "Congestion", pbx_builtin_congestion }, + { "ExecIfTime", pbx_builtin_execiftime }, + { "Goto", pbx_builtin_goto }, + { "GotoIf", pbx_builtin_gotoif }, + { "GotoIfTime", pbx_builtin_gotoiftime }, + { "ImportVar", pbx_builtin_importvar }, + { "Hangup", pbx_builtin_hangup }, + { "Incomplete", pbx_builtin_incomplete }, + { "KeepAlive", pbx_builtin_keepalive }, + { "NoOp", pbx_builtin_noop }, + { "Proceeding", pbx_builtin_proceeding }, + { "Progress", pbx_builtin_progress }, + { "RaiseException", pbx_builtin_raise_exception }, + { "ResetCDR", pbx_builtin_resetcdr }, + { "Ringing", pbx_builtin_ringing }, + { "SayAlpha", pbx_builtin_saycharacters }, + { "SayDigits", pbx_builtin_saydigits }, + { "SayNumber", pbx_builtin_saynumber }, + { "SayPhonetic", pbx_builtin_sayphonetic }, + { "Set", pbx_builtin_setvar }, + { "MSet", pbx_builtin_setvar_multiple }, + { "SetAMAFlags", pbx_builtin_setamaflags }, + { "Wait", pbx_builtin_wait }, + { "WaitExten", pbx_builtin_waitexten } }; static struct ast_context *contexts; @@ -2618,15 +2939,6 @@ static int acf_exception_read(struct ast_channel *chan, const char *name, char * static struct ast_custom_function exception_function = { .name = "EXCEPTION", - .synopsis = "Retrieve the details of the current dialplan exception", - .desc = -"The following fields are available for retrieval:\n" -" reason INVALID, ERROR, RESPONSETIMEOUT, ABSOLUTETIMEOUT, or custom\n" -" value set by the RaiseException() application\n" -" context The context executing when the exception occurred\n" -" exten The extension executing when the exception occurred\n" -" priority The numeric priority executing when the exception occurred\n", - .syntax = "EXCEPTION(<field>)", .read = acf_exception_read, }; @@ -2673,10 +2985,10 @@ static char *handle_show_function(struct ast_cli_entry *e, int cmd, struct ast_c { struct ast_custom_function *acf; /* Maximum number of characters added by terminal coloring is 22 */ - char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40]; - char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL; - char stxtitle[40], *syntax = NULL; - int synopsis_size, description_size, syntax_size; + char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40], argtitle[40], seealsotitle[40]; + char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL, *seealso = NULL; + char stxtitle[40], *syntax = NULL, *arguments = NULL; + int syntax_size, description_size, synopsis_size, arguments_size, seealso_size; char *ret = NULL; int which = 0; int wordlen; @@ -2703,49 +3015,75 @@ static char *handle_show_function(struct ast_cli_entry *e, int cmd, struct ast_c return ret; } - if (a->argc < 4) + if (a->argc < 4) { return CLI_SHOWUSAGE; + } if (!(acf = ast_custom_function_find(a->argv[3]))) { ast_cli(a->fd, "No function by that name registered.\n"); return CLI_FAILURE; + } + syntax_size = strlen(S_OR(acf->syntax, "Not Available")) + MAX_ESCAPE_CHARS; + if (!(syntax = ast_malloc(syntax_size))) { + ast_cli(a->fd, "Memory allocation failure!\n"); + return CLI_FAILURE; } - if (acf->synopsis) - synopsis_size = strlen(acf->synopsis) + 23; - else - synopsis_size = strlen("Not available") + 23; - synopsis = alloca(synopsis_size); + snprintf(info, sizeof(info), "\n -= Info about function '%s' =- \n\n", acf->name); + term_color(infotitle, info, COLOR_MAGENTA, 0, sizeof(infotitle)); + term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40); + term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40); + term_color(stxtitle, "[Syntax]\n", COLOR_MAGENTA, 0, 40); + term_color(argtitle, "[Arguments]\n", COLOR_MAGENTA, 0, 40); + term_color(seealsotitle, "[See Also]\n", COLOR_MAGENTA, 0, 40); + term_color(syntax, S_OR(acf->syntax, "Not available"), COLOR_CYAN, 0, syntax_size); +#ifdef AST_XML_DOCS + if (acf->docsrc == AST_XML_DOC) { + arguments = xmldoc_colorization(S_OR(acf->arguments, "Not available")); + synopsis = xmldoc_colorization(S_OR(acf->synopsis, "Not available")); + description = xmldoc_colorization(S_OR(acf->desc, "Not available")); + seealso = xmldoc_colorization(S_OR(acf->seealso, "Not available")); + } else +#endif + { + synopsis_size = strlen(S_OR(acf->synopsis, "Not Available")) + MAX_ESCAPE_CHARS; + synopsis = ast_malloc(synopsis_size); - if (acf->desc) - description_size = strlen(acf->desc) + 23; - else - description_size = strlen("Not available") + 23; - description = alloca(description_size); + description_size = strlen(S_OR(acf->desc, "Not Available")) + MAX_ESCAPE_CHARS; + description = ast_malloc(description_size); - if (acf->syntax) - syntax_size = strlen(acf->syntax) + 23; - else - syntax_size = strlen("Not available") + 23; - syntax = alloca(syntax_size); + arguments_size = strlen(S_OR(acf->arguments, "Not Available")) + MAX_ESCAPE_CHARS; + arguments = ast_malloc(arguments_size); - snprintf(info, 64 + AST_MAX_APP, "\n -= Info about function '%s' =- \n\n", acf->name); - term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22); - term_color(stxtitle, "[Syntax]\n", COLOR_MAGENTA, 0, 40); - term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40); - term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40); - term_color(syntax, - acf->syntax ? acf->syntax : "Not available", - COLOR_CYAN, 0, syntax_size); - term_color(synopsis, - acf->synopsis ? acf->synopsis : "Not available", - COLOR_CYAN, 0, synopsis_size); - term_color(description, - acf->desc ? acf->desc : "Not available", - COLOR_CYAN, 0, description_size); - - ast_cli(a->fd,"%s%s%s\n\n%s%s\n\n%s%s\n", infotitle, stxtitle, syntax, syntitle, synopsis, destitle, description); + seealso_size = strlen(S_OR(acf->seealso, "Not Available")) + MAX_ESCAPE_CHARS; + seealso = ast_malloc(seealso_size); + + /* check allocated memory. */ + if (!synopsis || !description || !arguments || !seealso) { + ast_free(synopsis); + ast_free(description); + ast_free(arguments); + ast_free(seealso); + ast_free(syntax); + return CLI_FAILURE; + } + + term_color(arguments, S_OR(acf->arguments, "Not available"), COLOR_CYAN, 0, arguments_size); + term_color(synopsis, S_OR(acf->synopsis, "Not available"), COLOR_CYAN, 0, synopsis_size); + term_color(description, S_OR(acf->desc, "Not available"), COLOR_CYAN, 0, description_size); + term_color(seealso, S_OR(acf->seealso, "Not available"), COLOR_CYAN, 0, seealso_size); + } + + ast_cli(a->fd,"%s%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n", + infotitle, syntitle, synopsis, destitle, description, + stxtitle, syntax, argtitle, arguments, seealsotitle, seealso); + + ast_free(arguments); + ast_free(synopsis); + ast_free(description); + ast_free(seealso); + ast_free(syntax); return CLI_SUCCESS; } @@ -2772,22 +3110,1533 @@ int ast_custom_function_unregister(struct ast_custom_function *acf) return -1; AST_RWLIST_WRLOCK(&acf_root); - if ((cur = AST_RWLIST_REMOVE(&acf_root, acf, acflist))) + if ((cur = AST_RWLIST_REMOVE(&acf_root, acf, acflist))) { + if (cur->docsrc == AST_XML_DOC) { + ast_string_field_free_memory(acf); + } ast_verb(2, "Unregistered custom function %s\n", cur->name); + } AST_RWLIST_UNLOCK(&acf_root); return cur ? 0 : -1; } +#ifdef AST_XML_DOCS +static const struct strcolorized_tags { + const char *init; /*!< Replace initial tag with this string. */ + const char *end; /*!< Replace end tag with this string. */ + const int colorfg; /*!< Foreground color. */ + const char *inittag; /*!< Initial tag description. */ + const char *endtag; /*!< Ending tag description. */ +} colorized_tags[] = { + { "<", ">", COLOR_GREEN, "<replaceable>", "</replaceable>" }, + { "\'", "\'", COLOR_BLUE, "<literal>", "</literal>" }, + { "*", "*", COLOR_RED, "<emphasis>", "</emphasis>" }, + { "\"", "\"", COLOR_YELLOW, "<filename>", "</filename>" }, + { "\"", "\"", COLOR_CYAN, "<directory>", "</directory>" }, + { "${", "}", COLOR_GREEN, "<variable>", "</variable>" }, + { "", "", COLOR_BLUE, "<value>", "</value>" }, + { "", "", COLOR_BLUE, "<enum>", "</enum>" }, + { "\'", "\'", COLOR_GRAY, "<astcli>", "</astcli>" }, + + /* Special tags */ + { "", "", COLOR_YELLOW, "<note>", "</note>" }, + { "", "", COLOR_RED, "<warning>", "</warning>" } +}; + +static const struct strspecial_tags { + const char *tagname; /*!< Special tag name. */ + const char *init; /*!< Print this at the beginning. */ + const char *end; /*!< Print this at the end. */ +} special_tags[] = { + { "note", "<note>NOTE:</note> ", "" }, + { "warning", "<warning>WARNING!!!:</warning> ", "" } +}; + +/*! \internal + * \brief Calculate the space in bytes used by a format string + * that will be passed to a sprintf function. + * \param postbr The format string to use to calculate the length. + * \retval The postbr length. + */ +static int xmldoc_postbrlen(const char *postbr) +{ + int postbrreallen = 0, i; + size_t postbrlen; + + if (!postbr) { + return 0; + } + postbrlen = strlen(postbr); + for (i = 0; i < postbrlen; i++) { + if (postbr[i] == '\t') { + postbrreallen += 8 - (postbrreallen % 8); + } else { + postbrreallen++; + } + } + return postbrreallen; +} + +/*! \internal + * \brief Setup postbr to be used while wrapping the text. + * Add to postbr array all the spaces and tabs at the beginning of text. + * \param postbr output array. + * \param len text array length. + * \param text Text with format string before the actual string. + */ +static void xmldoc_setpostbr(char *postbr, size_t len, const char *text) +{ + int c, postbrlen = 0; + + if (!text) { + return; + } + + for (c = 0; c < len; c++) { + if (text[c] == '\t' || text[c] == ' ') { + postbr[postbrlen++] = text[c]; + } else { + break; + } + } + postbr[postbrlen] = '\0'; +} + +/*! \internal + * \brief Try to find a space or a break in text starting at currentpost + * and moving at most maxdiff positions. + * Helper for xmldoc_string_wrap(). + * \param text Input string where it will search. + * \param currentpos Current position within text. + * \param maxdiff Not move more than maxdiff inside text. + * \retval 1 if a space or break is found inside text while moving. + * \retval 0 if no space or break is found. + */ +static int xmldoc_wait_nextspace(const char *text, int currentpos, int maxdiff) +{ + int i, textlen; + + if (!text) { + return 0; + } + + textlen = strlen(text); + for (i = currentpos; i < textlen; i++) { + if (text[i] == ESC) { + /* Move to the end of the escape sequence */ + while (i < textlen && text[i] != 'm') { + i++; + } + } else if (text[i] == ' ' || text[i] == '\n') { + /* Found the next space or linefeed */ + return 1; + } else if (i - currentpos > maxdiff) { + /* We have looked the max distance and didn't find it */ + return 0; + } + } + + /* Reached the end and did not find it */ + + return 0; +} + +/*! \internal + * \brief Helper function for xmldoc_string_wrap(). + * Try to found a space or a break inside text moving backward + * not more than maxdiff positions. + * \param text The input string where to search for a space. + * \param currentpos The current cursor position. + * \param maxdiff The max number of positions to move within text. + * \retval 0 If no space is found (Notice that text[currentpos] is not a space or a break) + * \retval > 0 If a space or a break is found, and the result is the position relative to + * currentpos. + */ +static int xmldoc_foundspace_backward(const char *text, int currentpos, int maxdiff) +{ + int i; + + for (i = currentpos; i > 0; i--) { + if (text[i] == ' ' || text[i] == '\n') { + return (currentpos - i); + } else if (text[i] == 'm' && (text[i - 1] >= '0' || text[i - 1] <= '9')) { + /* give up, we found the end of a possible ESC sequence. */ + return 0; + } else if (currentpos - i > maxdiff) { + /* give up, we can't move anymore. */ + return 0; + } + } + + /* we found the beginning of the text */ + + return 0; +} + +/*! \internal + * \brief Justify a text to a number of columns. + * \param text Input text to be justified. + * \param columns Number of columns to preserve in the text. + * \param maxdiff Try to not cut a word when goinf down. + * \retval NULL on error. + * \retval The wrapped text. + */ +static char *xmldoc_string_wrap(const char *text, int columns, int maxdiff) +{ + struct ast_str *tmp; + char *ret, postbr[160]; + int count = 1, i, backspace, needtobreak = 0, colmax, textlen; + + /* sanity check */ + if (!text || columns <= 0 || maxdiff < 0) { + ast_log(LOG_WARNING, "Passing wrong arguments while trying to wrap the text\n"); + return NULL; + } + + tmp = ast_str_create(strlen(text) * 3); + + if (!tmp) { + return NULL; + } + + /* Check for blanks and tabs and put them in postbr. */ + xmldoc_setpostbr(postbr, sizeof(postbr), text); + colmax = columns - xmldoc_postbrlen(postbr); + + textlen = strlen(text); + for (i = 0; i < textlen; i++) { + if (needtobreak || !(count % colmax)) { + if (text[i] == ' ') { + ast_str_append(&tmp, 0, "\n%s", postbr); + needtobreak = 0; + count = 1; + } else if (text[i] != '\n') { + needtobreak = 1; + if (xmldoc_wait_nextspace(text, i, maxdiff)) { + /* wait for the next space */ + ast_str_append(&tmp, 0, "%c", text[i]); + continue; + } + /* Try to look backwards */ + backspace = xmldoc_foundspace_backward(text, i, maxdiff); + if (backspace) { + needtobreak = 1; + tmp->used -= backspace; + tmp->str[tmp->used] = '\0'; + i -= backspace + 1; + continue; + } + ast_str_append(&tmp, 0, "\n%s", postbr); + needtobreak = 0; + count = 1; + } + /* skip blanks after a \n */ + while (text[i] == ' ') { + i++; + } + } + if (text[i] == '\n') { + xmldoc_setpostbr(postbr, sizeof(postbr), &text[i] + 1); + colmax = columns - xmldoc_postbrlen(postbr); + needtobreak = 0; + count = 1; + } + if (text[i] == ESC) { + /* Ignore Escape sequences. */ + do { + ast_str_append(&tmp, 0, "%c", text[i]); + i++; + } while (i < textlen && text[i] != 'm'); + } else { + count++; + } + ast_str_append(&tmp, 0, "%c", text[i]); + } + + ret = ast_strdup(tmp->str); + ast_free(tmp); + + return ret; +} + +/*! \internal + * \brief Colorize the xmldoc output. + * \param bwinput Not colorized input. + * \retval NULL on error. + * \retval New malloced buffer colorized. + */ +static char *xmldoc_colorization(const char *bwinput) +{ + struct ast_str *colorized; + char *wrapped = NULL; + int i, c, len, colorsection; + char *tmp; + size_t bwinputlen; + static const int base_fg = COLOR_CYAN; + + if (!bwinput) { + return NULL; + } + + bwinputlen = strlen(bwinput); + + if (!(colorized = ast_str_create(256))) { + return NULL; + } + + ast_term_color_code(&colorized, base_fg, 0); + if (!colorized) { + return NULL; + } + + for (i = 0; i < bwinputlen; i++) { + colorsection = 0; + /* Check if we are at the beginning of a tag to be colorized. */ + for (c = 0; c < ARRAY_LEN(colorized_tags); c++) { + if (strncasecmp(bwinput + i, colorized_tags[c].inittag, strlen(colorized_tags[c].inittag))) { + continue; + } + + if (!(tmp = strcasestr(bwinput + i + strlen(colorized_tags[c].inittag), colorized_tags[c].endtag))) { + continue; + } + + len = tmp - (bwinput + i + strlen(colorized_tags[c].inittag)); + + /* Setup color */ + ast_term_color_code(&colorized, colorized_tags[c].colorfg, 0); + if (!colorized) { + return NULL; + } + + /* copy initial string replace */ + ast_str_append(&colorized, 0, "%s", colorized_tags[c].init); + if (!colorized) { + return NULL; + } + { + char buf[len + 1]; + ast_copy_string(buf, bwinput + i + strlen(colorized_tags[c].inittag), sizeof(buf)); + ast_str_append(&colorized, 0, "%s", buf); + } + if (!colorized) { + return NULL; + } + + /* copy the ending string replace */ + ast_str_append(&colorized, 0, "%s", colorized_tags[c].end); + if (!colorized) { + return NULL; + } + + /* Continue with the last color. */ + ast_term_color_code(&colorized, base_fg, 0); + if (!colorized) { + return NULL; + } + + i += len + strlen(colorized_tags[c].endtag) + strlen(colorized_tags[c].inittag) - 1; + colorsection = 1; + break; + } + + if (!colorsection) { + ast_str_append(&colorized, 0, "%c", bwinput[i]); + if (!colorized) { + return NULL; + } + } + } + + ast_term_color_code(&colorized, COLOR_BRWHITE, 0); + if (!colorized) { + return NULL; + } + + /* Wrap the text, notice that string wrap will avoid cutting an ESC sequence. */ + wrapped = xmldoc_string_wrap(colorized->str, xmldoc_text_columns, xmldoc_max_diff); + + ast_free(colorized); + + return wrapped; +} + +/*! \internal + * \brief Cleanup spaces and tabs after a \n + * \param text String to be cleaned up. + * \param output buffer (not already allocated). + * \param lastspaces Remove last spaces in the string. + */ +static void xmldoc_string_cleanup(const char *text, struct ast_str **output, int lastspaces) +{ + int i; + size_t textlen; + + if (!text) { + *output = NULL; + return; + } + + textlen = strlen(text); + + *output = ast_str_create(textlen); + if (!(*output)) { + ast_log(LOG_ERROR, "Problem allocating output buffer\n"); + return; + } + + for (i = 0; i < textlen; i++) { + if (text[i] == '\n' || text[i] == '\r') { + /* remove spaces/tabs/\n after a \n. */ + while (text[i + 1] == '\t' || text[i + 1] == '\r' || text[i + 1] == '\n') { + i++; + } + ast_str_append(output, 0, " "); + continue; + } else { + ast_str_append(output, 0, "%c", text[i]); + } + } + + /* remove last spaces (we dont want always to remove the trailing spaces). */ + if (lastspaces) { + ast_str_trim_blanks(*output); + } +} + +/*! \internal + * \brief Get the application/function node for 'name' application/function with language 'language' + * if we don't find any, get the first application with 'name' no matter which language with. + * \param type 'application', 'function', ... + * \param name Application or Function name. + * \param language Try to get this language (if not found try with en_US) + * \retval NULL on error. + * \retval A node of type ast_xml_node. + */ +static struct ast_xml_node *xmldoc_get_node(const char *type, const char *name, const char *language) +{ + struct ast_xml_node *node = NULL; + struct documentation_tree *doctree; + const char *lang; + + AST_RWLIST_RDLOCK(&xmldoc_tree); + AST_LIST_TRAVERSE(&xmldoc_tree, doctree, entry) { + /* the core xml documents have priority over thirdparty document. */ + node = ast_xml_get_root(doctree->doc); + while ((node = ast_xml_find_element(node, type, "name", name))) { + /* Check language */ + lang = ast_xml_get_attribute(node, "language"); + if (lang && !strcmp(lang, language)) { + ast_xml_free_attr(lang); + break; + } else if (lang) { + ast_xml_free_attr(lang); + } + } + + if (node && ast_xml_node_get_children(node)) { + break; + } + + /* We didn't find the application documentation for the specified language, + so, try to load documentation for any language */ + node = ast_xml_get_root(doctree->doc); + if (ast_xml_node_get_children(node)) { + if ((node = ast_xml_find_element(ast_xml_node_get_children(node), type, "name", name))) { + break; + } + } + } + AST_RWLIST_UNLOCK(&xmldoc_tree); + + return node; +} + +/*! \internal + * \brief Helper function used to build the syntax, it allocates the needed buffer (or reallocates it), + * and based on the reverse value it makes use of fmt to print the parameter list inside the + * realloced buffer (syntax). + * \param reverse We are going backwards while generating the syntax? + * \param len Current length of 'syntax' buffer. + * \param syntax Output buffer for the concatenated values. + * \param fmt A format string that will be used in a sprintf call. + */ +static __attribute__((format(printf,4,5))) void xmldoc_reverse_helper(int reverse, int *len, char **syntax, const char *fmt, ...) +{ + int totlen, tmpfmtlen; + char *tmpfmt, tmp; + va_list ap; + + va_start(ap, fmt); + if (ast_vasprintf(&tmpfmt, fmt, ap) < 0) { + va_end(ap); + return; + } + va_end(ap); + + tmpfmtlen = strlen(tmpfmt); + totlen = *len + tmpfmtlen + 1; + + *syntax = ast_realloc(*syntax, totlen); + + if (!*syntax) { + ast_free(tmpfmt); + return; + } + + if (reverse) { + memmove(*syntax + tmpfmtlen, *syntax, *len); + /* Save this char, it will be overwritten by the \0 of strcpy. */ + tmp = (*syntax)[0]; + strcpy(*syntax, tmpfmt); + /* Restore the already saved char. */ + (*syntax)[tmpfmtlen] = tmp; + (*syntax)[totlen - 1] = '\0'; + } else { + strcpy(*syntax + *len, tmpfmt); + } + + *len = totlen - 1; + ast_free(tmpfmt); +} + +/*! \internal + * \brief Check if the passed node has <argument> tags inside it. + * \param node Root node to search argument elements. + * \retval 1 If a <argument> element is found inside 'node'. + * \retval 0 If no <argument> is found inside 'node'. + */ +static int xmldoc_has_arguments(struct ast_xml_node *fixnode) +{ + struct ast_xml_node *node = fixnode; + + for (node = ast_xml_node_get_children(fixnode); node; node = ast_xml_node_get_next(node)) { + if (!strcasecmp(ast_xml_node_get_name(node), "argument")) { + return 1; + } + } + return 0; +} + +/*! \internal + * \brief Build the syntax for a specified starting node. + * \param rootnode A pointer to the ast_xml root node. + * \param rootname Name of the application, function, option, etc. to build the syntax. + * \param childname The name of each parameter node. + * \param printparenthesis Boolean if we must print parenthesis if not parameters are found in the rootnode. + * \param printrootname Boolean if we must print the rootname before the syntax and parenthesis at the begining/end. + * \retval NULL on error. + * \retval An ast_malloc'ed string with the syntax generated. + */ +static char *xmldoc_get_syntax(struct ast_xml_node *rootnode, const char *rootname, const char *childname, int printparenthesis, int printrootname) +{ +#define GOTONEXT(__rev, __a) (__rev ? ast_xml_node_get_prev(__a) : ast_xml_node_get_next(__a)) +#define ISLAST(__rev, __a) (__rev == 1 ? (ast_xml_node_get_prev(__a) ? 0 : 1) : (ast_xml_node_get_next(__a) ? 0 : 1)) +#define MP(__a) ((multiple ? __a : "")) + struct ast_xml_node *node = NULL, *firstparam = NULL, *lastparam = NULL; + const char *paramtype, *multipletype, *paramname, *attrargsep, *parenthesis, *argname; + int reverse, required, paramcount = 0, openbrackets = 0, len = 0, hasparams=0; + int reqfinode = 0, reqlanode = 0, optmidnode = 0, prnparenthesis; + char *syntax = NULL, *argsep; + int paramnamemalloc, multiple; + + if (ast_strlen_zero(rootname) || ast_strlen_zero(childname)) { + ast_log(LOG_WARNING, "Tried to look in XML tree with faulty rootname or childname while creating a syntax.\n"); + return NULL; + } + + if (!rootnode || !ast_xml_node_get_children(rootnode)) { + /* If the rootnode field is not found, at least print name. */ + ast_asprintf(&syntax, "%s%s", (printrootname ? rootname : ""), (printparenthesis ? "()" : "")); + return syntax; + } + + /* Get the argument separator from the root node attribute name 'argsep', if not found + defaults to ','. */ + attrargsep = ast_xml_get_attribute(rootnode, "argsep"); + if (attrargsep) { + argsep = ast_strdupa(attrargsep); + ast_xml_free_attr(attrargsep); + } else { + argsep = ast_strdupa(","); + } + + /* Get order of evaluation. */ + for (node = ast_xml_node_get_children(rootnode); node; node = ast_xml_node_get_next(node)) { + if (strcasecmp(ast_xml_node_get_name(node), childname)) { + continue; + } + required = 0; + hasparams = 1; + if ((paramtype = ast_xml_get_attribute(node, "required"))) { + if (ast_true(paramtype)) { + required = 1; + } + ast_xml_free_attr(paramtype); + } + + lastparam = node; + reqlanode = required; + + if (!firstparam) { + /* first parameter node */ + firstparam = node; + reqfinode = required; + } + } + + if (!hasparams) { + /* This application, function, option, etc, doesn't have any params. */ + ast_asprintf(&syntax, "%s%s", (printrootname ? rootname : ""), (printparenthesis ? "()" : "")); + return syntax; + } + + if (reqfinode && reqlanode) { + /* check midnode */ + for (node = ast_xml_node_get_children(rootnode); node; node = ast_xml_node_get_next(node)) { + if (strcasecmp(ast_xml_node_get_name(node), childname)) { + continue; + } + if (node != firstparam && node != lastparam) { + if ((paramtype = ast_xml_get_attribute(node, "required"))) { + if (!ast_true(paramtype)) { + optmidnode = 1; + break; + } + ast_xml_free_attr(paramtype); + } + } + } + } + + if ((!reqfinode && reqlanode) || (reqfinode && reqlanode && optmidnode)) { + reverse = 1; + node = lastparam; + } else { + reverse = 0; + node = firstparam; + } + + /* init syntax string. */ + if (reverse) { + xmldoc_reverse_helper(reverse, &len, &syntax, + (printrootname ? (printrootname == 2 ? ")]" : ")"): "")); + } else { + xmldoc_reverse_helper(reverse, &len, &syntax, "%s%s", (printrootname ? rootname : ""), + (printrootname ? (printrootname == 2 ? "[(" : "(") : "")); + } + + for (; node; node = GOTONEXT(reverse, node)) { + if (strcasecmp(ast_xml_node_get_name(node), childname)) { + continue; + } + + /* Get the argument name, if it is not the leaf, go inside that parameter. */ + if (xmldoc_has_arguments(node)) { + parenthesis = ast_xml_get_attribute(node, "hasparams"); + prnparenthesis = 0; + if (parenthesis) { + prnparenthesis = ast_true(parenthesis); + if (!strcasecmp(parenthesis, "optional")) { + prnparenthesis = 2; + } + ast_xml_free_attr(parenthesis); + } + argname = ast_xml_get_attribute(node, "name"); + if (argname) { + paramname = xmldoc_get_syntax(node, argname, "argument", prnparenthesis, prnparenthesis); + ast_xml_free_attr(argname); + paramnamemalloc = 1; + } else { + /* Malformed XML, print **UNKOWN** */ + paramname = ast_strdup("**unknown**"); + } + paramnamemalloc = 1; + } else { + paramnamemalloc = 0; + paramname = ast_xml_get_attribute(node, "name"); + if (!paramname) { + ast_log(LOG_WARNING, "Malformed XML %s: no %s name\n", rootname, childname); + if (syntax) { + /* Free already allocated syntax */ + ast_free(syntax); + } + /* to give up is ok? */ + ast_asprintf(&syntax, "%s%s", (printrootname ? rootname : ""), (printparenthesis ? "()" : "")); + return syntax; + } + } + + /* Defaults to 'false'. */ + multiple = 0; + if ((multipletype = ast_xml_get_attribute(node, "multiple"))) { + if (ast_true(multipletype)) { + multiple = 1; + } + ast_xml_free_attr(multipletype); + } + + required = 0; /* Defaults to 'false'. */ + if ((paramtype = ast_xml_get_attribute(node, "required"))) { + if (ast_true(paramtype)) { + required = 1; + } + ast_xml_free_attr(paramtype); + } + + /* build syntax core. */ + + if (required) { + /* First parameter */ + if (!paramcount) { + xmldoc_reverse_helper(reverse, &len, &syntax, "%s%s%s%s", paramname, MP("["), MP(argsep), MP("...]")); + } else { + /* Time to close open brackets. */ + while (openbrackets > 0) { + xmldoc_reverse_helper(reverse, &len, &syntax, (reverse ? "[" : "]")); + openbrackets--; + } + if (reverse) { + xmldoc_reverse_helper(reverse, &len, &syntax, "%s%s", paramname, argsep); + } else { + xmldoc_reverse_helper(reverse, &len, &syntax, "%s%s", argsep, paramname); + } + xmldoc_reverse_helper(reverse, &len, &syntax, "%s%s%s", MP("["), MP(argsep), MP("...]")); + } + } else { + /* First parameter */ + if (!paramcount) { + xmldoc_reverse_helper(reverse, &len, &syntax, "[%s%s%s%s]", paramname, MP("["), MP(argsep), MP("...]")); + } else { + if (ISLAST(reverse, node)) { + /* This is the last parameter. */ + if (reverse) { + xmldoc_reverse_helper(reverse, &len, &syntax, "[%s%s%s%s]%s", paramname, + MP("["), MP(argsep), MP("...]"), argsep); + } else { + xmldoc_reverse_helper(reverse, &len, &syntax, "%s[%s%s%s%s]", argsep, paramname, + MP("["), MP(argsep), MP("...]")); + } + } else { + if (reverse) { + xmldoc_reverse_helper(reverse, &len, &syntax, "%s%s%s%s%s]", paramname, argsep, + MP("["), MP(argsep), MP("...]")); + } else { + xmldoc_reverse_helper(reverse, &len, &syntax, "[%s%s%s%s%s", argsep, paramname, + MP("["), MP(argsep), MP("...]")); + } + openbrackets++; + } + } + } + if (paramnamemalloc) { + ast_free((char *) paramname); + } else { + ast_xml_free_attr(paramname); + } + + paramcount++; + } + + /* Time to close open brackets. */ + while (openbrackets > 0) { + xmldoc_reverse_helper(reverse, &len, &syntax, (reverse ? "[" : "]")); + openbrackets--; + } + + /* close syntax string. */ + if (reverse) { + xmldoc_reverse_helper(reverse, &len, &syntax, "%s%s", (printrootname ? rootname : ""), + (printrootname ? (printrootname == 2 ? "[(" : "(") : "")); + } else { + xmldoc_reverse_helper(reverse, &len, &syntax, (printrootname ? (printrootname == 2 ? ")]" : ")") : "")); + } + + return syntax; +#undef ISLAST +#undef GOTONEXT +#undef MP +} + +/*! \internal + * \brief Get the syntax for a specified application or function. + * \param type Application or Function ? + * \param name Name of the application or function. + * \retval NULL on error. + * \retval The generated syntax in a ast_malloc'ed string. + */ +static char *xmldoc_build_syntax(const char *type, const char *name) +{ + struct ast_xml_node *node; + char *syntax = NULL; + + node = xmldoc_get_node(type, name, documentation_language); + if (!node) { + return NULL; + } + + for (node = ast_xml_node_get_children(node); node; node = ast_xml_node_get_next(node)) { + if (!strcasecmp(ast_xml_node_get_name(node), "syntax")) { + break; + } + } + + if (node) { + syntax = xmldoc_get_syntax(node, name, "parameter", 1, 1); + } + return syntax; +} + +/*! \internal + * \brief Parse a <para> element. + * \param node The <para> element pointer. + * \param tabs Added this string before the content of the <para> element. + * \param posttabs Added this string after the content of the <para> element. + * \param buffer This must be an already allocated ast_str. It will be used + * to store the result (if already has something it will be appended to the current + * string). + * \retval 1 If 'node' is a named 'para'. + * \retval 2 If data is appended in buffer. + * \retval 0 on error. + */ +static int xmldoc_parse_para(struct ast_xml_node *node, const char *tabs, const char *posttabs, struct ast_str **buffer) +{ + const char *tmptext; + struct ast_xml_node *tmp; + int ret = 0; + struct ast_str *tmpstr; + + if (!node || !ast_xml_node_get_children(node)) { + return ret; + } + + if (strcasecmp(ast_xml_node_get_name(node), "para")) { + return ret; + } + + ast_str_append(buffer, 0, "%s", tabs); + + ret = 1; + + for (tmp = ast_xml_node_get_children(node); tmp; tmp = ast_xml_node_get_next(tmp)) { + /* Get the text inside the <para> element and append it to buffer. */ + tmptext = ast_xml_get_text(tmp); + if (tmptext) { + /* Strip \n etc. */ + xmldoc_string_cleanup(tmptext, &tmpstr, 0); + ast_xml_free_text(tmptext); + if (tmpstr) { + if (strcasecmp(ast_xml_node_get_name(tmp), "text")) { + ast_str_append(buffer, 0, "<%s>%s</%s>", ast_xml_node_get_name(tmp), + tmpstr->str, ast_xml_node_get_name(tmp)); + } else { + ast_str_append(buffer, 0, "%s", tmpstr->str); + } + ast_free(tmpstr); + ret = 2; + } + } + } + + ast_str_append(buffer, 0, "%s", posttabs); + + return ret; +} + +/*! \internal + * \brief Parse special elements defined in 'struct special_tags' special elements must have a <para> element inside them. + * \param fixnode special tag node pointer. + * \param tabs put tabs before printing the node content. + * \param posttabs put posttabs after printing node content. + * \param buffer Output buffer, the special tags will be appended here. + * \retval 0 if no special element is parsed. + * \retval 1 if a special element is parsed (data is appended to buffer). + * \retval 2 if a special element is parsed and also a <para> element is parsed inside the specialtag. + */ +static int xmldoc_parse_specialtags(struct ast_xml_node *fixnode, const char *tabs, const char *posttabs, struct ast_str **buffer) +{ + struct ast_xml_node *node = fixnode; + int ret = 0, i, count = 0; + + if (!node || !ast_xml_node_get_children(node)) { + return ret; + } + + for (i = 0; i < ARRAY_LEN(special_tags); i++) { + if (strcasecmp(ast_xml_node_get_name(node), special_tags[i].tagname)) { + continue; + } + + ret = 1; + /* This is a special tag. */ + + /* concat data */ + if (!ast_strlen_zero(special_tags[i].init)) { + ast_str_append(buffer, 0, "%s%s", tabs, special_tags[i].init); + } + + /* parse <para> elements inside special tags. */ + for (node = ast_xml_node_get_children(node); node; node = ast_xml_node_get_next(node)) { + /* first <para> just print it without tabs at the begining. */ + if (xmldoc_parse_para(node, (!count ? "" : tabs), posttabs, buffer) == 2) { + ret = 2; + } + } + + if (!ast_strlen_zero(special_tags[i].end)) { + ast_str_append(buffer, 0, "%s%s", special_tags[i].end, posttabs); + } + + break; + } + + return ret; +} + +/*! \internal + * \brief Parse an <argument> element from the xml documentation. + * \param fixnode Pointer to the 'argument' xml node. + * \param insideparameter If we are parsing an <argument> inside a <parameter>. + * \param paramtabs pre tabs if we are inside a parameter element. + * \param tabs What to be printed before the argument name. + * \param buffer Output buffer to put values found inside the <argument> element. + * \retval 1 If there is content inside the argument. + * \retval 0 If the argument element is not parsed, or there is no content inside it. + */ +static int xmldoc_parse_argument(struct ast_xml_node *fixnode, int insideparameter, const char *paramtabs, const char *tabs, struct ast_str **buffer) +{ + struct ast_xml_node *node = fixnode; + const char *argname; + int count=0, ret = 0; + + if (!node || !ast_xml_node_get_children(node)) { + return ret; + } + + /* Print the argument names */ + argname = ast_xml_get_attribute(node, "name"); + if (!argname) { + return 0; + } + ast_str_append(buffer, 0, "%s%s%s", tabs, argname, (insideparameter ? "\n" : "")); + ast_xml_free_attr(argname); + + for (node = ast_xml_node_get_children(node); node; node = ast_xml_node_get_next(node)) { + if (xmldoc_parse_para(node, (insideparameter ? paramtabs : (!count ? " - " : tabs)), "\n", buffer) == 2) { + count++; + ret = 1; + } else if (xmldoc_parse_specialtags(node, (insideparameter ? paramtabs : (!count ? " - " : tabs)), "\n", buffer) == 2) { + count++; + ret = 1; + } + } + + return ret; +} + +/*! \internal + * \brief Parse a <variable> node inside a <variablelist> node. + * \param node The variable node to parse. + * \param tabs A string to be appended at the begining of the output that will be stored + * in buffer. + * \param buffer This must be an already created ast_str. It will be used + * to store the result (if already has something it will be appended to the current + * string). + * \retval 0 if no data is appended. + * \retval 1 if data is appended. + */ +static int xmldoc_parse_variable(struct ast_xml_node *node, const char *tabs, struct ast_str **buffer) +{ + struct ast_xml_node *tmp; + const char *valname; + const char *tmptext; + struct ast_str *cleanstr; + int ret = 0, printedpara=0; + + for (tmp = ast_xml_node_get_children(node); tmp; tmp = ast_xml_node_get_next(tmp)) { + if (xmldoc_parse_para(tmp, (ret ? tabs : ""), "\n", buffer)) { + printedpara = 1; + continue; + } else if (xmldoc_parse_specialtags(tmp, (ret ? tabs : ""), "\n", buffer)) { + printedpara = 1; + continue; + } + + if (strcasecmp(ast_xml_node_get_name(tmp), "value")) { + continue; + } + + /* Parse a <value> tag only. */ + if (!printedpara) { + ast_str_append(buffer, 0, "\n"); + printedpara = 1; + } + /* Parse each <value name='valuename'>desciption</value> */ + valname = ast_xml_get_attribute(tmp, "name"); + if (valname) { + ret = 1; + ast_str_append(buffer, 0, "%s<value>%s</value>", tabs, valname); + ast_xml_free_attr(valname); + } + tmptext = ast_xml_get_text(tmp); + /* Check inside this node for any explanation about its meaning. */ + if (tmptext) { + /* Cleanup text. */ + xmldoc_string_cleanup(tmptext, &cleanstr, 1); + ast_xml_free_text(tmptext); + if (cleanstr && cleanstr->used > 0) { + ast_str_append(buffer, 0, ":%s", cleanstr->str); + } + ast_free(cleanstr); + } + ast_str_append(buffer, 0, "\n"); + } + + return ret; +} + +/*! \internal + * \brief Parse a <variablelist> node and put all the output inside 'buffer'. + * \param node The variablelist node pointer. + * \param tabs A string to be appended at the begining of the output that will be stored + * in buffer. + * \param buffer This must be an already created ast_str. It will be used + * to store the result (if already has something it will be appended to the current + * string). + * \retval 1 If a <variablelist> element is parsed. + * \retval 0 On error. + */ +static int xmldoc_parse_variablelist(struct ast_xml_node *node, const char *tabs, struct ast_str **buffer) +{ + struct ast_xml_node *tmp; + const char *varname; + char *vartabs; + int ret = 0; + + if (!node || !ast_xml_node_get_children(node)) { + return ret; + } + + if (strcasecmp(ast_xml_node_get_name(node), "variablelist")) { + return ret; + } + + /* use this spacing (add 4 spaces) inside a variablelist node. */ + ast_asprintf(&vartabs, "%s ", tabs); + if (!vartabs) { + return ret; + } + for (tmp = ast_xml_node_get_children(node); tmp; tmp = ast_xml_node_get_next(tmp)) { + /* We can have a <para> element inside the variable list */ + if ((xmldoc_parse_para(tmp, (ret ? tabs : ""), "\n", buffer))) { + ret = 1; + continue; + } else if ((xmldoc_parse_specialtags(tmp, (ret ? tabs : ""), "\n", buffer))) { + ret = 1; + continue; + } + + if (!strcasecmp(ast_xml_node_get_name(tmp), "variable")) { + /* Store the variable name in buffer. */ + varname = ast_xml_get_attribute(tmp, "name"); + if (varname) { + ast_str_append(buffer, 0, "%s<variable>%s</variable>: ", tabs, varname); + ast_xml_free_attr(varname); + /* Parse the <variable> possible values. */ + xmldoc_parse_variable(tmp, vartabs, buffer); + ret = 1; + } + } + } + + ast_free(vartabs); + + return ret; +} + +/*! \internal + * \brief Parse the <see-also> node content. + * \param type 'application' or 'function'. + * \param name Application or functions name. + * \retval NULL on error. + * \retval Content of the see-also node. + */ +static char *xmldoc_build_seealso(const char *type, const char *name) +{ + struct ast_str *outputstr; + char *output; + struct ast_xml_node *node; + const char *typename; + const char *content; + + if (ast_strlen_zero(type) || ast_strlen_zero(name)) { + return NULL; + } + + /* get the application/function root node. */ + node = xmldoc_get_node(type, name, documentation_language); + if (!node || !ast_xml_node_get_children(node)) { + return NULL; + } + + /* Find the <see-also> node. */ + for (node = ast_xml_node_get_children(node); node; node = ast_xml_node_get_next(node)) { + if (!strcasecmp(ast_xml_node_get_name(node), "see-also")) { + break; + } + } + + if (!node || !ast_xml_node_get_children(node)) { + /* we couldnt find a <see-also> node. */ + return NULL; + } + + /* prepare the output string. */ + outputstr = ast_str_create(128); + if (!outputstr) { + return NULL; + } + + /* get into the <see-also> node. */ + for (node = ast_xml_node_get_children(node); node; node = ast_xml_node_get_next(node)) { + if (strcasecmp(ast_xml_node_get_name(node), "ref")) { + continue; + } + + /* parse the <ref> node. 'type' attribute is required. */ + typename = ast_xml_get_attribute(node, "type"); + if (!typename) { + continue; + } + content = ast_xml_get_text(node); + if (!content) { + ast_xml_free_attr(typename); + continue; + } + if (!strcasecmp(typename, "application") || !strcasecmp(typename, "function")) { + ast_str_append(&outputstr, 0, "%s: Type <astcli>core show %s %s</astcli> for more info.\n", + content, typename, content); + } else if (!strcasecmp(typename, "astcli")) { + ast_str_append(&outputstr, 0, "%s: Type <astcli>help %s</astcli> for more info.\n", content, content); + } else if (!strcasecmp(typename, "link")) { + ast_str_append(&outputstr, 0, "%s\n", content); + } else if (!strcasecmp(typename, "manpage")) { + ast_str_append(&outputstr, 0, "ManPage: %s\n", content); + } + ast_xml_free_text(content); + } + + output = ast_strdup(outputstr->str); + ast_free(outputstr); + + return output; +} + +/*! \internal + * \brief Parse a <enum> node. + * \brief fixnode An ast_xml_node pointer to the <enum> node. + * \bried buffer The output buffer. + * \retval 0 if content is not found inside the enum element (data is not appended to buffer). + * \retval 1 if content is found and data is appended to buffer. + */ +static int xmldoc_parse_enum(struct ast_xml_node *fixnode, const char *tabs, struct ast_str **buffer) +{ + struct ast_xml_node *node = fixnode; + int ret = 0; + + for (node = ast_xml_node_get_children(node); node; node = ast_xml_node_get_next(node)) { + if ((xmldoc_parse_para(node, (ret ? tabs : " - "), "\n", buffer))) { + ret = 1; + } else if ((xmldoc_parse_specialtags(node, (ret ? tabs : " - "), "\n", buffer))) { + ret = 1; + } + } + return ret; +} + +/*! \internal + * \brief Parse a <enumlist> node. + * \param fixnode As ast_xml pointer to the <enumlist> node. + * \param buffer The ast_str output buffer. + * \retval 0 if no <enumlist> node was parsed. + * \retval 1 if a <enumlist> node was parsed. + */ +static int xmldoc_parse_enumlist(struct ast_xml_node *fixnode, const char *tabs, struct ast_str **buffer) +{ + struct ast_xml_node *node = fixnode; + const char *enumname; + int ret = 0; + + for (node = ast_xml_node_get_children(node); node; node = ast_xml_node_get_next(node)) { + if (strcasecmp(ast_xml_node_get_name(node), "enum")) { + continue; + } + + enumname = ast_xml_get_attribute(node, "name"); + if (enumname) { + ast_str_append(buffer, 0, "%s<enum>%s</enum>", tabs, enumname); + ast_xml_free_attr(enumname); + + /* parse only enum elements inside a enumlist node. */ + if ((xmldoc_parse_enum(node, tabs, buffer))) { + ret = 1; + } else { + ast_str_append(buffer, 0, "\n"); + } + } + } + return ret; +} + +/*! \internal + * \brief Parse an <option> node. + * \param fixnode An ast_xml pointer to the <option> node. + * \param tabs A string to be appended at the begining of each line being added to the + * buffer string. + * \param buffer The output buffer. + * \retval 0 if no option node is parsed. + * \retval 1 if an option node is parsed. + */ +static int xmldoc_parse_option(struct ast_xml_node *fixnode, const char *tabs, struct ast_str **buffer) +{ + struct ast_xml_node *node; + int ret = 0; + char *optiontabs; + + ast_asprintf(&optiontabs, "%s ", tabs); + if (!optiontabs) { + return ret; + } + for (node = ast_xml_node_get_children(fixnode); node; node = ast_xml_node_get_next(node)) { + if (!strcasecmp(ast_xml_node_get_name(node), "argument")) { + /* if this is the first data appended to buffer, print a \n*/ + if (!ret && ast_xml_node_get_children(node)) { + /* print \n */ + ast_str_append(buffer, 0, "\n"); + } + if (xmldoc_parse_argument(node, 0, NULL, optiontabs, buffer)) { + ret = 1; + } + continue; + } + + if (xmldoc_parse_para(node, (ret ? tabs : ""), "\n", buffer)) { + ret = 1; + } else if (xmldoc_parse_specialtags(node, (ret ? tabs : ""), "\n", buffer)) { + ret = 1; + } + + xmldoc_parse_variablelist(node, optiontabs, buffer); + + xmldoc_parse_enumlist(node, optiontabs, buffer); + } + ast_free(optiontabs); + + return ret; +} + +/*! \internal + * \brief Parse an <optionlist> element from the xml documentation. + * \param fixnode Pointer to the optionlist xml node. + * \param tabs A string to be appended at the begining of each line being added to the + * buffer string. + * \param buffer Output buffer to put what is inside the optionlist tag. + */ +static void xmldoc_parse_optionlist(struct ast_xml_node *fixnode, const char *tabs, struct ast_str **buffer) +{ + struct ast_xml_node *node; + const char *optname; + char *optionsyntax; + + for (node = ast_xml_node_get_children(fixnode); node; node = ast_xml_node_get_next(node)) { + /* Start appending every option tag. */ + if (strcasecmp(ast_xml_node_get_name(node), "option")) { + continue; + } + + /* Get the option name. */ + optname = ast_xml_get_attribute(node, "name"); + if (!optname) { + continue; + } + + optionsyntax = xmldoc_get_syntax(node, optname, "argument", 0, 1); + if (!optionsyntax) { + continue; + } + + ast_str_append(buffer, 0, "%s%s: ", tabs, optionsyntax); + + if (!xmldoc_parse_option(node, tabs, buffer)) { + ast_str_append(buffer, 0, "\n"); + } + } +} + +/*! \internal + * \brief Parse a 'parameter' tag inside a syntax element. + * \param fixnode A pointer to the 'parameter' xml node. + * \param tabs A string to be appended at the beginning of each line being printed inside + * 'buffer'. + * \param buffer String buffer to put values found inside the parameter element. + */ +static void xmldoc_parse_parameter(struct ast_xml_node *fixnode, const char *tabs, struct ast_str **buffer) +{ + const char *paramname; + struct ast_xml_node *node = fixnode; + int hasarguments, printed = 0; + char *internaltabs; + + if (strcasecmp(ast_xml_node_get_name(node), "parameter")) { + return; + } + + hasarguments = xmldoc_has_arguments(node); + if (!(paramname = ast_xml_get_attribute(node, "name"))) { + /* parameter MUST have an attribute name. */ + return; + } + + ast_asprintf(&internaltabs, "%s ", tabs); + if (!internaltabs) { + return; + } + + if (!hasarguments) { + ast_str_append(buffer, 0, "%s\n", paramname); + ast_xml_free_attr(paramname); + printed = 1; + } + + for (node = ast_xml_node_get_children(node); node; node = ast_xml_node_get_next(node)) { + if (!strcasecmp(ast_xml_node_get_name(node), "optionlist")) { + xmldoc_parse_optionlist(node, internaltabs, buffer); + } else if (!strcasecmp(ast_xml_node_get_name(node), "enumlist")) { + xmldoc_parse_enumlist(node, internaltabs, buffer); + } else if (!strcasecmp(ast_xml_node_get_name(node), "argument")) { + xmldoc_parse_argument(node, 1, internaltabs, (!hasarguments ? " " : ""), buffer); + } else if (!strcasecmp(ast_xml_node_get_name(node), "para")) { + if (!printed) { + ast_str_append(buffer, 0, "%s\n", paramname); + ast_xml_free_attr(paramname); + printed = 1; + } + xmldoc_parse_para(node, internaltabs, "\n", buffer); + continue; + } else if ((xmldoc_parse_specialtags(node, internaltabs, "\n", buffer))) { + continue; + } + } + ast_free(internaltabs); +} + +/*! \internal + * \brief Generate the [arguments] tag based on type of node 'application' or + * 'function' and name. + * \param type 'application' or 'function' ? + * \param name Name of the application or function to build the 'arguments' tag. + * \retval NULL on error. + * \retval Output buffer with the [arguments] tag content. + */ +static char *xmldoc_build_arguments(const char *type, const char *name) +{ + struct ast_xml_node *node; + struct ast_str *ret = ast_str_create(128); + char *retstr = NULL; + + if (ast_strlen_zero(type) || ast_strlen_zero(name)) { + return NULL; + } + + node = xmldoc_get_node(type, name, documentation_language); + + if (!node || !ast_xml_node_get_children(node)) { + return NULL; + } + + /* Find the syntax field. */ + for (node = ast_xml_node_get_children(node); node; node = ast_xml_node_get_next(node)) { + if (!strcasecmp(ast_xml_node_get_name(node), "syntax")) { + break; + } + } + + if (!node || !ast_xml_node_get_children(node)) { + /* We couldn't find the syntax node. */ + return NULL; + } + + for (node = ast_xml_node_get_children(node); node; node = ast_xml_node_get_next(node)) { + xmldoc_parse_parameter(node, "", &ret); + } + + if (ret->used > 0) { + /* remove last '\n' */ + if (ret->str[ret->used - 1] == '\n') { + ret->str[ret->used - 1] = '\0'; + ret->used--; + } + retstr = ast_strdup(ret->str); + } + ast_free(ret); + + return retstr; +} + +/*! \internal + * \brief Return the string within a node formatted with <para> and <variablelist> elements. + * \param node Parent node where content resides. + * \param raw If set, return the node's content without further processing. + * \param raw_wrap Wrap raw text. + * \retval NULL on error + * \retval Node content on success. + */ +static struct ast_str *xmldoc_get_formatted(struct ast_xml_node *node, int raw_output, int raw_wrap) +{ + struct ast_xml_node *tmp; + const char *notcleanret, *tmpstr; + struct ast_str *ret = ast_str_create(128); + + if (raw_output) { + notcleanret = ast_xml_get_text(node); + tmpstr = notcleanret; + xmldoc_string_cleanup(ast_skip_blanks(notcleanret), &ret, 0); + ast_xml_free_text(tmpstr); + } else { + for (tmp = ast_xml_node_get_children(node); tmp; tmp = ast_xml_node_get_next(tmp)) { + /* if found, parse a <para> element. */ + if (xmldoc_parse_para(tmp, "", "\n", &ret)) { + continue; + } else if (xmldoc_parse_specialtags(tmp, "", "\n", &ret)) { + continue; + } + /* if found, parse a <variablelist> element. */ + xmldoc_parse_variablelist(tmp, "", &ret); + xmldoc_parse_enumlist(tmp, " ", &ret); + } + /* remove last '\n' */ + /* XXX Don't modify ast_str internals manually */ + if (ret->str[ret->used-1] == '\n') { + ret->str[ret->used-1] = '\0'; + ret->used--; + } + } + return ret; +} + +/*! \internal + * \brief Get the content of a field (synopsis, description, etc) from an asterisk document tree + * \param type Type of element (application, function, ...). + * \param name Name of element (Dial, Echo, Playback, ...). + * \param var Name of field to return (synopsis, description, etc). + * \param raw Field only contains text, no other elements inside it. + * \retval NULL On error. + * \retval Field text content on success. + */ +static char *xmldoc_build_field(const char *type, const char *name, const char *var, int raw) +{ + struct ast_xml_node *node; + char *ret = NULL; + struct ast_str *formatted; + + if (ast_strlen_zero(type) || ast_strlen_zero(name)) { + ast_log(LOG_ERROR, "Tried to look in XML tree with faulty values.\n"); + return ret; + } + + node = xmldoc_get_node(type, name, documentation_language); + + if (!node) { + ast_log(LOG_WARNING, "Counldn't find %s %s in XML documentation\n", type, name); + return ret; + } + + node = ast_xml_find_element(ast_xml_node_get_children(node), var, NULL, NULL); + + if (!node || !ast_xml_node_get_children(node)) { + ast_log(LOG_DEBUG, "Cannot find variable '%s' in tree '%s'\n", name, var); + return ret; + } + + formatted = xmldoc_get_formatted(node, raw, raw); + if (formatted->used > 0) { + ret = ast_strdup(formatted->str); + } + ast_free(formatted); + + return ret; +} +#endif /* AST_XML_DOCS */ + +/*! \internal + * \brief Retrieve the XML documentation of a specified ast_custom_function, + * and populate ast_custom_function string fields. + * \param acf ast_custom_function structure with empty 'desc' and 'synopsis' + * but with a function 'name'. + * \retval -1 On error. + * \retval 0 On succes. + */ +static int acf_retrieve_docs(struct ast_custom_function *acf) +{ +#ifdef AST_XML_DOCS + char *tmpxml; + + /* Let's try to find it in the Documentation XML */ + if (!ast_strlen_zero(acf->desc) || !ast_strlen_zero(acf->synopsis)) { + return 0; + } + + if (ast_string_field_init(acf, 128)) { + return -1; + } + + /* load synopsis */ + tmpxml = xmldoc_build_field("function", acf->name, "synopsis", 1); + ast_string_field_set(acf, synopsis, tmpxml); + ast_free(tmpxml); + + /* load description */ + tmpxml = xmldoc_build_field("function", acf->name, "description", 0); + ast_string_field_set(acf, desc, tmpxml); + ast_free(tmpxml); + + /* load syntax */ + tmpxml = xmldoc_build_syntax("function", acf->name); + ast_string_field_set(acf, syntax, tmpxml); + ast_free(tmpxml); + + /* load arguments */ + tmpxml = xmldoc_build_arguments("function", acf->name); + ast_string_field_set(acf, arguments, tmpxml); + ast_free(tmpxml); + + /* load seealso */ + tmpxml = xmldoc_build_seealso("function", acf->name); + ast_string_field_set(acf, seealso, tmpxml); + ast_free(tmpxml); + + acf->docsrc = AST_XML_DOC; +#endif + + return 0; +} + int __ast_custom_function_register(struct ast_custom_function *acf, struct ast_module *mod) { struct ast_custom_function *cur; char tmps[80]; - if (!acf) + if (!acf) { return -1; + } acf->mod = mod; + acf->docsrc = AST_STATIC_DOC; + + if (acf_retrieve_docs(acf)) { + return -1; + } AST_RWLIST_WRLOCK(&acf_root); @@ -2807,8 +4656,10 @@ int __ast_custom_function_register(struct ast_custom_function *acf, struct ast_m } } AST_RWLIST_TRAVERSE_SAFE_END; - if (!cur) + + if (!cur) { AST_RWLIST_INSERT_TAIL(&acf_root, acf, acflist); + } AST_RWLIST_UNLOCK(&acf_root); @@ -4478,6 +6329,9 @@ int ast_register_application2(const char *app, int (*execute)(struct ast_channel struct ast_app *tmp, *cur = NULL; char tmps[80]; int length, res; +#ifdef AST_XML_DOCS + char *tmpxml; +#endif AST_RWLIST_WRLOCK(&apps); AST_RWLIST_TRAVERSE(&apps, tmp, list) { @@ -4496,10 +6350,50 @@ int ast_register_application2(const char *app, int (*execute)(struct ast_channel return -1; } + if (ast_string_field_init(tmp, 128)) { + ast_free(tmp); + return -1; + } + +#ifdef AST_XML_DOCS + /* Try to lookup the docs in our XML documentation database */ + if (ast_strlen_zero(synopsis) && ast_strlen_zero(description)) { + /* load synopsis */ + tmpxml = xmldoc_build_field("application", app, "synopsis", 1); + ast_string_field_set(tmp, synopsis, tmpxml); + ast_free(tmpxml); + + /* load description */ + tmpxml = xmldoc_build_field("application", app, "description", 0); + ast_string_field_set(tmp, description, tmpxml); + ast_free(tmpxml); + + /* load syntax */ + tmpxml = xmldoc_build_syntax("application", app); + ast_string_field_set(tmp, syntax, tmpxml); + ast_free(tmpxml); + + /* load arguments */ + tmpxml = xmldoc_build_arguments("application", app); + ast_string_field_set(tmp, arguments, tmpxml); + ast_free(tmpxml); + + /* load seealso */ + tmpxml = xmldoc_build_seealso("application", app); + ast_string_field_set(tmp, seealso, tmpxml); + ast_free(tmpxml); + tmp->docsrc = AST_XML_DOC; + } else { +#endif + ast_string_field_set(tmp, synopsis, synopsis); + ast_string_field_set(tmp, description, description); + tmp->docsrc = AST_STATIC_DOC; +#ifdef AST_XML_DOCS + } +#endif + strcpy(tmp->name, app); tmp->execute = execute; - tmp->synopsis = synopsis; - tmp->description = description; tmp->module = mod; /* Store in alphabetical order */ @@ -4520,6 +6414,123 @@ int ast_register_application2(const char *app, int (*execute)(struct ast_channel return 0; } +#ifdef AST_XML_DOCS +/*! \brief Close and unload XML documentation. */ +static void xmldoc_unload_documentation(void) +{ + struct documentation_tree *doctree; + + AST_RWLIST_WRLOCK(&xmldoc_tree); + while ((doctree = AST_RWLIST_REMOVE_HEAD(&xmldoc_tree, entry))) { + ast_free(doctree->filename); + ast_xml_close(doctree->doc); + } + AST_RWLIST_UNLOCK(&xmldoc_tree); + + ast_xml_finish(); +} + +int ast_load_documentation(void) +{ + struct ast_xml_node *root_node; + struct ast_xml_doc *tmpdoc; + struct documentation_tree *doc_tree; + char *xmlpattern; + struct ast_config *cfg = NULL; + struct ast_variable *var = NULL; + struct ast_flags cnfflags = { 0 }; + int globret, i, dup, duplicate; + glob_t globbuf; + + /* setup default XML documentation language */ + snprintf(documentation_language, sizeof(documentation_language), default_documentation_language); + + if (!(cfg = ast_config_load2("asterisk.conf", "" /* core can't reload */, cnfflags))) { + ast_log(LOG_ERROR, "No asterisk.conf? That cannot be good.\n"); + } + + for (var = ast_variable_browse(cfg, "options"); var; var = var->next) { + if (!strcasecmp(var->name, "documentation_language")) { + if (!ast_strlen_zero(var->value)) { + snprintf(documentation_language, sizeof(documentation_language), "%s", var->value); + } + } + } + ast_config_destroy(cfg); + + /* initialize the XML library. */ + ast_xml_init(); + + /* register function to be run when asterisk finish. */ + ast_register_atexit(xmldoc_unload_documentation); + + /* Get every *-LANG.xml file inside $(ASTDATADIR)/documentation */ + ast_asprintf(&xmlpattern, "%s/documentation{/thirdparty/,/}*-{%s,%.2s_??,%s}.xml", ast_config_AST_DATA_DIR, + documentation_language, documentation_language, default_documentation_language); + globbuf.gl_offs = 0; /* initialize it to silence gcc */ + globret = glob(xmlpattern, MY_GLOB_FLAGS | GLOB_BRACE, NULL, &globbuf); + if (globret == GLOB_NOSPACE) { + ast_log(LOG_WARNING, "Glob Expansion of pattern '%s' failed: Not enough memory\n", xmlpattern); + ast_free(xmlpattern); + return 1; + } else if (globret == GLOB_ABORTED) { + ast_log(LOG_WARNING, "Glob Expansion of pattern '%s' failed: Read error\n", xmlpattern); + ast_free(xmlpattern); + return 1; + } + ast_free(xmlpattern); + + AST_RWLIST_WRLOCK(&xmldoc_tree); + /* loop over expanded files */ + for (i = 0; i < globbuf.gl_pathc; i++) { + /* check for duplicates (if we already [try to] open the same file. */ + duplicate = 0; + for (dup = 0; dup < i; dup++) { + if (!strcmp(globbuf.gl_pathv[i], globbuf.gl_pathv[dup])) { + duplicate = 1; + break; + } + } + if (duplicate) { + continue; + } + tmpdoc = NULL; + tmpdoc = ast_xml_open(globbuf.gl_pathv[i]); + if (!tmpdoc) { + ast_log(LOG_ERROR, "Could not open XML documentation at '%s'\n", globbuf.gl_pathv[i]); + continue; + } + /* Get doc root node and check if it starts with '<docs>' */ + root_node = ast_xml_get_root(tmpdoc); + if (!root_node) { + ast_log(LOG_ERROR, "Error getting documentation root node"); + ast_xml_close(tmpdoc); + continue; + } + /* Check root node name for malformed xmls. */ + if (strcmp(ast_xml_node_get_name(root_node), "docs")) { + ast_log(LOG_ERROR, "Documentation file is not well formed!\n"); + ast_xml_close(tmpdoc); + continue; + } + doc_tree = ast_calloc(1, sizeof(*doc_tree)); + if (!doc_tree) { + ast_log(LOG_ERROR, "Unable to allocate documentation_tree structure!\n"); + ast_xml_close(tmpdoc); + continue; + } + doc_tree->doc = tmpdoc; + doc_tree->filename = ast_strdup(globbuf.gl_pathv[i]); + AST_RWLIST_INSERT_TAIL(&xmldoc_tree, doc_tree, entry); + } + AST_RWLIST_UNLOCK(&xmldoc_tree); + + globfree(&globbuf); + + return 0; +} +#endif /* AST_XML_DOCS */ + /* * Append to the list. We don't have a tail pointer because we need * to scan the list anyways to check for duplicates during insertion. @@ -4553,6 +6564,78 @@ void ast_unregister_switch(struct ast_switch *sw) * Help for CLI commands ... */ +static void print_app_docs(struct ast_app *aa, int fd) +{ + /* Maximum number of characters added by terminal coloring is 22 */ + char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40], stxtitle[40], argtitle[40]; + char seealsotitle[40]; + char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL, *syntax = NULL, *arguments = NULL; + char *seealso = NULL; + int syntax_size, synopsis_size, description_size, arguments_size, seealso_size; + + snprintf(info, sizeof(info), "\n -= Info about application '%s' =- \n\n", aa->name); + term_color(infotitle, info, COLOR_MAGENTA, 0, sizeof(infotitle)); + + term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40); + term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40); + term_color(stxtitle, "[Syntax]\n", COLOR_MAGENTA, 0, 40); + term_color(argtitle, "[Arguments]\n", COLOR_MAGENTA, 0, 40); + term_color(seealsotitle, "[See Also]\n", COLOR_MAGENTA, 0, 40); + +#ifdef AST_XML_DOCS + if (aa->docsrc == AST_XML_DOC) { + description = xmldoc_colorization(S_OR(aa->description, "Not available")); + arguments = xmldoc_colorization(S_OR(aa->arguments, "Not available")); + synopsis = xmldoc_colorization(S_OR(aa->synopsis, "Not available")); + seealso = xmldoc_colorization(S_OR(aa->seealso, "Not available")); + + if (!synopsis || !description || !arguments || !seealso) { + goto return_cleanup; + } + } else +#endif + { + synopsis_size = strlen(S_OR(aa->synopsis, "Not Available")) + MAX_ESCAPE_CHARS; + synopsis = ast_malloc(synopsis_size); + + description_size = strlen(S_OR(aa->description, "Not Available")) + MAX_ESCAPE_CHARS; + description = ast_malloc(description_size); + + arguments_size = strlen(S_OR(aa->arguments, "Not Available")) + MAX_ESCAPE_CHARS; + arguments = ast_malloc(arguments_size); + + seealso_size = strlen(S_OR(aa->seealso, "Not Available")) + MAX_ESCAPE_CHARS; + seealso = ast_malloc(seealso_size); + + if (!synopsis || !description || !arguments || !seealso) { + goto return_cleanup; + } + + term_color(synopsis, S_OR(aa->synopsis, "Not available"), COLOR_CYAN, 0, synopsis_size); + term_color(description, S_OR(aa->description, "Not available"), COLOR_CYAN, 0, description_size); + term_color(arguments, S_OR(aa->arguments, "Not available"), COLOR_CYAN, 0, arguments_size); + term_color(seealso, S_OR(aa->seealso, "Not available"), COLOR_CYAN, 0, seealso_size); + } + + /* Handle the syntax the same for both XML and raw docs */ + syntax_size = strlen(S_OR(aa->syntax, "Not Available")) + MAX_ESCAPE_CHARS; + if (!(syntax = ast_malloc(syntax_size))) { + goto return_cleanup; + } + term_color(syntax, S_OR(aa->syntax, "Not available"), COLOR_CYAN, 0, syntax_size); + + ast_cli(fd, "%s%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n", + infotitle, syntitle, synopsis, destitle, description, + stxtitle, syntax, argtitle, arguments, seealsotitle, seealso); + +return_cleanup: + ast_free(description); + ast_free(arguments); + ast_free(synopsis); + ast_free(seealso); + ast_free(syntax); +} + /* * \brief 'show application' CLI command implementation function... */ @@ -4591,58 +6674,22 @@ static char *handle_show_application(struct ast_cli_entry *e, int cmd, struct as return ret; } - if (a->argc < 4) + if (a->argc < 4) { return CLI_SHOWUSAGE; + } - /* ... go through all applications ... */ AST_RWLIST_RDLOCK(&apps); AST_RWLIST_TRAVERSE(&apps, aa, list) { - /* ... compare this application name with all arguments given - * to 'show application' command ... */ + /* Check for each app that was supplied as an argument */ for (app = 3; app < a->argc; app++) { - if (!strcasecmp(aa->name, a->argv[app])) { - /* Maximum number of characters added by terminal coloring is 22 */ - char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40]; - char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL; - int synopsis_size, description_size; - - no_registered_app = 0; + if (strcasecmp(aa->name, a->argv[app])) { + continue; + } - if (aa->synopsis) - synopsis_size = strlen(aa->synopsis) + 23; - else - synopsis_size = strlen("Not available") + 23; - synopsis = alloca(synopsis_size); + /* We found it! */ + no_registered_app = 0; - if (aa->description) - description_size = strlen(aa->description) + 23; - else - description_size = strlen("Not available") + 23; - description = alloca(description_size); - - if (synopsis && description) { - snprintf(info, 64 + AST_MAX_APP, "\n -= Info about application '%s' =- \n\n", aa->name); - term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22); - term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40); - term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40); - term_color(synopsis, - aa->synopsis ? aa->synopsis : "Not available", - COLOR_CYAN, 0, synopsis_size); - term_color(description, - aa->description ? aa->description : "Not available", - COLOR_CYAN, 0, description_size); - - ast_cli(a->fd,"%s%s%s\n\n%s%s\n", infotitle, syntitle, synopsis, destitle, description); - } else { - /* ... one of our applications, show info ...*/ - ast_cli(a->fd,"\n -= Info about application '%s' =- \n\n" - "[Synopsis]\n %s\n\n" - "[Description]\n%s\n", - aa->name, - aa->synopsis ? aa->synopsis : "Not available", - aa->description ? aa->description : "Not available"); - } - } + print_app_docs(aa, a->fd); } } AST_RWLIST_UNLOCK(&apps); @@ -5744,6 +7791,11 @@ int ast_unregister_application(const char *app) unreference_cached_app(tmp); AST_RWLIST_REMOVE_CURRENT(list); ast_verb(2, "Unregistered application '%s'\n", tmp->name); +#ifdef AST_XML_DOCS + if (tmp->docsrc == AST_XML_DOC) { + ast_string_field_free_memory(tmp); + } +#endif ast_free(tmp); break; } @@ -8534,12 +10586,12 @@ int load_pbx(void) /* Register builtin applications */ for (x = 0; x < sizeof(builtins) / sizeof(struct pbx_builtin); x++) { ast_verb(1, "[%s]\n", builtins[x].name); - if (ast_register_application2(builtins[x].name, builtins[x].execute, builtins[x].synopsis, builtins[x].description, NULL)) { + if (ast_register_application2(builtins[x].name, builtins[x].execute, NULL, NULL, NULL)) { ast_log(LOG_ERROR, "Unable to register builtin application '%s'\n", builtins[x].name); return -1; } } - + /* Register manager application */ ast_manager_register2("ShowDialPlan", EVENT_FLAG_CONFIG | EVENT_FLAG_REPORTING, manager_show_dialplan, "List dialplan", mandescr_show_dialplan); diff --git a/main/term.c b/main/term.c index d12135f24..7f38ee5ce 100644 --- a/main/term.c +++ b/main/term.c @@ -199,32 +199,72 @@ char *term_color(char *outbuf, const char *inbuf, int fgcolor, int bgcolor, int return outbuf; } -char *term_color_code(char *outbuf, int fgcolor, int bgcolor, int maxout) +static void check_fgcolor(int *fgcolor, int *attr) { - int attr = 0; - if ((!vt100compat) || (!fgcolor)) { - *outbuf = '\0'; - return outbuf; + if (*fgcolor & 128) { + *attr = ast_opt_light_background ? 0 : ATTR_BRIGHT; + *fgcolor &= ~128; + } + + if (ast_opt_light_background) { + *fgcolor = opposite(*fgcolor); } +} - if (fgcolor & 128) { - attr = ast_opt_light_background ? 0 : ATTR_BRIGHT; - fgcolor &= ~128; +static void check_bgcolor(int *bgcolor) +{ + if (*bgcolor) { + *bgcolor &= ~128; } +} - if (ast_opt_light_background) { - fgcolor = opposite(fgcolor); +static int check_colors_allowed(int fgcolor) +{ + return (!vt100compat || !fgcolor) ? 0 : 1; +} + +int ast_term_color_code(struct ast_str **str, int fgcolor, int bgcolor) +{ + int attr = 0; + + if (!check_colors_allowed(fgcolor)) { + return -1; } - if (bgcolor) { - bgcolor &= ~128; + check_fgcolor(&fgcolor, &attr); + check_bgcolor(&bgcolor); + + if (ast_opt_force_black_background) { + ast_str_append(str, 0, "%c[%d;%d;%dm", ESC, attr, fgcolor, COLOR_BLACK + 10); + } else if (bgcolor) { + ast_str_append(str, 0, "%c[%d;%d;%dm", ESC, attr, fgcolor, bgcolor + 10); + } else { + ast_str_append(str, 0, "%c[%d;%dm", ESC, attr, fgcolor); } + return 0; +} + +char *term_color_code(char *outbuf, int fgcolor, int bgcolor, int maxout) +{ + int attr = 0; + + if (!check_colors_allowed(fgcolor)) { + *outbuf = '\0'; + return outbuf; + } + + check_fgcolor(&fgcolor, &attr); + check_bgcolor(&bgcolor); + if (ast_opt_force_black_background) { + snprintf(outbuf, maxout, "%c[%d;%d;%dm", ESC, attr, fgcolor, COLOR_BLACK + 10); + } else if (bgcolor) { snprintf(outbuf, maxout, "%c[%d;%d;%dm", ESC, attr, fgcolor, bgcolor + 10); } else { snprintf(outbuf, maxout, "%c[%d;%dm", ESC, attr, fgcolor); } + return outbuf; } diff --git a/main/xml.c b/main/xml.c new file mode 100644 index 000000000..9a0c66d90 --- /dev/null +++ b/main/xml.c @@ -0,0 +1,195 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2008, Eliel C. Sardanons (LU1ALY) <eliels@gmail.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 XML abstraction layer + * + * \author Eliel C. Sardanons (LU1ALY) <eliels@gmail.com> + */ + +#include "asterisk.h" +#include "asterisk/xml.h" + +ASTERISK_FILE_VERSION(__FILE__, "$Revision$") + +#if defined(HAVE_LIBXML2) +#include <libxml/parser.h> +#include <libxml/tree.h> +/* libxml2 ast_xml implementation. */ + + +int ast_xml_init(void) +{ + LIBXML_TEST_VERSION + + return 0; +} + +int ast_xml_finish(void) +{ + xmlCleanupParser(); + + return 0; +} + +struct ast_xml_doc *ast_xml_open(char *filename) +{ + xmlDoc *doc; + + if (!filename) { + return NULL; + } + + doc = xmlReadFile(filename, NULL, XML_PARSE_RECOVER); + + return (struct ast_xml_doc *) doc; +} + + +void ast_xml_close(struct ast_xml_doc *doc) +{ + if (!doc) { + return; + } + + xmlFreeDoc((xmlDoc *) doc); + doc = NULL; +} + + +struct ast_xml_node *ast_xml_get_root(struct ast_xml_doc *doc) +{ + xmlNode *root_node; + + if (!doc) { + return NULL; + } + + root_node = xmlDocGetRootElement((xmlDoc *) doc); + + return (struct ast_xml_node *) root_node; +} + +void ast_xml_free_node(struct ast_xml_node *node) +{ + if (!node) { + return; + } + + xmlFreeNode((xmlNode *) node); + node = NULL; +} + +void ast_xml_free_attr(const char *attribute) +{ + if (attribute) { + xmlFree((char *) attribute); + } +} + +void ast_xml_free_text(const char *text) +{ + if (text) { + xmlFree((char *) text); + } +} + +const char *ast_xml_get_attribute(struct ast_xml_node *node, const char *attrname) +{ + xmlChar *attrvalue; + + if (!node) { + return NULL; + } + + if (!attrname) { + return NULL; + } + + attrvalue = xmlGetProp((xmlNode *) node, (xmlChar *) attrname); + + return (const char *) attrvalue; +} + +struct ast_xml_node *ast_xml_find_element(struct ast_xml_node *root_node, const char *name, const char *attrname, const char *attrvalue) +{ + struct ast_xml_node *cur; + const char *attr; + + if (!root_node) { + return NULL; + } + + for (cur = root_node; cur; cur = ast_xml_node_get_next(cur)) { + /* Check if the name matchs */ + if (strcmp(ast_xml_node_get_name(cur), name)) { + continue; + } + /* We need to check for a specific attribute name? */ + if (!attrname || !attrvalue) { + return cur; + } + /* Get the attribute, we need to compare it. */ + if ((attr = ast_xml_get_attribute(cur, attrname))) { + /* does attribute name/value matches? */ + if (!strcmp(attr, attrvalue)) { + ast_xml_free_attr(attr); + return cur; + } + ast_xml_free_attr(attr); + } + } + + return NULL; +} + +const char *ast_xml_get_text(struct ast_xml_node *node) +{ + if (!node) { + return NULL; + } + + return (const char *) xmlNodeGetContent((xmlNode *) node); +} + +const char *ast_xml_node_get_name(struct ast_xml_node *node) +{ + return (const char *) ((xmlNode *) node)->name; +} + +struct ast_xml_node *ast_xml_node_get_children(struct ast_xml_node *node) +{ + return (struct ast_xml_node *) ((xmlNode *) node)->children; +} + +struct ast_xml_node *ast_xml_node_get_next(struct ast_xml_node *node) +{ + return (struct ast_xml_node *) ((xmlNode *) node)->next; +} + +struct ast_xml_node *ast_xml_node_get_prev(struct ast_xml_node *node) +{ + return (struct ast_xml_node *) ((xmlNode *) node)->prev; +} + +struct ast_xml_node *ast_xml_node_get_parent(struct ast_xml_node *node) +{ + return (struct ast_xml_node *) ((xmlNode *) node)->parent; +} + +#endif /* defined(HAVE_LIBXML2) */ + diff --git a/makeopts.in b/makeopts.in index 59f7f378d..0b6b3ff42 100644 --- a/makeopts.in +++ b/makeopts.in @@ -241,6 +241,9 @@ TERMCAP_INCLUDE=@TERMCAP_INCLUDE@ TERMCAP_LIB=@TERMCAP_LIB@ TERMCAP_DIR=@TERMCAP_DIR@ +LIBXML2_INCLUDE=@LIBXML2_INCLUDE@ +LIBXML2_LIB=@LIBXML2_LIB@ + TINFO_INCLUDE=@TINFO_INCLUDE@ TINFO_LIB=@TINFO_LIB@ TINFO_DIR=@TINFO_DIR@ |