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: 411313 $")
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 if (!chan) {
00573 ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
00574 return -1;
00575 }
00576
00577 ast_channel_lock(chan);
00578 if (!(stack_store = ast_channel_datastore_find(chan, &stack_info, NULL))) {
00579 ast_channel_unlock(chan);
00580 return -1;
00581 }
00582
00583 oldlist = stack_store->data;
00584 AST_LIST_LOCK(oldlist);
00585 if (!(frame = AST_LIST_FIRST(oldlist))) {
00586
00587 AST_LIST_UNLOCK(oldlist);
00588 ast_channel_unlock(chan);
00589 return -1;
00590 }
00591
00592 AST_LIST_TRAVERSE(&frame->varshead, variables, entries) {
00593 if (!strcmp(data, ast_var_name(variables))) {
00594 const char *tmp;
00595 tmp = pbx_builtin_getvar_helper(chan, data);
00596 ast_copy_string(buf, S_OR(tmp, ""), len);
00597 break;
00598 }
00599 }
00600 AST_LIST_UNLOCK(oldlist);
00601 ast_channel_unlock(chan);
00602 return 0;
00603 }
00604
00605 static int local_write(struct ast_channel *chan, const char *cmd, char *var, const char *value)
00606 {
00607 struct ast_datastore *stack_store;
00608 AST_LIST_HEAD(, gosub_stack_frame) *oldlist;
00609 struct gosub_stack_frame *frame;
00610
00611 if (!chan) {
00612 ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
00613 return -1;
00614 }
00615
00616 ast_channel_lock(chan);
00617 if (!(stack_store = ast_channel_datastore_find(chan, &stack_info, NULL))) {
00618 ast_log(LOG_ERROR, "Tried to set LOCAL(%s), but we aren't within a Gosub routine\n", var);
00619 ast_channel_unlock(chan);
00620 return -1;
00621 }
00622
00623 oldlist = stack_store->data;
00624 AST_LIST_LOCK(oldlist);
00625 frame = AST_LIST_FIRST(oldlist);
00626
00627 if (frame) {
00628 frame_set_var(chan, frame, var, value);
00629 }
00630
00631 AST_LIST_UNLOCK(oldlist);
00632 ast_channel_unlock(chan);
00633
00634 return 0;
00635 }
00636
00637 static struct ast_custom_function local_function = {
00638 .name = "LOCAL",
00639 .write = local_write,
00640 .read = local_read,
00641 };
00642
00643 static int peek_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
00644 {
00645 int found = 0, n;
00646 struct ast_var_t *variables;
00647 AST_DECLARE_APP_ARGS(args,
00648 AST_APP_ARG(n);
00649 AST_APP_ARG(name);
00650 );
00651
00652 if (!chan) {
00653 ast_log(LOG_ERROR, "LOCAL_PEEK must be called on an active channel\n");
00654 return -1;
00655 }
00656
00657 AST_STANDARD_RAW_ARGS(args, data);
00658
00659 if (ast_strlen_zero(args.n) || ast_strlen_zero(args.name)) {
00660 ast_log(LOG_ERROR, "LOCAL_PEEK requires parameters n and varname\n");
00661 return -1;
00662 }
00663
00664 n = atoi(args.n);
00665 *buf = '\0';
00666
00667 ast_channel_lock(chan);
00668 AST_LIST_TRAVERSE(&chan->varshead, variables, entries) {
00669 if (!strcmp(args.name, ast_var_name(variables)) && ++found > n) {
00670 ast_copy_string(buf, ast_var_value(variables), len);
00671 break;
00672 }
00673 }
00674 ast_channel_unlock(chan);
00675 return 0;
00676 }
00677
00678 static struct ast_custom_function peek_function = {
00679 .name = "LOCAL_PEEK",
00680 .read = peek_read,
00681 };
00682
00683 static int stackpeek_read(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **str, ssize_t len)
00684 {
00685 struct ast_datastore *stack_store;
00686 AST_LIST_HEAD(, gosub_stack_frame) *oldlist;
00687 struct gosub_stack_frame *frame;
00688 int n;
00689 AST_DECLARE_APP_ARGS(args,
00690 AST_APP_ARG(n);
00691 AST_APP_ARG(which);
00692 AST_APP_ARG(suppress);
00693 );
00694
00695 if (!chan) {
00696 ast_log(LOG_ERROR, "STACK_PEEK must be called on an active channel\n");
00697 return -1;
00698 }
00699
00700 data = ast_strdupa(data);
00701 AST_STANDARD_APP_ARGS(args, data);
00702
00703 if (ast_strlen_zero(args.n) || ast_strlen_zero(args.which)) {
00704 ast_log(LOG_ERROR, "STACK_PEEK requires parameters n and which\n");
00705 return -1;
00706 }
00707
00708 n = atoi(args.n);
00709 if (n <= 0) {
00710 ast_log(LOG_ERROR, "STACK_PEEK must be called with a positive peek value\n");
00711 return -1;
00712 }
00713
00714 ast_channel_lock(chan);
00715 if (!(stack_store = ast_channel_datastore_find(chan, &stack_info, NULL))) {
00716 if (!ast_true(args.suppress)) {
00717 ast_log(LOG_ERROR, "STACK_PEEK called on a channel without a gosub stack\n");
00718 }
00719 ast_channel_unlock(chan);
00720 return -1;
00721 }
00722
00723 oldlist = stack_store->data;
00724
00725 AST_LIST_LOCK(oldlist);
00726 AST_LIST_TRAVERSE(oldlist, frame, entries) {
00727 if (--n == 0) {
00728 break;
00729 }
00730 }
00731
00732 if (!frame) {
00733
00734 if (!ast_true(args.suppress)) {
00735 ast_log(LOG_ERROR, "Stack peek of '%s' is more stack frames than I have\n", args.n);
00736 }
00737 ast_channel_unlock(chan);
00738 return -1;
00739 }
00740
00741 args.which = ast_skip_blanks(args.which);
00742
00743 switch (args.which[0]) {
00744 case 'l':
00745 ast_str_set(str, len, "%s,%s,%d", frame->context, frame->extension, frame->priority - 1);
00746 break;
00747 case 'c':
00748 ast_str_set(str, len, "%s", frame->context);
00749 break;
00750 case 'e':
00751 ast_str_set(str, len, "%s", frame->extension);
00752 break;
00753 case 'p':
00754 ast_str_set(str, len, "%d", frame->priority - 1);
00755 break;
00756 default:
00757 ast_log(LOG_ERROR, "Unknown argument '%s' to STACK_PEEK\n", args.which);
00758 }
00759
00760 AST_LIST_UNLOCK(oldlist);
00761 ast_channel_unlock(chan);
00762
00763 return 0;
00764 }
00765
00766 static struct ast_custom_function stackpeek_function = {
00767 .name = "STACK_PEEK",
00768 .read2 = stackpeek_read,
00769 };
00770
00771 static int handle_gosub(struct ast_channel *chan, AGI *agi, int argc, const char * const *argv)
00772 {
00773 int old_priority, priority;
00774 char old_context[AST_MAX_CONTEXT], old_extension[AST_MAX_EXTENSION];
00775 struct ast_app *theapp;
00776 char *gosub_args;
00777
00778 if (argc < 4 || argc > 5) {
00779 return RESULT_SHOWUSAGE;
00780 }
00781
00782 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] : "");
00783
00784 if (sscanf(argv[3], "%30d", &priority) != 1 || priority < 1) {
00785
00786 priority = ast_findlabel_extension(chan, argv[1], argv[2], argv[3],
00787 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL));
00788 if (priority < 0) {
00789 ast_log(LOG_ERROR, "Priority '%s' not found in '%s@%s'\n", argv[3], argv[2], argv[1]);
00790 ast_agi_send(agi->fd, chan, "200 result=-1 Gosub label not found\n");
00791 return RESULT_FAILURE;
00792 }
00793 } else if (!ast_exists_extension(chan, argv[1], argv[2], priority,
00794 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
00795 ast_agi_send(agi->fd, chan, "200 result=-1 Gosub label not found\n");
00796 return RESULT_FAILURE;
00797 }
00798
00799
00800 ast_copy_string(old_context, chan->context, sizeof(old_context));
00801 ast_copy_string(old_extension, chan->exten, sizeof(old_extension));
00802 old_priority = chan->priority;
00803
00804 if (!(theapp = pbx_findapp("Gosub"))) {
00805 ast_log(LOG_ERROR, "Gosub() cannot be found in the list of loaded applications\n");
00806 ast_agi_send(agi->fd, chan, "503 result=-2 Gosub is not loaded\n");
00807 return RESULT_FAILURE;
00808 }
00809
00810
00811
00812
00813
00814
00815
00816 if (argc == 5) {
00817 if (ast_asprintf(&gosub_args, "%s,%s,%d(%s)", argv[1], argv[2], priority + (chan->pbx ? 1 : 0), argv[4]) < 0) {
00818 gosub_args = NULL;
00819 }
00820 } else {
00821 if (ast_asprintf(&gosub_args, "%s,%s,%d", argv[1], argv[2], priority + (chan->pbx ? 1 : 0)) < 0) {
00822 gosub_args = NULL;
00823 }
00824 }
00825
00826 if (gosub_args) {
00827 int res;
00828
00829 ast_debug(1, "Trying gosub with arguments '%s'\n", gosub_args);
00830
00831 if ((res = pbx_exec(chan, theapp, gosub_args)) == 0) {
00832 struct ast_pbx *pbx = chan->pbx;
00833 struct ast_pbx_args args;
00834 struct ast_datastore *stack_store = ast_channel_datastore_find(chan, &stack_info, NULL);
00835 AST_LIST_HEAD(, gosub_stack_frame) *oldlist;
00836 struct gosub_stack_frame *cur;
00837 if (!stack_store) {
00838 ast_log(LOG_WARNING, "No GoSub stack remaining after AGI GoSub execution.\n");
00839 ast_free(gosub_args);
00840 return RESULT_FAILURE;
00841 }
00842 oldlist = stack_store->data;
00843 cur = AST_LIST_FIRST(oldlist);
00844 cur->is_agi = 1;
00845
00846 memset(&args, 0, sizeof(args));
00847 args.no_hangup_chan = 1;
00848
00849 chan->pbx = NULL;
00850 ast_agi_send(agi->fd, chan, "100 result=0 Trying...\n");
00851 ast_pbx_run_args(chan, &args);
00852 ast_agi_send(agi->fd, chan, "200 result=0 Gosub complete\n");
00853 if (chan->pbx) {
00854 ast_free(chan->pbx);
00855 }
00856 chan->pbx = pbx;
00857 } else {
00858 ast_agi_send(agi->fd, chan, "200 result=%d Gosub failed\n", res);
00859 }
00860 ast_free(gosub_args);
00861 } else {
00862 ast_agi_send(agi->fd, chan, "503 result=-2 Memory allocation failure\n");
00863 return RESULT_FAILURE;
00864 }
00865
00866
00867 ast_copy_string(chan->context, old_context, sizeof(chan->context));
00868 ast_copy_string(chan->exten, old_extension, sizeof(chan->exten));
00869 chan->priority = old_priority;
00870
00871 return RESULT_SUCCESS;
00872 }
00873
00874 static struct agi_command gosub_agi_command =
00875 { { "gosub", NULL }, handle_gosub, NULL, NULL, 0 };
00876
00877 static int unload_module(void)
00878 {
00879 ast_agi_unregister(ast_module_info->self, &gosub_agi_command);
00880
00881 ast_unregister_application(app_return);
00882 ast_unregister_application(app_pop);
00883 ast_unregister_application(app_gosubif);
00884 ast_unregister_application(app_gosub);
00885 ast_custom_function_unregister(&local_function);
00886 ast_custom_function_unregister(&peek_function);
00887 ast_custom_function_unregister(&stackpeek_function);
00888
00889 return 0;
00890 }
00891
00892 static int load_module(void)
00893 {
00894 ast_agi_register(ast_module_info->self, &gosub_agi_command);
00895
00896 ast_register_application_xml(app_pop, pop_exec);
00897 ast_register_application_xml(app_return, return_exec);
00898 ast_register_application_xml(app_gosubif, gosubif_exec);
00899 ast_register_application_xml(app_gosub, gosub_exec);
00900 ast_custom_function_register(&local_function);
00901 ast_custom_function_register(&peek_function);
00902 ast_custom_function_register(&stackpeek_function);
00903
00904 return 0;
00905 }
00906
00907 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT | AST_MODFLAG_LOAD_ORDER, "Dialplan subroutines (Gosub, Return, etc)",
00908 .load = load_module,
00909 .unload = unload_module,
00910 .load_pri = AST_MODPRI_APP_DEPEND,
00911 .nonoptreq = "res_agi",
00912 );