aboutsummaryrefslogtreecommitdiffstats
path: root/res/res_features.c
diff options
context:
space:
mode:
Diffstat (limited to 'res/res_features.c')
-rw-r--r--res/res_features.c105
1 files changed, 68 insertions, 37 deletions
diff --git a/res/res_features.c b/res/res_features.c
index e44937e2c..2161f2446 100644
--- a/res/res_features.c
+++ b/res/res_features.c
@@ -72,6 +72,14 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#define AST_MAX_WATCHERS 256
#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 {
AST_FEATURE_FLAG_NEEDSDTMF = (1 << 0),
AST_FEATURE_FLAG_ONPEER = (1 << 1),
@@ -338,16 +346,15 @@ static int metermaidstate(const char *data)
return AST_DEVICE_INUSE;
}
-static int park_call_full(struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout, const char *orig_chan_name)
+static struct parkeduser *park_space_reserve(struct ast_channel *chan)
{
struct parkeduser *pu, *cur;
- int i, x = -1, parking_range, parkingnum_copy;
- struct ast_context *con;
+ int i, parking_space = -1, parking_range;
const char *parkingexten;
-
+
/* Allocate memory for parking data */
if (!(pu = ast_calloc(1, sizeof(*pu))))
- return -1;
+ return NULL;
/* Lock parking lot */
ast_mutex_lock(&parking_lock);
@@ -360,28 +367,28 @@ static int park_call_full(struct ast_channel *chan, struct ast_channel *peer, in
* limitation here. If extout was not numeric, we could permit
* arbitrary non-numeric extensions.
*/
- if (sscanf(parkingexten, "%d", &x) != 1 || x < 0) {
+ if (sscanf(parkingexten, "%d", &parking_space) != 1 || parking_space < 0) {
ast_log(LOG_WARNING, "PARKINGEXTEN does not indicate a valid parking slot: '%s'.\n", parkingexten);
ast_mutex_unlock(&parking_lock);
free(pu);
- 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)) {
ast_mutex_unlock(&parking_lock);
- free(pu);
ast_log(LOG_WARNING, "Requested parking extension already exists: %s@%s\n", parkingexten, parking_con);
- return 1; /* Continue execution if possible */
+ free(pu);
+ return NULL;
}
} else {
/* Select parking space within range */
parking_range = parking_stop - parking_start+1;
for (i = 0; i < parking_range; i++) {
- x = (i + parking_offset) % parking_range + parking_start;
+ parking_space = (i + parking_offset) % parking_range + parking_start;
cur = parkinglot;
while(cur) {
- if (cur->parkingnum == x)
+ if (cur->parkingnum == parking_space)
break;
cur = cur->next;
}
@@ -391,16 +398,38 @@ static int park_call_full(struct ast_channel *chan, struct ast_channel *peer, in
if (!(i < parking_range)) {
ast_log(LOG_WARNING, "No more parking spaces\n");
- free(pu);
ast_mutex_unlock(&parking_lock);
- return -1;
+ free(pu);
+ return NULL;
}
/* Set pointer for next parking */
if (parkfindnext)
- parking_offset = x - parking_start + 1;
- snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", x);
+ parking_offset = parking_space - parking_start + 1;
+ snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", parking_space);
}
+ pu->notquiteyet = 1;
+ pu->parkingnum = parking_space;
+ pu->next = parkinglot;
+ parkinglot = pu;
+ ast_mutex_unlock(&parking_lock);
+
+ return pu;
+}
+
+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;
+ int parkingnum_copy;
+
+ /* 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->data = NULL;
@@ -414,10 +443,9 @@ static int park_call_full(struct ast_channel *chan, struct ast_channel *peer, in
}
pu->start = ast_tvnow();
- pu->parkingnum = x;
pu->parkingtime = (timeout > 0) ? timeout : parkingtime;
if (extout)
- *extout = x;
+ *extout = pu->parkingnum;
if (peer) {
/* This is so ugly that it hurts, but implementing get_base_channel() on local channels
@@ -449,12 +477,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->exten, S_OR(chan->macroexten, chan->exten), sizeof(pu->exten));
pu->priority = chan->macropriority ? chan->macropriority : chan->priority;
- pu->next = parkinglot;
- parkinglot = pu;
parkingnum_copy = pu->parkingnum;
- /* If parking a channel directly, don't quite yet get parking running on it */
- if (peer == chan)
- pu->notquiteyet = 1;
+
+ /* If parking a channel directly (peer == chan), don't quite yet get parking running on it.
+ * All parking lot entires are put into the parking lot with notquiteyet on. */
+ if (peer != chan)
+ pu->notquiteyet = 0;
if (option_verbose > 1)
ast_verbose(VERBOSE_PREFIX_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));
@@ -488,7 +516,6 @@ static int park_call_full(struct ast_channel *chan, struct ast_channel *peer, in
}
}
- ast_mutex_unlock(&parking_lock);
/* Wake up the (presumably select()ing) thread */
pthread_kill(parking_thread, SIGURG);
@@ -517,15 +544,21 @@ static int park_call_full(struct ast_channel *chan, struct ast_channel *peer, in
after these channels too */
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)
{
struct ast_channel *chan;
struct ast_frame *f;
+ struct parkeduser *pu;
int park_status;
+ if ((pu = park_space_reserve(rchan)) == NULL) {
+ ast_stream_and_wait(peer, "beeperr", peer->language, "");
+ return FEATURE_RETURN_PARKFAILED;
+ }
+
/* 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))) {
ast_log(LOG_WARNING, "Unable to create parked channel\n");
@@ -553,7 +586,7 @@ static int masq_park_call(struct ast_channel *rchan, struct ast_channel *peer, i
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) {
/* would be nice to play: "invalid parking extension" */
ast_hangup(chan);
@@ -572,12 +605,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);
}
-#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_SENSE_CHAN (1 << 0)
#define FEATURE_SENSE_PEER (1 << 1)
@@ -624,8 +651,8 @@ static int builtin_parkcall(struct ast_channel *chan, struct ast_channel *peer,
res = ast_safe_sleep(chan, 1000);
if (!res) { /* one direction used to call park_call.... */
- masq_park_call_announce(parkee, parker, 0, NULL, orig_chan_name);
- res = 0; /* PBX should hangup zombie channel */
+ res = masq_park_call_announce(parkee, parker, 0, NULL, orig_chan_name);
+ /* PBX should hangup zombie channel if a masquerade actually occurred (res=0) */
}
ast_module_user_remove(u);
@@ -751,6 +778,7 @@ static int builtin_blindtransfer(struct ast_channel *chan, struct ast_channel *p
char xferto[256];
int res;
const char *orig_chan_name;
+ int parkstatus = 0;
set_peers(&transferer, &transferee, peer, chan, sense);
orig_chan_name = ast_strdupa(transferer->name);
@@ -780,13 +808,13 @@ static int builtin_blindtransfer(struct ast_channel *chan, struct ast_channel *p
res = finishup(transferee);
if (res)
res = -1;
- else if (!masq_park_call_announce(transferee, transferer, 0, NULL, orig_chan_name)) { /* success */
+ else if (!(parkstatus = masq_park_call_announce(transferee, transferer, 0, NULL, orig_chan_name))) { /* success */
/* 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
hanging up the channel, else it will never be hung up! */
return 0;
} 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 */
} else if (ast_exists_extension(transferee, transferer_real_context, xferto, 1, transferer->cid.cid_num)) {
@@ -825,7 +853,7 @@ static int builtin_blindtransfer(struct ast_channel *chan, struct ast_channel *p
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "Unable to find extension '%s' in context '%s'\n", xferto, transferer_real_context);
}
- if (ast_stream_and_wait(transferer, xferfailsound, transferer->language, AST_DIGIT_ANY) < 0 ) {
+ if (parkstatus != FEATURE_RETURN_PARKFAILED && ast_stream_and_wait(transferer, xferfailsound, transferer->language, AST_DIGIT_ANY) < 0 ) {
finishup(transferee);
return -1;
}
@@ -1213,6 +1241,9 @@ static int ast_feature_interpret(struct ast_channel *chan, struct ast_channel *p
!ast_strlen_zero(builtin_features[x].exten)) {
/* Feature is up for consideration */
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);
feature_detected = 1;
break;