Asterisk - The Open Source Telephony Project GIT-master-754dea3
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Modules Pages
app_stack.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (c) 2004-2006 Tilghman Lesher <app_stack_v003@the-tilghman.com>.
5 *
6 * This code is released by the author with no restrictions on usage.
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/*! \file
20 *
21 * \brief Stack applications Gosub, Return, etc.
22 *
23 * \author Tilghman Lesher <app_stack_v003@the-tilghman.com>
24 *
25 * \ingroup applications
26 */
27
28/*** MODULEINFO
29 <use type="module">res_agi</use>
30 <support_level>core</support_level>
31 ***/
32
33#include "asterisk.h"
34
35#include "asterisk/pbx.h"
36#include "asterisk/module.h"
37#include "asterisk/app.h"
38#include "asterisk/manager.h"
39#include "asterisk/channel.h"
40#include "asterisk/agi.h"
42
43/*** DOCUMENTATION
44 <application name="Gosub" language="en_US">
45 <since>
46 <version>1.2.0</version>
47 </since>
48 <synopsis>
49 Jump to label, saving return address.
50 </synopsis>
51 <syntax>
52 <parameter name="context" documentationtype="dialplan_context" />
53 <parameter name="extension" documentationtype="dialplan_extension" />
54 <parameter name="priority" documentationtype="dialplan_priority" required="true" hasparams="optional">
55 <argument name="arg1" multiple="true" required="true" />
56 <argument name="argN" />
57 </parameter>
58 </syntax>
59 <description>
60 <para>Jumps to the label specified, saving the return address.</para>
61 </description>
62 <see-also>
63 <ref type="application">GosubIf</ref>
64 <ref type="application">Goto</ref>
65 <ref type="application">Return</ref>
66 <ref type="application">StackPop</ref>
67 </see-also>
68 </application>
69 <application name="GosubIf" language="en_US">
70 <since>
71 <version>1.2.0</version>
72 </since>
73 <synopsis>
74 Conditionally jump to label, saving return address.
75 </synopsis>
76 <syntax argsep="?">
77 <parameter name="condition" required="true" />
78 <parameter name="destination" required="true" argsep=":">
79 <argument name="labeliftrue" hasparams="optional">
80 <para>Continue at <replaceable>labeliftrue</replaceable> if the condition is true.
81 Takes the form similar to Goto() of [[context,]extension,]priority.</para>
82 <argument name="arg1" required="true" multiple="true" />
83 <argument name="argN" />
84 </argument>
85 <argument name="labeliffalse" hasparams="optional">
86 <para>Continue at <replaceable>labeliffalse</replaceable> if the condition is false.
87 Takes the form similar to Goto() of [[context,]extension,]priority.</para>
88 <argument name="arg1" required="true" multiple="true" />
89 <argument name="argN" />
90 </argument>
91 </parameter>
92 </syntax>
93 <description>
94 <para>If the condition is true, then jump to labeliftrue. If false, jumps to
95 labeliffalse, if specified. In either case, a jump saves the return point
96 in the dialplan, to be returned to with a Return.</para>
97 </description>
98 <see-also>
99 <ref type="application">Gosub</ref>
100 <ref type="application">Return</ref>
101 <ref type="function">IF</ref>
102 <ref type="application">GotoIf</ref>
103 <ref type="application">Goto</ref>
104 </see-also>
105 </application>
106 <application name="Return" language="en_US">
107 <since>
108 <version>1.2.0</version>
109 </since>
110 <synopsis>
111 Return from gosub routine.
112 </synopsis>
113 <syntax>
114 <parameter name="value">
115 <para>Return value.</para>
116 </parameter>
117 </syntax>
118 <description>
119 <para>Jumps to the last label on the stack, removing it. The return <replaceable>value</replaceable>, if
120 any, is saved in the channel variable <variable>GOSUB_RETVAL</variable>.</para>
121 </description>
122 <see-also>
123 <ref type="application">Gosub</ref>
124 <ref type="application">StackPop</ref>
125 </see-also>
126 </application>
127 <application name="StackPop" language="en_US">
128 <since>
129 <version>1.2.0</version>
130 </since>
131 <synopsis>
132 Remove one address from gosub stack.
133 </synopsis>
134 <syntax />
135 <description>
136 <para>Removes last label on the stack, discarding it.</para>
137 </description>
138 <see-also>
139 <ref type="application">Return</ref>
140 <ref type="application">Gosub</ref>
141 </see-also>
142 </application>
143 <function name="LOCAL" language="en_US">
144 <since>
145 <version>1.6.1.0</version>
146 </since>
147 <synopsis>
148 Manage variables local to the gosub stack frame.
149 </synopsis>
150 <syntax>
151 <parameter name="varname" required="true" />
152 </syntax>
153 <description>
154 <para>Read and write a variable local to the gosub stack frame, once we Return() it will be lost
155 (or it will go back to whatever value it had before the Gosub()).</para>
156 </description>
157 <see-also>
158 <ref type="application">Gosub</ref>
159 <ref type="application">GosubIf</ref>
160 <ref type="application">Return</ref>
161 </see-also>
162 </function>
163 <function name="LOCAL_PEEK" language="en_US">
164 <since>
165 <version>1.6.1.0</version>
166 </since>
167 <synopsis>
168 Retrieve variables hidden by the local gosub stack frame.
169 </synopsis>
170 <syntax>
171 <parameter name="n" required="true" />
172 <parameter name="varname" required="true" />
173 </syntax>
174 <description>
175 <para>Read a variable <replaceable>varname</replaceable> hidden by
176 <replaceable>n</replaceable> levels of gosub stack frames. Note that ${LOCAL_PEEK(0,foo)}
177 is the same as <variable>foo</variable>, since the value of <replaceable>n</replaceable>
178 peeks under 0 levels of stack frames; in other words, 0 is the current level. If
179 <replaceable>n</replaceable> exceeds the available number of stack frames, then an empty
180 string is returned.</para>
181 </description>
182 <see-also>
183 <ref type="application">Gosub</ref>
184 <ref type="application">GosubIf</ref>
185 <ref type="application">Return</ref>
186 </see-also>
187 </function>
188 <function name="STACK_PEEK" language="en_US">
189 <since>
190 <version>1.8.11.0</version>
191 <version>10.3.0</version>
192 </since>
193 <synopsis>
194 View info about the location which called Gosub
195 </synopsis>
196 <syntax>
197 <parameter name="n" required="true" />
198 <parameter name="which" required="true" />
199 <parameter name="suppress" required="false" />
200 </syntax>
201 <description>
202 <para>Read the calling <literal>c</literal>ontext, <literal>e</literal>xtension,
203 <literal>p</literal>riority, or <literal>l</literal>abel, as specified by
204 <replaceable>which</replaceable>, by going up <replaceable>n</replaceable> frames
205 in the Gosub stack. If <replaceable>suppress</replaceable> is true, then if the
206 number of available stack frames is exceeded, then no error message will be
207 printed.</para>
208 </description>
209 </function>
210 <agi name="gosub" language="en_US">
211 <synopsis>
212 Cause the channel to execute the specified dialplan subroutine.
213 </synopsis>
214 <syntax>
215 <parameter name="context" required="true" />
216 <parameter name="extension" required="true" />
217 <parameter name="priority" required="true" />
218 <parameter name="optional-argument" />
219 </syntax>
220 <description>
221 <para>Cause the channel to execute the specified dialplan subroutine,
222 returning to the dialplan with execution of a Return().</para>
223 </description>
224 <see-also>
225 <ref type="application">Gosub</ref>
226 </see-also>
227 </agi>
228 <managerEvent language="en_US" name="VarSet">
229 <managerEventInstance class="EVENT_FLAG_DIALPLAN">
230 <since>
231 <version>12.0.0</version>
232 </since>
233 <synopsis>Raised when a variable local to the gosub stack frame is set due to a subroutine call.</synopsis>
234 <syntax>
235 <channel_snapshot/>
236 <parameter name="Variable">
237 <para>The LOCAL variable being set.</para>
238 <note><para>The variable name will always be enclosed with
239 <literal>LOCAL()</literal></para></note>
240 </parameter>
241 <parameter name="Value">
242 <para>The new value of the variable.</para>
243 </parameter>
244 </syntax>
245 <see-also>
246 <ref type="application">Gosub</ref>
247 <ref type="agi">gosub</ref>
248 <ref type="function">LOCAL</ref>
249 <ref type="function">LOCAL_PEEK</ref>
250 </see-also>
251 </managerEventInstance>
252 </managerEvent>
253 ***/
254
255static const char app_gosub[] = "Gosub";
256static const char app_gosubif[] = "GosubIf";
257static const char app_return[] = "Return";
258static const char app_pop[] = "StackPop";
259
260static void gosub_free(void *data);
261
262static const struct ast_datastore_info stack_info = {
263 .type = "GOSUB",
264 .destroy = gosub_free,
265};
266
269 /* 100 arguments is all that we support anyway, but this will handle up to 255 */
270 unsigned char arguments;
273 /*! TRUE if the return location marks the end of a special routine. */
274 unsigned int is_special:1;
275 /*! Whether or not we were in a subroutine when this one was created */
276 unsigned int in_subroutine:1;
277 char *context;
278 char extension[0];
279};
280
282
283static int frame_set_var(struct ast_channel *chan, struct gosub_stack_frame *frame, const char *var, const char *value)
284{
285 struct ast_var_t *variables;
286 int found = 0;
287 int len;
288 RAII_VAR(char *, local_buffer, NULL, ast_free);
289
290 /* Does this variable already exist? */
291 AST_LIST_TRAVERSE(&frame->varshead, variables, entries) {
292 if (!strcmp(var, ast_var_name(variables))) {
293 found = 1;
294 break;
295 }
296 }
297
298 if (!found) {
299 if ((variables = ast_var_assign(var, ""))) {
300 AST_LIST_INSERT_HEAD(&frame->varshead, variables, entries);
301 }
303 } else {
305 }
306
307 len = 8 + strlen(var); /* LOCAL() + var */
308 local_buffer = ast_malloc(len);
309 if (!local_buffer) {
310 return 0;
311 }
312 sprintf(local_buffer, "LOCAL(%s)", var);
313 ast_channel_publish_varset(chan, local_buffer, value);
314 return 0;
315}
316
317static void gosub_release_frame(struct ast_channel *chan, struct gosub_stack_frame *frame)
318{
319 struct ast_var_t *vardata;
320
321 /* If chan is not defined, then we're calling it as part of gosub_free,
322 * and the channel variables will be deallocated anyway. Otherwise, we're
323 * just releasing a single frame, so we need to clean up the arguments for
324 * that frame, so that we re-expose the variables from the previous frame
325 * that were hidden by this one.
326 */
327 while ((vardata = AST_LIST_REMOVE_HEAD(&frame->varshead, entries))) {
328 if (chan)
330 ast_var_delete(vardata);
331 }
332
333 ast_free(frame);
334}
335
336static struct gosub_stack_frame *gosub_allocate_frame(const char *context, const char *extension, int priority, int in_subroutine, unsigned char arguments)
337{
338 struct gosub_stack_frame *new = NULL;
339 int len_extension = strlen(extension) + 1;
340 int len_context = strlen(context) + 1;
341
342 if ((new = ast_calloc(1, sizeof(*new) + len_extension + len_context))) {
343 AST_LIST_HEAD_INIT_NOLOCK(&new->varshead);
344 ast_copy_string(new->extension, extension, len_extension);
345 new->context = new->extension + len_extension;
346 ast_copy_string(new->context, context, len_context);
347 new->priority = priority;
348 new->in_subroutine = in_subroutine ? 1 : 0;
349 new->arguments = arguments;
350 }
351 return new;
352}
353
354static void gosub_free(void *data)
355{
356 struct gosub_stack_list *oldlist = data;
357 struct gosub_stack_frame *oldframe;
358
359 AST_LIST_LOCK(oldlist);
360 while ((oldframe = AST_LIST_REMOVE_HEAD(oldlist, entries))) {
361 gosub_release_frame(NULL, oldframe);
362 }
363 AST_LIST_UNLOCK(oldlist);
364 AST_LIST_HEAD_DESTROY(oldlist);
365 ast_free(oldlist);
366}
367
368static int pop_exec(struct ast_channel *chan, const char *data)
369{
370 struct ast_datastore *stack_store;
371 struct gosub_stack_frame *oldframe;
372 struct gosub_stack_list *oldlist;
373 int res = 0;
374
375 ast_channel_lock(chan);
376 if (!(stack_store = ast_channel_datastore_find(chan, &stack_info, NULL))) {
377 ast_log(LOG_WARNING, "%s called with no gosub stack allocated.\n", app_pop);
378 ast_channel_unlock(chan);
379 return 0;
380 }
381
382 oldlist = stack_store->data;
383 AST_LIST_LOCK(oldlist);
384 oldframe = AST_LIST_FIRST(oldlist);
385 if (oldframe) {
386 if (oldframe->is_special) {
387 ast_debug(1, "%s attempted to pop special return location.\n", app_pop);
388
389 /* Abort the special routine dialplan execution. Dialplan programming error. */
390 res = -1;
391 } else {
392 AST_LIST_REMOVE_HEAD(oldlist, entries);
393 gosub_release_frame(chan, oldframe);
394 }
395 } else {
396 ast_debug(1, "%s called with an empty gosub stack\n", app_pop);
397 }
398 AST_LIST_UNLOCK(oldlist);
399 ast_channel_unlock(chan);
400 return res;
401}
402
403static int return_exec(struct ast_channel *chan, const char *data)
404{
405 struct ast_datastore *stack_store;
406 struct gosub_stack_frame *oldframe;
407 struct gosub_stack_list *oldlist;
408 const char *retval = data;
409 int res = 0;
410
411 ast_channel_lock(chan);
412 if (!(stack_store = ast_channel_datastore_find(chan, &stack_info, NULL))) {
413 ast_log(LOG_ERROR, "Return without Gosub: stack is unallocated\n");
414 ast_channel_unlock(chan);
415 return -1;
416 }
417
418 oldlist = stack_store->data;
419 AST_LIST_LOCK(oldlist);
420 oldframe = AST_LIST_REMOVE_HEAD(oldlist, entries);
421 AST_LIST_UNLOCK(oldlist);
422
423 if (!oldframe) {
424 ast_log(LOG_ERROR, "Return without Gosub: stack is empty\n");
425 ast_channel_unlock(chan);
426 return -1;
427 }
428 if (oldframe->is_special) {
429 /* Exit from special routine. */
430 res = -1;
431 }
432
433 /*
434 * We cannot use ast_explicit_goto() because we MUST restore
435 * what was there before. Channels that do not have a PBX may
436 * not have the context or exten set.
437 */
438 ast_channel_context_set(chan, oldframe->context);
439 ast_channel_exten_set(chan, oldframe->extension);
441 --oldframe->priority;
442 }
443 ast_channel_priority_set(chan, oldframe->priority);
445
446 gosub_release_frame(chan, oldframe);
447
448 /* Set a return value, if any */
449 pbx_builtin_setvar_helper(chan, "GOSUB_RETVAL", S_OR(retval, ""));
450 ast_channel_unlock(chan);
451 return res;
452}
453
454/*!
455 * \internal
456 * \brief Add missing context and/or exten to Gosub application argument string.
457 * \since 11.0
458 *
459 * \param chan Channel to obtain context/exten.
460 * \param args Gosub application argument string.
461 *
462 * \details
463 * Fills in the optional context and exten from the given channel.
464 * Convert: [[context,]exten,]priority[(arg1[,...][,argN])]
465 * To: context,exten,priority[(arg1[,...][,argN])]
466 *
467 * \retval expanded Gosub argument string on success. Must be freed.
468 * \retval NULL on error.
469 *
470 * \note The parsing needs to be kept in sync with the
471 * gosub_exec() argument format.
472 */
473static const char *expand_gosub_args(struct ast_channel *chan, const char *args)
474{
475 int len;
476 char *parse;
477 char *label;
478 char *new_args;
479 const char *context;
480 const char *exten;
481 const char *pri;
482
483 /* Separate the context,exten,pri from the optional routine arguments. */
484 parse = ast_strdupa(args);
485 label = strsep(&parse, "(");
486 if (parse) {
487 char *endparen;
488
489 endparen = strrchr(parse, ')');
490 if (endparen) {
491 *endparen = '\0';
492 } else {
493 ast_log(LOG_WARNING, "Ouch. No closing paren: '%s'?\n", args);
494 }
495 }
496
497 /* Split context,exten,pri */
498 context = strsep(&label, ",");
499 exten = strsep(&label, ",");
500 pri = strsep(&label, ",");
501 if (!exten) {
502 /* Only a priority in this one */
503 pri = context;
504 exten = NULL;
505 context = NULL;
506 } else if (!pri) {
507 /* Only an extension and priority in this one */
508 pri = exten;
509 exten = context;
510 context = NULL;
511 }
512
513 ast_channel_lock(chan);
514 if (ast_strlen_zero(exten)) {
515 exten = ast_channel_exten(chan);
516 }
519 }
520 len = strlen(context) + strlen(exten) + strlen(pri) + 3;
521 if (!ast_strlen_zero(parse)) {
522 len += 2 + strlen(parse);
523 }
524 new_args = ast_malloc(len);
525 if (new_args) {
526 if (ast_strlen_zero(parse)) {
527 snprintf(new_args, len, "%s,%s,%s", context, exten, pri);
528 } else {
529 snprintf(new_args, len, "%s,%s,%s(%s)", context, exten, pri, parse);
530 }
531 }
532 ast_channel_unlock(chan);
533
534 ast_debug(4, "Gosub args:%s new_args:%s\n", args, new_args ? new_args : "");
535
536 return new_args;
537}
538
539static int gosub_exec(struct ast_channel *chan, const char *data)
540{
541 struct ast_datastore *stack_store;
542 struct gosub_stack_list *oldlist;
543 struct gosub_stack_frame *newframe;
544 struct gosub_stack_frame *lastframe;
545 char argname[15];
546 char *parse;
547 char *label;
548 char *caller_id;
549 char *orig_context;
550 char *orig_exten;
551 char *dest_context;
552 char *dest_exten;
553 int orig_in_subroutine;
554 int orig_priority;
555 int dest_priority;
556 int i;
557 int max_argc = 0;
559 AST_APP_ARG(argval)[100];
560 );
561
562 if (ast_strlen_zero(data)) {
563 ast_log(LOG_ERROR, "%s requires an argument: %s([[context,]exten,]priority[(arg1[,...][,argN])])\n", app_gosub, app_gosub);
564 return -1;
565 }
566
567 /*
568 * Separate the arguments from the label
569 *
570 * NOTE: You cannot use ast_app_separate_args for this, because
571 * '(' cannot be used as a delimiter.
572 */
573 parse = ast_strdupa(data);
574 label = strsep(&parse, "(");
575 if (parse) {
576 char *endparen;
577
578 endparen = strrchr(parse, ')');
579 if (endparen) {
580 *endparen = '\0';
581 } else {
582 ast_log(LOG_WARNING, "Ouch. No closing paren: '%s'?\n", data);
583 }
584 AST_STANDARD_RAW_ARGS(args2, parse);
585 } else {
586 args2.argc = 0;
587 }
588
589 ast_channel_lock(chan);
590 orig_context = ast_strdupa(ast_channel_context(chan));
592 orig_priority = ast_channel_priority(chan);
593 orig_in_subroutine = ast_test_flag(ast_channel_flags(chan), AST_FLAG_SUBROUTINE_EXEC);
594 ast_channel_unlock(chan);
595
596 if (ast_parseable_goto(chan, label)) {
597 ast_log(LOG_ERROR, "%s address is invalid: '%s'\n", app_gosub, data);
598 goto error_exit;
599 }
600
601 ast_channel_lock(chan);
602 dest_context = ast_strdupa(ast_channel_context(chan));
603 dest_exten = ast_strdupa(ast_channel_exten(chan));
604 dest_priority = ast_channel_priority(chan);
606 ++dest_priority;
607 }
608 caller_id = S_COR(ast_channel_caller(chan)->id.number.valid,
609 ast_channel_caller(chan)->id.number.str, NULL);
610 if (caller_id) {
611 caller_id = ast_strdupa(caller_id);
612 }
613 ast_channel_unlock(chan);
614
615 if (!ast_exists_extension(chan, dest_context, dest_exten, dest_priority, caller_id)) {
616 ast_log(LOG_ERROR, "%s attempted to reach non-existent destination '%s,%s,%d' from '%s,%s,%d'",
617 app_gosub, dest_context, dest_exten, dest_priority, orig_context, orig_exten, orig_priority);
618 goto error_exit;
619 }
620
621 /* Now we know that we're going to a new location */
622
623 ast_channel_lock(chan);
624
625 /* Find stack datastore return list. */
626 if (!(stack_store = ast_channel_datastore_find(chan, &stack_info, NULL))) {
627 ast_debug(1, "Channel %s has no datastore, so we're allocating one.\n",
628 ast_channel_name(chan));
629 stack_store = ast_datastore_alloc(&stack_info, NULL);
630 if (!stack_store) {
631 ast_log(LOG_ERROR, "Unable to allocate new datastore. %s failed.\n",
632 app_gosub);
633 goto error_exit_locked;
634 }
635
636 oldlist = ast_calloc(1, sizeof(*oldlist));
637 if (!oldlist) {
638 ast_log(LOG_ERROR, "Unable to allocate datastore list head. %s failed.\n",
639 app_gosub);
640 ast_datastore_free(stack_store);
641 goto error_exit_locked;
642 }
643 AST_LIST_HEAD_INIT(oldlist);
644
645 stack_store->data = oldlist;
646 ast_channel_datastore_add(chan, stack_store);
647 } else {
648 oldlist = stack_store->data;
649 }
650
651 if ((lastframe = AST_LIST_FIRST(oldlist))) {
652 max_argc = lastframe->arguments;
653 }
654
655 /* Mask out previous Gosub arguments in this invocation */
656 if (args2.argc > max_argc) {
657 max_argc = args2.argc;
658 }
659
660 /* Create the return address */
661 newframe = gosub_allocate_frame(orig_context, orig_exten, orig_priority + 1, orig_in_subroutine, max_argc);
662 if (!newframe) {
663 goto error_exit_locked;
664 }
665
666 /* Set our arguments */
667 for (i = 0; i < max_argc; i++) {
668 snprintf(argname, sizeof(argname), "ARG%d", i + 1);
669 frame_set_var(chan, newframe, argname, i < args2.argc ? args2.argval[i] : "");
670 ast_debug(1, "Setting '%s' to '%s'\n", argname, i < args2.argc ? args2.argval[i] : "");
671 }
672 snprintf(argname, sizeof(argname), "%u", args2.argc);
673 frame_set_var(chan, newframe, "ARGC", argname);
674
676
677 /* And finally, save our return address */
678 AST_LIST_LOCK(oldlist);
679 AST_LIST_INSERT_HEAD(oldlist, newframe, entries);
680 AST_LIST_UNLOCK(oldlist);
681 ast_channel_unlock(chan);
682
683 return 0;
684
685error_exit:
686 ast_channel_lock(chan);
687
688error_exit_locked:
689 /* Restore the original dialplan location. */
690 ast_channel_context_set(chan, orig_context);
692 ast_channel_priority_set(chan, orig_priority);
693 ast_channel_unlock(chan);
694 return -1;
695}
696
697static int gosubif_exec(struct ast_channel *chan, const char *data)
698{
699 char *args;
700 int res=0;
702 AST_APP_ARG(ition);
703 AST_APP_ARG(labels);
704 );
706 AST_APP_ARG(iftrue);
707 AST_APP_ARG(iffalse);
708 );
709
710 if (ast_strlen_zero(data)) {
711 ast_log(LOG_WARNING, "GosubIf requires an argument: GosubIf(cond?label1(args):label2(args)\n");
712 return 0;
713 }
714
715 args = ast_strdupa(data);
717 if (cond.argc != 2) {
718 ast_log(LOG_WARNING, "GosubIf requires an argument: GosubIf(cond?label1(args):label2(args)\n");
719 return 0;
720 }
721
722 AST_NONSTANDARD_RAW_ARGS(label, cond.labels, ':');
723
724 if (pbx_checkcondition(cond.ition)) {
725 if (!ast_strlen_zero(label.iftrue))
726 res = gosub_exec(chan, label.iftrue);
727 } else if (!ast_strlen_zero(label.iffalse)) {
728 res = gosub_exec(chan, label.iffalse);
729 }
730
731 return res;
732}
733
734static int local_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
735{
736 struct ast_datastore *stack_store;
737 struct gosub_stack_list *oldlist;
738 struct gosub_stack_frame *frame;
739 struct ast_var_t *variables;
740
741 if (!chan) {
742 ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
743 return -1;
744 }
745
746 ast_channel_lock(chan);
747 if (!(stack_store = ast_channel_datastore_find(chan, &stack_info, NULL))) {
748 ast_channel_unlock(chan);
749 return -1;
750 }
751
752 oldlist = stack_store->data;
753 AST_LIST_LOCK(oldlist);
754 if (!(frame = AST_LIST_FIRST(oldlist))) {
755 /* Not within a Gosub routine */
756 AST_LIST_UNLOCK(oldlist);
757 ast_channel_unlock(chan);
758 return -1;
759 }
760
761 AST_LIST_TRAVERSE(&frame->varshead, variables, entries) {
762 if (!strcmp(data, ast_var_name(variables))) {
763 const char *tmp;
764 tmp = pbx_builtin_getvar_helper(chan, data);
765 ast_copy_string(buf, S_OR(tmp, ""), len);
766 break;
767 }
768 }
769 AST_LIST_UNLOCK(oldlist);
770 ast_channel_unlock(chan);
771 return 0;
772}
773
774static int local_write(struct ast_channel *chan, const char *cmd, char *var, const char *value)
775{
776 struct ast_datastore *stack_store;
777 struct gosub_stack_list *oldlist;
778 struct gosub_stack_frame *frame;
779
780 if (!chan) {
781 ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
782 return -1;
783 }
784
785 ast_channel_lock(chan);
786 if (!(stack_store = ast_channel_datastore_find(chan, &stack_info, NULL))) {
787 ast_log(LOG_ERROR, "Tried to set LOCAL(%s), but we aren't within a Gosub routine\n", var);
788 ast_channel_unlock(chan);
789 return -1;
790 }
791
792 oldlist = stack_store->data;
793 AST_LIST_LOCK(oldlist);
794 frame = AST_LIST_FIRST(oldlist);
795
796 if (frame) {
797 frame_set_var(chan, frame, var, value);
798 }
799
800 AST_LIST_UNLOCK(oldlist);
801 ast_channel_unlock(chan);
802
803 return 0;
804}
805
807 .name = "LOCAL",
808 .write = local_write,
809 .read = local_read,
810};
811
812static int peek_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
813{
814 int found = 0, n;
815 struct ast_var_t *variables;
817 AST_APP_ARG(n);
819 );
820
821 if (!chan) {
822 ast_log(LOG_ERROR, "LOCAL_PEEK must be called on an active channel\n");
823 return -1;
824 }
825
827
828 if (ast_strlen_zero(args.n) || ast_strlen_zero(args.name)) {
829 ast_log(LOG_ERROR, "LOCAL_PEEK requires parameters n and varname\n");
830 return -1;
831 }
832
833 n = atoi(args.n);
834 *buf = '\0';
835
836 ast_channel_lock(chan);
838 if (!strcmp(args.name, ast_var_name(variables)) && ++found > n) {
839 ast_copy_string(buf, ast_var_value(variables), len);
840 break;
841 }
842 }
843 ast_channel_unlock(chan);
844 return 0;
845}
846
848 .name = "LOCAL_PEEK",
849 .read = peek_read,
850};
851
852static int stackpeek_read(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **str, ssize_t len)
853{
854 struct ast_datastore *stack_store;
855 struct gosub_stack_list *oldlist;
856 struct gosub_stack_frame *frame;
857 int n;
859 AST_APP_ARG(n);
860 AST_APP_ARG(which);
861 AST_APP_ARG(suppress);
862 );
863
864 if (!chan) {
865 ast_log(LOG_ERROR, "STACK_PEEK must be called on an active channel\n");
866 return -1;
867 }
868
869 data = ast_strdupa(data);
871
872 if (ast_strlen_zero(args.n) || ast_strlen_zero(args.which)) {
873 ast_log(LOG_ERROR, "STACK_PEEK requires parameters n and which\n");
874 return -1;
875 }
876
877 n = atoi(args.n);
878 if (n <= 0) {
879 ast_log(LOG_ERROR, "STACK_PEEK must be called with a positive peek value\n");
880 return -1;
881 }
882
883 ast_channel_lock(chan);
884 if (!(stack_store = ast_channel_datastore_find(chan, &stack_info, NULL))) {
885 if (!ast_true(args.suppress)) {
886 ast_log(LOG_ERROR, "STACK_PEEK called on a channel without a gosub stack\n");
887 }
888 ast_channel_unlock(chan);
889 return -1;
890 }
891
892 oldlist = stack_store->data;
893
894 AST_LIST_LOCK(oldlist);
895 AST_LIST_TRAVERSE(oldlist, frame, entries) {
896 if (--n == 0) {
897 break;
898 }
899 }
900
901 if (!frame) {
902 /* Too deep */
903 if (!ast_true(args.suppress)) {
904 ast_log(LOG_ERROR, "Stack peek of '%s' is more stack frames than I have\n", args.n);
905 }
906 AST_LIST_UNLOCK(oldlist);
907 ast_channel_unlock(chan);
908 return -1;
909 }
910
911 args.which = ast_skip_blanks(args.which);
912
913 switch (args.which[0]) {
914 case 'l': /* label */
915 ast_str_set(str, len, "%s,%s,%d", frame->context, frame->extension, frame->priority - 1);
916 break;
917 case 'c': /* context */
918 ast_str_set(str, len, "%s", frame->context);
919 break;
920 case 'e': /* extension */
921 ast_str_set(str, len, "%s", frame->extension);
922 break;
923 case 'p': /* priority */
924 ast_str_set(str, len, "%d", frame->priority - 1);
925 break;
926 default:
927 ast_log(LOG_ERROR, "Unknown argument '%s' to STACK_PEEK\n", args.which);
928 break;
929 }
930
931 AST_LIST_UNLOCK(oldlist);
932 ast_channel_unlock(chan);
933
934 return 0;
935}
936
938 .name = "STACK_PEEK",
939 .read2 = stackpeek_read,
940};
941
942/*!
943 * \internal
944 * \brief Pop stack frames until remove a special return location.
945 * \since 11.0
946 *
947 * \param chan Channel to balance stack on.
948 *
949 * \note The channel is already locked when called.
950 */
951static void balance_stack(struct ast_channel *chan)
952{
953 struct ast_datastore *stack_store;
954 struct gosub_stack_list *oldlist;
955 struct gosub_stack_frame *oldframe;
956 int found;
957
958 stack_store = ast_channel_datastore_find(chan, &stack_info, NULL);
959 if (!stack_store) {
960 ast_log(LOG_WARNING, "No %s stack allocated.\n", app_gosub);
961 return;
962 }
963
964 oldlist = stack_store->data;
965 AST_LIST_LOCK(oldlist);
966 do {
967 oldframe = AST_LIST_REMOVE_HEAD(oldlist, entries);
968 if (!oldframe) {
969 break;
970 }
971 found = oldframe->is_special;
972 gosub_release_frame(chan, oldframe);
973 } while (!found);
974 AST_LIST_UNLOCK(oldlist);
975}
976
977/*!
978 * \internal
979 * \brief Run a subroutine on a channel.
980 * \since 11.0
981 *
982 * \note Absolutely _NO_ channel locks should be held before calling this function.
983 *
984 * \param chan Channel to execute subroutine on.
985 * \param sub_args Gosub application argument string.
986 * \param ignore_hangup TRUE if a hangup does not stop execution of the routine.
987 *
988 * \retval 0 success
989 * \retval -1 on error
990 */
991static int gosub_run(struct ast_channel *chan, const char *sub_args, int ignore_hangup)
992{
993 const char *saved_context;
994 const char *saved_exten;
995 int saved_priority;
996 int saved_hangup_flags;
997 int saved_autoloopflag;
998 int saved_in_subroutine;
999 int res;
1000
1001 ast_channel_lock(chan);
1002
1003 ast_verb(3, "%s Internal %s(%s) start\n",
1004 ast_channel_name(chan), app_gosub, sub_args);
1005
1006 /* Save non-hangup softhangup flags. */
1007 saved_hangup_flags = ast_channel_softhangup_internal_flag(chan)
1009 if (saved_hangup_flags) {
1011 }
1012
1013 /* Save autoloop flag */
1014 saved_autoloopflag = ast_test_flag(ast_channel_flags(chan), AST_FLAG_IN_AUTOLOOP);
1016
1017 /* Save current dialplan location */
1018 saved_context = ast_strdupa(ast_channel_context(chan));
1019 saved_exten = ast_strdupa(ast_channel_exten(chan));
1020 saved_priority = ast_channel_priority(chan);
1021
1022 /* Save whether or not we are in a subroutine */
1023 saved_in_subroutine = ast_test_flag(ast_channel_flags(chan), AST_FLAG_SUBROUTINE_EXEC);
1024
1025 ast_debug(4, "%s Original location: %s,%s,%d\n", ast_channel_name(chan),
1026 saved_context, saved_exten, saved_priority);
1027
1028 ast_channel_unlock(chan);
1029 res = gosub_exec(chan, sub_args);
1030 ast_debug(4, "%s exited with status %d\n", app_gosub, res);
1031 ast_channel_lock(chan);
1032 if (!res) {
1033 struct ast_datastore *stack_store;
1034
1035 /* Mark the return location as special. */
1036 stack_store = ast_channel_datastore_find(chan, &stack_info, NULL);
1037 if (!stack_store) {
1038 /* Should never happen! */
1039 ast_log(LOG_ERROR, "No %s stack!\n", app_gosub);
1040 res = -1;
1041 } else {
1042 struct gosub_stack_list *oldlist;
1043 struct gosub_stack_frame *cur;
1044
1045 oldlist = stack_store->data;
1046 cur = AST_LIST_FIRST(oldlist);
1047 cur->is_special = 1;
1048 }
1049 }
1050 if (!res) {
1051 int found = 0; /* set if we find at least one match */
1052
1053 /*
1054 * Run gosub body autoloop.
1055 *
1056 * Note that this loop is inverted from the normal execution
1057 * loop because we just executed the Gosub application as the
1058 * first extension of the autoloop.
1059 */
1060 do {
1061 /* Check for hangup. */
1062 if (ast_check_hangup(chan)) {
1064 ast_log(LOG_ERROR, "%s An async goto just messed up our execution location.\n",
1065 ast_channel_name(chan));
1066 break;
1067 }
1068 if (!ignore_hangup) {
1069 break;
1070 }
1071 }
1072
1073 /* Next dialplan priority. */
1075
1076 ast_channel_unlock(chan);
1077 res = ast_spawn_extension(chan, ast_channel_context(chan),
1079 S_COR(ast_channel_caller(chan)->id.number.valid,
1080 ast_channel_caller(chan)->id.number.str, NULL),
1081 &found, 1);
1082 ast_channel_lock(chan);
1083 } while (!res);
1084 if (found && res) {
1085 /* Something bad happened, or a hangup has been requested. */
1086 ast_debug(1, "Spawn extension (%s,%s,%d) exited with %d on '%s'\n",
1088 ast_channel_priority(chan), res, ast_channel_name(chan));
1089 ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n",
1092 }
1093
1094 /* Did the routine return? */
1095 if (ast_channel_priority(chan) == saved_priority
1096 && !strcmp(ast_channel_context(chan), saved_context)
1097 && !strcmp(ast_channel_exten(chan), saved_exten)) {
1098 ast_verb(3, "%s Internal %s(%s) complete GOSUB_RETVAL=%s\n",
1099 ast_channel_name(chan), app_gosub, sub_args,
1100 S_OR(pbx_builtin_getvar_helper(chan, "GOSUB_RETVAL"), ""));
1101 } else {
1102 ast_log(LOG_WARNING, "%s Abnormal '%s(%s)' exit. Popping routine return locations.\n",
1103 ast_channel_name(chan), app_gosub, sub_args);
1104 balance_stack(chan);
1105 pbx_builtin_setvar_helper(chan, "GOSUB_RETVAL", "");
1106 }
1107
1108 /* We executed the requested subroutine to the best of our ability. */
1109 res = 0;
1110 }
1111
1112 ast_debug(4, "%s Ending location: %s,%s,%d\n", ast_channel_name(chan),
1114 ast_channel_priority(chan));
1115
1116 /* Restore dialplan location */
1118 ast_channel_context_set(chan, saved_context);
1119 ast_channel_exten_set(chan, saved_exten);
1120 ast_channel_priority_set(chan, saved_priority);
1121 }
1122
1123 /* Restore autoloop flag */
1124 ast_set2_flag(ast_channel_flags(chan), saved_autoloopflag, AST_FLAG_IN_AUTOLOOP);
1125
1126 /* Restore subroutine flag */
1127 ast_set2_flag(ast_channel_flags(chan), saved_in_subroutine, AST_FLAG_SUBROUTINE_EXEC);
1128
1129 /* Restore non-hangup softhangup flags. */
1130 if (saved_hangup_flags) {
1131 ast_softhangup_nolock(chan, saved_hangup_flags);
1132 }
1133
1134 ast_channel_unlock(chan);
1135
1136 return res;
1137}
1138
1139static int handle_gosub(struct ast_channel *chan, AGI *agi, int argc, const char * const *argv)
1140{
1141 int res;
1142 int priority;
1143 int old_autoloopflag;
1144 int old_in_subroutine;
1145 int old_priority;
1146 const char *old_context;
1147 const char *old_extension;
1148 char *gosub_args;
1149
1150 if (argc < 4 || argc > 5) {
1151 return RESULT_SHOWUSAGE;
1152 }
1153
1154 ast_debug(1, "Gosub called with %d arguments: 0:%s 1:%s 2:%s 3:%s 4:%s\n", argc, argv[0], argv[1], argv[2], argv[3], argc == 5 ? argv[4] : "");
1155
1156 if (sscanf(argv[3], "%30d", &priority) != 1 || priority < 1) {
1157 /* Lookup the priority label */
1158 priority = ast_findlabel_extension(chan, argv[1], argv[2], argv[3],
1159 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL));
1160 if (priority < 0) {
1161 ast_log(LOG_ERROR, "Priority '%s' not found in '%s@%s'\n", argv[3], argv[2], argv[1]);
1162 ast_agi_send(agi->fd, chan, "200 result=-1 Gosub label not found\n");
1163 return RESULT_FAILURE;
1164 }
1165 } else if (!ast_exists_extension(chan, argv[1], argv[2], priority,
1166 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
1167 ast_agi_send(agi->fd, chan, "200 result=-1 Gosub label not found\n");
1168 return RESULT_FAILURE;
1169 }
1170
1171 if (argc == 5) {
1172 if (ast_asprintf(&gosub_args, "%s,%s,%d(%s)", argv[1], argv[2], priority, argv[4]) < 0) {
1173 gosub_args = NULL;
1174 }
1175 } else {
1176 if (ast_asprintf(&gosub_args, "%s,%s,%d", argv[1], argv[2], priority) < 0) {
1177 gosub_args = NULL;
1178 }
1179 }
1180 if (!gosub_args) {
1181 ast_agi_send(agi->fd, chan, "503 result=-2 Memory allocation failure\n");
1182 return RESULT_FAILURE;
1183 }
1184
1185 ast_channel_lock(chan);
1186
1187 ast_verb(3, "%s AGI %s(%s) start\n", ast_channel_name(chan), app_gosub, gosub_args);
1188
1189 /* Save autoloop flag */
1190 old_autoloopflag = ast_test_flag(ast_channel_flags(chan), AST_FLAG_IN_AUTOLOOP);
1192
1193 /* Save subroutine flag */
1194 old_in_subroutine = ast_test_flag(ast_channel_flags(chan), AST_FLAG_SUBROUTINE_EXEC);
1195
1196 /* Save previous location, since we're going to change it */
1197 old_context = ast_strdupa(ast_channel_context(chan));
1198 old_extension = ast_strdupa(ast_channel_exten(chan));
1199 old_priority = ast_channel_priority(chan);
1200
1201 ast_debug(4, "%s Original location: %s,%s,%d\n", ast_channel_name(chan),
1202 old_context, old_extension, old_priority);
1203 ast_channel_unlock(chan);
1204
1205 res = gosub_exec(chan, gosub_args);
1206 if (!res) {
1207 struct ast_datastore *stack_store;
1208
1209 /* Mark the return location as special. */
1210 ast_channel_lock(chan);
1211 stack_store = ast_channel_datastore_find(chan, &stack_info, NULL);
1212 if (!stack_store) {
1213 /* Should never happen! */
1214 ast_log(LOG_ERROR, "No %s stack!\n", app_gosub);
1215 res = -1;
1216 } else {
1217 struct gosub_stack_list *oldlist;
1218 struct gosub_stack_frame *cur;
1219
1220 oldlist = stack_store->data;
1221 cur = AST_LIST_FIRST(oldlist);
1222 cur->is_special = 1;
1223 }
1224 ast_channel_unlock(chan);
1225 }
1226 if (!res) {
1227 struct ast_pbx *pbx;
1228 struct ast_pbx_args args;
1229 int abnormal_exit;
1230
1231 memset(&args, 0, sizeof(args));
1232 args.no_hangup_chan = 1;
1233
1234 ast_channel_lock(chan);
1235
1236 /* Next dialplan priority. */
1238
1239 /* Suppress warning about PBX already existing */
1240 pbx = ast_channel_pbx(chan);
1242 ast_channel_unlock(chan);
1243
1244 ast_agi_send(agi->fd, chan, "100 result=0 Trying...\n");
1245 ast_pbx_run_args(chan, &args);
1246
1247 ast_channel_lock(chan);
1249 ast_channel_pbx_set(chan, pbx);
1250
1251 /* Did the routine return? */
1252 if (ast_channel_priority(chan) == old_priority
1253 && !strcmp(ast_channel_context(chan), old_context)
1254 && !strcmp(ast_channel_exten(chan), old_extension)) {
1255 ast_verb(3, "%s AGI %s(%s) complete GOSUB_RETVAL=%s\n",
1256 ast_channel_name(chan), app_gosub, gosub_args,
1257 S_OR(pbx_builtin_getvar_helper(chan, "GOSUB_RETVAL"), ""));
1258 abnormal_exit = 0;
1259 } else {
1260 ast_log(LOG_NOTICE, "%s Abnormal AGI %s(%s) exit. Popping routine return locations.\n",
1261 ast_channel_name(chan), app_gosub, gosub_args);
1262 balance_stack(chan);
1263 pbx_builtin_setvar_helper(chan, "GOSUB_RETVAL", "");
1264 abnormal_exit = 1;
1265 }
1266 ast_channel_unlock(chan);
1267
1268 ast_agi_send(agi->fd, chan, "200 result=0 Gosub complete%s\n",
1269 abnormal_exit ? " (abnormal exit)" : "");
1270 } else {
1271 ast_agi_send(agi->fd, chan, "200 result=%d Gosub failed\n", res);
1272 }
1273
1274 ast_free(gosub_args);
1275
1276 ast_channel_lock(chan);
1277 ast_debug(4, "%s Ending location: %s,%s,%d\n", ast_channel_name(chan),
1279 ast_channel_priority(chan));
1280
1281 /* Restore previous location */
1282 ast_channel_context_set(chan, old_context);
1283 ast_channel_exten_set(chan, old_extension);
1284 ast_channel_priority_set(chan, old_priority);
1285
1286 /* Restore autoloop flag */
1287 ast_set2_flag(ast_channel_flags(chan), old_autoloopflag, AST_FLAG_IN_AUTOLOOP);
1288
1289 /* Restore subroutine flag */
1290 ast_set2_flag(ast_channel_flags(chan), old_in_subroutine, AST_FLAG_SUBROUTINE_EXEC);
1291 ast_channel_unlock(chan);
1292
1293 return RESULT_SUCCESS;
1294}
1295
1297 { { "gosub", NULL }, handle_gosub, NULL, NULL, 0 };
1298
1299static int unload_module(void)
1300{
1302
1304
1312
1313 return 0;
1314}
1315
1316static int load_module(void)
1317{
1318 /* Setup the stack application callback functions. */
1319 static struct ast_app_stack_funcs funcs = {
1320 .run_sub = gosub_run,
1321 .expand_sub_args = expand_gosub_args,
1322 };
1323
1325
1333
1334 funcs.module = ast_module_info->self,
1336
1337 return 0;
1338}
1339
1340AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT | AST_MODFLAG_LOAD_ORDER, "Dialplan subroutines (Gosub, Return, etc)",
1341 .support_level = AST_MODULE_SUPPORT_CORE,
1342 .load = load_module,
1343 .unload = unload_module,
1344 .load_pri = AST_MODPRI_APP_DEPEND,
1345 .optional_modules = "res_agi",
AGI Extension interfaces - Asterisk Gateway Interface.
int ast_agi_send(int fd, struct ast_channel *chan, char *fmt,...)
Sends a string of text to an application connected via AGI.
Definition: res_agi.c:1646
int ast_agi_register(struct ast_module *mod, agi_command *cmd)
Registers an AGI command.
Definition: res_agi.c:3988
int ast_agi_unregister(agi_command *cmd)
Unregisters an AGI command.
Definition: res_agi.c:4034
@ ignore_hangup
const char * str
Definition: app_jack.c:150
ast_cond_t cond
Definition: app_sla.c:336
static void gosub_release_frame(struct ast_channel *chan, struct gosub_stack_frame *frame)
Definition: app_stack.c:317
static int gosubif_exec(struct ast_channel *chan, const char *data)
Definition: app_stack.c:697
static struct ast_custom_function local_function
Definition: app_stack.c:806
static int gosub_exec(struct ast_channel *chan, const char *data)
Definition: app_stack.c:539
static int handle_gosub(struct ast_channel *chan, AGI *agi, int argc, const char *const *argv)
Definition: app_stack.c:1139
static int gosub_run(struct ast_channel *chan, const char *sub_args, int ignore_hangup)
Definition: app_stack.c:991
static const char * expand_gosub_args(struct ast_channel *chan, const char *args)
Definition: app_stack.c:473
static int stackpeek_read(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **str, ssize_t len)
Definition: app_stack.c:852
static int local_write(struct ast_channel *chan, const char *cmd, char *var, const char *value)
Definition: app_stack.c:774
static struct agi_command gosub_agi_command
Definition: app_stack.c:1296
static int local_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Definition: app_stack.c:734
static int return_exec(struct ast_channel *chan, const char *data)
Definition: app_stack.c:403
static void gosub_free(void *data)
Definition: app_stack.c:354
static const char app_return[]
Definition: app_stack.c:257
static const char app_gosub[]
Definition: app_stack.c:255
static struct ast_custom_function peek_function
Definition: app_stack.c:847
static int frame_set_var(struct ast_channel *chan, struct gosub_stack_frame *frame, const char *var, const char *value)
Definition: app_stack.c:283
static struct gosub_stack_frame * gosub_allocate_frame(const char *context, const char *extension, int priority, int in_subroutine, unsigned char arguments)
Definition: app_stack.c:336
static void balance_stack(struct ast_channel *chan)
Definition: app_stack.c:951
static const struct ast_datastore_info stack_info
Definition: app_stack.c:262
static const char app_gosubif[]
Definition: app_stack.c:256
static const char app_pop[]
Definition: app_stack.c:258
static int load_module(void)
Definition: app_stack.c:1316
static int peek_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Definition: app_stack.c:812
static int unload_module(void)
Definition: app_stack.c:1299
static struct ast_custom_function stackpeek_function
Definition: app_stack.c:937
static int pop_exec(struct ast_channel *chan, const char *data)
Definition: app_stack.c:368
#define var
Definition: ast_expr2f.c:605
char * strsep(char **str, const char *delims)
Asterisk main include file. File version handling, generic pbx functions.
#define ast_free(a)
Definition: astmm.h:180
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
Definition: astmm.h:267
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
#define ast_malloc(len)
A wrapper for malloc()
Definition: astmm.h:191
#define ast_log
Definition: astobj2.c:42
static int priority
General Asterisk PBX channel definitions.
void ast_channel_exten_set(struct ast_channel *chan, const char *value)
const char * ast_channel_name(const struct ast_channel *chan)
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Definition: channel.c:2414
void ast_channel_clear_softhangup(struct ast_channel *chan, int flag)
Clear a set of softhangup flags from a channel.
Definition: channel.c:2461
struct varshead * ast_channel_varshead(struct ast_channel *chan)
#define ast_channel_lock(chan)
Definition: channel.h:2970
struct ast_flags * ast_channel_flags(struct ast_channel *chan)
int ast_channel_priority(const struct ast_channel *chan)
const char * ast_channel_context(const struct ast_channel *chan)
int ast_check_hangup(struct ast_channel *chan)
Check to see if a channel is needing hang up.
Definition: channel.c:445
@ AST_FLAG_IN_AUTOLOOP
Definition: channel.h:1017
@ AST_FLAG_SUBROUTINE_EXEC
Definition: channel.h:1078
void ast_channel_context_set(struct ast_channel *chan, const char *value)
int ast_softhangup_nolock(struct ast_channel *chan, int cause)
Softly hangup up a channel (no channel lock)
Definition: channel.c:2487
struct ast_pbx * ast_channel_pbx(const struct ast_channel *chan)
int ast_channel_softhangup_internal_flag(struct ast_channel *chan)
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
void ast_channel_priority_set(struct ast_channel *chan, int value)
const char * ast_channel_exten(const struct ast_channel *chan)
#define ast_channel_unlock(chan)
Definition: channel.h:2971
void ast_channel_pbx_set(struct ast_channel *chan, struct ast_pbx *value)
struct ast_datastore * ast_channel_datastore_find(struct ast_channel *chan, const struct ast_datastore_info *info, const char *uid)
Find a datastore on a channel.
Definition: channel.c:2428
@ AST_SOFTHANGUP_ASYNCGOTO
Definition: channel.h:1146
const char * ast_var_name(const struct ast_var_t *var)
Definition: chanvars.c:60
#define ast_var_assign(name, value)
Definition: chanvars.h:40
const char * ast_var_value(const struct ast_var_t *var)
Definition: chanvars.c:80
void ast_var_delete(struct ast_var_t *var)
Definition: extconf.c:2471
#define RESULT_SHOWUSAGE
Definition: cli.h:41
#define RESULT_SUCCESS
Definition: cli.h:40
#define RESULT_FAILURE
Definition: cli.h:42
#define ast_datastore_alloc(info, uid)
Definition: datastore.h:85
int ast_datastore_free(struct ast_datastore *datastore)
Free a data store object.
Definition: datastore.c:68
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
static const char name[]
Definition: format_mp3.c:68
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
void ast_channel_publish_varset(struct ast_channel *chan, const char *variable, const char *value)
Publish a ast_channel_publish_varset for a channel.
Application convenience functions, designed to give consistent look and feel to Asterisk apps.
#define AST_APP_ARG(name)
Define an application argument.
#define AST_STANDARD_RAW_ARGS(args, parse)
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
void ast_install_stack_functions(const struct ast_app_stack_funcs *funcs)
Set stack application function callbacks.
Definition: main/app.c:273
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
#define AST_NONSTANDARD_RAW_ARGS(args, parse, sep)
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_ERROR
#define ast_verb(level,...)
#define LOG_NOTICE
#define LOG_WARNING
#define AST_LIST_HEAD_INIT_NOLOCK(head)
Initializes a list head structure.
Definition: linkedlists.h:681
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:491
#define AST_LIST_HEAD_DESTROY(head)
Destroys a list head structure.
Definition: linkedlists.h:653
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
Definition: linkedlists.h:410
#define AST_LIST_HEAD_INIT(head)
Initializes a list head structure.
Definition: linkedlists.h:626
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:40
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
Definition: linkedlists.h:711
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:833
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:140
#define AST_LIST_HEAD(name, type)
Defines a structure to be used to hold a list of specified type.
Definition: linkedlists.h:173
#define AST_LIST_FIRST(head)
Returns the first entry contained in a list.
Definition: linkedlists.h:421
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
Asterisk module definitions.
@ AST_MODFLAG_LOAD_ORDER
Definition: module.h:331
@ AST_MODFLAG_DEFAULT
Definition: module.h:329
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
Definition: module.h:557
@ AST_MODPRI_APP_DEPEND
Definition: module.h:342
@ AST_MODULE_SUPPORT_CORE
Definition: module.h:121
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx_app.c:392
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:640
Core PBX routines and definitions.
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:4195
enum ast_pbx_result ast_pbx_run_args(struct ast_channel *c, struct ast_pbx_args *args)
Execute the PBX in the current thread.
Definition: pbx.c:4750
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
Determine whether an extension exists.
Definition: pbx.c:4190
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name.
#define ast_custom_function_register(acf)
Register a custom function.
Definition: pbx.h:1559
int ast_spawn_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid, int *found, int combined_find_spawn)
Launch a new extension (i.e. new stack)
Definition: pbx.c:4215
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
void pbx_builtin_pushvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, without removing any previously set value.
int pbx_checkcondition(const char *condition)
Evaluate a condition.
Definition: pbx.c:8297
int ast_parseable_goto(struct ast_channel *chan, const char *goto_string)
Definition: pbx.c:8881
static char * orig_exten(int fd, const char *chan, const char *data)
orginate from extension
#define NULL
Definition: resample.c:96
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
Definition: strings.h:80
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true"....
Definition: utils.c:2199
#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:87
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition: strings.h:1113
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
char * ast_skip_blanks(const char *str)
Gets a pointer to the first non-whitespace character in a string.
Definition: strings.h:161
Definition: agi.h:34
int fd
Definition: agi.h:35
Stack applications callback functions.
int(* run_sub)(struct ast_channel *chan, const char *args, int ignore_hangup)
Callback for the routine to run a subroutine on a channel.
Main Channel structure associated with a channel.
Data structure associated with a custom dialplan function.
Definition: pbx.h:118
const char * name
Definition: pbx.h:119
Structure for a data store type.
Definition: datastore.h:31
const char * type
Definition: datastore.h:32
Structure for a data store object.
Definition: datastore.h:64
void * data
Definition: datastore.h:66
struct ast_module * self
Definition: module.h:356
Options for ast_pbx_run()
Definition: pbx.h:408
Definition: pbx.h:215
Support for dynamic strings.
Definition: strings.h:623
struct ast_var_t::@213 entries
structure to hold extensions
unsigned char arguments
Definition: app_stack.c:270
char extension[0]
Definition: app_stack.c:278
unsigned int in_subroutine
Definition: app_stack.c:276
struct gosub_stack_frame::@81 entries
struct varshead varshead
Definition: app_stack.c:271
unsigned int is_special
Definition: app_stack.c:274
Number structure.
Definition: app_followme.c:157
int value
Definition: syslog.c:37
const char * args
#define ast_test_flag(p, flag)
Definition: utils.h:63
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:941
#define ast_set2_flag(p, value, flag)
Definition: utils.h:94
#define ast_set_flag(p, flag)
Definition: utils.h:70