func_logic.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999 - 2006, Digium, Inc.
00005  * Portions Copyright (C) 2005, Anthony Minessale II
00006  *
00007  * See http://www.asterisk.org for more information about
00008  * the Asterisk project. Please do not directly contact
00009  * any of the maintainers of this project for assistance;
00010  * the project provides a web site, mailing lists and IRC
00011  * channels for your use.
00012  *
00013  * This program is free software, distributed under the terms of
00014  * the GNU General Public License Version 2. See the LICENSE file
00015  * at the top of the source tree.
00016  */
00017 
00018 /*! \file
00019  * 
00020  * \brief Conditional logic dialplan functions
00021  * 
00022  * \author Anthony Minessale II
00023  *
00024  * \ingroup functions
00025  */
00026 
00027 /*** MODULEINFO
00028    <support_level>core</support_level>
00029  ***/
00030 
00031 #include "asterisk.h"
00032 
00033 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 370655 $")
00034 
00035 #include "asterisk/module.h"
00036 #include "asterisk/channel.h"
00037 #include "asterisk/pbx.h"
00038 #include "asterisk/utils.h"
00039 #include "asterisk/app.h"
00040 
00041 /*** DOCUMENTATION
00042    <function name="ISNULL" language="en_US">
00043       <synopsis>
00044          Check if a value is NULL.
00045       </synopsis>
00046       <syntax>
00047          <parameter name="data" required="true" />
00048       </syntax>
00049       <description>
00050          <para>Returns <literal>1</literal> if NULL or <literal>0</literal> otherwise.</para>
00051       </description>
00052    </function>
00053    <function name="SET" language="en_US">
00054       <synopsis>
00055          SET assigns a value to a channel variable.
00056       </synopsis>
00057       <syntax argsep="=">
00058          <parameter name="varname" required="true" />
00059          <parameter name="value" />
00060       </syntax>
00061       <description>
00062       </description>
00063    </function>
00064    <function name="EXISTS" language="en_US">
00065       <synopsis>
00066          Test the existence of a value.
00067       </synopsis>
00068       <syntax>
00069          <parameter name="data" required="true" />
00070       </syntax>
00071       <description>
00072          <para>Returns <literal>1</literal> if exists, <literal>0</literal> otherwise.</para>
00073       </description>
00074    </function>
00075    <function name="IF" language="en_US">
00076       <synopsis>
00077          Check for an expresion.
00078       </synopsis>
00079       <syntax argsep="?">
00080          <parameter name="expresion" required="true" />
00081          <parameter name="retvalue" argsep=":" required="true">
00082             <argument name="true" />
00083             <argument name="false" />
00084          </parameter>
00085       </syntax>
00086       <description>
00087          <para>Returns the data following <literal>?</literal> if true, else the data following <literal>:</literal></para>
00088       </description> 
00089    </function>
00090    <function name="IFTIME" language="en_US">
00091       <synopsis>
00092          Temporal Conditional.
00093       </synopsis>
00094       <syntax argsep="?">
00095          <parameter name="timespec" required="true" />
00096          <parameter name="retvalue" required="true" argsep=":">
00097             <argument name="true" />
00098             <argument name="false" />
00099          </parameter>
00100       </syntax>
00101       <description>
00102          <para>Returns the data following <literal>?</literal> if true, else the data following <literal>:</literal></para>
00103       </description>
00104    </function>
00105    <function name="IMPORT" language="en_US">
00106       <synopsis>
00107          Retrieve the value of a variable from another channel.
00108       </synopsis>
00109       <syntax>
00110          <parameter name="channel" required="true" />
00111          <parameter name="variable" required="true" />
00112       </syntax>
00113       <description>
00114       </description>
00115    </function>
00116  ***/
00117 
00118 static int isnull(struct ast_channel *chan, const char *cmd, char *data,
00119         char *buf, size_t len)
00120 {
00121    strcpy(buf, data && *data ? "0" : "1");
00122 
00123    return 0;
00124 }
00125 
00126 static int exists(struct ast_channel *chan, const char *cmd, char *data, char *buf,
00127         size_t len)
00128 {
00129    strcpy(buf, data && *data ? "1" : "0");
00130 
00131    return 0;
00132 }
00133 
00134 static int iftime(struct ast_channel *chan, const char *cmd, char *data, char *buf,
00135         size_t len)
00136 {
00137    struct ast_timing timing;
00138    char *expr;
00139    char *iftrue;
00140    char *iffalse;
00141 
00142    data = ast_strip_quoted(data, "\"", "\"");
00143    expr = strsep(&data, "?");
00144    iftrue = strsep(&data, ":");
00145    iffalse = data;
00146 
00147    if (ast_strlen_zero(expr) || !(iftrue || iffalse)) {
00148       ast_log(LOG_WARNING,
00149             "Syntax IFTIME(<timespec>?[<true>][:<false>])\n");
00150       return -1;
00151    }
00152 
00153    if (!ast_build_timing(&timing, expr)) {
00154       ast_log(LOG_WARNING, "Invalid Time Spec.\n");
00155       ast_destroy_timing(&timing);
00156       return -1;
00157    }
00158 
00159    if (iftrue)
00160       iftrue = ast_strip_quoted(iftrue, "\"", "\"");
00161    if (iffalse)
00162       iffalse = ast_strip_quoted(iffalse, "\"", "\"");
00163 
00164    ast_copy_string(buf, ast_check_timing(&timing) ? S_OR(iftrue, "") : S_OR(iffalse, ""), len);
00165    ast_destroy_timing(&timing);
00166 
00167    return 0;
00168 }
00169 
00170 static int acf_if(struct ast_channel *chan, const char *cmd, char *data, char *buf,
00171         size_t len)
00172 {
00173    AST_DECLARE_APP_ARGS(args1,
00174       AST_APP_ARG(expr);
00175       AST_APP_ARG(remainder);
00176    );
00177    AST_DECLARE_APP_ARGS(args2,
00178       AST_APP_ARG(iftrue);
00179       AST_APP_ARG(iffalse);
00180    );
00181    args2.iftrue = args2.iffalse = NULL; /* you have to set these, because if there is nothing after the '?',
00182                                  then args1.remainder will be NULL, not a pointer to a null string, and
00183                                  then any garbage in args2.iffalse will not be cleared, and you'll crash.
00184                                   -- and if you mod the ast_app_separate_args func instead, you'll really
00185                                  mess things up badly, because the rest of everything depends on null args
00186                                  for non-specified stuff. */
00187    
00188    AST_NONSTANDARD_APP_ARGS(args1, data, '?');
00189    AST_NONSTANDARD_APP_ARGS(args2, args1.remainder, ':');
00190 
00191    if (ast_strlen_zero(args1.expr) || !(args2.iftrue || args2.iffalse)) {
00192       ast_log(LOG_WARNING, "Syntax IF(<expr>?[<true>][:<false>])  (expr must be non-null, and either <true> or <false> must be non-null)\n");
00193       ast_log(LOG_WARNING, "      In this case, <expr>='%s', <true>='%s', and <false>='%s'\n", args1.expr, args2.iftrue, args2.iffalse);
00194       return -1;
00195    }
00196 
00197    args1.expr = ast_strip(args1.expr);
00198    if (args2.iftrue)
00199       args2.iftrue = ast_strip(args2.iftrue);
00200    if (args2.iffalse)
00201       args2.iffalse = ast_strip(args2.iffalse);
00202 
00203    ast_copy_string(buf, pbx_checkcondition(args1.expr) ? (S_OR(args2.iftrue, "")) : (S_OR(args2.iffalse, "")), len);
00204 
00205    return 0;
00206 }
00207 
00208 static int set(struct ast_channel *chan, const char *cmd, char *data, char *buf,
00209           size_t len)
00210 {
00211    char *varname;
00212    char *val;
00213 
00214    varname = strsep(&data, "=");
00215    val = data;
00216 
00217    if (ast_strlen_zero(varname) || !val) {
00218       ast_log(LOG_WARNING, "Syntax SET(<varname>=[<value>])\n");
00219       return -1;
00220    }
00221 
00222    varname = ast_strip(varname);
00223    val = ast_strip(val);
00224    pbx_builtin_setvar_helper(chan, varname, val);
00225    ast_copy_string(buf, val, len);
00226 
00227    return 0;
00228 }
00229 
00230 static int set2(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **str, ssize_t len)
00231 {
00232    if (len > -1) {
00233       ast_str_make_space(str, len == 0 ? strlen(data) : len);
00234    }
00235    return set(chan, cmd, data, ast_str_buffer(*str), ast_str_size(*str));
00236 }
00237 
00238 static int import_helper(struct ast_channel *chan, const char *cmd, char *data, char *buf, struct ast_str **str, ssize_t len)
00239 {
00240    AST_DECLARE_APP_ARGS(args,
00241       AST_APP_ARG(channel);
00242       AST_APP_ARG(varname);
00243    );
00244    AST_STANDARD_APP_ARGS(args, data);
00245    if (buf) {
00246       *buf = '\0';
00247    }
00248 
00249    if (!ast_strlen_zero(args.varname)) {
00250       struct ast_channel *chan2;
00251 
00252       if ((chan2 = ast_channel_get_by_name(args.channel))) {
00253          char *s = ast_alloca(strlen(args.varname) + 4);
00254          sprintf(s, "${%s}", args.varname);
00255          ast_channel_lock(chan2);
00256          if (buf) {
00257             pbx_substitute_variables_helper(chan2, s, buf, len);
00258          } else {
00259             ast_str_substitute_variables(str, len, chan2, s);
00260          }
00261          ast_channel_unlock(chan2);
00262          chan2 = ast_channel_unref(chan2);
00263       }
00264    }
00265 
00266    return 0;
00267 }
00268 
00269 static int import_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
00270 {
00271    return import_helper(chan, cmd, data, buf, NULL, len);
00272 }
00273 
00274 static int import_read2(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **str, ssize_t len)
00275 {
00276    return import_helper(chan, cmd, data, NULL, str, len);
00277 }
00278 
00279 static struct ast_custom_function isnull_function = {
00280    .name = "ISNULL",
00281    .read = isnull,
00282    .read_max = 2,
00283 };
00284 
00285 static struct ast_custom_function set_function = {
00286    .name = "SET",
00287    .read = set,
00288    .read2 = set2,
00289 };
00290 
00291 static struct ast_custom_function exists_function = {
00292    .name = "EXISTS",
00293    .read = exists,
00294    .read_max = 2,
00295 };
00296 
00297 static struct ast_custom_function if_function = {
00298    .name = "IF",
00299    .read = acf_if,
00300 };
00301 
00302 static struct ast_custom_function if_time_function = {
00303    .name = "IFTIME",
00304    .read = iftime,
00305 };
00306 
00307 static struct ast_custom_function import_function = {
00308    .name = "IMPORT",
00309    .read = import_read,
00310    .read2 = import_read2,
00311 };
00312 
00313 static int unload_module(void)
00314 {
00315    int res = 0;
00316 
00317    res |= ast_custom_function_unregister(&isnull_function);
00318    res |= ast_custom_function_unregister(&set_function);
00319    res |= ast_custom_function_unregister(&exists_function);
00320    res |= ast_custom_function_unregister(&if_function);
00321    res |= ast_custom_function_unregister(&if_time_function);
00322    res |= ast_custom_function_unregister(&import_function);
00323 
00324    return res;
00325 }
00326 
00327 static int load_module(void)
00328 {
00329    int res = 0;
00330 
00331    res |= ast_custom_function_register(&isnull_function);
00332    res |= ast_custom_function_register(&set_function);
00333    res |= ast_custom_function_register(&exists_function);
00334    res |= ast_custom_function_register(&if_function);
00335    res |= ast_custom_function_register(&if_time_function);
00336    res |= ast_custom_function_register(&import_function);
00337 
00338    return res;
00339 }
00340 
00341 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Logical dialplan functions");

Generated on Thu Apr 16 06:27:35 2015 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6