func_logic.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. /*
  2. * Asterisk -- An open source telephony toolkit.
  3. *
  4. * Copyright (C) 1999 - 2006, Digium, Inc.
  5. * Portions Copyright (C) 2005, Anthony Minessale II
  6. *
  7. * See http://www.asterisk.org for more information about
  8. * the Asterisk project. Please do not directly contact
  9. * any of the maintainers of this project for assistance;
  10. * the project provides a web site, mailing lists and IRC
  11. * channels for your use.
  12. *
  13. * This program is free software, distributed under the terms of
  14. * the GNU General Public License Version 2. See the LICENSE file
  15. * at the top of the source tree.
  16. */
  17. /*! \file
  18. *
  19. * \brief Conditional logic dialplan functions
  20. *
  21. * \author Anthony Minessale II
  22. *
  23. * \ingroup functions
  24. */
  25. #include "asterisk.h"
  26. ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
  27. #include "asterisk/module.h"
  28. #include "asterisk/channel.h"
  29. #include "asterisk/pbx.h"
  30. #include "asterisk/utils.h"
  31. #include "asterisk/app.h"
  32. static int isnull(struct ast_channel *chan, const char *cmd, char *data,
  33. char *buf, size_t len)
  34. {
  35. strcpy(buf, data && *data ? "0" : "1");
  36. return 0;
  37. }
  38. static int exists(struct ast_channel *chan, const char *cmd, char *data, char *buf,
  39. size_t len)
  40. {
  41. strcpy(buf, data && *data ? "1" : "0");
  42. return 0;
  43. }
  44. static int iftime(struct ast_channel *chan, const char *cmd, char *data, char *buf,
  45. size_t len)
  46. {
  47. struct ast_timing timing;
  48. char *expr;
  49. char *iftrue;
  50. char *iffalse;
  51. data = ast_strip_quoted(data, "\"", "\"");
  52. expr = strsep(&data, "?");
  53. iftrue = strsep(&data, ":");
  54. iffalse = data;
  55. if (ast_strlen_zero(expr) || !(iftrue || iffalse)) {
  56. ast_log(LOG_WARNING,
  57. "Syntax IFTIME(<timespec>?[<true>][:<false>])\n");
  58. return -1;
  59. }
  60. if (!ast_build_timing(&timing, expr)) {
  61. ast_log(LOG_WARNING, "Invalid Time Spec.\n");
  62. return -1;
  63. }
  64. if (iftrue)
  65. iftrue = ast_strip_quoted(iftrue, "\"", "\"");
  66. if (iffalse)
  67. iffalse = ast_strip_quoted(iffalse, "\"", "\"");
  68. ast_copy_string(buf, ast_check_timing(&timing) ? S_OR(iftrue, "") : S_OR(iffalse, ""), len);
  69. return 0;
  70. }
  71. static int acf_if(struct ast_channel *chan, const char *cmd, char *data, char *buf,
  72. size_t len)
  73. {
  74. AST_DECLARE_APP_ARGS(args1,
  75. AST_APP_ARG(expr);
  76. AST_APP_ARG(remainder);
  77. );
  78. AST_DECLARE_APP_ARGS(args2,
  79. AST_APP_ARG(iftrue);
  80. AST_APP_ARG(iffalse);
  81. );
  82. args2.iftrue = args2.iffalse = NULL; /* you have to set these, because if there is nothing after the '?',
  83. then args1.remainder will be NULL, not a pointer to a null string, and
  84. then any garbage in args2.iffalse will not be cleared, and you'll crash.
  85. -- and if you mod the ast_app_separate_args func instead, you'll really
  86. mess things up badly, because the rest of everything depends on null args
  87. for non-specified stuff. */
  88. AST_NONSTANDARD_APP_ARGS(args1, data, '?');
  89. AST_NONSTANDARD_APP_ARGS(args2, args1.remainder, ':');
  90. if (ast_strlen_zero(args1.expr) || !(args2.iftrue || args2.iffalse)) {
  91. ast_log(LOG_WARNING, "Syntax IF(<expr>?[<true>][:<false>]) (expr must be non-null, and either <true> or <false> must be non-null)\n");
  92. ast_log(LOG_WARNING, " In this case, <expr>='%s', <true>='%s', and <false>='%s'\n", args1.expr, args2.iftrue, args2.iffalse);
  93. return -1;
  94. }
  95. args1.expr = ast_strip(args1.expr);
  96. if (args2.iftrue)
  97. args2.iftrue = ast_strip(args2.iftrue);
  98. if (args2.iffalse)
  99. args2.iffalse = ast_strip(args2.iffalse);
  100. ast_copy_string(buf, pbx_checkcondition(args1.expr) ? (S_OR(args2.iftrue, "")) : (S_OR(args2.iffalse, "")), len);
  101. return 0;
  102. }
  103. static int set(struct ast_channel *chan, const char *cmd, char *data, char *buf,
  104. size_t len)
  105. {
  106. char *varname;
  107. char *val;
  108. varname = strsep(&data, "=");
  109. val = data;
  110. if (ast_strlen_zero(varname) || !val) {
  111. ast_log(LOG_WARNING, "Syntax SET(<varname>=[<value>])\n");
  112. return -1;
  113. }
  114. varname = ast_strip(varname);
  115. val = ast_strip(val);
  116. pbx_builtin_setvar_helper(chan, varname, val);
  117. ast_copy_string(buf, val, len);
  118. return 0;
  119. }
  120. static int acf_import(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
  121. {
  122. AST_DECLARE_APP_ARGS(args,
  123. AST_APP_ARG(channel);
  124. AST_APP_ARG(varname);
  125. );
  126. AST_STANDARD_APP_ARGS(args, data);
  127. buf[0] = 0;
  128. if (!ast_strlen_zero(args.varname)) {
  129. struct ast_channel *chan2 = ast_get_channel_by_name_locked(args.channel);
  130. if (chan2) {
  131. char *s = alloca(strlen(args.varname) + 4);
  132. if (s) {
  133. sprintf(s, "${%s}", args.varname);
  134. pbx_substitute_variables_helper(chan2, s, buf, len);
  135. }
  136. ast_channel_unlock(chan2);
  137. }
  138. }
  139. return 0;
  140. }
  141. static struct ast_custom_function isnull_function = {
  142. .name = "ISNULL",
  143. .synopsis = "NULL Test: Returns 1 if NULL or 0 otherwise",
  144. .syntax = "ISNULL(<data>)",
  145. .read = isnull,
  146. };
  147. static struct ast_custom_function set_function = {
  148. .name = "SET",
  149. .synopsis = "SET assigns a value to a channel variable",
  150. .syntax = "SET(<varname>=[<value>])",
  151. .read = set,
  152. };
  153. static struct ast_custom_function exists_function = {
  154. .name = "EXISTS",
  155. .synopsis = "Existence Test: Returns 1 if exists, 0 otherwise",
  156. .syntax = "EXISTS(<data>)",
  157. .read = exists,
  158. };
  159. static struct ast_custom_function if_function = {
  160. .name = "IF",
  161. .synopsis =
  162. "Conditional: Returns the data following '?' if true, else the data following ':'",
  163. .syntax = "IF(<expr>?[<true>][:<false>])",
  164. .read = acf_if,
  165. };
  166. static struct ast_custom_function if_time_function = {
  167. .name = "IFTIME",
  168. .synopsis =
  169. "Temporal Conditional: Returns the data following '?' if true, else the data following ':'",
  170. .syntax = "IFTIME(<timespec>?[<true>][:<false>])",
  171. .read = iftime,
  172. };
  173. static struct ast_custom_function import_function = {
  174. .name = "IMPORT",
  175. .synopsis =
  176. "Retrieve the value of a variable from another channel\n",
  177. .syntax = "IMPORT(channel,variable)",
  178. .read = acf_import,
  179. };
  180. static int unload_module(void)
  181. {
  182. int res = 0;
  183. res |= ast_custom_function_unregister(&isnull_function);
  184. res |= ast_custom_function_unregister(&set_function);
  185. res |= ast_custom_function_unregister(&exists_function);
  186. res |= ast_custom_function_unregister(&if_function);
  187. res |= ast_custom_function_unregister(&if_time_function);
  188. res |= ast_custom_function_unregister(&import_function);
  189. return res;
  190. }
  191. static int load_module(void)
  192. {
  193. int res = 0;
  194. res |= ast_custom_function_register(&isnull_function);
  195. res |= ast_custom_function_register(&set_function);
  196. res |= ast_custom_function_register(&exists_function);
  197. res |= ast_custom_function_register(&if_function);
  198. res |= ast_custom_function_register(&if_time_function);
  199. res |= ast_custom_function_register(&import_function);
  200. return res;
  201. }
  202. AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Logical dialplan functions");