[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