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: 396279 $")
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 if ((variables = ast_var_assign(var, ""))) {
00246 AST_LIST_INSERT_HEAD(&frame->varshead, variables, entries);
00247 }
00248 pbx_builtin_pushvar_helper(chan, var, value);
00249 } else {
00250 pbx_builtin_setvar_helper(chan, var, value);
00251 }
00252
00253 manager_event(EVENT_FLAG_DIALPLAN, "VarSet",
00254 "Channel: %s\r\n"
00255 "Variable: LOCAL(%s)\r\n"
00256 "Value: %s\r\n"
00257 "Uniqueid: %s\r\n",
00258 chan->name, var, value, chan->uniqueid);
00259 return 0;
00260 }
00261
00262 static void gosub_release_frame(struct ast_channel *chan, struct gosub_stack_frame *frame)
00263 {
00264 struct ast_var_t *vardata;
00265
00266
00267
00268
00269
00270
00271
00272 while ((vardata = AST_LIST_REMOVE_HEAD(&frame->varshead, entries))) {
00273 if (chan)
00274 pbx_builtin_setvar_helper(chan, ast_var_name(vardata), NULL);
00275 ast_var_delete(vardata);
00276 }
00277
00278 ast_free(frame);
00279 }
00280
00281 static struct gosub_stack_frame *gosub_allocate_frame(const char *context, const char *extension, int priority, unsigned char arguments)
00282 {
00283 struct gosub_stack_frame *new = NULL;
00284 int len_extension = strlen(extension), len_context = strlen(context);
00285
00286 if ((new = ast_calloc(1, sizeof(*new) + 2 + len_extension + len_context))) {
00287 AST_LIST_HEAD_INIT_NOLOCK(&new->varshead);
00288 strcpy(new->extension, extension);
00289 new->context = new->extension + len_extension + 1;
00290 strcpy(new->context, context);
00291 new->priority = priority;
00292 new->arguments = arguments;
00293 }
00294 return new;
00295 }
00296
00297 static void gosub_free(void *data)
00298 {
00299 AST_LIST_HEAD(, gosub_stack_frame) *oldlist = data;
00300 struct gosub_stack_frame *oldframe;
00301 AST_LIST_LOCK(oldlist);
00302 while ((oldframe = AST_LIST_REMOVE_HEAD(oldlist, entries))) {
00303 gosub_release_frame(NULL, oldframe);
00304 }
00305 AST_LIST_UNLOCK(oldlist);
00306 AST_LIST_HEAD_DESTROY(oldlist);
00307 ast_free(oldlist);
00308 }
00309
00310 static int pop_exec(struct ast_channel *chan, const char *data)
00311 {
00312 struct ast_datastore *stack_store;
00313 struct gosub_stack_frame *oldframe;
00314 AST_LIST_HEAD(, gosub_stack_frame) *oldlist;
00315
00316 ast_channel_lock(chan);
00317 if (!(stack_store = ast_channel_datastore_find(chan, &stack_info, NULL))) {
00318 ast_log(LOG_WARNING, "%s called with no gosub stack allocated.\n", app_pop);
00319 ast_channel_unlock(chan);
00320 return 0;
00321 }
00322
00323 oldlist = stack_store->data;
00324 AST_LIST_LOCK(oldlist);
00325 oldframe = AST_LIST_REMOVE_HEAD(oldlist, entries);
00326 AST_LIST_UNLOCK(oldlist);
00327
00328 if (oldframe) {
00329 gosub_release_frame(chan, oldframe);
00330 } else {
00331 ast_debug(1, "%s called with an empty gosub stack\n", app_pop);
00332 }
00333 ast_channel_unlock(chan);
00334 return 0;
00335 }
00336
00337 static int return_exec(struct ast_channel *chan, const char *data)
00338 {
00339 struct ast_datastore *stack_store;
00340 struct gosub_stack_frame *oldframe;
00341 AST_LIST_HEAD(, gosub_stack_frame) *oldlist;
00342 const char *retval = data;
00343 int res = 0;
00344
00345 ast_channel_lock(chan);
00346 if (!(stack_store = ast_channel_datastore_find(chan, &stack_info, NULL))) {
00347 ast_log(LOG_ERROR, "Return without Gosub: stack is unallocated\n");
00348 ast_channel_unlock(chan);
00349 return -1;
00350 }
00351
00352 oldlist = stack_store->data;
00353 AST_LIST_LOCK(oldlist);
00354 oldframe = AST_LIST_REMOVE_HEAD(oldlist, entries);
00355 AST_LIST_UNLOCK(oldlist);
00356
00357 if (!oldframe) {
00358 ast_log(LOG_ERROR, "Return without Gosub: stack is empty\n");
00359 ast_channel_unlock(chan);
00360 return -1;
00361 } else if (oldframe->is_agi) {
00362
00363 res = -1;
00364 }
00365
00366 ast_explicit_goto(chan, oldframe->context, oldframe->extension, oldframe->priority);
00367 gosub_release_frame(chan, oldframe);
00368
00369
00370 pbx_builtin_setvar_helper(chan, "GOSUB_RETVAL", S_OR(retval, ""));
00371 ast_channel_unlock(chan);
00372 return res;
00373 }
00374
00375 static int gosub_exec(struct ast_channel *chan, const char *data)
00376 {
00377 struct ast_datastore *stack_store;
00378 AST_LIST_HEAD(, gosub_stack_frame) *oldlist;
00379 struct gosub_stack_frame *newframe;
00380 struct gosub_stack_frame *lastframe;
00381 char argname[15];
00382 char *parse;
00383 char *label;
00384 char *caller_id;
00385 char *orig_context;
00386 char *orig_exten;
00387 char *dest_context;
00388 char *dest_exten;
00389 int orig_priority;
00390 int dest_priority;
00391 int i;
00392 int max_argc = 0;
00393 AST_DECLARE_APP_ARGS(args2,
00394 AST_APP_ARG(argval)[100];
00395 );
00396
00397 if (ast_strlen_zero(data)) {
00398 ast_log(LOG_ERROR, "%s requires an argument: %s([[context,]exten,]priority[(arg1[,...][,argN])])\n", app_gosub, app_gosub);
00399 return -1;
00400 }
00401
00402
00403
00404
00405
00406
00407
00408 parse = ast_strdupa(data);
00409 label = strsep(&parse, "(");
00410 if (parse) {
00411 char *endparen;
00412
00413 endparen = strrchr(parse, ')');
00414 if (endparen) {
00415 *endparen = '\0';
00416 } else {
00417 ast_log(LOG_WARNING, "Ouch. No closing paren: '%s'?\n", data);
00418 }
00419 AST_STANDARD_RAW_ARGS(args2, parse);
00420 } else {
00421 args2.argc = 0;
00422 }
00423
00424 ast_channel_lock(chan);
00425 orig_context = ast_strdupa(chan->context);
00426 orig_exten = ast_strdupa(chan->exten);
00427 orig_priority = chan->priority;
00428 ast_channel_unlock(chan);
00429
00430 if (ast_parseable_goto(chan, label)) {
00431 ast_log(LOG_ERROR, "%s address is invalid: '%s'\n", app_gosub, data);
00432 goto error_exit;
00433 }
00434
00435 ast_channel_lock(chan);
00436 dest_context = ast_strdupa(chan->context);
00437 dest_exten = ast_strdupa(chan->exten);
00438 dest_priority = chan->priority;
00439 if (ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP)) {
00440 ++dest_priority;
00441 }
00442 caller_id = S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL);
00443 if (caller_id) {
00444 caller_id = ast_strdupa(caller_id);
00445 }
00446 ast_channel_unlock(chan);
00447
00448 if (!ast_exists_extension(chan, dest_context, dest_exten, dest_priority, caller_id)) {
00449 ast_log(LOG_ERROR, "Attempt to reach a non-existent destination for %s: (Context:%s, Extension:%s, Priority:%d)\n",
00450 app_gosub, dest_context, dest_exten, dest_priority);
00451 goto error_exit;
00452 }
00453
00454
00455
00456 ast_channel_lock(chan);
00457
00458
00459 if (!(stack_store = ast_channel_datastore_find(chan, &stack_info, NULL))) {
00460 ast_debug(1, "Channel %s has no datastore, so we're allocating one.\n",
00461 chan->name);
00462 stack_store = ast_datastore_alloc(&stack_info, NULL);
00463 if (!stack_store) {
00464 ast_log(LOG_ERROR, "Unable to allocate new datastore. %s failed.\n",
00465 app_gosub);
00466 goto error_exit_locked;
00467 }
00468
00469 oldlist = ast_calloc(1, sizeof(*oldlist));
00470 if (!oldlist) {
00471 ast_log(LOG_ERROR, "Unable to allocate datastore list head. %s failed.\n",
00472 app_gosub);
00473 ast_datastore_free(stack_store);
00474 goto error_exit_locked;
00475 }
00476 AST_LIST_HEAD_INIT(oldlist);
00477
00478 stack_store->data = oldlist;
00479 ast_channel_datastore_add(chan, stack_store);
00480 } else {
00481 oldlist = stack_store->data;
00482 }
00483
00484 if ((lastframe = AST_LIST_FIRST(oldlist))) {
00485 max_argc = lastframe->arguments;
00486 }
00487
00488
00489 if (args2.argc > max_argc) {
00490 max_argc = args2.argc;
00491 }
00492
00493
00494 newframe = gosub_allocate_frame(orig_context, orig_exten, orig_priority + 1, max_argc);
00495 if (!newframe) {
00496 goto error_exit_locked;
00497 }
00498
00499
00500 for (i = 0; i < max_argc; i++) {
00501 snprintf(argname, sizeof(argname), "ARG%d", i + 1);
00502 frame_set_var(chan, newframe, argname, i < args2.argc ? args2.argval[i] : "");
00503 ast_debug(1, "Setting '%s' to '%s'\n", argname, i < args2.argc ? args2.argval[i] : "");
00504 }
00505 snprintf(argname, sizeof(argname), "%d", args2.argc);
00506 frame_set_var(chan, newframe, "ARGC", argname);
00507
00508
00509 AST_LIST_LOCK(oldlist);
00510 AST_LIST_INSERT_HEAD(oldlist, newframe, entries);
00511 AST_LIST_UNLOCK(oldlist);
00512 ast_channel_unlock(chan);
00513
00514 return 0;
00515
00516 error_exit:
00517 ast_channel_lock(chan);
00518
00519 error_exit_locked:
00520
00521 ast_copy_string(chan->context, orig_context, sizeof(chan->context));
00522 ast_copy_string(chan->exten, orig_exten, sizeof(chan->exten));
00523 chan->priority = orig_priority;
00524 ast_channel_unlock(chan);
00525 return -1;
00526 }
00527
00528 static int gosubif_exec(struct ast_channel *chan, const char *data)
00529 {
00530 char *args;
00531 int res=0;
00532 AST_DECLARE_APP_ARGS(cond,
00533 AST_APP_ARG(ition);
00534 AST_APP_ARG(labels);
00535 );
00536 AST_DECLARE_APP_ARGS(label,
00537 AST_APP_ARG(iftrue);
00538 AST_APP_ARG(iffalse);
00539 );
00540
00541 if (ast_strlen_zero(data)) {
00542 ast_log(LOG_WARNING, "GosubIf requires an argument: GosubIf(cond?label1(args):label2(args)\n");
00543 return 0;
00544 }
00545
00546 args = ast_strdupa(data);
00547 AST_NONSTANDARD_RAW_ARGS(cond, args, '?');
00548 if (cond.argc != 2) {
00549 ast_log(LOG_WARNING, "GosubIf requires an argument: GosubIf(cond?label1(args):label2(args)\n");
00550 return 0;
00551 }
00552
00553 AST_NONSTANDARD_RAW_ARGS(label, cond.labels, ':');
00554
00555 if (pbx_checkcondition(cond.ition)) {
00556 if (!ast_strlen_zero(label.iftrue))
00557 res = gosub_exec(chan, label.iftrue);
00558 } else if (!ast_strlen_zero(label.iffalse)) {
00559 res = gosub_exec(chan, label.iffalse);
00560 }
00561
00562 return res;
00563 }
00564
00565 static int local_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
00566 {
00567 struct ast_datastore *stack_store;
00568 AST_LIST_HEAD(, gosub_stack_frame) *oldlist;
00569 struct gosub_stack_frame *frame;
00570 struct ast_var_t *variables;
00571
00572 ast_channel_lock(chan);
00573 if (!(stack_store = ast_channel_datastore_find(chan, &stack_info, NULL))) {
00574 ast_channel_unlock(chan);
00575 return -1;
00576 }
00577
00578 oldlist = stack_store->data;
00579 AST_LIST_LOCK(oldlist);
00580 if (!(frame = AST_LIST_FIRST(oldlist))) {
00581
00582 AST_LIST_UNLOCK(oldlist);
00583 ast_channel_unlock(chan);
00584 return -1;
00585 }
00586
00587 AST_LIST_TRAVERSE(&frame->varshead, variables, entries) {
00588 if (!strcmp(data, ast_var_name(variables))) {
00589 const char *tmp;
00590 tmp = pbx_builtin_getvar_helper(chan, data);
00591 ast_copy_string(buf, S_OR(tmp, ""), len);
00592 break;
00593 }
00594 }
00595 AST_LIST_UNLOCK(oldlist);
00596 ast_channel_unlock(chan);
00597 return 0;
00598 }
00599
00600 static int local_write(struct ast_channel *chan, const char *cmd, char *var, const char *value)
00601 {
00602 struct ast_datastore *stack_store;
00603 AST_LIST_HEAD(, gosub_stack_frame) *oldlist;
00604 struct gosub_stack_frame *frame;
00605
00606 ast_channel_lock(chan);
00607 if (!(stack_store = ast_channel_datastore_find(chan, &stack_info, NULL))) {
00608 ast_log(LOG_ERROR, "Tried to set LOCAL(%s), but we aren't within a Gosub routine\n", var);
00609 ast_channel_unlock(chan);
00610 return -1;
00611 }
00612
00613 oldlist = stack_store->data;
00614 AST_LIST_LOCK(oldlist);
00615 frame = AST_LIST_FIRST(oldlist);
00616
00617 if (frame) {
00618 frame_set_var(chan, frame, var, value);
00619 }
00620
00621 AST_LIST_UNLOCK(oldlist);
00622 ast_channel_unlock(chan);
00623
00624 return 0;
00625 }
00626
00627 static struct ast_custom_function local_function = {
00628 .name = "LOCAL",
00629 .write = local_write,
00630 .read = local_read,
00631 };
00632
00633 static int peek_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
00634 {
00635 int found = 0, n;
00636 struct ast_var_t *variables;
00637 AST_DECLARE_APP_ARGS(args,
00638 AST_APP_ARG(n);
00639 AST_APP_ARG(name);
00640 );
00641
00642 if (!chan) {
00643 ast_log(LOG_ERROR, "LOCAL_PEEK must be called on an active channel\n");
00644 return -1;
00645 }
00646
00647 AST_STANDARD_RAW_ARGS(args, data);
00648 n = atoi(args.n);
00649 *buf = '\0';
00650
00651 ast_channel_lock(chan);
00652 AST_LIST_TRAVERSE(&chan->varshead, variables, entries) {
00653 if (!strcmp(args.name, ast_var_name(variables)) && ++found > n) {
00654 ast_copy_string(buf, ast_var_value(variables), len);
00655 break;
00656 }
00657 }
00658 ast_channel_unlock(chan);
00659 return 0;
00660 }
00661
00662 static struct ast_custom_function peek_function = {
00663 .name = "LOCAL_PEEK",
00664 .read = peek_read,
00665 };
00666
00667 static int stackpeek_read(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **str, ssize_t len)
00668 {
00669 struct ast_datastore *stack_store;
00670 AST_LIST_HEAD(, gosub_stack_frame) *oldlist;
00671 struct gosub_stack_frame *frame;
00672 int n;
00673 AST_DECLARE_APP_ARGS(args,
00674 AST_APP_ARG(n);
00675 AST_APP_ARG(which);
00676 AST_APP_ARG(suppress);
00677 );
00678
00679 if (!chan) {
00680 ast_log(LOG_ERROR, "STACK_PEEK must be called on an active channel\n");
00681 return -1;
00682 }
00683
00684 data = ast_strdupa(data);
00685 AST_STANDARD_APP_ARGS(args, data);
00686
00687 n = atoi(args.n);
00688 if (n <= 0) {
00689 ast_log(LOG_ERROR, "STACK_PEEK must be called with a positive peek value\n");
00690 return -1;
00691 }
00692
00693 ast_channel_lock(chan);
00694 if (!(stack_store = ast_channel_datastore_find(chan, &stack_info, NULL))) {
00695 if (!ast_true(args.suppress)) {
00696 ast_log(LOG_ERROR, "STACK_PEEK called on a channel without a gosub stack\n");
00697 }
00698 ast_channel_unlock(chan);
00699 return -1;
00700 }
00701
00702 oldlist = stack_store->data;
00703
00704 AST_LIST_LOCK(oldlist);
00705 AST_LIST_TRAVERSE(oldlist, frame, entries) {
00706 if (--n == 0) {
00707 break;
00708 }
00709 }
00710
00711 if (!frame) {
00712
00713 if (!ast_true(args.suppress)) {
00714 ast_log(LOG_ERROR, "Stack peek of '%s' is more stack frames than I have\n", args.n);
00715 }
00716 ast_channel_unlock(chan);
00717 return -1;
00718 }
00719
00720 args.which = ast_skip_blanks(args.which);
00721
00722 switch (args.which[0]) {
00723 case 'l':
00724 ast_str_set(str, len, "%s,%s,%d", frame->context, frame->extension, frame->priority - 1);
00725 break;
00726 case 'c':
00727 ast_str_set(str, len, "%s", frame->context);
00728 break;
00729 case 'e':
00730 ast_str_set(str, len, "%s", frame->extension);
00731 break;
00732 case 'p':
00733 ast_str_set(str, len, "%d", frame->priority - 1);
00734 break;
00735 default:
00736 ast_log(LOG_ERROR, "Unknown argument '%s' to STACK_PEEK\n", args.which);
00737 }
00738
00739 AST_LIST_UNLOCK(oldlist);
00740 ast_channel_unlock(chan);
00741
00742 return 0;
00743 }
00744
00745 static struct ast_custom_function stackpeek_function = {
00746 .name = "STACK_PEEK",
00747 .read2 = stackpeek_read,
00748 };
00749
00750 static int handle_gosub(struct ast_channel *chan, AGI *agi, int argc, const char * const *argv)
00751 {
00752 int old_priority, priority;
00753 char old_context[AST_MAX_CONTEXT], old_extension[AST_MAX_EXTENSION];
00754 struct ast_app *theapp;
00755 char *gosub_args;
00756
00757 if (argc < 4 || argc > 5) {
00758 return RESULT_SHOWUSAGE;
00759 }
00760
00761 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] : "");
00762
00763 if (sscanf(argv[3], "%30d", &priority) != 1 || priority < 1) {
00764
00765 priority = ast_findlabel_extension(chan, argv[1], argv[2], argv[3],
00766 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL));
00767 if (priority < 0) {
00768 ast_log(LOG_ERROR, "Priority '%s' not found in '%s@%s'\n", argv[3], argv[2], argv[1]);
00769 ast_agi_send(agi->fd, chan, "200 result=-1 Gosub label not found\n");
00770 return RESULT_FAILURE;
00771 }
00772 } else if (!ast_exists_extension(chan, argv[1], argv[2], priority,
00773 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
00774 ast_agi_send(agi->fd, chan, "200 result=-1 Gosub label not found\n");
00775 return RESULT_FAILURE;
00776 }
00777
00778
00779 ast_copy_string(old_context, chan->context, sizeof(old_context));
00780 ast_copy_string(old_extension, chan->exten, sizeof(old_extension));
00781 old_priority = chan->priority;
00782
00783 if (!(theapp = pbx_findapp("Gosub"))) {
00784 ast_log(LOG_ERROR, "Gosub() cannot be found in the list of loaded applications\n");
00785 ast_agi_send(agi->fd, chan, "503 result=-2 Gosub is not loaded\n");
00786 return RESULT_FAILURE;
00787 }
00788
00789
00790
00791
00792
00793
00794
00795 if (argc == 5) {
00796 if (ast_asprintf(&gosub_args, "%s,%s,%d(%s)", argv[1], argv[2], priority + (chan->pbx ? 1 : 0), argv[4]) < 0) {
00797 gosub_args = NULL;
00798 }
00799 } else {
00800 if (ast_asprintf(&gosub_args, "%s,%s,%d", argv[1], argv[2], priority + (chan->pbx ? 1 : 0)) < 0) {
00801 gosub_args = NULL;
00802 }
00803 }
00804
00805 if (gosub_args) {
00806 int res;
00807
00808 ast_debug(1, "Trying gosub with arguments '%s'\n", gosub_args);
00809
00810 if ((res = pbx_exec(chan, theapp, gosub_args)) == 0) {
00811 struct ast_pbx *pbx = chan->pbx;
00812 struct ast_pbx_args args;
00813 struct ast_datastore *stack_store = ast_channel_datastore_find(chan, &stack_info, NULL);
00814 AST_LIST_HEAD(, gosub_stack_frame) *oldlist;
00815 struct gosub_stack_frame *cur;
00816 if (!stack_store) {
00817 ast_log(LOG_WARNING, "No GoSub stack remaining after AGI GoSub execution.\n");
00818 ast_free(gosub_args);
00819 return RESULT_FAILURE;
00820 }
00821 oldlist = stack_store->data;
00822 cur = AST_LIST_FIRST(oldlist);
00823 cur->is_agi = 1;
00824
00825 memset(&args, 0, sizeof(args));
00826 args.no_hangup_chan = 1;
00827
00828 chan->pbx = NULL;
00829 ast_agi_send(agi->fd, chan, "100 result=0 Trying...\n");
00830 ast_pbx_run_args(chan, &args);
00831 ast_agi_send(agi->fd, chan, "200 result=0 Gosub complete\n");
00832 if (chan->pbx) {
00833 ast_free(chan->pbx);
00834 }
00835 chan->pbx = pbx;
00836 } else {
00837 ast_agi_send(agi->fd, chan, "200 result=%d Gosub failed\n", res);
00838 }
00839 ast_free(gosub_args);
00840 } else {
00841 ast_agi_send(agi->fd, chan, "503 result=-2 Memory allocation failure\n");
00842 return RESULT_FAILURE;
00843 }
00844
00845
00846 ast_copy_string(chan->context, old_context, sizeof(chan->context));
00847 ast_copy_string(chan->exten, old_extension, sizeof(chan->exten));
00848 chan->priority = old_priority;
00849
00850 return RESULT_SUCCESS;
00851 }
00852
00853 static struct agi_command gosub_agi_command =
00854 { { "gosub", NULL }, handle_gosub, NULL, NULL, 0 };
00855
00856 static int unload_module(void)
00857 {
00858 ast_agi_unregister(ast_module_info->self, &gosub_agi_command);
00859
00860 ast_unregister_application(app_return);
00861 ast_unregister_application(app_pop);
00862 ast_unregister_application(app_gosubif);
00863 ast_unregister_application(app_gosub);
00864 ast_custom_function_unregister(&local_function);
00865 ast_custom_function_unregister(&peek_function);
00866 ast_custom_function_unregister(&stackpeek_function);
00867
00868 return 0;
00869 }
00870
00871 static int load_module(void)
00872 {
00873 ast_agi_register(ast_module_info->self, &gosub_agi_command);
00874
00875 ast_register_application_xml(app_pop, pop_exec);
00876 ast_register_application_xml(app_return, return_exec);
00877 ast_register_application_xml(app_gosubif, gosubif_exec);
00878 ast_register_application_xml(app_gosub, gosub_exec);
00879 ast_custom_function_register(&local_function);
00880 ast_custom_function_register(&peek_function);
00881 ast_custom_function_register(&stackpeek_function);
00882
00883 return 0;
00884 }
00885
00886 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT | AST_MODFLAG_LOAD_ORDER, "Dialplan subroutines (Gosub, Return, etc)",
00887 .load = load_module,
00888 .unload = unload_module,
00889 .load_pri = AST_MODPRI_APP_DEPEND,
00890 .nonoptreq = "res_agi",
00891 );