Files
asterisk/apps/app_while.c
Tilghman Lesher 107dfe787e Merged revisions 152969,153122,154264,154268,154366,155399,155863,156166,156295,156690,156756,158066,158082,158540,158602,159276 via svnmerge from
https://origsvn.digium.com/svn/asterisk/trunk

................
  r152969 | tilghman | 2008-10-30 15:35:46 -0500 (Thu, 30 Oct 2008) | 10 lines
  
  Merged revisions 152958 via svnmerge from 
  https://origsvn.digium.com/svn/asterisk/branches/1.4
  
  ........
    r152958 | tilghman | 2008-10-30 15:33:28 -0500 (Thu, 30 Oct 2008) | 3 lines
    
    Cannot join detached threads.  See http://www.opengroup.org/onlinepubs/000095399/functions/pthread_join.html
    (Closes issue #13400)
  ........
................
  r153122 | tilghman | 2008-10-31 11:35:21 -0500 (Fri, 31 Oct 2008) | 10 lines
  
  Merged revisions 153114 via svnmerge from 
  https://origsvn.digium.com/svn/asterisk/branches/1.4
  
  ........
    r153114 | tilghman | 2008-10-31 11:30:32 -0500 (Fri, 31 Oct 2008) | 3 lines
    
    Turn off qualify on uncached realtime peers.
    (Closes issue #13383)
  ........
................
  r154264 | tilghman | 2008-11-04 12:59:48 -0600 (Tue, 04 Nov 2008) | 10 lines
  
  Recorded merge of revisions 154263 via svnmerge from 
  https://origsvn.digium.com/svn/asterisk/branches/1.4
  
  ........
    r154263 | tilghman | 2008-11-04 12:58:05 -0600 (Tue, 04 Nov 2008) | 3 lines
    
    Make the monitor thread non-detached, so it can be joined (suggested by Russell
    on -dev list).
  ........
................
  r154268 | rmudgett | 2008-11-04 13:07:26 -0600 (Tue, 04 Nov 2008) | 11 lines
  
  Merged revisions 154266 via svnmerge from 
  https://origsvn.digium.com/svn/asterisk/branches/1.4
  
  ........
    r154266 | rmudgett | 2008-11-04 13:01:08 -0600 (Tue, 04 Nov 2008) | 4 lines
    
    JIRA ABE-1703
    mISDN sets the channel to the wrong state when it receives
    the indication AST_CONTROL_RINGING.
  ........
................
  r154366 | tilghman | 2008-11-04 14:51:18 -0600 (Tue, 04 Nov 2008) | 16 lines
  
  Merged revisions 154365 via svnmerge from 
  https://origsvn.digium.com/svn/asterisk/branches/1.4
  
  ........
    r154365 | tilghman | 2008-11-04 14:49:33 -0600 (Tue, 04 Nov 2008) | 9 lines
    
    On busy systems, it's possible for the values checked within a single line
    of code to change, unless the structure is locked to ensure a consistent
    state.
    (closes issue #13717)
     Reported by: kowalma
     Patches: 
           20081102__bug13717.diff.txt uploaded by Corydon76 (license 14)
     Tested by: kowalma
  ........
................
  r155399 | tilghman | 2008-11-07 16:28:58 -0600 (Fri, 07 Nov 2008) | 14 lines
  
  Merged revisions 155398 via svnmerge from 
  https://origsvn.digium.com/svn/asterisk/branches/1.4
  
  ........
    r155398 | tilghman | 2008-11-07 16:27:32 -0600 (Fri, 07 Nov 2008) | 7 lines
    
    Clarify error message.
    (closes issue #13809)
     Reported by: denke
     Patches: 
           20081104__bug13809.diff.txt uploaded by Corydon76 (license 14)
     Tested by: denke
  ........
................
  r155863 | mmichelson | 2008-11-10 15:14:44 -0600 (Mon, 10 Nov 2008) | 22 lines
  
  Merged revisions 155861 via svnmerge from 
  https://origsvn.digium.com/svn/asterisk/branches/1.4
  
  ........
  r155861 | mmichelson | 2008-11-10 15:07:39 -0600 (Mon, 10 Nov 2008) | 14 lines
  
  Channel drivers assume that when their indicate callback
  is invoked, that the channel on which the callback was called
  is locked. This patch corrects an instance in chan_agent where
  a channel's indicate callback is called directly without first
  locking the channel.
  
  This was leading to some observed locking issues in chan_local,
  but considering that all channel drivers operate under the
  same expectations, the generic fix in chan_agent is the right
  way to go.
  
  AST-126
  
  
  ........
................
  r156166 | russell | 2008-11-12 11:38:20 -0600 (Wed, 12 Nov 2008) | 15 lines
  
  Merged revisions 156164 via svnmerge from 
  https://origsvn.digium.com/svn/asterisk/branches/1.4
  
  ........
  r156164 | russell | 2008-11-12 11:29:52 -0600 (Wed, 12 Nov 2008) | 7 lines
  
  Move the sanity check that makes sure "always fork" is not set along with the 
  console option to be after the code that reads options from asterisk.conf.  
  This resolves a situation where Asterisk can start taking up 100% when
  misconfigured.
  (Thanks to Bryce Porter (x86 on IRC) for letting me log in to his system to
   figure out what was causing the 100% CPU problem.)
  
  ........
................
  r156295 | tilghman | 2008-11-12 13:28:22 -0600 (Wed, 12 Nov 2008) | 13 lines
  
  Merged revisions 156294 via svnmerge from 
  https://origsvn.digium.com/svn/asterisk/branches/1.4
  
  ........
    r156294 | tilghman | 2008-11-12 13:26:45 -0600 (Wed, 12 Nov 2008) | 6 lines
    
    If the SLA thread is not started, then reload causes a memory leak.
    (closes issue #13889)
     Reported by: eliel
     Patches: 
           app_meetme.c.patch uploaded by eliel (license 64)
  ........
................
  r156690 | tilghman | 2008-11-13 15:30:41 -0600 (Thu, 13 Nov 2008) | 14 lines
  
  Merged revisions 156688 via svnmerge from 
  https://origsvn.digium.com/svn/asterisk/branches/1.4
  
  ........
    r156688 | tilghman | 2008-11-13 15:24:00 -0600 (Thu, 13 Nov 2008) | 7 lines
    
    Provide more space for all the data which can appear in an originating
    channel name.
    (closes issue #13398)
     Reported by: bamby
     Patches: 
           manager.c.diff uploaded by bamby (license 430)
  ........
................
  r156756 | tilghman | 2008-11-13 18:43:13 -0600 (Thu, 13 Nov 2008) | 13 lines
  
  Merged revisions 156755 via svnmerge from 
  https://origsvn.digium.com/svn/asterisk/branches/1.4
  
  ........
    r156755 | tilghman | 2008-11-13 18:41:37 -0600 (Thu, 13 Nov 2008) | 6 lines
    
    ast_waitfordigit() requires that the channel be up, for no good logical
    reason.  This prevents While/EndWhile from working within the "h"
    extension.
    Reported by: jgalarneau (for ABE C.2)
    Fixed by: me
  ........
................
  r158066 | mmichelson | 2008-11-20 11:39:06 -0600 (Thu, 20 Nov 2008) | 20 lines
  
  Merged revisions 158053 via svnmerge from 
  https://origsvn.digium.com/svn/asterisk/branches/1.4
  
  ........
  r158053 | mmichelson | 2008-11-20 11:33:06 -0600 (Thu, 20 Nov 2008) | 12 lines
  
  Make sure to set the hangup cause on the calling channel in the case
  that ast_call() fails. For incoming SIP channels, this was causing
  us to send a 603 instead of a 486 when the call-limit was reached on
  the destination channel.
  
  (closes issue #13867)
  Reported by: still_nsk
  Patches:
        13867.diff uploaded by putnopvut (license 60)
  Tested by: blitzrage
  
  
  ........
................
  r158082 | mmichelson | 2008-11-20 11:54:31 -0600 (Thu, 20 Nov 2008) | 24 lines
  
  Merged revisions 158071 via svnmerge from 
  https://origsvn.digium.com/svn/asterisk/branches/1.4
  
  ........
  r158071 | mmichelson | 2008-11-20 11:48:42 -0600 (Thu, 20 Nov 2008) | 16 lines
  
  We don't handle 4XX responses to BYE well. According to
  section 15 of RFC 3261, we should terminate a dialog if we
  receive a 481 or 408 in response to our BYE. Since I am aware
  of at least one phone manufacturer who may sometimes send a 
  404 as well, I am being liberal and saying that any 4XX response
  to a BYE should result in a terminated dialog.
  
  
  (closes issue #12994)
  Reported by: pabelanger
  Patches:
        12994.patch uploaded by putnopvut (license 60)
  
  Closes AST-129
  
  
  ........
................
  r158540 | russell | 2008-11-21 16:12:37 -0600 (Fri, 21 Nov 2008) | 10 lines
  
  Merged revisions 158539 via svnmerge from 
  https://origsvn.digium.com/svn/asterisk/branches/1.4
  
  ........
  r158539 | russell | 2008-11-21 16:05:55 -0600 (Fri, 21 Nov 2008) | 2 lines
  
  When compiling with DEBUG_THREADS, report the real file/func/line for ao2_lock/ao2_unlock
  
  ........
................
  r158602 | tilghman | 2008-11-21 17:14:11 -0600 (Fri, 21 Nov 2008) | 12 lines
  
  Merged revisions 158600 via svnmerge from 
  https://origsvn.digium.com/svn/asterisk/branches/1.4
  
  ........
    r158600 | tilghman | 2008-11-21 17:07:46 -0600 (Fri, 21 Nov 2008) | 5 lines
    
    The passed extension may not be the same in the list as the current entry,
    because we strip spaces when copying the extension into the structure.
    Therefore, use the copied item to place the item into the list.
    (found by lmadsen on -dev, fixed by me)
  ........
................
  r159276 | tilghman | 2008-11-25 15:57:59 -0600 (Tue, 25 Nov 2008) | 14 lines
  
  Merged revisions 159269 via svnmerge from 
  https://origsvn.digium.com/svn/asterisk/branches/1.4
  
  ........
    r159269 | tilghman | 2008-11-25 15:56:48 -0600 (Tue, 25 Nov 2008) | 7 lines
    
    Don't try to send a response on a NULL pvt.
    (closes issue #13919)
     Reported by: barthpbx
     Patches: 
           chan_iax2.c.patch uploaded by eliel (license 64)
     Tested by: barthpbx
  ........
................


git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/1.6.0@160389 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-12-02 22:56:36 +00:00

313 lines
8.5 KiB
C

/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright 2004 - 2005, Anthony Minessale <anthmct@yahoo.com>
*
* Anthony Minessale <anthmct@yahoo.com>
*
* See http://www.asterisk.org for more information about
* the Asterisk project. Please do not directly contact
* any of the maintainers of this project for assistance;
* the project provides a web site, mailing lists and IRC
* channels for your use.
*
* This program is free software, distributed under the terms of
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree.
*/
/*! \file
*
* \brief While Loop Implementation
*
* \author Anthony Minessale <anthmct@yahoo.com>
*
* \ingroup applications
*/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/channel.h"
static char *start_app = "While";
static char *start_desc =
" While(<expr>): Start a While Loop. Execution will return to this\n"
"point when EndWhile() is called until expr is no longer true.\n";
static char *start_synopsis = "Start a while loop";
static char *stop_app = "EndWhile";
static char *stop_desc =
" EndWhile(): Return to the previous called While()\n";
static char *stop_synopsis = "End a while loop";
static char *exit_app = "ExitWhile";
static char *exit_desc =
" ExitWhile(): Exits a While() loop, whether or not the conditional has been satisfied.\n";
static char *exit_synopsis = "End a While loop";
static char *continue_app = "ContinueWhile";
static char *continue_desc =
" ContinueWhile(): Returns to the top of the while loop and re-evaluates the conditional.\n";
static char *continue_synopsis = "Restart a While loop";
#define VAR_SIZE 64
static const char *get_index(struct ast_channel *chan, const char *prefix, int index) {
char varname[VAR_SIZE];
snprintf(varname, VAR_SIZE, "%s_%d", prefix, index);
return pbx_builtin_getvar_helper(chan, varname);
}
static struct ast_exten *find_matching_priority(struct ast_context *c, const char *exten, int priority, const char *callerid)
{
struct ast_exten *e;
struct ast_include *i;
struct ast_context *c2;
for (e=ast_walk_context_extensions(c, NULL); e; e=ast_walk_context_extensions(c, e)) {
if (ast_extension_match(ast_get_extension_name(e), exten)) {
int needmatch = ast_get_extension_matchcid(e);
if ((needmatch && ast_extension_match(ast_get_extension_cidmatch(e), callerid)) ||
(!needmatch)) {
/* This is the matching extension we want */
struct ast_exten *p;
for (p=ast_walk_extension_priorities(e, NULL); p; p=ast_walk_extension_priorities(e, p)) {
if (priority != ast_get_extension_priority(p))
continue;
return p;
}
}
}
}
/* No match; run through includes */
for (i=ast_walk_context_includes(c, NULL); i; i=ast_walk_context_includes(c, i)) {
for (c2=ast_walk_contexts(NULL); c2; c2=ast_walk_contexts(c2)) {
if (!strcmp(ast_get_context_name(c2), ast_get_include_name(i))) {
e = find_matching_priority(c2, exten, priority, callerid);
if (e)
return e;
}
}
}
return NULL;
}
static int find_matching_endwhile(struct ast_channel *chan)
{
struct ast_context *c;
int res=-1;
if (ast_rdlock_contexts()) {
ast_log(LOG_ERROR, "Failed to lock contexts list\n");
return -1;
}
for (c=ast_walk_contexts(NULL); c; c=ast_walk_contexts(c)) {
struct ast_exten *e;
if (!ast_rdlock_context(c)) {
if (!strcmp(ast_get_context_name(c), chan->context)) {
/* This is the matching context we want */
int cur_priority = chan->priority + 1, level=1;
for (e = find_matching_priority(c, chan->exten, cur_priority, chan->cid.cid_num); e; e = find_matching_priority(c, chan->exten, ++cur_priority, chan->cid.cid_num)) {
if (!strcasecmp(ast_get_extension_app(e), "WHILE")) {
level++;
} else if (!strcasecmp(ast_get_extension_app(e), "ENDWHILE")) {
level--;
}
if (level == 0) {
res = cur_priority;
break;
}
}
}
ast_unlock_context(c);
if (res > 0) {
break;
}
}
}
ast_unlock_contexts();
return res;
}
static int _while_exec(struct ast_channel *chan, void *data, int end)
{
int res=0;
const char *while_pri = NULL;
char *my_name = NULL;
const char *condition = NULL, *label = NULL;
char varname[VAR_SIZE], end_varname[VAR_SIZE];
const char *prefix = "WHILE";
size_t size=0;
int used_index_i = -1, x=0;
char used_index[VAR_SIZE] = "0", new_index[VAR_SIZE] = "0";
if (!chan) {
/* huh ? */
return -1;
}
#if 0
/* dont want run away loops if the chan isn't even up
this is up for debate since it slows things down a tad ......
Debate is over... this prevents While/EndWhile from working
within the "h" extension. Not good.
*/
if (ast_waitfordigit(chan,1) < 0)
return -1;
#endif
for (x=0;;x++) {
if (get_index(chan, prefix, x)) {
used_index_i = x;
} else
break;
}
snprintf(used_index, VAR_SIZE, "%d", used_index_i);
snprintf(new_index, VAR_SIZE, "%d", used_index_i + 1);
if (!end)
condition = ast_strdupa(data);
size = strlen(chan->context) + strlen(chan->exten) + 32;
my_name = alloca(size);
memset(my_name, 0, size);
snprintf(my_name, size, "%s_%s_%d", chan->context, chan->exten, chan->priority);
if (ast_strlen_zero(label)) {
if (end)
label = used_index;
else if (!(label = pbx_builtin_getvar_helper(chan, my_name))) {
label = new_index;
pbx_builtin_setvar_helper(chan, my_name, label);
}
}
snprintf(varname, VAR_SIZE, "%s_%s", prefix, label);
while_pri = pbx_builtin_getvar_helper(chan, varname);
if ((while_pri = pbx_builtin_getvar_helper(chan, varname)) && !end) {
snprintf(end_varname,VAR_SIZE,"END_%s",varname);
}
if ((!end && !pbx_checkcondition(condition)) || (end == 2)) {
/* Condition Met (clean up helper vars) */
const char *goto_str;
pbx_builtin_setvar_helper(chan, varname, NULL);
pbx_builtin_setvar_helper(chan, my_name, NULL);
snprintf(end_varname,VAR_SIZE,"END_%s",varname);
if ((goto_str=pbx_builtin_getvar_helper(chan, end_varname))) {
ast_parseable_goto(chan, goto_str);
pbx_builtin_setvar_helper(chan, end_varname, NULL);
} else {
int pri = find_matching_endwhile(chan);
if (pri > 0) {
ast_verb(3, "Jumping to priority %d\n", pri);
chan->priority = pri;
} else {
ast_log(LOG_WARNING, "Couldn't find matching EndWhile? (While at %s@%s priority %d)\n", chan->context, chan->exten, chan->priority);
}
}
return res;
}
if (!end && !while_pri) {
char *goto_str;
size = strlen(chan->context) + strlen(chan->exten) + 32;
goto_str = alloca(size);
memset(goto_str, 0, size);
snprintf(goto_str, size, "%s,%s,%d", chan->context, chan->exten, chan->priority);
pbx_builtin_setvar_helper(chan, varname, goto_str);
}
else if (end && while_pri) {
/* END of loop */
snprintf(end_varname, VAR_SIZE, "END_%s", varname);
if (! pbx_builtin_getvar_helper(chan, end_varname)) {
char *goto_str;
size = strlen(chan->context) + strlen(chan->exten) + 32;
goto_str = alloca(size);
memset(goto_str, 0, size);
snprintf(goto_str, size, "%s,%s,%d", chan->context, chan->exten, chan->priority+1);
pbx_builtin_setvar_helper(chan, end_varname, goto_str);
}
ast_parseable_goto(chan, while_pri);
}
return res;
}
static int while_start_exec(struct ast_channel *chan, void *data) {
return _while_exec(chan, data, 0);
}
static int while_end_exec(struct ast_channel *chan, void *data) {
return _while_exec(chan, data, 1);
}
static int while_exit_exec(struct ast_channel *chan, void *data) {
return _while_exec(chan, data, 2);
}
static int while_continue_exec(struct ast_channel *chan, void *data)
{
int x;
const char *prefix = "WHILE", *while_pri=NULL;
for (x = 0; ; x++) {
const char *tmp = get_index(chan, prefix, x);
if (tmp)
while_pri = tmp;
else
break;
}
if (while_pri)
ast_parseable_goto(chan, while_pri);
return 0;
}
static int unload_module(void)
{
int res;
res = ast_unregister_application(start_app);
res |= ast_unregister_application(stop_app);
res |= ast_unregister_application(exit_app);
res |= ast_unregister_application(continue_app);
return res;
}
static int load_module(void)
{
int res;
res = ast_register_application(start_app, while_start_exec, start_synopsis, start_desc);
res |= ast_register_application(stop_app, while_end_exec, stop_synopsis, stop_desc);
res |= ast_register_application(exit_app, while_exit_exec, exit_synopsis, exit_desc);
res |= ast_register_application(continue_app, while_continue_exec, continue_synopsis, continue_desc);
return res;
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "While Loops and Conditional Execution");