77933b6dbf2d4efd57447f872ddfeba871427f52
[asterisk/asterisk.git] / funcs / func_strings.c
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
19 /*
20  *
21  * String manipulation dialplan functions
22  * 
23  */
24
25 #include <stdlib.h>
26 #include <string.h>
27 #include <sys/types.h>
28 #include <regex.h>
29
30 #include "asterisk.h"
31
32 /* ASTERISK_FILE_VERSION(__FILE__, "$Revision$") */
33
34 #include "asterisk/channel.h"
35 #include "asterisk/pbx.h"
36 #include "asterisk/logger.h"
37 #include "asterisk/utils.h"
38 #include "asterisk/app.h"
39 #include "asterisk/localtime.h"
40
41 static char *function_fieldqty(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
42 {
43         char *varname, *varval, workspace[256];
44         char *delim = ast_strdupa(data);
45         int fieldcount = 0;
46
47         if (delim) {
48                 varname = strsep(&delim, "|");
49                 pbx_retrieve_variable(chan, varname, &varval, workspace, sizeof(workspace), NULL);
50                 while (strsep(&varval, delim))
51                         fieldcount++;
52                 snprintf(buf, len, "%d", fieldcount);
53         } else {
54                 ast_log(LOG_ERROR, "Out of memory\n");
55                 strncpy(buf, "1", len);
56         }
57         return buf;
58 }
59
60 #ifndef BUILTIN_FUNC
61 static
62 #endif
63 struct ast_custom_function fieldqty_function = {
64         .name = "FIELDQTY",
65         .synopsis = "Count the fields, with an arbitrary delimiter",
66         .syntax = "FIELDQTY(<varname>,<delim>)",
67         .read = function_fieldqty,
68 };
69
70 static char *builtin_function_regex(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len) 
71 {
72         char *ret_true = "1", *ret_false = "0", *ret;
73         char *arg, *earg, *tmp, errstr[256] = "";
74         int errcode;
75         regex_t regexbuf;
76
77         ret = ret_false; /* convince me otherwise */
78         tmp = ast_strdupa(data);
79         if (tmp) {
80                 /* Regex in quotes */
81                 arg = strchr(tmp, '"');
82                 if (arg) {
83                         arg++;
84                         earg = strrchr(arg, '"');
85                         if (earg) {
86                                 *earg = '\0';
87                         }
88                 } else {
89                         arg = tmp;
90                 }
91
92                 if ((errcode = regcomp(&regexbuf, arg, REG_EXTENDED | REG_NOSUB))) {
93                         regerror(errcode, &regexbuf, errstr, sizeof(errstr));
94                         ast_log(LOG_WARNING, "Malformed input %s(%s): %s\n", cmd, data, errstr);
95                         ret = NULL;
96                 } else {
97                         ret = regexec(&regexbuf, data, 0, NULL, 0) ? ret_false : ret_true;
98                 }
99                 regfree(&regexbuf);
100         } else {
101                 ast_log(LOG_ERROR, "Out of memory in %s(%s)\n", cmd, data);
102         }
103
104         return ret;
105 }
106
107 #ifndef BUILTIN_FUNC
108 static
109 #endif
110 struct ast_custom_function regex_function = {
111         .name = "REGEX",
112         .synopsis = "Regular Expression: Returns 1 if data matches regular expression.",
113         .syntax = "REGEX(\"<regular expression>\" <data>)",
114         .read = builtin_function_regex,
115 };
116
117 static char *builtin_function_len(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len) 
118 {
119         int length = 0;
120         if (data) {
121                 length = strlen(data);
122         }
123         snprintf(buf, len, "%d", length);
124         return buf;
125 }
126
127 #ifndef BUILTIN_FUNC
128 static
129 #endif
130 struct ast_custom_function len_function = {
131         .name = "LEN",
132         .synopsis = "Returns the length of the argument given",
133         .syntax = "LEN(<string>)",
134         .read = builtin_function_len,
135 };
136
137 static char *acf_strftime(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len) 
138 {
139         char *format, *epoch, *timezone;
140         long epochi;
141         struct tm time;
142
143         if (data) {
144                 format = ast_strdupa(data);
145                 if (format) {
146                         epoch = strsep(&format, "|");
147                         timezone = strsep(&format, "|");
148
149                         if (epoch && !ast_strlen_zero(epoch) && sscanf(epoch, "%ld", &epochi) == 1) {
150                         } else {
151                                 struct timeval tv = ast_tvnow();
152                                 epochi = tv.tv_sec;
153                         }
154
155                         ast_localtime(&epochi, &time, timezone);
156
157                         if (!format) {
158                                 format = "%c";
159                         }
160
161                         buf[0] = '\0';
162                         if (! strftime(buf, len, format, &time)) {
163                                 ast_log(LOG_WARNING, "C function strftime() output nothing?!!\n");
164                         }
165                         buf[len - 1] = '\0';
166
167                         return buf;
168                 } else {
169                         ast_log(LOG_ERROR, "Out of memory\n");
170                 }
171         } else {
172                 ast_log(LOG_ERROR, "Asterisk function STRFTIME() requires an argument.\n");
173         }
174         return "";
175 }
176
177 #ifndef BUILTIN_FUNC
178 static
179 #endif
180 struct ast_custom_function strftime_function = {
181         .name = "STRFTIME",
182         .synopsis = "Returns the current date/time in a specified format.",
183         .syntax = "STRFTIME([<epoch>][,[timezone][,format]])",
184         .read = acf_strftime,
185 };
186
187 static char *function_eval(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len) 
188 {
189         if (!data || ast_strlen_zero(data)) {
190                 ast_log(LOG_WARNING, "EVAL requires an argument: EVAL(<variable>)\n");
191                 return buf;
192         }
193         
194         pbx_substitute_variables_helper(chan, data, buf, len - 1);
195
196         return buf;
197 }
198
199 #ifndef BUILTIN_FUNC
200 static
201 #endif
202 struct ast_custom_function eval_function = {
203         .name = "EVAL",
204         .synopsis = "Evaluate stored variables.",
205         .syntax = "EVAL(<variable>)",
206         .desc = "Using EVAL basically causes a string to be evaluated twice.\n"
207                 "When a variable or expression is in the dialplan, it will be\n"
208                 "evaluated at runtime. However, if the result of the evaluation\n"
209                 "is in fact a variable or expression, using EVAL will have it\n"
210                 "evaluated a second time. For example, if the variable ${MYVAR}\n"
211                 "contains \"${OTHERVAR}\", then the result of putting ${EVAL(${MYVAR})}\n"
212                 "in the dialplan will be the contents of the variable, OTHERVAR.\n"
213                 "Normally, by just putting ${MYVAR} in the dialplan, you would be\n"
214                 "left with \"${OTHERVAR}\".\n", 
215         .read = function_eval,
216 };
217