Merged revisions 173500 via svnmerge from

https://origsvn.digium.com/svn/asterisk/trunk

................
  r173500 | jpeeler | 2009-02-04 15:17:53 -0600 (Wed, 04 Feb 2009) | 23 lines
  
  Merged revisions 173211 via svnmerge from 
  https://origsvn.digium.com/svn/asterisk/branches/1.4
  
  ........
    r173211 | jpeeler | 2009-02-03 15:57:01 -0600 (Tue, 03 Feb 2009) | 17 lines
    
    Parking attempts made to one end of a bridge no longer will hang up due to a
    parking failure.
    
    Parking attempts made using either one-touch, or doing either a blind or 
    assisted transfer to the parking extension now keep up the bridge instead of
    hanging up the attempted parked party. Normal causes for the parking attempt
    to fail includes the specific specified extension (via PARKINGEXTEN) not being 
    available or if all the parking spaces are currently in use. To avoid having
    to reverse a masquerade park_space_reserve was made to provide foresight if
    a parking attempt will succeed and if so reserve the parking space.
    
    (closes issue #13494)
    Reported by: mdu113
    
    Reviewed by Russell: http://reviewboard.digium.com/r/133/
  ........
................


git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/1.6.0@173546 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
Jeff Peeler
2009-02-04 23:38:54 +00:00
parent f94677ac39
commit 58d71a9470

View File

@@ -66,6 +66,14 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#define AST_MAX_WATCHERS 256 #define AST_MAX_WATCHERS 256
#define MAX_DIAL_FEATURE_OPTIONS 30 #define MAX_DIAL_FEATURE_OPTIONS 30
#define FEATURE_RETURN_HANGUP -1
#define FEATURE_RETURN_SUCCESSBREAK 0
#define FEATURE_RETURN_PASSDIGITS 21
#define FEATURE_RETURN_STOREDIGITS 22
#define FEATURE_RETURN_SUCCESS 23
#define FEATURE_RETURN_KEEPTRYING 24
#define FEATURE_RETURN_PARKFAILED 25
enum { enum {
AST_FEATURE_FLAG_NEEDSDTMF = (1 << 0), AST_FEATURE_FLAG_NEEDSDTMF = (1 << 0),
AST_FEATURE_FLAG_ONPEER = (1 << 1), AST_FEATURE_FLAG_ONPEER = (1 << 1),
@@ -409,17 +417,15 @@ static enum ast_device_state metermaidstate(const char *data)
return AST_DEVICE_INUSE; return AST_DEVICE_INUSE;
} }
/* Park a call */ static struct parkeduser *park_space_reserve(struct ast_channel *chan)
static int park_call_full(struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout, const char *orig_chan_name)
{ {
struct parkeduser *pu, *cur; struct parkeduser *pu, *cur;
int i, x = -1, parking_range; int i, parking_space = -1, parking_range;
struct ast_context *con;
const char *parkingexten; const char *parkingexten;
/* Allocate memory for parking data */ /* Allocate memory for parking data */
if (!(pu = ast_calloc(1, sizeof(*pu)))) if (!(pu = ast_calloc(1, sizeof(*pu))))
return -1; return NULL;
/* Lock parking lot */ /* Lock parking lot */
AST_LIST_LOCK(&parkinglot); AST_LIST_LOCK(&parkinglot);
@@ -432,27 +438,27 @@ static int park_call_full(struct ast_channel *chan, struct ast_channel *peer, in
* limitation here. If extout was not numeric, we could permit * limitation here. If extout was not numeric, we could permit
* arbitrary non-numeric extensions. * arbitrary non-numeric extensions.
*/ */
if (sscanf(parkingexten, "%d", &x) != 1 || x < 0) { if (sscanf(parkingexten, "%d", &parking_space) != 1 || parking_space < 0) {
AST_LIST_UNLOCK(&parkinglot); AST_LIST_UNLOCK(&parkinglot);
ast_free(pu); ast_free(pu);
ast_log(LOG_WARNING, "PARKINGEXTEN does not indicate a valid parking slot: '%s'.\n", parkingexten); ast_log(LOG_WARNING, "PARKINGEXTEN does not indicate a valid parking slot: '%s'.\n", parkingexten);
return 1; /* Continue execution if possible */ return NULL;
} }
snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", x); snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", parking_space);
if (ast_exists_extension(NULL, parking_con, pu->parkingexten, 1, NULL)) { if (ast_exists_extension(NULL, parking_con, pu->parkingexten, 1, NULL)) {
AST_LIST_UNLOCK(&parkinglot); AST_LIST_UNLOCK(&parkinglot);
ast_free(pu); ast_free(pu);
ast_log(LOG_WARNING, "Requested parking extension already exists: %s@%s\n", parkingexten, parking_con); ast_log(LOG_WARNING, "Requested parking extension already exists: %s@%s\n", parkingexten, parking_con);
return 1; /* Continue execution if possible */ return NULL;
} }
} else { } else {
/* Select parking space within range */ /* Select parking space within range */
parking_range = parking_stop - parking_start+1; parking_range = parking_stop - parking_start+1;
for (i = 0; i < parking_range; i++) { for (i = 0; i < parking_range; i++) {
x = (i + parking_offset) % parking_range + parking_start; parking_space = (i + parking_offset) % parking_range + parking_start;
AST_LIST_TRAVERSE(&parkinglot, cur, list) { AST_LIST_TRAVERSE(&parkinglot, cur, list) {
if (cur->parkingnum == x) if (cur->parkingnum == parking_space)
break; break;
} }
if (!cur) if (!cur)
@@ -463,14 +469,35 @@ static int park_call_full(struct ast_channel *chan, struct ast_channel *peer, in
ast_log(LOG_WARNING, "No more parking spaces\n"); ast_log(LOG_WARNING, "No more parking spaces\n");
ast_free(pu); ast_free(pu);
AST_LIST_UNLOCK(&parkinglot); AST_LIST_UNLOCK(&parkinglot);
return -1; return NULL;
} }
/* Set pointer for next parking */ /* Set pointer for next parking */
if (parkfindnext) if (parkfindnext)
parking_offset = x - parking_start + 1; parking_offset = parking_space - parking_start + 1;
snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", x); snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", parking_space);
} }
pu->notquiteyet = 1;
pu->parkingnum = parking_space;
AST_LIST_INSERT_TAIL(&parkinglot, pu, list);
AST_LIST_UNLOCK(&parkinglot);
return pu;
}
/* Park a call */
static int park_call_full(struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout, const char *orig_chan_name, struct parkeduser *pu)
{
struct ast_context *con;
/* Get a valid space if not already done */
if (pu == NULL)
pu = park_space_reserve(chan);
if (pu == NULL)
return 1; /* Continue execution if possible */
snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", pu->parkingnum);
chan->appl = "Parked Call"; chan->appl = "Parked Call";
chan->data = NULL; chan->data = NULL;
@@ -484,10 +511,9 @@ static int park_call_full(struct ast_channel *chan, struct ast_channel *peer, in
} }
pu->start = ast_tvnow(); pu->start = ast_tvnow();
pu->parkingnum = x;
pu->parkingtime = (timeout > 0) ? timeout : parkingtime; pu->parkingtime = (timeout > 0) ? timeout : parkingtime;
if (extout) if (extout)
*extout = x; *extout = pu->parkingnum;
if (peer) { if (peer) {
/* This is so ugly that it hurts, but implementing get_base_channel() on local channels /* This is so ugly that it hurts, but implementing get_base_channel() on local channels
@@ -519,12 +545,12 @@ static int park_call_full(struct ast_channel *chan, struct ast_channel *peer, in
ast_copy_string(pu->context, S_OR(chan->macrocontext, chan->context), sizeof(pu->context)); ast_copy_string(pu->context, S_OR(chan->macrocontext, chan->context), sizeof(pu->context));
ast_copy_string(pu->exten, S_OR(chan->macroexten, chan->exten), sizeof(pu->exten)); ast_copy_string(pu->exten, S_OR(chan->macroexten, chan->exten), sizeof(pu->exten));
pu->priority = chan->macropriority ? chan->macropriority : chan->priority; pu->priority = chan->macropriority ? chan->macropriority : chan->priority;
AST_LIST_INSERT_TAIL(&parkinglot, pu, list);
/* If parking a channel directly, don't quiet yet get parking running on it */ /* If parking a channel directly, don't quiet yet get parking running on it.
if (peer == chan) * All parking lot entries are put into the parking lot with notquiteyet on. */
pu->notquiteyet = 1; if (peer != chan)
AST_LIST_UNLOCK(&parkinglot); pu->notquiteyet = 0;
/* Wake up the (presumably select()ing) thread */ /* Wake up the (presumably select()ing) thread */
pthread_kill(parking_thread, SIGURG); pthread_kill(parking_thread, SIGURG);
ast_verb(2, "Parked %s on %d@%s. Will timeout back to extension [%s] %s, %d in %d seconds\n", pu->chan->name, pu->parkingnum, parking_con, pu->context, pu->exten, pu->priority, (pu->parkingtime/1000)); ast_verb(2, "Parked %s on %d@%s. Will timeout back to extension [%s] %s, %d in %d seconds\n", pu->chan->name, pu->parkingnum, parking_con, pu->context, pu->exten, pu->priority, (pu->parkingtime/1000));
@@ -577,15 +603,21 @@ static int park_call_full(struct ast_channel *chan, struct ast_channel *peer, in
/*! \brief Park a call */ /*! \brief Park a call */
int ast_park_call(struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout) int ast_park_call(struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout)
{ {
return park_call_full(chan, peer, timeout, extout, NULL); return park_call_full(chan, peer, timeout, extout, NULL, NULL);
} }
static int masq_park_call(struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout, int play_announcement, const char *orig_chan_name) static int masq_park_call(struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout, int play_announcement, const char *orig_chan_name)
{ {
struct ast_channel *chan; struct ast_channel *chan;
struct ast_frame *f; struct ast_frame *f;
struct parkeduser *pu;
int park_status; int park_status;
if ((pu = park_space_reserve(rchan)) == NULL) {
ast_stream_and_wait(peer, "beeperr", "");
return FEATURE_RETURN_PARKFAILED;
}
/* Make a new, fake channel that we'll use to masquerade in the real one */ /* Make a new, fake channel that we'll use to masquerade in the real one */
if (!(chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, rchan->accountcode, rchan->exten, rchan->context, rchan->amaflags, "Parked/%s",rchan->name))) { if (!(chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, rchan->accountcode, rchan->exten, rchan->context, rchan->amaflags, "Parked/%s",rchan->name))) {
ast_log(LOG_WARNING, "Unable to create parked channel\n"); ast_log(LOG_WARNING, "Unable to create parked channel\n");
@@ -612,7 +644,7 @@ static int masq_park_call(struct ast_channel *rchan, struct ast_channel *peer, i
orig_chan_name = ast_strdupa(chan->name); orig_chan_name = ast_strdupa(chan->name);
} }
park_status = park_call_full(chan, peer, timeout, extout, orig_chan_name); park_status = park_call_full(chan, peer, timeout, extout, orig_chan_name, pu);
if (park_status == 1) { if (park_status == 1) {
/* would be nice to play "invalid parking extension" */ /* would be nice to play "invalid parking extension" */
ast_hangup(chan); ast_hangup(chan);
@@ -632,15 +664,6 @@ static int masq_park_call_announce(struct ast_channel *rchan, struct ast_channel
return masq_park_call(rchan, peer, timeout, extout, 1, orig_chan_name); return masq_park_call(rchan, peer, timeout, extout, 1, orig_chan_name);
} }
#define FEATURE_RETURN_HANGUP -1
#define FEATURE_RETURN_SUCCESSBREAK 0
#define FEATURE_RETURN_PBX_KEEPALIVE AST_PBX_KEEPALIVE
#define FEATURE_RETURN_NO_HANGUP_PEER AST_PBX_NO_HANGUP_PEER
#define FEATURE_RETURN_PASSDIGITS 21
#define FEATURE_RETURN_STOREDIGITS 22
#define FEATURE_RETURN_SUCCESS 23
#define FEATURE_RETURN_KEEPTRYING 24
#define FEATURE_SENSE_CHAN (1 << 0) #define FEATURE_SENSE_CHAN (1 << 0)
#define FEATURE_SENSE_PEER (1 << 1) #define FEATURE_SENSE_PEER (1 << 1)
@@ -695,8 +718,8 @@ static int builtin_parkcall(struct ast_channel *chan, struct ast_channel *peer,
res = ast_safe_sleep(chan, 1000); res = ast_safe_sleep(chan, 1000);
if (!res) { /* one direction used to call park_call.... */ if (!res) { /* one direction used to call park_call.... */
masq_park_call_announce(parkee, parker, 0, NULL, NULL); res = masq_park_call_announce(parkee, parker, 0, NULL, NULL);
res = 0; /* PBX should hangup zombie channel */ /* PBX should hangup zombie channel if a masquerade actually occurred (res=0) */
} }
return res; return res;
} }
@@ -968,6 +991,7 @@ static int builtin_blindtransfer(struct ast_channel *chan, struct ast_channel *p
const char *transferer_real_context; const char *transferer_real_context;
char xferto[256]; char xferto[256];
int res; int res;
int parkstatus = 0;
set_peers(&transferer, &transferee, peer, chan, sense); set_peers(&transferer, &transferee, peer, chan, sense);
transferer_real_context = real_ctx(transferer, transferee); transferer_real_context = real_ctx(transferer, transferee);
@@ -996,14 +1020,14 @@ static int builtin_blindtransfer(struct ast_channel *chan, struct ast_channel *p
res = finishup(transferee); res = finishup(transferee);
if (res) if (res)
res = -1; res = -1;
else if (!masq_park_call_announce(transferee, transferer, 0, NULL, NULL)) { /* success */ else if (!(parkstatus = masq_park_call_announce(transferee, transferer, 0, NULL, NULL))) { /* success */
/* We return non-zero, but tell the PBX not to hang the channel when /* We return non-zero, but tell the PBX not to hang the channel when
the thread dies -- We have to be careful now though. We are responsible for the thread dies -- We have to be careful now though. We are responsible for
hanging up the channel, else it will never be hung up! */ hanging up the channel, else it will never be hung up! */
return 0; return 0;
} else { } else {
ast_log(LOG_WARNING, "Unable to park call %s\n", transferee->name); ast_log(LOG_WARNING, "Unable to park call %s, parkstatus = %d\n", transferee->name, parkstatus);
} }
/*! \todo XXX Maybe we should have another message here instead of invalid extension XXX */ /*! \todo XXX Maybe we should have another message here instead of invalid extension XXX */
} else if (ast_exists_extension(transferee, transferer_real_context, xferto, 1, transferer->cid.cid_num)) { } else if (ast_exists_extension(transferee, transferer_real_context, xferto, 1, transferer->cid.cid_num)) {
@@ -1046,7 +1070,7 @@ static int builtin_blindtransfer(struct ast_channel *chan, struct ast_channel *p
} else { } else {
ast_verb(3, "Unable to find extension '%s' in context '%s'\n", xferto, transferer_real_context); ast_verb(3, "Unable to find extension '%s' in context '%s'\n", xferto, transferer_real_context);
} }
if (ast_stream_and_wait(transferer, xferfailsound, AST_DIGIT_ANY) < 0) { if (parkstatus != FEATURE_RETURN_PARKFAILED && ast_stream_and_wait(transferer, xferfailsound, AST_DIGIT_ANY) < 0) {
finishup(transferee); finishup(transferee);
return -1; return -1;
} }
@@ -1704,6 +1728,9 @@ static int ast_feature_interpret(struct ast_channel *chan, struct ast_channel *p
!ast_strlen_zero(builtin_features[x].exten)) { !ast_strlen_zero(builtin_features[x].exten)) {
/* Feature is up for consideration */ /* Feature is up for consideration */
if (!strcmp(builtin_features[x].exten, code)) { if (!strcmp(builtin_features[x].exten, code)) {
if (option_debug > 2) {
ast_log(LOG_DEBUG, "Feature detected: fname=%s sname=%s exten=%s\n", builtin_features[x].fname, builtin_features[x].sname, builtin_features[x].exten);
}
res = builtin_features[x].operation(chan, peer, config, code, sense, NULL); res = builtin_features[x].operation(chan, peer, config, code, sense, NULL);
feature_detected = 1; feature_detected = 1;
break; break;