00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033 #include "asterisk.h"
00034
00035 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 370183 $")
00036
00037 #include "asterisk/pbx.h"
00038 #include "asterisk/module.h"
00039 #include "asterisk/app.h"
00040 #include "asterisk/manager.h"
00041 #include "asterisk/channel.h"
00042 #include "asterisk/agi.h"
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208 static const char * const app_gosub = "Gosub";
00209 static const char * const app_gosubif = "GosubIf";
00210 static const char * const app_return = "Return";
00211 static const char * const app_pop = "StackPop";
00212
00213 static void gosub_free(void *data);
00214
00215 static const struct ast_datastore_info stack_info = {
00216 .type = "GOSUB",
00217 .destroy = gosub_free,
00218 };
00219
00220 struct gosub_stack_frame {
00221 AST_LIST_ENTRY(gosub_stack_frame) entries;
00222
00223 unsigned char arguments;
00224 struct varshead varshead;
00225 int priority;
00226 unsigned int is_agi:1;
00227 char *context;
00228 char extension[0];
00229 };
00230
00231 static int frame_set_var(struct ast_channel *chan, struct gosub_stack_frame *frame, const char *var, const char *value)
00232 {
00233 struct ast_var_t *variables;
00234 int found = 0;
00235
00236
00237 AST_LIST_TRAVERSE(&frame->varshead, variables, entries) {
00238 if (!strcmp(var, ast_var_name(variables))) {
00239 found = 1;
00240 break;
00241 }
00242 }
00243
00244 if (!found) {
00245 variables = ast_var_assign(var, "");
00246 AST_LIST_INSERT_HEAD(&frame->varshead, variables, entries);
00247 pbx_builtin_pushvar_helper(chan, var, value);
00248 } else {
00249 pbx_builtin_setvar_helper(chan, var, value);
00250 }
00251
00252 manager_event(EVENT_FLAG_DIALPLAN, "VarSet",
00253 "Channel: %s\r\n"
00254 "Variable: LOCAL(%s)\r\n"
00255 "Value: %s\r\n"
00256 "Uniqueid: %s\r\n",
00257 chan->name, var, value, chan->uniqueid);
00258 return 0;
00259 }
00260
00261 static void gosub_release_frame(struct ast_channel *chan, struct gosub_stack_frame *frame)
00262 {
00263 struct ast_var_t *vardata;
00264
00265
00266
00267
00268
00269
00270
00271 while ((vardata = AST_LIST_REMOVE_HEAD(&frame->varshead, entries))) {
00272 if (chan)
00273 pbx_builtin_setvar_helper(chan, ast_var_name(vardata), NULL);
00274 ast_var_delete(vardata);
00275 }
00276
00277 ast_free(frame);
00278 }
00279
00280 static struct gosub_stack_frame *gosub_allocate_frame(const char *context, const char *extension, int priority, unsigned char arguments)
00281 {
00282 struct gosub_stack_frame *new = NULL;
00283 int len_extension = strlen(extension), len_context = strlen(context);
00284
00285 if ((new = ast_calloc(1, sizeof(*new) + 2 + len_extension + len_context))) {
00286 AST_LIST_HEAD_INIT_NOLOCK(&new->varshead);
00287 strcpy(new->extension, extension);
00288 new->context = new->extension + len_extension + 1;
00289 strcpy(new->context, context);
00290 new->priority = priority;
00291 new->arguments = arguments;
00292 }
00293 return new;
00294 }
00295
00296 static void gosub_free(void *data)
00297 {
00298 AST_LIST_HEAD(, gosub_stack_frame) *oldlist = data;
00299 struct gosub_stack_frame *oldframe;
00300 AST_LIST_LOCK(oldlist);
00301 while ((oldframe = AST_LIST_REMOVE_HEAD(oldlist, entries))) {
00302 gosub_release_frame(NULL, oldframe);
00303 }
00304 AST_LIST_UNLOCK(oldlist);
00305 AST_LIST_HEAD_DESTROY(oldlist);
00306 ast_free(oldlist);
00307 }
00308
00309 static int pop_exec(struct ast_channel *chan, const char *data)
00310 {
00311 struct ast_datastore *stack_store;
00312 struct gosub_stack_frame *oldframe;
00313 AST_LIST_HEAD(, gosub_stack_frame) *oldlist;
00314
00315 ast_channel_lock(chan);
00316 if (!(stack_store = ast_channel_datastore_find(chan, &stack_info, NULL))) {
00317 ast_log(LOG_WARNING, "%s called with no gosub stack allocated.\n", app_pop);
00318 ast_channel_unlock(chan);
00319 return 0;
00320 }
00321
00322 oldlist = stack_store->data;
00323 AST_LIST_LOCK(oldlist);
00324 oldframe = AST_LIST_REMOVE_HEAD(oldlist, entries);
00325 AST_LIST_UNLOCK(oldlist);
00326
00327 if (oldframe) {
00328 gosub_release_frame(chan, oldframe);
00329 } else {
00330 ast_debug(1, "%s called with an empty gosub stack\n", app_pop);
00331 }
00332 ast_channel_unlock(chan);
00333 return 0;
00334 }
00335
00336 static int return_exec(struct ast_channel *chan, const char *data)
00337 {
00338 struct ast_datastore *stack_store;
00339 struct gosub_stack_frame *oldframe;
00340 AST_LIST_HEAD(, gosub_stack_frame) *oldlist;
00341 const char *retval = data;
00342 int res = 0;
00343
00344 ast_channel_lock(chan);
00345 if (!(stack_store = ast_channel_datastore_find(chan, &stack_info, NULL))) {
00346 ast_log(LOG_ERROR, "Return without Gosub: stack is unallocated\n");
00347 ast_channel_unlock(chan);
00348 return -1;
00349 }
00350
00351 oldlist = stack_store->data;
00352 AST_LIST_LOCK(oldlist);
00353 oldframe = AST_LIST_REMOVE_HEAD(oldlist, entries);
00354 AST_LIST_UNLOCK(oldlist);
00355
00356 if (!oldframe) {
00357 ast_log(LOG_ERROR, "Return without Gosub: stack is empty\n");
00358 ast_channel_unlock(chan);
00359 return -1;
00360 } else if (oldframe->is_agi) {
00361
00362 res = -1;
00363 }
00364
00365 ast_explicit_goto(chan, oldframe->context, oldframe->extension, oldframe->priority);
00366 gosub_release_frame(chan, oldframe);
00367
00368
00369 pbx_builtin_setvar_helper(chan, "GOSUB_RETVAL", S_OR(retval, ""));
00370 ast_channel_unlock(chan);
00371 return res;
00372 }
00373
00374 static int gosub_exec(struct ast_channel *chan, const char *data)
00375 {
00376 struct ast_datastore *stack_store;
00377 AST_LIST_HEAD(, gosub_stack_frame) *oldlist;
00378 struct gosub_stack_frame *newframe;
00379 struct gosub_stack_frame *lastframe;
00380 char argname[15];
00381 char *parse;
00382 char *label;
00383 char *caller_id;
00384 char *orig_context;
00385 char *orig_exten;
00386 char *dest_context;
00387 char *dest_exten;
00388 int orig_priority;
00389 int dest_priority;
00390 int i;
00391 int max_argc = 0;
00392 AST_DECLARE_APP_ARGS(args2,
00393 AST_APP_ARG(argval)[100];
00394 );
00395
00396 if (ast_strlen_zero(data)) {
00397 ast_log(LOG_ERROR, "%s requires an argument: %s([[context,]exten,]priority[(arg1[,...][,argN])])\n", app_gosub, app_gosub);
00398 return -1;
00399 }
00400
00401
00402
00403
00404
00405
00406
00407 parse = ast_strdupa(data);
00408 label = strsep(&parse, "(");
00409 if (parse) {
00410 char *endparen;
00411
00412 endparen = strrchr(parse, ')');
00413 if (endparen) {
00414 *endparen = '\0';
00415 } else {
00416 ast_log(LOG_WARNING, "Ouch. No closing paren: '%s'?\n", data);
00417 }
00418 AST_STANDARD_RAW_ARGS(args2, parse);
00419 } else {
00420 args2.argc = 0;
00421 }
00422
00423 ast_channel_lock(chan);
00424 orig_context = ast_strdupa(chan->context);
00425 orig_exten = ast_strdupa(chan->exten);
00426 orig_priority = chan->priority;
00427 ast_channel_unlock(chan);
00428
00429 if (ast_parseable_goto(chan, label)) {
00430 ast_log(LOG_ERROR, "%s address is invalid: '%s'\n", app_gosub, data);
00431 goto error_exit;
00432 }
00433
00434 ast_channel_lock(chan);
00435 dest_context = ast_strdupa(chan->context);
00436 dest_exten = ast_strdupa(chan->exten);
00437 dest_priority = chan->priority;
00438 if (ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP)) {
00439 ++dest_priority;
00440 }
00441 caller_id = S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL);
00442 if (caller_id) {
00443 caller_id = ast_strdupa(caller_id);
00444 }
00445 ast_channel_unlock(chan);
00446
00447 if (!ast_exists_extension(chan, dest_context, dest_exten, dest_priority, caller_id)) {
00448 ast_log(LOG_ERROR, "Attempt to reach a non-existent destination for %s: (Context:%s, Extension:%s, Priority:%d)\n",
00449 app_gosub, dest_context, dest_exten, dest_priority);
00450 goto error_exit;
00451 }
00452
00453
00454
00455 ast_channel_lock(chan);
00456
00457
00458 if (!(stack_store = ast_channel_datastore_find(chan, &stack_info, NULL))) {
00459 ast_debug(1, "Channel %s has no datastore, so we're allocating one.\n",
00460 chan->name);
00461 stack_store = ast_datastore_alloc(&stack_info, NULL);
00462 if (!stack_store) {
00463 ast_log(LOG_ERROR, "Unable to allocate new datastore. %s failed.\n",
00464 app_gosub);
00465 goto error_exit_locked;
00466 }
00467
00468 oldlist = ast_calloc(1, sizeof(*oldlist));
00469 if (!oldlist) {
00470 ast_log(LOG_ERROR, "Unable to allocate datastore list head. %s failed.\n",
00471 app_gosub);
00472 ast_datastore_free(stack_store);
00473 goto error_exit_locked;
00474 }
00475 AST_LIST_HEAD_INIT(oldlist);
00476
00477 stack_store->data = oldlist;
00478 ast_channel_datastore_add(chan, stack_store);
00479 } else {
00480 oldlist = stack_store->data;
00481 }
00482
00483 if ((lastframe = AST_LIST_FIRST(oldlist))) {
00484 max_argc = lastframe->arguments;
00485 }
00486
00487
00488 if (args2.argc > max_argc) {
00489 max_argc = args2.argc;
00490 }
00491
00492
00493 newframe = gosub_allocate_frame(orig_context, orig_exten, orig_priority + 1, max_argc);
00494 if (!newframe) {
00495 goto error_exit_locked;
00496 }
00497
00498
00499 for (i = 0; i < max_argc; i++) {
00500 snprintf(argname, sizeof(argname), "ARG%d", i + 1);
00501 frame_set_var(chan, newframe, argname, i < args2.argc ? args2.argval[i] : "");
00502 ast_debug(1, "Setting '%s' to '%s'\n", argname, i < args2.argc ? args2.argval[i] : "");
00503 }
00504 snprintf(argname, sizeof(argname), "%d", args2.argc);
00505 frame_set_var(chan, newframe, "ARGC", argname);
00506
00507
00508 AST_LIST_LOCK(oldlist);
00509 AST_LIST_INSERT_HEAD(oldlist, newframe, entries);
00510 AST_LIST_UNLOCK(oldlist);
00511 ast_channel_unlock(chan);
00512
00513 return 0;
00514
00515 error_exit:
00516 ast_channel_lock(chan);
00517
00518 error_exit_locked:
00519
00520 ast_copy_string(chan->context, orig_context, sizeof(chan->context));
00521 ast_copy_string(chan->exten, orig_exten, sizeof(chan->exten));
00522 chan->priority = orig_priority;
00523 ast_channel_unlock(chan);
00524 return -1;
00525 }
00526
00527 static int gosubif_exec(struct ast_channel *chan, const char *data)
00528 {
00529 char *args;
00530 int res=0;
00531 AST_DECLARE_APP_ARGS(cond,
00532 AST_APP_ARG(ition);
00533 AST_APP_ARG(labels);
00534 );
00535 AST_DECLARE_APP_ARGS(label,
00536 AST_APP_ARG(iftrue);
00537 AST_APP_ARG(iffalse);
00538 );
00539
00540 if (ast_strlen_zero(data)) {
00541 ast_log(LOG_WARNING, "GosubIf requires an argument: GosubIf(cond?label1(args):label2(args)\n");
00542 return 0;
00543 }
00544
00545 args = ast_strdupa(data);
00546 AST_NONSTANDARD_RAW_ARGS(cond, args, '?');
00547 if (cond.argc != 2) {
00548 ast_log(LOG_WARNING, "GosubIf requires an argument: GosubIf(cond?label1(args):label2(args)\n");
00549 return 0;
00550 }
00551
00552 AST_NONSTANDARD_RAW_ARGS(label, cond.labels, ':');
00553
00554 if (pbx_checkcondition(cond.ition)) {
00555 if (!ast_strlen_zero(label.iftrue))
00556 res = gosub_exec(chan, label.iftrue);
00557 } else if (!ast_strlen_zero(label.iffalse)) {
00558 res = gosub_exec(chan, label.iffalse);
00559 }
00560
00561 return res;
00562 }
00563
00564 static int local_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
00565 {
00566 struct ast_datastore *stack_store;
00567 AST_LIST_HEAD(, gosub_stack_frame) *oldlist;
00568 struct gosub_stack_frame *frame;
00569 struct ast_var_t *variables;
00570
00571 ast_channel_lock(chan);
00572 if (!(stack_store = ast_channel_datastore_find(chan, &stack_info, NULL))) {
00573 ast_channel_unlock(chan);
00574 return -1;
00575 }
00576
00577 oldlist = stack_store->data;
00578 AST_LIST_LOCK(oldlist);
00579 if (!(frame = AST_LIST_FIRST(oldlist))) {
00580
00581 AST_LIST_UNLOCK(oldlist);
00582 ast_channel_unlock(chan);
00583 return -1;
00584 }
00585
00586 AST_LIST_TRAVERSE(&frame->varshead, variables, entries) {
00587 if (!strcmp(data, ast_var_name(variables))) {
00588 const char *tmp;
00589 tmp = pbx_builtin_getvar_helper(chan, data);
00590 ast_copy_string(buf, S_OR(tmp, ""), len);
00591 break;
00592 }
00593 }
00594 AST_LIST_UNLOCK(oldlist);
00595 ast_channel_unlock(chan);
00596 return 0;
00597 }
00598
00599 static int local_write(struct ast_channel *chan, const char *cmd, char *var, const char *value)
00600 {
00601 struct ast_datastore *stack_store;
00602 AST_LIST_HEAD(, gosub_stack_frame) *oldlist;
00603 struct gosub_stack_frame *frame;
00604
00605 ast_channel_lock(chan);
00606 if (!(stack_store = ast_channel_datastore_find(chan, &stack_info, NULL))) {
00607 ast_log(LOG_ERROR, "Tried to set LOCAL(%s), but we aren't within a Gosub routine\n", var);
00608 ast_channel_unlock(chan);
00609 return -1;
00610 }
00611
00612 oldlist = stack_store->data;
00613 AST_LIST_LOCK(oldlist);
00614 frame = AST_LIST_FIRST(oldlist);
00615
00616 if (frame) {
00617 frame_set_var(chan, frame, var, value);
00618 }
00619
00620 AST_LIST_UNLOCK(oldlist);
00621 ast_channel_unlock(chan);
00622
00623 return 0;
00624 }
00625
00626 static struct ast_custom_function local_function = {
00627 .name = "LOCAL",
00628 .write = local_write,
00629 .read = local_read,
00630 };
00631
00632 static int peek_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
00633 {
00634 int found = 0, n;
00635 struct ast_var_t *variables;
00636 AST_DECLARE_APP_ARGS(args,
00637 AST_APP_ARG(n);
00638 AST_APP_ARG(name);
00639 );
00640
00641 if (!chan) {
00642 ast_log(LOG_ERROR, "LOCAL_PEEK must be called on an active channel\n");
00643 return -1;
00644 }
00645
00646 AST_STANDARD_RAW_ARGS(args, data);
00647 n = atoi(args.n);
00648 *buf = '\0';
00649
00650 ast_channel_lock(chan);
00651 AST_LIST_TRAVERSE(&chan->varshead, variables, entries) {
00652 if (!strcmp(args.name, ast_var_name(variables)) && ++found > n) {
00653 ast_copy_string(buf, ast_var_value(variables), len);
00654 break;
00655 }
00656 }
00657 ast_channel_unlock(chan);
00658 return 0;
00659 }
00660
00661 static struct ast_custom_function peek_function = {
00662 .name = "LOCAL_PEEK",
00663 .read = peek_read,
00664 };
00665
00666 static int stackpeek_read(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **str, ssize_t len)
00667 {
00668 struct ast_datastore *stack_store;
00669 AST_LIST_HEAD(, gosub_stack_frame) *oldlist;
00670 struct gosub_stack_frame *frame;
00671 int n;
00672 AST_DECLARE_APP_ARGS(args,
00673 AST_APP_ARG(n);
00674 AST_APP_ARG(which);
00675 AST_APP_ARG(suppress);
00676 );
00677
00678 if (!chan) {
00679 ast_log(LOG_ERROR, "STACK_PEEK must be called on an active channel\n");
00680 return -1;
00681 }
00682
00683 data = ast_strdupa(data);
00684 AST_STANDARD_APP_ARGS(args, data);
00685
00686 n = atoi(args.n);
00687 if (n <= 0) {
00688 ast_log(LOG_ERROR, "STACK_PEEK must be called with a positive peek value\n");
00689 return -1;
00690 }
00691
00692 ast_channel_lock(chan);
00693 if (!(stack_store = ast_channel_datastore_find(chan, &stack_info, NULL))) {
00694 if (!ast_true(args.suppress)) {
00695 ast_log(LOG_ERROR, "STACK_PEEK called on a channel without a gosub stack\n");
00696 }
00697 ast_channel_unlock(chan);
00698 return -1;
00699 }
00700
00701 oldlist = stack_store->data;
00702
00703 AST_LIST_LOCK(oldlist);
00704 AST_LIST_TRAVERSE(oldlist, frame, entries) {
00705 if (--n == 0) {
00706 break;
00707 }
00708 }
00709
00710 if (!frame) {
00711
00712 if (!ast_true(args.suppress)) {
00713 ast_log(LOG_ERROR, "Stack peek of '%s' is more stack frames than I have\n", args.n);
00714 }
00715 ast_channel_unlock(chan);
00716 return -1;
00717 }
00718
00719 args.which = ast_skip_blanks(args.which);
00720
00721 switch (args.which[0]) {
00722 case 'l':
00723 ast_str_set(str, len, "%s,%s,%d", frame->context, frame->extension, frame->priority - 1);
00724 break;
00725 case 'c':
00726 ast_str_set(str, len, "%s", frame->context);
00727 break;
00728 case 'e':
00729 ast_str_set(str, len, "%s", frame->extension);
00730 break;
00731 case 'p':
00732 ast_str_set(str, len, "%d", frame->priority - 1);
00733 break;
00734 default:
00735 ast_log(LOG_ERROR, "Unknown argument '%s' to STACK_PEEK\n", args.which);
00736 }
00737
00738 AST_LIST_UNLOCK(oldlist);
00739 ast_channel_unlock(chan);
00740
00741 return 0;
00742 }
00743
00744 static struct ast_custom_function stackpeek_function = {
00745 .name = "STACK_PEEK",
00746 .read2 = stackpeek_read,
00747 };
00748
00749 static int handle_gosub(struct ast_channel *chan, AGI *agi, int argc, const char * const *argv)
00750 {
00751 int old_priority, priority;
00752 char old_context[AST_MAX_CONTEXT], old_extension[AST_MAX_EXTENSION];
00753 struct ast_app *theapp;
00754 char *gosub_args;
00755
00756 if (argc < 4 || argc > 5) {
00757 return RESULT_SHOWUSAGE;
00758 }
00759
00760 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] : "");
00761
00762 if (sscanf(argv[3], "%30d", &priority) != 1 || priority < 1) {
00763
00764 priority = ast_findlabel_extension(chan, argv[1], argv[2], argv[3],
00765 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL));
00766 if (priority < 0) {
00767 ast_log(LOG_ERROR, "Priority '%s' not found in '%s@%s'\n", argv[3], argv[2], argv[1]);
00768 ast_agi_send(agi->fd, chan, "200 result=-1 Gosub label not found\n");
00769 return RESULT_FAILURE;
00770 }
00771 } else if (!ast_exists_extension(chan, argv[1], argv[2], priority,
00772 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
00773 ast_agi_send(agi->fd, chan, "200 result=-1 Gosub label not found\n");
00774 return RESULT_FAILURE;
00775 }
00776
00777
00778 ast_copy_string(old_context, chan->context, sizeof(old_context));
00779 ast_copy_string(old_extension, chan->exten, sizeof(old_extension));
00780 old_priority = chan->priority;
00781
00782 if (!(theapp = pbx_findapp("Gosub"))) {
00783 ast_log(LOG_ERROR, "Gosub() cannot be found in the list of loaded applications\n");
00784 ast_agi_send(agi->fd, chan, "503 result=-2 Gosub is not loaded\n");
00785 return RESULT_FAILURE;
00786 }
00787
00788
00789
00790
00791
00792
00793
00794 if (argc == 5) {
00795 if (asprintf(&gosub_args, "%s,%s,%d(%s)", argv[1], argv[2], priority + (chan->pbx ? 1 : 0), argv[4]) < 0) {
00796 ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno));
00797 gosub_args = NULL;
00798 }
00799 } else {
00800 if (asprintf(&gosub_args, "%s,%s,%d", argv[1], argv[2], priority + (chan->pbx ? 1 : 0)) < 0) {
00801 ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno));
00802 gosub_args = NULL;
00803 }
00804 }
00805
00806 if (gosub_args) {
00807 int res;
00808
00809 ast_debug(1, "Trying gosub with arguments '%s'\n", gosub_args);
00810
00811 if ((res = pbx_exec(chan, theapp, gosub_args)) == 0) {
00812 struct ast_pbx *pbx = chan->pbx;
00813 struct ast_pbx_args args;
00814 struct ast_datastore *stack_store = ast_channel_datastore_find(chan, &stack_info, NULL);
00815 AST_LIST_HEAD(, gosub_stack_frame) *oldlist;
00816 struct gosub_stack_frame *cur;
00817 if (!stack_store) {
00818 ast_log(LOG_WARNING, "No GoSub stack remaining after AGI GoSub execution.\n");
00819 ast_free(gosub_args);
00820 return RESULT_FAILURE;
00821 }
00822 oldlist = stack_store->data;
00823 cur = AST_LIST_FIRST(oldlist);
00824 cur->is_agi = 1;
00825
00826 memset(&args, 0, sizeof(args));
00827 args.no_hangup_chan = 1;
00828
00829 chan->pbx = NULL;
00830 ast_agi_send(agi->fd, chan, "100 result=0 Trying...\n");
00831 ast_pbx_run_args(chan, &args);
00832 ast_agi_send(agi->fd, chan, "200 result=0 Gosub complete\n");
00833 if (chan->pbx) {
00834 ast_free(chan->pbx);
00835 }
00836 chan->pbx = pbx;
00837 } else {
00838 ast_agi_send(agi->fd, chan, "200 result=%d Gosub failed\n", res);
00839 }
00840 ast_free(gosub_args);
00841 } else {
00842 ast_agi_send(agi->fd, chan, "503 result=-2 Memory allocation failure\n");
00843 return RESULT_FAILURE;
00844 }
00845
00846
00847 ast_copy_string(chan->context, old_context, sizeof(chan->context));
00848 ast_copy_string(chan->exten, old_extension, sizeof(chan->exten));
00849 chan->priority = old_priority;
00850
00851 return RESULT_SUCCESS;
00852 }
00853
00854 static struct agi_command gosub_agi_command =
00855 { { "gosub", NULL }, handle_gosub, NULL, NULL, 0 };
00856
00857 static int unload_module(void)
00858 {
00859 ast_agi_unregister(ast_module_info->self, &gosub_agi_command);
00860
00861 ast_unregister_application(app_return);
00862 ast_unregister_application(app_pop);
00863 ast_unregister_application(app_gosubif);
00864 ast_unregister_application(app_gosub);
00865 ast_custom_function_unregister(&local_function);
00866 ast_custom_function_unregister(&peek_function);
00867 ast_custom_function_unregister(&stackpeek_function);
00868
00869 return 0;
00870 }
00871
00872 static int load_module(void)
00873 {
00874 ast_agi_register(ast_module_info->self, &gosub_agi_command);
00875
00876 ast_register_application_xml(app_pop, pop_exec);
00877 ast_register_application_xml(app_return, return_exec);
00878 ast_register_application_xml(app_gosubif, gosubif_exec);
00879 ast_register_application_xml(app_gosub, gosub_exec);
00880 ast_custom_function_register(&local_function);
00881 ast_custom_function_register(&peek_function);
00882 ast_custom_function_register(&stackpeek_function);
00883
00884 return 0;
00885 }
00886
00887 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT | AST_MODFLAG_LOAD_ORDER, "Dialplan subroutines (Gosub, Return, etc)",
00888 .load = load_module,
00889 .unload = unload_module,
00890 .load_pri = AST_MODPRI_APP_DEPEND,
00891 .nonoptreq = "res_agi",
00892 );