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