Asterisk - The Open Source Telephony Project  18.5.0
func_evalexten.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2021, Naveen Albert
5  *
6  * See http://www.asterisk.org for more information about
7  * the Asterisk project. Please do not directly contact
8  * any of the maintainers of this project for assistance;
9  * the project provides a web site, mailing lists and IRC
10  * channels for your use.
11  *
12  * This program is free software, distributed under the terms of
13  * the GNU General Public License Version 2. See the LICENSE file
14  * at the top of the source tree.
15  */
16 
17 /*! \file
18  *
19  * \brief Dialplan extension evaluation function
20  *
21  * \author Naveen Albert <[email protected]>
22  *
23  * \ingroup functions
24  */
25 
26 /*** MODULEINFO
27  <support_level>extended</support_level>
28  ***/
29 
30 #include "asterisk.h"
31 
32 #include "asterisk/module.h"
33 #include "asterisk/channel.h"
34 #include "asterisk/pbx.h"
35 #include "asterisk/utils.h"
36 #include "asterisk/app.h"
37 
38 /*** DOCUMENTATION
39  <function name="EVAL_EXTEN" language="en_US">
40  <synopsis>
41  Evaluates the contents of a dialplan extension and returns it as a string.
42  </synopsis>
43  <syntax>
44  <parameter name="context" />
45  <parameter name="extensions" />
46  <parameter name="priority" required="true" />
47  </syntax>
48  <description>
49  <para>The EVAL_EXTEN function looks up a dialplan entry by context,extension,priority,
50  evaluates the contents of a Return statement to resolve any variable or function
51  references, and returns the result as a string.</para>
52  <para>You can use this function to create simple user-defined lookup tables or
53  user-defined functions.</para>
54  <example title="Custom dialplan functions">
55  [call-types]
56  exten => _1NNN,1,Return(internal)
57  exten => _NXXNXXXXXX,1,Return(external)
58 
59  [udf]
60  exten => calleridlen,1,Return(${LEN(${CALLERID(num)})})
61 
62  [default]
63  exten => _X!,1,Verbose(Call type ${EVAL_EXTEN(call-types,${EXTEN},1)} - ${EVAL_EXTEN(udf,calleridlen,1)})
64  </example>
65  <para>Any variables in the evaluated data will be resolved in the context of
66  that extension. For example, <literal>${EXTEN}</literal> would refer to the
67  EVAL_EXTEN extension, not the extension in the context invoking the function.
68  This behavior is similar to other applications, e.g. <literal>Gosub</literal>.</para>
69  <example title="Choosing which prompt to use">
70  same => n,Read(input,${EVAL_EXTEN(prompts,${CALLERID(num)},1)})
71 
72  [prompts]
73  exten => _X!,1,Return(default)
74  exten => _20X,1,Return(welcome)
75  exten => _2XX,1,Return(${DB(promptsettings/${EXTEN})})
76  </example>
77  <para>Extensions on which EVAL_EXTEN is invoked are not different from other
78  extensions. However, the application at that extension is not executed.
79  Only the application data is parsed and evaluated.</para>
80  <para>A limitation of this function is that the application at the specified
81  extension isn't actually executed, and thus unlike a Gosub, you can't pass
82  arguments in the EVAL_EXTEN function.</para>
83  </description>
84  <see-also>
85  <ref type="function">EVAL</ref>
86  </see-also>
87  </function>
88  ***/
89 
90 static int get_extension_data(char *name, int namesize, struct ast_channel *c,
91  const char *context, const char *exten, int priority)
92 {
93  struct ast_exten *e;
94  struct pbx_find_info q = { .stacklen = 0 }; /* the rest is set in pbx_find_context */
96  e = pbx_find_extension(c, NULL, &q, context, exten, priority, NULL, "", E_MATCH);
98  if (e) {
99  if (name) {
100  const char *tmp = ast_get_extension_app_data(e);
101  if (tmp) {
102  ast_copy_string(name, tmp, namesize);
103  }
104  }
105  return 0;
106  }
107  return -1;
108 }
109 
110 static int eval_exten_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
111 {
112  char *exten, *pri, *context, *parse;
113  int ipri;
114  const char *realcontext, *realexten;
115  int realpriority;
116  char tmpbuf[len];
117 
118  if (ast_strlen_zero(data)) {
119  ast_log(LOG_WARNING, "The EVAL_EXTEN function requires an extension\n");
120  return -1;
121  }
122 
123  parse = ast_strdupa(data);
124  /* Split context,exten,pri */
125  context = strsep(&parse, ",");
126  exten = strsep(&parse, ",");
127  pri = strsep(&parse, ",");
128  if (!exten) {
129  /* Only a priority in this one */
130  pri = context;
131  exten = NULL;
132  context = NULL;
133  } else if (!pri) {
134  /* Only an extension and priority in this one */
135  pri = exten;
136  exten = context;
137  context = NULL;
138  }
139  ast_debug(1, "Context, extension, priority: %s, %s, %s\n", context, exten, pri);
140  if (sscanf(pri, "%30d", &ipri) != 1) {
141  ipri = ast_findlabel_extension(chan, context ? context : ast_channel_context(chan),
142  exten ? exten : ast_channel_exten(chan), pri,
143  S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL));
144  if (ipri < 1) {
145  ast_log(LOG_WARNING, "Priority '%s' must be a number > 0, or valid label\n", pri);
146  return -1;
147  }
148  }
149  ast_debug(1, "Context, extension, priority: %s, %s, %d\n", context, exten, ipri);
150 
151  ast_channel_lock(chan);
152  realcontext = ast_strdupa(ast_channel_context(chan));
153  realexten = ast_strdupa(ast_channel_exten(chan));
154  realpriority = ast_channel_priority(chan);
155  ast_channel_unlock(chan);
156  if (ast_strlen_zero(exten)) {
157  exten = ast_strdupa(realexten);
158  }
159  if (ast_strlen_zero(context)) {
160  context = ast_strdupa(realcontext);
161  }
162 
163  if (get_extension_data(tmpbuf, len, chan, context, exten, ipri)) {
164  return -1; /* EVAL_EXTEN failed */
165  }
166  /* Substitute variables now, using the location of the evaluated extension */
167  /* strdupa required or we'll just overwrite what we read when we set these */
168  ast_channel_lock(chan);
169  ast_channel_context_set(chan, context);
170  ast_channel_exten_set(chan, exten);
171  ast_channel_priority_set(chan, ipri);
172  ast_channel_unlock(chan);
173 
174  pbx_substitute_variables_helper(chan, tmpbuf, buf, len);
175 
176  ast_channel_lock(chan);
177  ast_channel_context_set(chan, realcontext);
178  ast_channel_exten_set(chan, realexten);
179  ast_channel_priority_set(chan, realpriority);
180  ast_channel_unlock(chan);
181 
182  return 0;
183 }
184 
186  .name = "EVAL_EXTEN",
187  .read = eval_exten_read,
188 };
189 
190 static int unload_module(void)
191 {
192  return ast_custom_function_unregister(&eval_exten_function);
193 }
194 
195 static int load_module(void)
196 {
197  return ast_custom_function_register(&eval_exten_function);
198 }
199 
200 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Extension evaluation function");
const char * name
Definition: pbx.h:119
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
static int unload_module(void)
#define ast_channel_lock(chan)
Definition: channel.h:2945
static char exten[AST_MAX_EXTENSION]
Definition: chan_alsa.c:118
Main Channel structure associated with a channel.
#define AST_MODULE_INFO_STANDARD(keystr, desc)
Definition: module.h:567
Asterisk main include file. File version handling, generic pbx functions.
ast_exten: An extension The dialplan is saved as a linked list with each context having it&#39;s own link...
Definition: pbx.c:237
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
#define LOG_WARNING
Definition: logger.h:274
static int tmp()
Definition: bt_open.c:389
static struct ast_custom_function eval_exten_function
void * ast_get_extension_app_data(struct ast_exten *e)
Definition: pbx.c:8601
int ast_rdlock_contexts(void)
Read locks the context list.
Definition: pbx.c:8507
static struct test_val c
#define NULL
Definition: resample.c:96
static int priority
int ast_channel_priority(const struct ast_channel *chan)
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
Utility functions.
#define ast_strlen_zero(foo)
Definition: strings.h:52
Number structure.
Definition: app_followme.c:154
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
General Asterisk PBX channel definitions.
const char * data
Definition: extconf.h:241
Data structure associated with a custom dialplan function.
Definition: pbx.h:118
#define S_COR(a, b, c)
returns the equivalent of logic or for strings, with an additional boolean check: second one if not e...
Definition: strings.h:85
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
static int get_extension_data(char *name, int namesize, struct ast_channel *c, const char *context, const char *exten, int priority)
static int eval_exten_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
const char * ast_channel_exten(const struct ast_channel *chan)
Core PBX routines and definitions.
int ast_unlock_contexts(void)
Unlocks contexts.
Definition: pbx.c:8512
int ast_findlabel_extension(struct ast_channel *c, const char *context, const char *exten, const char *label, const char *callerid)
Find the priority of an extension that has the specified label.
Definition: pbx.c:4184
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
#define ast_channel_unlock(chan)
Definition: channel.h:2946
static void parse(struct mgcp_request *req)
Definition: chan_mgcp.c:1872
static const char name[]
Definition: cdr_mysql.c:74
int stacklen
Definition: extconf.h:238
void ast_channel_exten_set(struct ast_channel *chan, const char *value)
char * strsep(char **str, const char *delims)
void ast_channel_context_set(struct ast_channel *chan, const char *value)
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
Definition: ael_main.c:211
const char * ast_channel_context(const struct ast_channel *chan)
static char context[AST_MAX_CONTEXT]
Definition: chan_alsa.c:116
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
void ast_channel_priority_set(struct ast_channel *chan, int value)
Asterisk module definitions.
struct ast_exten * pbx_find_extension(struct ast_channel *chan, struct ast_context *bypass, struct pbx_find_info *q, const char *context, const char *exten, int priority, const char *label, const char *callerid, enum ext_match_t action)
Definition: ael_main.c:152
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
#define ast_custom_function_register(acf)
Register a custom function.
Definition: pbx.h:1508
static int load_module(void)