func_strings.c 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. /*
  2. * Asterisk -- An open source telephony toolkit.
  3. *
  4. * Copyright (C) 2005, Digium, Inc.
  5. * Portions Copyright (C) 2005, Tilghman Lesher. All rights reserved.
  6. * Portions Copyright (C) 2005, Anthony Minessale II
  7. *
  8. * See http://www.asterisk.org for more information about
  9. * the Asterisk project. Please do not directly contact
  10. * any of the maintainers of this project for assistance;
  11. * the project provides a web site, mailing lists and IRC
  12. * channels for your use.
  13. *
  14. * This program is free software, distributed under the terms of
  15. * the GNU General Public License Version 2. See the LICENSE file
  16. * at the top of the source tree.
  17. */
  18. /*! \file
  19. *
  20. * \brief String manipulation dialplan functions
  21. *
  22. */
  23. #include <stdlib.h>
  24. #include <stdio.h>
  25. #include <string.h>
  26. #include <sys/types.h>
  27. #include <regex.h>
  28. #include "asterisk.h"
  29. /* ASTERISK_FILE_VERSION(__FILE__, "$Revision$") */
  30. #include "asterisk/channel.h"
  31. #include "asterisk/pbx.h"
  32. #include "asterisk/logger.h"
  33. #include "asterisk/utils.h"
  34. #include "asterisk/app.h"
  35. #include "asterisk/localtime.h"
  36. static char *function_fieldqty(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
  37. {
  38. char *varname, *varval, workspace[256];
  39. char *delim = ast_strdupa(data);
  40. int fieldcount = 0;
  41. if (delim) {
  42. varname = strsep(&delim, "|");
  43. pbx_retrieve_variable(chan, varname, &varval, workspace, sizeof(workspace), NULL);
  44. while (strsep(&varval, delim))
  45. fieldcount++;
  46. snprintf(buf, len, "%d", fieldcount);
  47. } else {
  48. ast_log(LOG_ERROR, "Out of memory\n");
  49. strncpy(buf, "1", len);
  50. }
  51. return buf;
  52. }
  53. #ifndef BUILTIN_FUNC
  54. static
  55. #endif
  56. struct ast_custom_function fieldqty_function = {
  57. .name = "FIELDQTY",
  58. .synopsis = "Count the fields, with an arbitrary delimiter",
  59. .syntax = "FIELDQTY(<varname>,<delim>)",
  60. .read = function_fieldqty,
  61. };
  62. static char *builtin_function_regex(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
  63. {
  64. char *arg, *earg = NULL, *tmp, errstr[256] = "";
  65. int errcode;
  66. regex_t regexbuf;
  67. ast_copy_string(buf, "0", len);
  68. tmp = ast_strdupa(data);
  69. if (!tmp) {
  70. ast_log(LOG_ERROR, "Out of memory in %s(%s)\n", cmd, data);
  71. return buf;
  72. }
  73. /* Regex in quotes */
  74. arg = strchr(tmp, '"');
  75. if (arg) {
  76. arg++;
  77. earg = strrchr(arg, '"');
  78. if (earg) {
  79. *earg++ = '\0';
  80. /* Skip over any spaces before the data we are checking */
  81. while (*earg == ' ')
  82. earg++;
  83. }
  84. } else {
  85. arg = tmp;
  86. }
  87. if ((errcode = regcomp(&regexbuf, arg, REG_EXTENDED | REG_NOSUB))) {
  88. regerror(errcode, &regexbuf, errstr, sizeof(errstr));
  89. ast_log(LOG_WARNING, "Malformed input %s(%s): %s\n", cmd, data, errstr);
  90. } else {
  91. if (!regexec(&regexbuf, earg ? earg : "", 0, NULL, 0))
  92. ast_copy_string(buf, "1", len);
  93. }
  94. regfree(&regexbuf);
  95. return buf;
  96. }
  97. #ifndef BUILTIN_FUNC
  98. static
  99. #endif
  100. struct ast_custom_function regex_function = {
  101. .name = "REGEX",
  102. .synopsis = "Regular Expression: Returns 1 if data matches regular expression.",
  103. .syntax = "REGEX(\"<regular expression>\" <data>)",
  104. .read = builtin_function_regex,
  105. };
  106. static char *builtin_function_len(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
  107. {
  108. int length = 0;
  109. if (data) {
  110. length = strlen(data);
  111. }
  112. snprintf(buf, len, "%d", length);
  113. return buf;
  114. }
  115. #ifndef BUILTIN_FUNC
  116. static
  117. #endif
  118. struct ast_custom_function len_function = {
  119. .name = "LEN",
  120. .synopsis = "Returns the length of the argument given",
  121. .syntax = "LEN(<string>)",
  122. .read = builtin_function_len,
  123. };
  124. static char *acf_strftime(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
  125. {
  126. char *format, *epoch, *timezone = NULL;
  127. long epochi;
  128. struct tm time;
  129. buf[0] = '\0';
  130. if (!data) {
  131. ast_log(LOG_ERROR, "Asterisk function STRFTIME() requires an argument.\n");
  132. return buf;
  133. }
  134. format = ast_strdupa(data);
  135. if (!format) {
  136. ast_log(LOG_ERROR, "Out of memory\n");
  137. return buf;
  138. }
  139. epoch = strsep(&format, "|");
  140. timezone = strsep(&format, "|");
  141. if (ast_strlen_zero(epoch) || !sscanf(epoch, "%ld", &epochi)) {
  142. struct timeval tv = ast_tvnow();
  143. epochi = tv.tv_sec;
  144. }
  145. ast_localtime(&epochi, &time, timezone);
  146. if (!format) {
  147. format = "%c";
  148. }
  149. if (!strftime(buf, len, format, &time)) {
  150. ast_log(LOG_WARNING, "C function strftime() output nothing?!!\n");
  151. }
  152. buf[len - 1] = '\0';
  153. return buf;
  154. }
  155. #ifndef BUILTIN_FUNC
  156. static
  157. #endif
  158. struct ast_custom_function strftime_function = {
  159. .name = "STRFTIME",
  160. .synopsis = "Returns the current date/time in a specified format.",
  161. .syntax = "STRFTIME([<epoch>][,[timezone][,format]])",
  162. .read = acf_strftime,
  163. };
  164. static char *function_eval(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
  165. {
  166. memset(buf, 0, len);
  167. if (ast_strlen_zero(data)) {
  168. ast_log(LOG_WARNING, "EVAL requires an argument: EVAL(<string>)\n");
  169. return buf;
  170. }
  171. pbx_substitute_variables_helper(chan, data, buf, len - 1);
  172. return buf;
  173. }
  174. #ifndef BUILTIN_FUNC
  175. static
  176. #endif
  177. struct ast_custom_function eval_function = {
  178. .name = "EVAL",
  179. .synopsis = "Evaluate stored variables.",
  180. .syntax = "EVAL(<variable>)",
  181. .desc = "Using EVAL basically causes a string to be evaluated twice.\n"
  182. "When a variable or expression is in the dialplan, it will be\n"
  183. "evaluated at runtime. However, if the result of the evaluation\n"
  184. "is in fact a variable or expression, using EVAL will have it\n"
  185. "evaluated a second time. For example, if the variable ${MYVAR}\n"
  186. "contains \"${OTHERVAR}\", then the result of putting ${EVAL(${MYVAR})}\n"
  187. "in the dialplan will be the contents of the variable, OTHERVAR.\n"
  188. "Normally, by just putting ${MYVAR} in the dialplan, you would be\n"
  189. "left with \"${OTHERVAR}\".\n",
  190. .read = function_eval,
  191. };