[asterisk-commits] rmudgett: branch rmudgett/parking r329612 - in /team/rmudgett/parking: apps/ ...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Tue Jul 26 19:18:14 CDT 2011
Author: rmudgett
Date: Tue Jul 26 19:18:10 2011
New Revision: 329612
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=329612
Log:
Work in progress.
Modified:
team/rmudgett/parking/apps/app_parkandannounce.c
team/rmudgett/parking/channels/chan_iax2.c
team/rmudgett/parking/channels/chan_sip.c
team/rmudgett/parking/main/features.c
Modified: team/rmudgett/parking/apps/app_parkandannounce.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/parking/apps/app_parkandannounce.c?view=diff&rev=329612&r1=329611&r2=329612
==============================================================================
--- team/rmudgett/parking/apps/app_parkandannounce.c (original)
+++ team/rmudgett/parking/apps/app_parkandannounce.c Tue Jul 26 19:18:10 2011
@@ -142,8 +142,10 @@
before we are done announcing and the channel is messed with, Kablooeee. So we use Masq to prevent this. */
res = ast_masq_park_call(chan, NULL, timeout, &lot);
- if (res == -1)
- return res;
+ if (res) {
+ /* Parking failed. */
+ return -1;
+ }
ast_verb(3, "Call Parking Called, lot: %d, timeout: %d, context: %s\n", lot, timeout, args.return_context);
Modified: team/rmudgett/parking/channels/chan_iax2.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/parking/channels/chan_iax2.c?view=diff&rev=329612&r1=329611&r2=329612
==============================================================================
--- team/rmudgett/parking/channels/chan_iax2.c (original)
+++ team/rmudgett/parking/channels/chan_iax2.c Tue Jul 26 19:18:10 2011
@@ -9255,7 +9255,8 @@
struct ast_channel *chan1, *chan2;
struct iax_dual *d;
struct ast_frame *f;
- int ext;
+ int ext = 0;
+
d = stuff;
chan1 = d->chan1;
chan2 = d->chan2;
Modified: team/rmudgett/parking/channels/chan_sip.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/parking/channels/chan_sip.c?view=diff&rev=329612&r1=329611&r2=329612
==============================================================================
--- team/rmudgett/parking/channels/chan_sip.c (original)
+++ team/rmudgett/parking/channels/chan_sip.c Tue Jul 26 19:18:10 2011
@@ -20764,7 +20764,7 @@
#ifdef WHEN_WE_KNOW_THAT_THE_CLIENT_SUPPORTS_MESSAGE
- if (!res) {
+ if (res) {
transmit_message_with_text(transferer->tech_pvt, "Unable to park call.\n");
} else {
/* Then tell the transferer what happened */
Modified: team/rmudgett/parking/main/features.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/parking/main/features.c?view=diff&rev=329612&r1=329611&r2=329612
==============================================================================
--- team/rmudgett/parking/main/features.c (original)
+++ team/rmudgett/parking/main/features.c Tue Jul 26 19:18:10 2011
@@ -390,9 +390,9 @@
* The list belongs to a parkinglot.
*/
struct parkeduser {
- struct ast_channel *chan; /*!< Parking channel */
- struct timeval start; /*!< Time the parking started */
- int parkingnum; /*!< Parking lot */
+ struct ast_channel *chan; /*!< Parked channel */
+ struct timeval start; /*!< Time the park started */
+ int parkingnum; /*!< Parking lot space used */
char parkingexten[AST_MAX_EXTENSION]; /*!< If set beforehand, parking extension used for this call */
char context[AST_MAX_CONTEXT]; /*!< Where to go if our parking time expires */
char exten[AST_MAX_EXTENSION];
@@ -478,9 +478,11 @@
/*! Parking lot user configuration. */
struct parkinglot_cfg cfg;
-/* BUGBUG could use the_mark as a disabled parking lot flag if it is set. Do not park any new calls on this lot. */
- /*! Used during reloads, that which bears the_mark shall be deleted! */
+ /*! That which bears the_mark shall be deleted if parking lot empty! (Used during reloads.) */
unsigned int the_mark:1;
+/* BUGBUG need to make use disabled flag to prevent new calls going into the parking lot. */
+ /*! TRUE if the parking lot is disabled. */
+ unsigned int disabled:1;
/*! List of active parkings in this parkinglot */
AST_LIST_HEAD(parkinglot_parklist, parkeduser) parkings;
@@ -644,30 +646,6 @@
static struct ast_parkinglot *find_parkinglot(const char *name);
static struct ast_parkinglot *create_parkinglot(const char *name);
static struct ast_parkinglot *copy_parkinglot(const char *name, const struct ast_parkinglot *parkinglot);
-
-static int find_parkinglot_by_position_cb(void *obj, void *args, int flags)
-{
- struct ast_parkinglot *parkinglot = obj;
- int *parkpos = args;
-
- if (*parkpos >= parkinglot->cfg.parking_start && *parkpos <= parkinglot->cfg.parking_stop) {
- return CMP_MATCH | CMP_STOP;
- }
-
- return 0;
-}
-
-static int find_parkinglot_by_exten_cb(void *obj, void *args, int flags)
-{
- struct ast_parkinglot *parkinglot = obj;
- const char *parkext = args;
-
- if (!strcmp(parkinglot->cfg.parkext, parkext)) {
- return CMP_MATCH | CMP_STOP;
- }
-
- return 0;
-}
int ast_parking_ext_valid(const char *exten_str, struct ast_channel *chan, const char *context)
{
@@ -870,16 +848,15 @@
*/
static const char *findparkinglotname(struct ast_channel *chan)
{
- const char *parkinglot;
+ const char *name;
/* The channel variable overrides everything */
- parkinglot = pbx_builtin_getvar_helper(chan, "PARKINGLOT");
- if (!parkinglot
- && !ast_strlen_zero(chan->parkinglot)) {
+ name = pbx_builtin_getvar_helper(chan, "PARKINGLOT");
+ if (!name && !ast_strlen_zero(chan->parkinglot)) {
/* Use the channel's parking lot. */
- parkinglot = chan->parkinglot;
- }
- return parkinglot;
+ name = chan->parkinglot;
+ }
+ return name;
}
/*! \brief Notify metermaids that we've changed an extension */
@@ -922,6 +899,7 @@
AST_PARK_OPT_SILENCE = (1 << 2),
};
+/*! Optional additional parking options when parking a call. */
struct ast_park_call_args {
/*! How long to wait in the parking lot before the call gets sent back
* to the specified return extension (or a best guess at where it came
@@ -937,10 +915,7 @@
uint32_t flags;
/*! Parked user that has already obtained a parking space */
struct parkeduser *pu;
- /*!
- * \brief Parkinglot to be parked in, based on parkext
- * \note BUGBUG check reference use!
- */
+ /*! \brief Parkinglot to be parked in */
struct ast_parkinglot *parkinglot;
};
@@ -950,7 +925,7 @@
*
* \param chan Channel being parked.
* \param peer Channel parking the call.
- * \param args BUGBUG
+ * \param args Optional additional parking options when parking a call.
*
* \return Parked call descriptor or NULL if failed.
* \note The parking lot list is locked if successful.
@@ -958,37 +933,37 @@
static struct parkeduser *park_space_reserve(struct ast_channel *chan, struct ast_channel *peer, struct ast_park_call_args *args)
{
struct parkeduser *pu;
- int i, parking_space = -1;
- const char *parkinglotname = NULL;
+ int i;
+ int parking_space = -1;
+ const char *parkinglotname;
const char *parkingexten;
+ struct parkeduser *cur;
struct ast_parkinglot *parkinglot = NULL;
if (args->parkinglot) {
- parkinglot = args->parkinglot;
+ parkinglot = parkinglot_addref(args->parkinglot);
parkinglotname = parkinglot->name;
- } else if (peer) {
- parkinglotname = findparkinglotname(peer);
- } else { /* peer was NULL, check chan (ParkAndAnnounce / res_agi) */
- parkinglotname = findparkinglotname(chan);
- }
-
- if (!parkinglot) {
- if (parkinglotname) {
+ } else {
+ if (peer) {
+ parkinglotname = findparkinglotname(peer);
+ } else { /* peer was NULL, check chan (ParkAndAnnounce / res_agi) */
+ parkinglotname = findparkinglotname(chan);
+ }
+ if (!ast_strlen_zero(parkinglotname)) {
parkinglot = find_parkinglot(parkinglotname);
- } else {
- ast_debug(4, "This could be an indication channel driver needs updating, using default lot.\n");
- parkinglot = parkinglot_addref(default_parkinglot);
- }
- ast_debug(1, "Found chanvar Parkinglot: %s\n", parkinglot->name);
+ }
}
/* Dynamically create parkinglot */
if (!parkinglot && parkeddynamic && !ast_strlen_zero(parkinglotname)) {
- const char *dyn_context, *dyn_range;
- const char *parkinglotname_copy = NULL;
+ const char *dyn_context;
+ const char *dyn_range;
+ const char *parkinglotname_copy;
struct ast_parkinglot *parkinglot_copy = NULL;
- int dyn_start, dyn_end;
-
+ int dyn_start;
+ int dyn_end;
+
+ /* XXX Why are we getting dynamic parkinglot information from chan and not peer? */
ast_channel_lock(chan);
parkinglotname_copy = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGDYNAMIC"), ""));
dyn_context = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGDYNCONTEXT"), ""));
@@ -999,23 +974,34 @@
parkinglot_copy = find_parkinglot(parkinglotname_copy);
if (parkinglot_copy && parkinglot_copy->cfg.is_invalid) {
ast_debug(1, "Requested parking lot has invalid config.\n");
- parkinglot_unref(parkinglot);
- parkinglot = NULL;
+ parkinglot_unref(parkinglot_copy);
+ parkinglot_copy = NULL;
}
}
if (!parkinglot_copy) {
parkinglot_copy = parkinglot_addref(default_parkinglot);
ast_debug(1, "Using default parking lot for copy\n");
}
- if (!(parkinglot = copy_parkinglot(parkinglotname, parkinglot_copy))) {
+ parkinglot = copy_parkinglot(parkinglotname, parkinglot_copy);
+
+ /* unref our temporary copy */
+ parkinglot_unref(parkinglot_copy);
+ parkinglot_copy = NULL;
+
+ if (!parkinglot) {
ast_log(LOG_ERROR, "Could not build dynamic parking lot!\n");
} else {
if (!ast_strlen_zero(dyn_context)) {
- ast_copy_string(parkinglot->cfg.parking_con, dyn_context, sizeof(parkinglot->cfg.parking_con));
+ ast_copy_string(parkinglot->cfg.parking_con, dyn_context,
+ sizeof(parkinglot->cfg.parking_con));
}
if (!ast_strlen_zero(dyn_range)) {
if (sscanf(dyn_range, "%30d-%30d", &dyn_start, &dyn_end) != 2) {
- ast_log(LOG_WARNING, "Format for parking positions is a-b, where a and b are numbers\n");
+ ast_log(LOG_WARNING,
+ "Format for parking positions is a-b, where a and b are numbers\n");
+ } else if (dyn_end < dyn_start || dyn_start <= 0 || dyn_end <= 0) {
+ ast_log(LOG_WARNING,
+ "Format for parking positions is a-b, where a <= b\n");
} else {
parkinglot->cfg.parking_start = dyn_start;
parkinglot->cfg.parking_stop = dyn_end;
@@ -1024,15 +1010,10 @@
/* BUGBUG need to create the dynamic parking lot context and park extension if they do not already exist! */
ao2_link(parkinglots, parkinglot);
}
-
- if (parkinglot_copy) {
- /* unref our tempory copy */
- parkinglot_unref(parkinglot_copy);
- parkinglot_copy = NULL;
- }
}
if (!parkinglot) {
+ /* We'll just have to use the default parking lot. */
parkinglot = parkinglot_addref(default_parkinglot);
}
@@ -1057,46 +1038,69 @@
* limitation here. If extout was not numeric, we could permit
* arbitrary non-numeric extensions.
*/
- if (sscanf(parkingexten, "%30d", &parking_space) != 1 || parking_space < 0) {
- ast_log(LOG_WARNING, "PARKINGEXTEN does not indicate a valid parking slot: '%s'.\n", parkingexten);
- AST_LIST_UNLOCK(&parkinglot->parkings);
- parkinglot_unref(parkinglot);
- ast_free(pu);
- return NULL;
- }
- snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", parking_space);
-
- if (ast_exists_extension(NULL, parkinglot->cfg.parking_con, pu->parkingexten, 1, NULL)) {
- ast_log(LOG_WARNING, "Requested parking extension already exists: %s@%s\n", parkingexten, parkinglot->cfg.parking_con);
+ if (sscanf(parkingexten, "%30d", &parking_space) != 1 || parking_space <= 0) {
+ ast_log(LOG_WARNING,
+ "PARKINGEXTEN does not indicate a valid parking space: '%s'.\n",
+ parkingexten);
AST_LIST_UNLOCK(&parkinglot->parkings);
parkinglot_unref(parkinglot);
ast_free(pu);
return NULL;
}
+
+ if (parking_space < parkinglot->cfg.parking_start
+ || parkinglot->cfg.parking_stop < parking_space) {
+ /*
+ * Cannot allow park because parkinglot not setup for spaces
+ * outside of lot. (Things like dialplan hints don't exist for
+ * outside lot space.)
+ */
+ ast_log(LOG_WARNING,
+ "PARKINGEXTEN requested parking space %d is not in %s (%d-%d).\n",
+ parking_space, parkinglot->name, parkinglot->cfg.parking_start,
+ parkinglot->cfg.parking_stop);
+ AST_LIST_UNLOCK(&parkinglot->parkings);
+ parkinglot_unref(parkinglot);
+ ast_free(pu);
+ return NULL;
+ }
+
+ /* Check if requested parking space is in use. */
+ AST_LIST_TRAVERSE(&parkinglot->parkings, cur, list) {
+ if (cur->parkingnum == parking_space) {
+ ast_log(LOG_WARNING,
+ "PARKINGEXTEN requested parking space %d is in use in %s\n",
+ parking_space, parkinglot->name);
+ AST_LIST_UNLOCK(&parkinglot->parkings);
+ parkinglot_unref(parkinglot);
+ ast_free(pu);
+ return NULL;
+ }
+ }
} else {
- /* parkingexten is empty, so find a usable extension in the lot to park the call */
+ /* PARKINGEXTEN is empty, so find a usable extension in the lot to park the call */
int start; /* The first slot we look in the parkinglot. It can be randomized. */
int start_checked = 0; /* flag raised once the first slot is checked */
- struct parkeduser *cur = NULL;
/* If using randomize mode, set start to random position on parking range */
if (ast_test_flag(args, AST_PARK_OPT_RANDOMIZE)) {
start = ast_random() % (parkinglot->cfg.parking_stop - parkinglot->cfg.parking_start + 1);
- start+=parkinglot->cfg.parking_start;
+ start += parkinglot->cfg.parking_start;
} else { /* Otherwise, just set it to the start position. */
start = parkinglot->cfg.parking_start;
}
/* free parking extension linear search: O(n^2) */
+ //parking_space = -1;
for (i = start; ; i++) {
/* If we are past the end, wrap around to the first parking slot*/
if (i == parkinglot->cfg.parking_stop + 1) {
i = parkinglot->cfg.parking_start;
}
- if (i == start) { /* At this point, if start_checked, we've exhausted all the possible slots. */
+ if (i == start) {
+ /* At this point, if start_checked, we've exhausted all the possible slots. */
if (start_checked) {
- i = -1;
break;
} else {
start_checked = 1;
@@ -1109,26 +1113,23 @@
break;
}
}
-
- /* If list traversal was successful, we can terminate the loop here at parkinglot i */
if (!cur) {
+ /* We found a parking space. */
parking_space = i;
break;
}
}
-
- /* If we exited without a match, our i value was set to -1 and we still have an item in cur. */
- if (i == -1 && cur) {
- ast_log(LOG_WARNING, "No more parking spaces\n");
+ if (parking_space == -1) {
+ /* We did not find a parking space. Lot is full. */
+ ast_log(LOG_WARNING, "No more parking spaces in %s\n", parkinglot->name);
AST_LIST_UNLOCK(&parkinglot->parkings);
parkinglot_unref(parkinglot);
ast_free(pu);
return NULL;
}
-
- snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", parking_space);
- }
-
+ }
+
+ snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", parking_space);
pu->notquiteyet = 1;
pu->parkingnum = parking_space;
pu->parkinglot = parkinglot;
@@ -1144,18 +1145,19 @@
struct parkeduser *pu = args->pu;
const char *event_from;
- if (pu == NULL)
+ if (pu == NULL) {
args->pu = pu = park_space_reserve(chan, peer, args);
- if (pu == NULL)
- return 1; /* Continue execution if possible */
-
- snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", pu->parkingnum);
+ if (pu == NULL) {
+ return -1;
+ }
+ }
chan->appl = "Parked Call";
chan->data = NULL;
pu->chan = chan;
+/* BUGBUG should make note if call put on hold or did ringing to undo it later. */
/* Put the parked channel on hold if we have two different channels */
if (chan != peer) {
if (ast_test_flag(args, AST_PARK_OPT_RINGING)) {
@@ -1173,15 +1175,20 @@
*(args->extout) = pu->parkingnum;
if (peer) {
- /* This is so ugly that it hurts, but implementing get_base_channel() on local channels
- could have ugly side effects. We could have transferer<->local,1<->local,2<->parking
- and we need the callback name to be that of transferer. Since local,1/2 have the same
- name we can be tricky and just grab the bridged channel from the other side of the local
- */
+ /*
+ * This is so ugly that it hurts, but implementing
+ * get_base_channel() on local channels could have ugly side
+ * effects. We could have
+ * transferer<->local,1<->local,2<->parking and we need the
+ * callback name to be that of transferer. Since local,1/2 have
+ * the same name we can be tricky and just grab the bridged
+ * channel from the other side of the local.
+ */
if (!strcasecmp(peer->tech->type, "Local")) {
struct ast_channel *tmpchan, *base_peer;
char other_side[AST_CHANNEL_NAME];
char *c;
+
ast_copy_string(other_side, S_OR(args->orig_chan_name, peer->name), sizeof(other_side));
if ((c = strrchr(other_side, ';'))) {
*++c = '1';
@@ -1199,15 +1206,19 @@
}
}
- /* Remember what had been dialed, so that if the parking
- expires, we try to come back to the same place */
-
+ /*
+ * Remember what had been dialed, so that if the parking
+ * expires, we try to come back to the same place
+ */
pu->options_specified = (!ast_strlen_zero(args->return_con) || !ast_strlen_zero(args->return_ext) || args->return_pri);
- /* If extension has options specified, they override all other possibilities
- such as the returntoorigin flag and transferred context. Information on
- extension options is lost here, so we set a flag */
-
+/* BUGBUG this may be what we need to save here to use when the parked call is retrieved. */
+ /*
+ * If extension has options specified, they override all other
+ * possibilities such as the returntoorigin flag and transferred
+ * context. Information on extension options is lost here, so
+ * we set a flag
+ */
ast_copy_string(pu->context,
S_OR(args->return_con, S_OR(chan->macrocontext, chan->context)),
sizeof(pu->context));
@@ -1217,14 +1228,20 @@
pu->priority = args->return_pri ? args->return_pri :
(chan->macropriority ? chan->macropriority : chan->priority);
- /* If parking a channel directly, don't quite yet get parking running on it.
- * All parking lot entries are put into the parking lot with notquiteyet on. */
- if (peer != chan)
+ /*
+ * If parking a channel directly, don't quite yet get parking
+ * running on it. All parking lot entries are put into the
+ * parking lot with notquiteyet on.
+ */
+ if (peer != chan) {
pu->notquiteyet = 0;
+ }
/* Wake up the (presumably select()ing) thread */
pthread_kill(parking_thread, SIGURG);
- ast_verb(2, "Parked %s on %d (lot %s). Will timeout back to extension [%s] %s, %d in %d seconds\n", pu->chan->name, pu->parkingnum, pu->parkinglot->name, pu->context, pu->exten, pu->priority, (pu->parkingtime/1000));
+ ast_verb(2, "Parked %s on %d (lot %s). Will timeout back to extension [%s] %s, %d in %d seconds\n",
+ pu->chan->name, pu->parkingnum, pu->parkinglot->name,
+ pu->context, pu->exten, pu->priority, (pu->parkingtime / 1000));
ast_cel_report_event(pu->chan, AST_CEL_PARK_START, NULL, pu->parkinglot->name, peer);
@@ -1260,9 +1277,9 @@
}
con = ast_context_find_or_create(NULL, NULL, pu->parkinglot->cfg.parking_con, registrar);
- if (!con) /* Still no context? Bad */
+ if (!con) { /* Still no context? Bad */
ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", pu->parkinglot->cfg.parking_con);
- if (con) {
+ } else {
if (!ast_add_extension2(con, 1, pu->parkingexten, 1, NULL, NULL, parkedcall, ast_strdup(pu->parkingexten), ast_free_ptr, registrar))
notify_metermaids(pu->parkingexten, pu->parkinglot->cfg.parking_con, AST_DEVICE_INUSE);
}
@@ -1270,8 +1287,13 @@
AST_LIST_UNLOCK(&pu->parkinglot->parkings);
/* Only say number if it's a number and the channel hasn't been masqueraded away */
- if (peer && !ast_test_flag(args, AST_PARK_OPT_SILENCE) && (ast_strlen_zero(args->orig_chan_name) || !strcasecmp(peer->name, args->orig_chan_name))) {
- /* If a channel is masqueraded into peer while playing back the parking slot number do not continue playing it back. This is the case if an attended transfer occurs. */
+ if (peer && !ast_test_flag(args, AST_PARK_OPT_SILENCE)
+ && (ast_strlen_zero(args->orig_chan_name) || !strcasecmp(peer->name, args->orig_chan_name))) {
+ /*
+ * If a channel is masqueraded into peer while playing back the
+ * parking space number do not continue playing it back. This
+ * is the case if an attended transfer occurs.
+ */
ast_set_flag(peer, AST_FLAG_MASQ_NOSTREAM);
/* Tell the peer channel the number of the parking space */
ast_say_digits(peer, pu->parkingnum, "", peer->language);
@@ -1291,13 +1313,9 @@
/*! \brief Park a call */
int ast_park_call(struct ast_channel *chan, struct ast_channel *peer, int timeout, const char *parkexten, int *extout)
{
-/* BUGBUG the next line breaks named parking lots. */
- struct ast_parkinglot *found_lot = ao2_callback(parkinglots, 0, find_parkinglot_by_exten_cb, (char *) parkexten);
-
struct ast_park_call_args args = {
.timeout = timeout,
.extout = extout,
- .parkinglot = found_lot,
};
return park_call_full(chan, peer, &args);
@@ -1310,7 +1328,6 @@
static int masq_park_call(struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout, int play_announcement, struct ast_park_call_args *args)
{
struct ast_channel *chan;
- struct ast_frame *f;
struct ast_park_call_args park_args = {0,};
if (!args) {
@@ -1319,17 +1336,25 @@
args->extout = extout;
}
- if ((args->pu = park_space_reserve(rchan, peer, args)) == NULL) {
+ /* Make a new, channel that we'll use to masquerade in the real one */
+ chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, rchan->accountcode, rchan->exten,
+ rchan->context, rchan->linkedid, rchan->amaflags, "Parked/%s", rchan->name);
+ if (!chan) {
+ ast_log(LOG_WARNING, "Unable to create parked channel\n");
if (peer) {
ast_stream_and_wait(peer, "pbx-parkingfailed", "");
}
return AST_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->linkedid, rchan->amaflags, "Parked/%s",rchan->name))) {
- ast_log(LOG_WARNING, "Unable to create parked channel\n");
- return -1;
+ args->pu = park_space_reserve(rchan, peer, args);
+ if (!args->pu) {
+ chan->hangupcause = AST_CAUSE_SWITCH_CONGESTION;
+ ast_hangup(chan);
+ if (peer) {
+ ast_stream_and_wait(peer, "pbx-parkingfailed", "");
+ }
+ return AST_FEATURE_RETURN_PARKFAILED;
}
/* Make formats okay */
@@ -1345,9 +1370,8 @@
ast_copy_string(chan->macroexten,rchan->macroexten,sizeof(chan->macroexten));
chan->macropriority = rchan->macropriority;
- /* Make the masq execute */
- if ((f = ast_read(chan)))
- ast_frfree(f);
+ /* Manually do the masquerade to make sure it is complete. */
+ ast_do_masquerade(chan);
if (peer == rchan) {
peer = chan;
@@ -1363,12 +1387,12 @@
return 0;
}
-/* Park call via masqueraded channel */
int ast_masq_park_call(struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout)
{
- return masq_park_call(rchan, peer, timeout, extout, 0, NULL);
-}
-
+ return masq_park_call(rchan, peer, timeout, extout, 0, NULL) ? -1 : 0;
+}
+
+/* Park call via masqueraded channel and announce parking spot on peer channel. */
static int masq_park_call_announce(struct ast_channel *rchan, struct ast_channel *peer, struct ast_park_call_args *args)
{
return masq_park_call(rchan, peer, 0, NULL, 1, args);
@@ -1383,8 +1407,10 @@
static struct ast_channel *create_test_channel(const struct ast_channel_tech *fake_tech)
{
struct ast_channel *test_channel1;
+
if (!(test_channel1 = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
NULL, NULL, 0, 0, "TestChannel1"))) {
+ ast_log(LOG_WARNING, "Whoa, test channel creation failed.\n");
return NULL;
}
@@ -1403,21 +1429,12 @@
{
struct ast_context *con;
struct parkeduser *pu_toremove;
+ int res = 0;
+
args->pu->notquiteyet = 1; /* go ahead and stop processing the test parking */
+
AST_LIST_LOCK(&args->pu->parkinglot->parkings);
AST_LIST_TRAVERSE_SAFE_BEGIN(&args->pu->parkinglot->parkings, pu_toremove, list) {
- con = ast_context_find(args->pu->parkinglot->cfg.parking_con);
- if (con) {
- if (ast_context_remove_extension2(con, args->pu->parkingexten, 1, NULL, 0)) {
- ast_log(LOG_WARNING, "Whoa, failed to remove the parking extension!\n");
- return -1;
- } else {
- notify_metermaids(args->pu->parkingexten, pu_toremove->parkinglot->cfg.parking_con, AST_DEVICE_NOT_INUSE);
- }
- } else {
- ast_log(LOG_WARNING, "Whoa, no parking context?\n");
- return -1;
- }
if (pu_toremove == args->pu) {
AST_LIST_REMOVE_CURRENT(list);
break;
@@ -1426,25 +1443,47 @@
AST_LIST_TRAVERSE_SAFE_END;
AST_LIST_UNLOCK(&args->pu->parkinglot->parkings);
- /* the only way this would be unsafe is if a timeout occurred, which is set at 45 sec */
- ast_free(args->pu);
+ if (!pu_toremove) {
+ ast_log(LOG_WARNING, "Whoa, could not find parking test call!\n");
+ return -1;
+ }
+
+ con = ast_context_find(args->pu->parkinglot->cfg.parking_con);
+ if (con) {
+ if (ast_context_remove_extension2(con, args->pu->parkingexten, 1, NULL, 0)) {
+ ast_log(LOG_WARNING, "Whoa, failed to remove the parking extension!\n");
+ res = -1;
+ } else {
+ notify_metermaids(args->pu->parkingexten,
+ pu_toremove->parkinglot->cfg.parking_con, AST_DEVICE_NOT_INUSE);
+ }
+ } else {
+ ast_log(LOG_WARNING, "Whoa, no parking context?\n");
+ res = -1;
+ }
+
+ parkinglot_unref(pu_toremove->parkinglot);
+ ast_free(pu_toremove);
args->pu = NULL;
- ast_hangup(toremove);
- return 0;
-}
-
+ if (!res && toremove) {
+ ast_hangup(toremove);
+ }
+ return res;
+}
+
+/* BUGBUG need to reexamine tests for reference leaks and locking issues. */
+/* BUGBUG this internal test is rubbish. */
AST_TEST_DEFINE(features_test)
{
- int saved_parkeddynamic;
struct ast_channel *test_channel1 = NULL;
struct ast_channel *parked_chan = NULL;
- struct ast_parkinglot *dynlot = NULL;
+ struct ast_parkinglot *dynlot;
struct ast_park_call_args args = {
.timeout = DEFAULT_PARK_TIME,
};
- int res = -1;
+ int res = 0;
static const struct ast_channel_tech fake_tech = {
.fixup = fake_fixup, /* silence warning from masquerade */
@@ -1466,67 +1505,91 @@
}
/* changing a config option is a bad practice, but must be done in this case */
- saved_parkeddynamic = parkeddynamic;
parkeddynamic = 1;
+
+ ast_test_status_update(test, "Test parking functionality with defaults\n");
if (!(test_channel1 = create_test_channel(&fake_tech))) {
+ res = -1;
goto exit_features_test;
}
-
- ast_test_status_update(test, "Test parking functionality with defaults\n");
if (park_call_full(test_channel1, NULL, &args)) {
+ res = -1;
goto exit_features_test;
}
if (unpark_test_channel(test_channel1, &args)) {
+ res = -1;
goto exit_features_test;
}
+
ast_test_status_update(test, "Check that certain parking options are respected\n");
if (!(test_channel1 = create_test_channel(&fake_tech))) {
+ res = -1;
goto exit_features_test;
}
pbx_builtin_setvar_helper(test_channel1, "PARKINGLOT", unique_parkinglot);
pbx_builtin_setvar_helper(test_channel1, "PARKINGDYNPOS", parkinglot_range);
if (park_call_full(test_channel1, NULL, &args)) {
+ res = -1;
goto exit_features_test;
}
/* grab newly created parking lot for destruction in the end */
dynlot = args.pu->parkinglot;
- if (!args.pu->parkingnum == 750 || strcasecmp(args.pu->parkinglot->name, unique_parkinglot)) {
+ if (args.pu->parkingnum != 750
+ || strcasecmp(dynlot->name, unique_parkinglot)
+ || dynlot->cfg.parking_start != 750
+ || dynlot->cfg.parking_stop != 760) {
ast_test_status_update(test, "Parking settings were not respected\n");
+ if (!unpark_test_channel(test_channel1, &args)) {
+ test_channel1 = NULL;
+ }
+ res = -1;
goto exit_features_test;
} else {
ast_test_status_update(test, "Parking settings for non-masquerading park verified\n");
}
if (unpark_test_channel(test_channel1, &args)) {
+ res = -1;
goto exit_features_test;
}
+
ast_test_status_update(test, "Check #2 that certain parking options are respected\n");
if (!(test_channel1 = create_test_channel(&fake_tech))) {
+ res = -1;
goto exit_features_test;
}
pbx_builtin_setvar_helper(test_channel1, "PARKINGLOT", unique_parkinglot);
pbx_builtin_setvar_helper(test_channel1, "PARKINGDYNPOS", parkinglot_range);
- if (masq_park_call(test_channel1, NULL, 0, NULL, 0, &args) == AST_FEATURE_RETURN_PARKFAILED) {
+ if (masq_park_call(test_channel1, NULL, 0, NULL, 0, &args)) {
+ res = -1;
goto exit_features_test;
}
/* hangup zombie channel */
ast_hangup(test_channel1);
test_channel1 = NULL;
- if (!args.pu->parkingnum == 750 || strcasecmp(args.pu->parkinglot->name, unique_parkinglot)) {
+
+ dynlot = args.pu->parkinglot;
+ if (args.pu->parkingnum != 750
+ || strcasecmp(dynlot->name, unique_parkinglot)
+ || dynlot->cfg.parking_start != 750
+ || dynlot->cfg.parking_stop != 760) {
ast_test_status_update(test, "Parking settings were not respected\n");
- goto exit_features_test;
+ res = -1;
} else {
ast_test_status_update(test, "Parking settings for masquerading park verified\n");
}
+
/* find the real channel */
parked_chan = ast_channel_get_by_name("TestChannel1");
if (unpark_test_channel(parked_chan, &args)) {
- goto exit_features_test;
- }
-
- res = 0;
+ if (parked_chan) {
+ ast_hangup(parked_chan);
+ }
+ res = -1;
+ }
+
exit_features_test:
@@ -1534,9 +1597,7 @@
ast_hangup(test_channel1);
}
- /* careful, if PARKINGDYNCONTEXT is tested, need to delete context */
- ao2_unlink(parkinglots, dynlot);
- parkeddynamic = saved_parkeddynamic;
+ ast_features_reload();
return res ? AST_TEST_FAIL : AST_TEST_PASS;
}
#endif
@@ -1558,38 +1619,6 @@
*callee = peer;
*caller = chan;
}
-}
-
-static int parkcall_helper(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, struct ast_park_call_args *args)
-{
- int res = 0;
-
- if (args) {
- ast_debug(1, "Parkinglot specified for builtin_parkcall: %s\n", args->parkinglot->name);
- }
-
- /* we used to set chan's exten and priority to "s" and 1
- here, but this generates (in some cases) an invalid
- extension, and if "s" exists, could errantly
- cause execution of extensions you don't expect. It
- makes more sense to let nature take its course
- when chan finishes, and let the pbx do its thing
- and hang up when the park is over.
- */
- if (chan->_state != AST_STATE_UP)
- res = ast_answer(chan);
- if (!res)
- res = ast_safe_sleep(chan, 1000);
-
- if (!res) { /* one direction used to call park_call.... */
- struct ast_channel *parker;
- struct ast_channel *parkee;
- set_peers(&parker, &parkee, peer, chan, sense);
- res = masq_park_call_announce(parkee, parker, args);
- /* PBX should hangup zombie channel if a masquerade actually occurred (res=0) */
- }
-
- return res;
}
/*!
@@ -1606,7 +1635,37 @@
*/
static int builtin_parkcall(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data)
{
- return parkcall_helper(chan, peer, config, code, sense, NULL);
+ struct ast_channel *parker;
+ struct ast_channel *parkee;
+ int res;
+
+ /*
+ * We used to set chan's exten and priority to "s" and 1 here,
+ * but this generates (in some cases) an invalid extension, and
+ * if "s" exists, could errantly cause execution of extensions
+ * you don't expect. It makes more sense to let nature take its
+ * course when chan finishes, and let the pbx do its thing and
+ * hang up when the park is over.
+ */
+
+ /* Answer if call is not up */
+ if (chan->_state != AST_STATE_UP) {
+ if (ast_answer(chan)) {
+ return -1;
+ }
+
+ /* Sleep to allow VoIP streams to settle down */
+ if (ast_safe_sleep(chan, 1000)) {
+ return -1;
+ }
+ }
+
+ /* one direction used to call park_call.... */
+ set_peers(&parker, &parkee, peer, chan, sense);
+ res = masq_park_call_announce(parkee, parker, NULL);
+ /* PBX should hangup zombie channel if a masquerade actually occurred (res=0) */
+
+ return res;
}
/*!
@@ -1917,18 +1976,15 @@
struct ast_channel *transferer;
struct ast_channel *transferee;
const char *transferer_real_context;
- struct ast_parkinglot *found_lot = NULL;
- char xferto[256];
- int res, parkstatus = 0;
+ char xferto[256] = "";
+ int res;
set_peers(&transferer, &transferee, peer, chan, sense);
transferer_real_context = real_ctx(transferer, transferee);
- /* Start autoservice on chan while we talk to the originator */
+
+ /* Start autoservice on transferee while we talk to the transferer */
ast_autoservice_start(transferee);
- ast_autoservice_ignore(transferee, AST_FRAME_DTMF_END);
ast_indicate(transferee, AST_CONTROL_HOLD);
-
- memset(xferto, 0, sizeof(xferto));
/* Transfer */
res = ast_stream_and_wait(transferer, "pbx-transfer", AST_DIGIT_ANY);
@@ -1936,10 +1992,10 @@
finishup(transferee);
return -1; /* error ? */
}
- if (res > 0) /* If they've typed a digit already, handle it */
+ if (res > 0) { /* If they've typed a digit already, handle it */
xferto[0] = (char) res;
-
- ast_stopstream(transferer);
+ }
+
res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout);
if (res < 0) { /* hangup or error, (would be 0 for invalid and 1 for valid) */
finishup(transferee);
@@ -1958,78 +2014,61 @@
return AST_FEATURE_RETURN_SUCCESS;
}
-/* BUGBUG the next line breaks named parking lots. */
- found_lot = ao2_callback(parkinglots, 0, find_parkinglot_by_exten_cb, &xferto);
- if (found_lot) {
- struct ast_park_call_args args = {
- .parkinglot = found_lot,
- };
- res = finishup(transferee);
- if (res) {
- } else if (!(parkstatus = masq_park_call_announce(transferee, transferer, &args))) { /* 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, parkstatus = %d\n", transferee->name, parkstatus);
- }
- ast_autoservice_start(transferee);
+ if (ast_parking_ext_valid(xferto, transferer, transferer_real_context)) {
+ /* We are transfering the transferee to a parking lot. */
+ finishup(transferee);
+ return masq_park_call_announce(transferee, transferer, NULL);
+ }
+
+ /* Do blind transfer. */
+ ast_cel_report_event(transferer, AST_CEL_BLINDTRANSFER, NULL, xferto, transferee);
+ pbx_builtin_setvar_helper(transferer, "BLINDTRANSFER", transferee->name);
+ pbx_builtin_setvar_helper(transferee, "BLINDTRANSFER", transferer->name);
+ res = finishup(transferee);
+ if (!transferer->cdr) { /* this code should never get called (in a perfect world) */
+ transferer->cdr = ast_cdr_alloc();
+ if (transferer->cdr) {
+ ast_cdr_init(transferer->cdr, transferer); /* initialize our channel's cdr */
+ ast_cdr_start(transferer->cdr);
+ }
+ }
+ if (transferer->cdr) {
+ struct ast_cdr *swap = transferer->cdr;
+
+ ast_log(LOG_DEBUG,
+ "transferer=%s; transferee=%s; lastapp=%s; lastdata=%s; chan=%s; dstchan=%s\n",
+ transferer->name, transferee->name, transferer->cdr->lastapp,
+ transferer->cdr->lastdata, transferer->cdr->channel,
+ transferer->cdr->dstchannel);
+ ast_log(LOG_DEBUG, "TRANSFEREE; lastapp=%s; lastdata=%s, chan=%s; dstchan=%s\n",
+ transferee->cdr->lastapp, transferee->cdr->lastdata, transferee->cdr->channel,
+ transferee->cdr->dstchannel);
+ ast_log(LOG_DEBUG, "transferer_real_context=%s; xferto=%s\n",
+ transferer_real_context, xferto);
+ /* swap cdrs-- it will save us some time & work */
+ transferer->cdr = transferee->cdr;
+ transferee->cdr = swap;
+ }
+ if (!transferee->pbx) {
+ /* Doh! Use our handy async_goto functions */
+ ast_verb(3, "Transferring %s to '%s' (context %s) priority 1\n",
+ transferee->name, xferto, transferer_real_context);
+ if (ast_async_goto(transferee, transferer_real_context, xferto, 1)) {
+ ast_log(LOG_WARNING, "Async goto failed :-(\n");
+ }
} else {
- ast_cel_report_event(transferer, AST_CEL_BLINDTRANSFER, NULL, xferto, transferee);
- pbx_builtin_setvar_helper(transferer, "BLINDTRANSFER", transferee->name);
- pbx_builtin_setvar_helper(transferee, "BLINDTRANSFER", transferer->name);
- res=finishup(transferee);
- if (!transferer->cdr) { /* this code should never get called (in a perfect world) */
- transferer->cdr=ast_cdr_alloc();
- if (transferer->cdr) {
- ast_cdr_init(transferer->cdr, transferer); /* initialize our channel's cdr */
- ast_cdr_start(transferer->cdr);
- }
- }
- if (transferer->cdr) {
- struct ast_cdr *swap = transferer->cdr;
- ast_log(LOG_DEBUG,"transferer=%s; transferee=%s; lastapp=%s; lastdata=%s; chan=%s; dstchan=%s\n",
- transferer->name, transferee->name, transferer->cdr->lastapp, transferer->cdr->lastdata,
- transferer->cdr->channel, transferer->cdr->dstchannel);
- ast_log(LOG_DEBUG,"TRANSFEREE; lastapp=%s; lastdata=%s, chan=%s; dstchan=%s\n",
- transferee->cdr->lastapp, transferee->cdr->lastdata, transferee->cdr->channel, transferee->cdr->dstchannel);
- ast_log(LOG_DEBUG,"transferer_real_context=%s; xferto=%s\n", transferer_real_context, xferto);
- /* swap cdrs-- it will save us some time & work */
- transferer->cdr = transferee->cdr;
- transferee->cdr = swap;
- }
- if (!transferee->pbx) {
- /* Doh! Use our handy async_goto functions */
- ast_verb(3, "Transferring %s to '%s' (context %s) priority 1\n"
- ,transferee->name, xferto, transferer_real_context);
- if (ast_async_goto(transferee, transferer_real_context, xferto, 1))
- ast_log(LOG_WARNING, "Async goto failed :-(\n");
- } else {
- /* Set the channel's new extension, since it exists, using transferer context */
- ast_set_flag(transferee, AST_FLAG_BRIDGE_HANGUP_DONT); /* don't let the after-bridge code run the h-exten */
- ast_log(LOG_DEBUG,"ABOUT TO AST_ASYNC_GOTO, have a pbx... set HANGUP_DONT on chan=%s\n", transferee->name);
- if (ast_channel_connected_line_macro(transferee, transferer, &transferer->connected, 1, 0)) {
- ast_channel_update_connected_line(transferer, &transferer->connected, NULL);
- }
- set_c_e_p(transferee, transferer_real_context, xferto, 0);
- }
- check_goto_on_transfer(transferer);
- return res;
- }
- if (parkstatus != AST_FEATURE_RETURN_PARKFAILED
- && ast_stream_and_wait(transferer, xferfailsound, "")) {
- finishup(transferee);
- return -1;
- }
- ast_stopstream(transferer);
- res = finishup(transferee);
- if (res) {
- ast_verb(2, "Hungup during autoservice stop on '%s'\n", transferee->name);
- return res;
- }
- return AST_FEATURE_RETURN_SUCCESS;
+ /* Set the channel's new extension, since it exists, using transferer context */
+ ast_set_flag(transferee, AST_FLAG_BRIDGE_HANGUP_DONT); /* don't let the after-bridge code run the h-exten */
+ ast_log(LOG_DEBUG,
+ "ABOUT TO AST_ASYNC_GOTO, have a pbx... set HANGUP_DONT on chan=%s\n",
+ transferee->name);
+ if (ast_channel_connected_line_macro(transferee, transferer, &transferer->connected, 1, 0)) {
+ ast_channel_update_connected_line(transferer, &transferer->connected, NULL);
+ }
+ set_c_e_p(transferee, transferer_real_context, xferto, 0);
+ }
+ check_goto_on_transfer(transferer);
[... 434 lines stripped ...]
More information about the asterisk-commits
mailing list