applied final release of bug 1353 per Mark's permission
authorAnthony Minessale II <anthmct@yahoo.com>
Mon, 26 Apr 2004 23:22:34 +0000 (23:22 +0000)
committerAnthony Minessale II <anthmct@yahoo.com>
Mon, 26 Apr 2004 23:22:34 +0000 (23:22 +0000)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@2782 65c4cc65-6c06-0410-ace0-fbb531ad65f3

apps/app_dial.c
apps/app_queue.c
channel.c
contrib/scripts/astxs [new file with mode: 0755]
include/asterisk/channel.h
include/asterisk/parking.h
res/res_parking.c

index af3c70c..3492c10 100755 (executable)
@@ -20,6 +20,7 @@
 #include <asterisk/module.h>
 #include <asterisk/translate.h>
 #include <asterisk/say.h>
+#include <asterisk/config.h>
 #include <asterisk/parking.h>
 #include <asterisk/musiconhold.h>
 #include <asterisk/callerid.h>
@@ -68,6 +69,15 @@ static char *descrip =
 "      'g' -- goes on in context if the destination channel hangs up\n"
 "      'A(x)' -- play an announcement to the called party, using x as file\n"
 "      'S(x)' -- hangup the call after x seconds AFTER called party picked up\n"       
+"      'L(x[:y][:z])' -- Limit the call to 'x' ms warning when 'y' ms are left (repeated every 'z' ms)\n"
+"                     -- Only 'x' is required, 'y' and 'z' are optional.\n"
+"                     -- The following special variables are optional:\n"
+"                       ** LIMIT_PLAYAUDIO_CALLER    (default yes) Play sounds to the caller.\n"
+"                       ** LIMIT_PLAYAUDIO_CALLEE    Play sounds to the callee.\n"
+"                       ** LIMIT_TIMEOUT_FILE        File to play when time is up.\n"
+"                       ** LIMIT_CONNECT_FILE        File to play when call begins.\n"
+"                       ** LIMIT_WARNING_FILE        File to play as warning if 'y' is defined.\n"
+"                     -- 'timeleft' is a special sound macro to auto-say the time left and is the default.\n\n"
 "  In addition to transferring the call, a call may be parked and then picked\n"
 "up by another user.\n"
 "  The optional URL will be sent to the called party if the channel supports\n"
@@ -390,7 +400,19 @@ static int dial_exec(struct ast_channel *chan, void *data)
        unsigned int calldurationlimit=0;
        char *cdl;
        time_t now;
-       
+       struct ast_bridge_config config;
+       long timelimit = 0;
+       long play_warning = 0;
+       long warning_freq=0;
+       char *warning_sound=NULL;
+       char *end_sound=NULL;
+       char *start_sound=NULL;
+       char *limitptr;
+       char limitdata[256];
+       char *stack,*var;
+       int play_to_caller=0,play_to_callee=0;
+       int playargs=0;
+
        if (!data) {
                ast_log(LOG_WARNING, "Dial requires an argument (technology1/number1&technology2/number2...|optional timeout|options)\n");
                return -1;
@@ -430,13 +452,81 @@ static int dial_exec(struct ast_channel *chan, void *data)
        
 
        if (transfer) {
+
                /* Extract call duration limit */
                if ((cdl = strstr(transfer, "S("))) {
                        calldurationlimit=atoi(cdl+2);
                        if (option_verbose > 2)
                                ast_verbose(VERBOSE_PREFIX_3 "Setting call duration limit to %i seconds.\n",calldurationlimit);                 
                } 
-               
+
+               /* XXX LIMIT SUPPORT */
+               if ((limitptr = strstr(transfer, "L("))) {
+                       strncpy(limitdata, limitptr + 2, sizeof(limitdata) - 1);
+                       /* Overwrite with X's what was the limit info */
+                       while(*limitptr && (*limitptr != ')')) 
+                               *(limitptr++) = 'X';
+            if (*limitptr)
+                *limitptr = 'X';
+            /* Now find the end of the privdb */
+            limitptr = strchr(limitdata, ')');
+            if (limitptr)
+                *limitptr = '\0';
+            else {
+                ast_log(LOG_WARNING, "Limit Data lacking trailing ')'\n");
+            }
+
+            var = pbx_builtin_getvar_helper(chan,"LIMIT_PLAYAUDIO_CALLER");
+            play_to_caller = var ? ast_true(var) : 1;
+
+            var = pbx_builtin_getvar_helper(chan,"LIMIT_PLAYAUDIO_CALLEE");
+            play_to_callee = var ? ast_true(var) : 0;
+            
+            if(! play_to_caller && ! play_to_callee)
+                play_to_caller=1;
+
+            var = pbx_builtin_getvar_helper(chan,"LIMIT_WARNING_FILE");
+            warning_sound = var ? var : "timeleft";
+            
+            var = pbx_builtin_getvar_helper(chan,"LIMIT_TIMEOUT_FILE");
+            end_sound = var ? var : NULL;
+
+            var = pbx_builtin_getvar_helper(chan,"LIMIT_CONNECT_FILE");
+            start_sound = var ? var : NULL;
+            
+            var=stack=limitdata;
+            
+            var = strsep(&stack, ":");
+            if(var) {
+                timelimit = atol(var);
+                playargs++;
+            }
+            var = strsep(&stack, ":");
+            if(var) {
+                play_warning = atol(var);
+                playargs++;
+            }
+
+            var = strsep(&stack, ":");
+            if(var) {
+                warning_freq = atol(var);
+                playargs++;
+            }
+            
+            if(! timelimit) {
+                timelimit=play_to_caller=play_to_callee=play_warning=warning_freq=0;
+                warning_sound=NULL;
+            }
+            calldurationlimit=0; /* undo effect of S(x) in case they are both used */
+            if(! play_warning && ! start_sound && ! end_sound && timelimit) { /* more efficient do it like S(x) does since no advanced opts*/
+                               calldurationlimit=timelimit/1000;
+                               timelimit=play_to_caller=play_to_callee=play_warning=warning_freq=0;
+                       }
+                       else 
+                ast_verbose(VERBOSE_PREFIX_3"Limit Data: timelimit=%ld\n    -- play_warning=%ld\n    -- play_to_caller=%s\n    -- play_to_callee=%s\n    -- warning_freq=%ld\n    -- warning_sound=%s\n    -- end_sound=%s\n    -- start_sound=%s\n",timelimit,play_warning,play_to_caller ? "yes" : "no",play_to_callee ? "yes" : "no",warning_freq,warning_sound ? warning_sound : "UNDEF",end_sound ? end_sound : "UNDEF",start_sound ? start_sound : "UNDEF");
+                               
+               }
+
                /* XXX ANNOUNCE SUPPORT */
                if ((ann = strstr(transfer, "A("))) {
                        announce = 1;
@@ -729,7 +819,20 @@ static int dial_exec(struct ast_channel *chan, void *data)
                        time(&now);
                        chan->whentohangup = now + calldurationlimit;
                }
-               res = ast_bridge_call(chan, peer, allowredir_in, allowredir_out, allowdisconnect);
+
+               memset(&config,0,sizeof(struct ast_bridge_config));
+               config.play_to_caller=play_to_caller;
+               config.play_to_callee=play_to_callee;
+               config.allowredirect_in = allowredir_in;
+               config.allowredirect_out = allowredir_out;
+               config.allowdisconnect = allowdisconnect;
+               config.timelimit = timelimit;
+               config.play_warning = play_warning;
+               config.warning_freq = warning_freq;
+               config.warning_sound = warning_sound;
+               config.end_sound = end_sound;
+               config.start_sound = start_sound;
+               res = ast_bridge_call(chan,peer,&config);
 
                if (res != AST_PBX_NO_HANGUP_PEER)
                        ast_hangup(peer);
index d8e1331..611b1f2 100755 (executable)
@@ -874,6 +874,7 @@ static int try_calling(struct queue_ent *qe, char *options, char *announceoverri
        char digit = 0;
        time_t callstart;
        time_t now;
+       struct ast_bridge_config config;
        /* Hold the lock while we setup the outgoing calls */
        ast_mutex_lock(&qe->parent->lock);
        strncpy(queuename, qe->parent->name, sizeof(queuename) - 1);
@@ -1030,7 +1031,13 @@ static int try_calling(struct queue_ent *qe, char *options, char *announceoverri
                strncpy(oldcontext, qe->chan->context, sizeof(oldcontext) - 1);
                strncpy(oldexten, qe->chan->exten, sizeof(oldexten) - 1);
                time(&callstart);
-               bridge = ast_bridge_call(qe->chan, peer, allowredir_in, allowredir_out, allowdisconnect);
+
+               memset(&config,0,sizeof(struct ast_bridge_config));
+        config.allowredirect_in = allowredir_in;
+        config.allowredirect_out = allowredir_out;
+        config.allowdisconnect = allowdisconnect;
+        bridge = ast_bridge_call(qe->chan,peer,&config);
+
                if (strcasecmp(oldcontext, qe->chan->context) || strcasecmp(oldexten, qe->chan->exten)) {
                        ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "TRANSFER", "%s|%s", qe->chan->exten, qe->chan->context);
                } else if (qe->chan->_softhangup) {
index 91b81b9..9a083fd 100755 (executable)
--- a/channel.c
+++ b/channel.c
@@ -28,6 +28,7 @@
 #include <asterisk/channel.h>
 #include <asterisk/channel_pvt.h>
 #include <asterisk/logger.h>
+#include <asterisk/say.h>
 #include <asterisk/file.h>
 #include <asterisk/translate.h>
 #include <asterisk/manager.h>
@@ -40,7 +41,7 @@
 #include <sys/ioctl.h>
 #include <linux/zaptel.h>
 #ifndef ZT_TIMERPING
-#error "You need newer zaptel!  Please cvs update zaptel"
+#error "You need newer zaptel! Please cvs update zaptel"
 #endif
 #endif
 
@@ -140,17 +141,19 @@ void ast_channel_setwhentohangup(struct ast_channel *chan, time_t offset)
 time_t myt;
 
        time(&myt);
-        if (offset)
+               if (offset)
          chan->whentohangup = myt + offset;
-        else
-          chan->whentohangup = 0;
+               else
+                 chan->whentohangup = 0;
        return;
 }
 
+
+
 int ast_channel_register(char *type, char *description, int capabilities,
                struct ast_channel *(*requester)(char *type, int format, void *data))
 {
-    return ast_channel_register_ex(type, description, capabilities, requester, NULL);
+       return ast_channel_register_ex(type, description, capabilities, requester, NULL);
 }
 
 int ast_channel_register_ex(char *type, char *description, int capabilities,
@@ -271,8 +274,8 @@ struct ast_channel *ast_channel_alloc(int needqueue)
        struct ast_channel_pvt *pvt;
        int x;
        int flags;
-       struct varshead *headp;        
-               
+       struct varshead *headp;            
+                       
        
        /* If shutting down, don't allocate any new channels */
        if (shutting_down)
@@ -333,7 +336,7 @@ struct ast_channel *ast_channel_alloc(int needqueue)
                                        snprintf(tmp->uniqueid, sizeof(tmp->uniqueid), "%li.%d", (long)time(NULL), uniqueint++);
                                        headp=&tmp->varshead;
                                        ast_mutex_init(&tmp->lock);
-                                       AST_LIST_HEAD_INIT(headp);
+                                               AST_LIST_HEAD_INIT(headp);
                                        tmp->vars=ast_var_assign("tempvar","tempval");
                                        AST_LIST_INSERT_HEAD(headp,tmp->vars,entries);
                                        strncpy(tmp->context, "default", sizeof(tmp->context)-1);
@@ -461,7 +464,7 @@ struct ast_channel *ast_channel_walk(struct ast_channel *prev)
        
 }
 
-int ast_safe_sleep_conditional(        struct ast_channel *chan, int ms,
+int ast_safe_sleep_conditional( struct ast_channel *chan, int ms,
                                                                int (*cond)(void*), void *data )
 {
        struct ast_frame *f;
@@ -569,13 +572,13 @@ void ast_channel_free(struct ast_channel *chan)
        /* loop over the variables list, freeing all data and deleting list items */
        /* no need to lock the list, as the channel is already locked */
        
-       while (!AST_LIST_EMPTY(headp)) {           /* List Deletion. */
-                   vardata = AST_LIST_FIRST(headp);
-                   AST_LIST_REMOVE_HEAD(headp, entries);
-//                 printf("deleting var %s=%s\n",ast_var_name(vardata),ast_var_value(vardata));
-                   ast_var_delete(vardata);
+       while (!AST_LIST_EMPTY(headp)) {                   /* List Deletion. */
+                               vardata = AST_LIST_FIRST(headp);
+                               AST_LIST_REMOVE_HEAD(headp, entries);
+//                             printf("deleting var %s=%s\n",ast_var_name(vardata),ast_var_value(vardata));
+                               ast_var_delete(vardata);
        }
-                                                        
+                                                                                                        
 
        free(chan->pvt);
        chan->pvt = NULL;
@@ -665,7 +668,7 @@ int ast_hangup(struct ast_channel *chan)
        }
        if (chan->blocking) {
                ast_log(LOG_WARNING, "Hard hangup called by thread %ld on %s, while fd "
-                                       "is blocked by thread %ld in procedure %s!  Expect a failure\n",
+                                       "is blocked by thread %ld in procedure %s!      Expect a failure\n",
                                        (long)pthread_self(), chan->name, (long)chan->blocker, chan->blockproc);
                CRASH;
        }
@@ -681,9 +684,9 @@ int ast_hangup(struct ast_channel *chan)
        ast_mutex_unlock(&chan->lock);
        manager_event(EVENT_FLAG_CALL, "Hangup", 
                        "Channel: %s\r\n"
-                        "Uniqueid: %s\r\n"
-                        "Cause: %i\r\n",
-                        chan->name, chan->uniqueid, chan->hangupcause);
+                                               "Uniqueid: %s\r\n"
+                                               "Cause: %i\r\n",
+                                               chan->name, chan->uniqueid, chan->hangupcause);
        ast_channel_free(chan);
        return res;
 }
@@ -1114,7 +1117,7 @@ struct ast_frame *ast_read(struct ast_channel *chan)
                        ast_log(LOG_WARNING, "Failed to perform masquerade\n");
                        f = NULL;
                } else
-                       f =  &null_frame;
+                       f =      &null_frame;
                ast_mutex_unlock(&chan->lock);
                return f;
        }
@@ -1128,7 +1131,7 @@ struct ast_frame *ast_read(struct ast_channel *chan)
        }
 
        if (!chan->deferdtmf && strlen(chan->dtmfq)) {
-               /* We have DTMF that has been deferred.  Return it now */
+               /* We have DTMF that has been deferred.  Return it now */
                chan->dtmff.frametype = AST_FRAME_DTMF;
                chan->dtmff.subclass = chan->dtmfq[0];
                /* Drop first digit */
@@ -1181,7 +1184,7 @@ struct ast_frame *ast_read(struct ast_channel *chan)
                                chan->timingdata = NULL;
                                ast_mutex_unlock(&chan->lock);
                        }
-                       f =  &null_frame;
+                       f =      &null_frame;
                        return f;
                } else
                        ast_log(LOG_NOTICE, "No/unknown event '%d' on timer for '%s'?\n", blah, chan->name);
@@ -1361,10 +1364,10 @@ int ast_recvchar(struct ast_channel *chan, int timeout)
                f = ast_read(chan);
                if (f == NULL) return -1; /* if hangup */
                if ((f->frametype == AST_FRAME_CONTROL) &&
-                   (f->subclass == AST_CONTROL_HANGUP)) return -1; /* if hangup */
-               if (f->frametype == AST_FRAME_TEXT)  /* if a text frame */
+                       (f->subclass == AST_CONTROL_HANGUP)) return -1; /* if hangup */
+               if (f->frametype == AST_FRAME_TEXT)      /* if a text frame */
                   {
-                       c = *((char *)f->data);  /* get the data */
+                       c = *((char *)f->data);  /* get the data */
                        ast_frfree(f);
                        return(c);
                   }
@@ -1397,21 +1400,21 @@ static int do_senddigit(struct ast_channel *chan, char digit)
                 * it by doing our own generation. (PM2002)
                 */
                static const char* dtmf_tones[] = {
-                       "!941+1336/100,!0/100", /* 0 */
-                       "!697+1209/100,!0/100", /* 1 */
-                       "!697+1336/100,!0/100", /* 2 */
-                       "!697+1477/100,!0/100", /* 3 */
-                       "!770+1209/100,!0/100", /* 4 */
-                       "!770+1336/100,!0/100", /* 5 */
-                       "!770+1477/100,!0/100", /* 6 */
-                       "!852+1209/100,!0/100", /* 7 */
-                       "!852+1336/100,!0/100", /* 8 */
-                       "!852+1477/100,!0/100", /* 9 */
-                       "!697+1633/100,!0/100", /* A */
-                       "!770+1633/100,!0/100", /* B */
-                       "!852+1633/100,!0/100", /* C */
-                       "!941+1633/100,!0/100", /* D */
-                       "!941+1209/100,!0/100", /* * */
+                       "!941+1336/100,!0/100", /* 0 */
+                       "!697+1209/100,!0/100", /* 1 */
+                       "!697+1336/100,!0/100", /* 2 */
+                       "!697+1477/100,!0/100", /* 3 */
+                       "!770+1209/100,!0/100", /* 4 */
+                       "!770+1336/100,!0/100", /* 5 */
+                       "!770+1477/100,!0/100", /* 6 */
+                       "!852+1209/100,!0/100", /* 7 */
+                       "!852+1336/100,!0/100", /* 8 */
+                       "!852+1477/100,!0/100", /* 9 */
+                       "!697+1633/100,!0/100", /* A */
+                       "!770+1633/100,!0/100", /* B */
+                       "!852+1633/100,!0/100", /* C */
+                       "!941+1633/100,!0/100", /* D */
+                       "!941+1209/100,!0/100", /* * */
                        "!941+1477/100,!0/100" };       /* # */
                if (digit >= '0' && digit <='9')
                        ast_playtones_start(chan,0,dtmf_tones[digit-'0'], 0);
@@ -1462,7 +1465,7 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr)
        struct ast_frame *f = NULL;
        /* Stop if we're a zombie or need a soft hangup */
        ast_mutex_lock(&chan->lock);
-       if (chan->zombie || ast_check_hangup(chan))  {
+       if (chan->zombie || ast_check_hangup(chan))      {
                ast_mutex_unlock(&chan->lock);
                return -1;
        }
@@ -1582,7 +1585,7 @@ int ast_set_write_format(struct ast_channel *chan, int fmts)
                return -1;
        }
        
-       /* Now we have a good choice for both.  We'll write using our native format. */
+       /* Now we have a good choice for both.  We'll write using our native format. */
        chan->pvt->rawwriteformat = native;
        /* User perspective is fmt */
        chan->writeformat = fmt;
@@ -1615,7 +1618,7 @@ int ast_set_read_format(struct ast_channel *chan, int fmts)
                return -1;
        }
        
-       /* Now we have a good choice for both.  We'll write using our native format. */
+       /* Now we have a good choice for both.  We'll write using our native format. */
        chan->pvt->rawreadformat = native;
        /* User perspective is fmt */
        chan->readformat = fmt;
@@ -1643,7 +1646,7 @@ struct ast_channel *__ast_request_and_dial(char *type, int format, void *data, i
                        char *tmp, *var;
                        /* JDG chanvar */
                        tmp = oh->variable;
-                       /* FIXME replace this call with strsep  NOT*/
+                       /* FIXME replace this call with strsep  NOT*/
                        while( (var = strtok_r(NULL, "|", &tmp)) ) {
                                pbx_builtin_setvar( chan, var );
                        } /* /JDG */
@@ -1795,9 +1798,9 @@ int ast_parse_device_state(char *device)
                strncpy(name, chan->name, sizeof(name)-1);
                cut = strchr(name,'-');
                if (cut)
-                       *cut = 0;
+                               *cut = 0;
                if (!strcmp(name, device))
-                       return AST_DEVICE_INUSE;
+                               return AST_DEVICE_INUSE;
                chan = ast_channel_walk(chan);
        }
        return AST_DEVICE_UNKNOWN;
@@ -1813,7 +1816,7 @@ int ast_device_state(char *device)
        strncpy(tech, device, sizeof(tech)-1);
        number = strchr(tech, '/');
        if (!number) {
-           return AST_DEVICE_INVALID;
+               return AST_DEVICE_INVALID;
        }
        *number = 0;
        number++;
@@ -2090,8 +2093,8 @@ int ast_do_masquerade(struct ast_channel *original)
                clone->name, clone->_state, original->name, original->_state);
 #endif
        /* XXX This is a seriously wacked out operation.  We're essentially putting the guts of
-          the clone channel into the original channel.  Start by killing off the original
-          channel's backend.   I'm not sure we're going to keep this function, because 
+          the clone channel into the original channel.  Start by killing off the original
+          channel's backend.   I'm not sure we're going to keep this function, because 
           while the features are nice, the cost is very high in terms of pure nastiness. XXX */
 
        /* We need the clone's lock, too */
@@ -2126,7 +2129,7 @@ int ast_do_masquerade(struct ast_channel *original)
        manager_event(EVENT_FLAG_CALL, "Rename", "Oldname: %s\r\nNewname: %s\r\n", newn, masqn);
        manager_event(EVENT_FLAG_CALL, "Rename", "Oldname: %s\r\nNewname: %s\r\n", orig, newn);
 
-       /* Swap the guts */     
+       /* Swap the guts */ 
        p = original->pvt;
        original->pvt = clone->pvt;
        clone->pvt = p;
@@ -2175,7 +2178,7 @@ int ast_do_masquerade(struct ast_channel *original)
        strncpy(clone->name, zombn, sizeof(clone->name) - 1);
        manager_event(EVENT_FLAG_CALL, "Rename", "Oldname: %s\r\nNewname: %s\r\n", masqn, zombn);
 
-       /* Keep the same language.  */
+       /* Keep the same language.      */
        /* Update the type. */
        original->type = clone->type;
        /* Copy the FD's */
@@ -2183,7 +2186,7 @@ int ast_do_masquerade(struct ast_channel *original)
                original->fds[x] = clone->fds[x];
        }
        /* Append variables from clone channel into original channel */
-       /* XXX Is this always correct?  We have to in order to keep MACROS working XXX */
+       /* XXX Is this always correct?  We have to in order to keep MACROS working XXX */
        varptr = original->varshead.first;
        if (varptr) {
                while(varptr->entries.next) {
@@ -2200,12 +2203,12 @@ int ast_do_masquerade(struct ast_channel *original)
        /* CDR fields remain the same */
        /* XXX What about blocking, softhangup, blocker, and lock and blockproc? XXX */
        /* Application and data remain the same */
-       /* Clone exception  becomes real one, as with fdno */
+       /* Clone exception      becomes real one, as with fdno */
        original->exception = clone->exception;
        original->fdno = clone->fdno;
        /* Schedule context remains the same */
        /* Stream stuff stays the same */
-       /* Keep the original state.  The fixup code will need to work with it most likely */
+       /* Keep the original state.      The fixup code will need to work with it most likely */
 
        /* dnid and callerid change to become the new, HOWEVER, we also link the original's
           fields back into the defunct 'clone' so that they will be freed when
@@ -2229,7 +2232,7 @@ int ast_do_masquerade(struct ast_channel *original)
           these separate */
        original->_state = clone->_state;
        
-       /* Context, extension, priority, app data, jump table,  remain the same */
+       /* Context, extension, priority, app data, jump table,  remain the same */
        /* pvt switches.  pbx stays the same, as does next */
        
        /* Set the write format */
@@ -2327,16 +2330,73 @@ int ast_setstate(struct ast_channel *chan, int state)
        return 0;
 }
 
-int ast_channel_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc)
-{
-       /* Copy voice back and forth between the two channels.  Give the peer
+
+static long tvdiff(struct timeval *now,struct timeval *then) {
+       return (((now->tv_sec * 1000) + now->tv_usec / 1000) - ((then->tv_sec * 1000) + then->tv_usec / 1000));
+}
+
+static void     bridge_playfile(struct ast_channel *chan,char *sound,int remain) {
+       int res=0,min=0,sec=0;
+       
+       if(remain > 0) {
+               if(remain / 60 > 1) {
+                       min = remain / 60;
+                       sec = remain % 60;
+               }
+               else {
+                       sec = remain;
+               }
+       }
+       
+       if(!strcmp(sound,"timeleft")) {
+               res=ast_streamfile(chan,"vm-youhave",chan->language);
+               res = ast_waitstream(chan, "");
+               if(min) {
+                       res = ast_say_number(chan,min, AST_DIGIT_ANY, chan->language);
+                       res=ast_streamfile(chan,"minutes",chan->language);
+                       res = ast_waitstream(chan, "");
+               }
+               if(sec) {
+                       res = ast_say_number(chan,sec, AST_DIGIT_ANY, chan->language);
+                       res=ast_streamfile(chan,"seconds",chan->language);
+                       res = ast_waitstream(chan, "");
+               }
+       }
+       else {
+               res=ast_streamfile(chan,sound,chan->language);
+               res = ast_waitstream(chan, "");
+       }
+}
+
+int ast_channel_bridge(struct ast_channel *c0,struct ast_channel *c1,struct ast_bridge_config *config, struct ast_frame **fo, struct ast_channel **rc) {
+       /* Copy voice back and forth between the two channels.  Give the peer
           the ability to transfer calls with '#<extension' syntax. */
+       int flags;
        struct ast_channel *cs[3];
        int to = -1;
        struct ast_frame *f;
        struct ast_channel *who = NULL;
-       int res;
+       int res=0;
        int nativefailed=0;
+       struct timeval start_time,precise_now;
+       long elapsed_ms=0,time_left_ms=0;
+       int playit=0,playitagain=1,first_time=1;
+       
+
+       flags = (config->allowdisconnect||config->allowredirect_out ? AST_BRIDGE_DTMF_CHANNEL_0 : 0) + (config->allowredirect_in ? AST_BRIDGE_DTMF_CHANNEL_1 : 0);
+
+       /* timestamp */
+       gettimeofday(&start_time,NULL);
+       time_left_ms = config->timelimit;
+
+       if(config->play_to_caller && config->start_sound){
+               bridge_playfile(c0,config->start_sound,time_left_ms / 1000);
+       }
+       if(config->play_to_callee && config->start_sound){
+               bridge_playfile(c1,config->start_sound,time_left_ms / 1000);
+       }
+
+
 
        /* Stop if we're a zombie or need a soft hangup */
        if (c0->zombie || ast_check_hangup_locked(c0) || c1->zombie || ast_check_hangup_locked(c1)) 
@@ -2366,6 +2426,57 @@ int ast_channel_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags
                        c0->name, c1->name, c0->uniqueid, c1->uniqueid);
 
        for (/* ever */;;) {
+
+               /* timestamp */
+               if(config->timelimit) {
+                       gettimeofday(&precise_now,NULL);
+                       elapsed_ms = tvdiff(&precise_now,&start_time);
+                       time_left_ms = config->timelimit - elapsed_ms;
+
+                       if(playitagain && (config->play_to_caller || config->play_to_callee) && (config->play_warning && time_left_ms <= config->play_warning)) { 
+                               /* narrowing down to the end */
+                               if(config->warning_freq == 0) {
+                                       playit = 1;
+                                       first_time=0;
+                                       playitagain=0;
+                               }
+                               else if(first_time) {
+                                       playit = 1;
+                                       first_time=0;
+                               }
+                               else {
+                                       if((time_left_ms % config->warning_freq) <= 50) {
+                                               playit = 1;
+                                       }
+                               }
+                       }
+
+                       if(time_left_ms <= 0) {
+                               if(config->play_to_caller && config->end_sound){
+                                       bridge_playfile(c0,config->end_sound,0);
+                               }
+
+                               if(config->play_to_callee && config->end_sound){
+                                       bridge_playfile(c1,config->end_sound,0);
+                }
+                               break;
+                       }
+
+                       if(time_left_ms >= 5000 && playit) {
+                               if(config->play_to_caller && config->warning_sound && config->play_warning){
+                                       bridge_playfile(c0,config->warning_sound,time_left_ms / 1000);
+                               }
+
+                               if(config->play_to_callee && config->warning_sound && config->play_warning){
+                                       bridge_playfile(c1,config->warning_sound,time_left_ms / 1000);
+                               }
+                               playit = 0;
+                       }
+                       
+               }
+
+
+
                /* Stop if we're a zombie or need a soft hangup */
                if (c0->zombie || ast_check_hangup_locked(c0) || c1->zombie || ast_check_hangup_locked(c1)) {
                        *fo = NULL;
@@ -2374,7 +2485,7 @@ int ast_channel_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags
                        ast_log(LOG_DEBUG, "Bridge stops because we're zombie or need a soft hangup: c0=%s, c1=%s, flags: %s,%s,%s,%s\n",c0->name,c1->name,c0->zombie?"Yes":"No",ast_check_hangup(c0)?"Yes":"No",c1->zombie?"Yes":"No",ast_check_hangup(c1)?"Yes":"No");
                        break;
                }
-               if (c0->pvt->bridge && 
+               if (c0->pvt->bridge && config->timelimit==0 &&
                        (c0->pvt->bridge == c1->pvt->bridge) && !nativefailed && !c0->monitor && !c1->monitor) {
                                /* Looks like they share a bridge code */
                        if (option_verbose > 2) 
diff --git a/contrib/scripts/astxs b/contrib/scripts/astxs
new file mode 100755 (executable)
index 0000000..663617e
--- /dev/null
@@ -0,0 +1,114 @@
+#!/usr/bin/perl
+
+my $astdir = $ENV{ASTSRC} or "/usr/src/asterisk";
+
+
+sub esystem($) {
+  my $cmd = shift;
+  print "$cmd\n";
+  system($cmd);
+}
+sub usage($) {
+  my $str = shift;
+  print "\n$str\n\n";
+  print "Usage $0 [ <module.c> [-set=<varname>:<value>] [-append=<varname>:<value>] [-install] ] | [-help]  \n\n";
+
+  print "varnames of interest:
+===============================================================================
+'INCLUDES' 'ASTLIBDIR' 'AGI_DIR' 'ASTVARRUNDIR' 'CC' 'ASTETCDIR' 'EXTOBJ'
+'ASTSPOOLDIR' 'ASTLOGDIR' 'MODULES_DIR' 'ASTSBINDIR' 'ASTHEADERDIR' 'LDFLAGS'
+'ASTVARLIBDIR' 'ASTBINDIR' 'INSTALL_PREFIX' 'ASTCONFPATH' 'ASTSRC' 'CFLAGS'
+===============================================================================
+";
+
+  exit;
+
+}
+
+
+my %avars = ();
+my %svars = ();
+my %vars = ();
+
+
+
+
+my %args = ();
+
+
+foreach(@ARGV) {
+
+  if(/^\-set=([^\:]+):(.*)/) {
+    $svars{$1} = $2;
+  }
+  elsif(/^\-append=([^\:]+):(.*)/) {
+    $avars{$1} .= " $2";
+  }
+  elsif(/^\-([^\=]+)=(.*)/) {
+    $args{$1} = $2;
+  }
+  elsif(/^\-([^\=]+)$/) {
+    $args{$1}++;
+  }
+  else {
+    push(@{$args{plain}},$_);
+  }
+}
+
+if($args{help} or $args{h}) {
+  usage "Help";
+}
+
+
+my $pwd = `/bin/pwd`;
+chomp($pwd);
+
+$vars{astdir} ||= $astdir;
+
+chdir($vars{astdir});
+my $type = $args{type} || "apps";
+my $env = `make ${type}_env`;
+chdir($pwd);
+
+foreach(split("\n",$env)) {
+    my($var,$val) = /([^\=]+)\=(.*)/;
+    $vars{$var} = $val;
+}
+
+
+
+
+foreach(keys %svars) {
+    $vars{$_} = $svars{$_};
+}
+
+foreach(keys %avars) {
+    $vars{$_} .= $avars{$_};
+}
+
+
+if($args{print}) {
+    print "$vars{$args{print}}";
+    exit;
+}
+
+
+my($base,$ext);
+my $cfile = $args{plain}->[0];
+if($cfile) {
+  ($base,$ext) = $cfile =~ /^([^\.]+)\.(.)/;
+}
+
+if($ext ne "c") {
+  usage "Bad Input File";
+}
+
+my $bad=0;
+
+$bad = esystem("$vars{CC} $vars{CFLAGS} -c ${base}.c -o ${base}.o");
+$bad = esystem("$vars{CC} $vars{SOLINK} -o $vars{LDFLAGS} ${base}.so $base.o $vars{EXTOBJ}") if(!$bad);
+
+if($args{install} and $vars{MODULES_DIR}) {
+  $bad = esystem("/bin/cp -p ${base}.so $vars{MODULES_DIR}") if(!$bad);
+}
+
index ef1d847..2a2a96a 100755 (executable)
@@ -267,6 +267,22 @@ static inline void ast_dup_flag(struct ast_channel *dstchan, struct ast_channel
                ast_clear_flag(dstchan, mode);
 }      
 
+
+struct ast_bridge_config {
+       int play_to_caller;
+       int play_to_callee;
+       int allowredirect_in;
+       int allowredirect_out;
+       int allowdisconnect;
+    long timelimit;
+    long play_warning;
+       long warning_freq;
+    char *warning_sound;
+    char *end_sound;
+    char *start_sound;
+};
+
+
 struct chanmon;
 
 #define LOAD_OH(oh) {  \
@@ -666,7 +682,9 @@ int ast_channel_make_compatible(struct ast_channel *c0, struct ast_channel *c1);
  * \param rc destination channel(?)
  * Bridge two channels (c0 and c1) together.  If an important frame occurs, we return that frame in
    *rf (remember, it could be NULL) and which channel (0 or 1) in rc */
-int ast_channel_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc);
+//int ast_channel_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc);
+int ast_channel_bridge(struct ast_channel *c0,struct ast_channel *c1,struct ast_bridge_config *config, struct ast_frame **fo, struct ast_channel **rc);
+
 
 //! Weird function made for call transfers
 /*! 
index 4b98595..836909d 100755 (executable)
@@ -44,9 +44,13 @@ extern int ast_masq_park_call(struct ast_channel *rchan, struct ast_channel *hos
 extern char *ast_parking_ext(void);
 extern char *ast_pickup_ext(void);
 
+
+
 //! Bridge a call, optionally allowing redirection
 
-extern int ast_bridge_call(struct ast_channel *chan, struct ast_channel *peer, int allowredirect_in, int allowredirect_out, int allowdisconnect);
+extern int ast_bridge_call(struct ast_channel *chan, struct ast_channel *peer,struct ast_bridge_config *config);
+
+
 
 extern int ast_pickup_call(struct ast_channel *chan);
 
index 1c9c11b..9c11f6a 100755 (executable)
@@ -214,11 +214,13 @@ int ast_masq_park_call(struct ast_channel *rchan, struct ast_channel *peer, int
        return 0;
 }
 
-int ast_bridge_call(struct ast_channel *chan, struct ast_channel *peer, int allowredirect_in, int allowredirect_out, int allowdisconnect)
+
+int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast_bridge_config *config)
 {
        /* Copy voice back and forth between the two channels.  Give the peer
           the ability to transfer calls with '#<extension' syntax. */
-       int len;
+
+        int len;
        struct ast_frame *f;
        struct ast_channel *who;
        char newext[256], *ptr;
@@ -226,7 +228,12 @@ int ast_bridge_call(struct ast_channel *chan, struct ast_channel *peer, int allo
        struct ast_option_header *aoh;
        struct ast_channel *transferer;
        struct ast_channel *transferee;
-  char *transferer_real_context;
+        char *transferer_real_context;
+        int allowdisconnect,allowredirect_in,allowredirect_out;
+
+       allowdisconnect = config->allowdisconnect;
+       allowredirect_in = config->allowredirect_in;
+       allowredirect_out = config->allowredirect_out;
 
        /* Answer if need be */
        if (ast_answer(chan))
@@ -246,7 +253,7 @@ int ast_bridge_call(struct ast_channel *chan, struct ast_channel *peer, int allo
                peer->cdr = NULL;
        }
        for (;;) {
-               res = ast_channel_bridge(chan, peer, (allowdisconnect||allowredirect_out ? AST_BRIDGE_DTMF_CHANNEL_0 : 0) + (allowredirect_in ? AST_BRIDGE_DTMF_CHANNEL_1 : 0), &f, &who);
+         res = ast_channel_bridge(chan,peer,config,&f, &who);
                if (res < 0) {
                        ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name);
                        return -1;
@@ -534,6 +541,8 @@ static int park_exec(struct ast_channel *chan, void *data)
        struct parkeduser *pu, *pl=NULL;
        int park;
        int dres;
+       struct ast_bridge_config config;
+
        if (!data) {
                ast_log(LOG_WARNING, "Park requires an argument (extension number)\n");
                return -1;
@@ -575,7 +584,17 @@ static int park_exec(struct ast_channel *chan, void *data)
                   were the person called. */
                if (option_verbose > 2) 
                        ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to parked call %d\n", chan->name, park);
-               res = ast_bridge_call(chan, peer, 1, 1, 0);
+
+               memset(&config,0,sizeof(struct ast_bridge_config));
+                config.allowredirect_in = 1;
+                config.allowredirect_out = 1;
+                config.allowdisconnect = 0;
+                config.timelimit = 0;
+                config.play_warning = 0;
+                config.warning_freq = 0;
+                config.warning_sound=NULL;
+                res = ast_bridge_call(chan,peer,&config);
+
                /* Simulate the PBX hanging up */
                if (res != AST_PBX_NO_HANGUP_PEER)
                        ast_hangup(peer);