[asterisk-commits] rmudgett: branch rmudgett/parking r329059 - in /team/rmudgett/parking: channe...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Wed Jul 20 16:58:47 CDT 2011


Author: rmudgett
Date: Wed Jul 20 16:58:43 2011
New Revision: 329059

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=329059
Log:
Work so far.

Modified:
    team/rmudgett/parking/channels/chan_dahdi.c
    team/rmudgett/parking/channels/chan_iax2.c
    team/rmudgett/parking/configs/chan_dahdi.conf.sample
    team/rmudgett/parking/configs/features.conf.sample
    team/rmudgett/parking/main/asterisk.c
    team/rmudgett/parking/main/features.c

Modified: team/rmudgett/parking/channels/chan_dahdi.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/parking/channels/chan_dahdi.c?view=diff&rev=329059&r1=329058&r2=329059
==============================================================================
--- team/rmudgett/parking/channels/chan_dahdi.c (original)
+++ team/rmudgett/parking/channels/chan_dahdi.c Wed Jul 20 16:58:43 2011
@@ -396,8 +396,6 @@
 
 static char defaultcic[64] = "";
 static char defaultozz[64] = "";
-
-static char parkinglot[AST_MAX_EXTENSION] = "";		/*!< Default parking lot for this channel */
 
 /*! Run this script when the MWI state changes on an FXO line, if mwimonitor is enabled */
 static char mwimonitornotify[PATH_MAX] = "";
@@ -16803,8 +16801,6 @@
 			ast_copy_string(confp->chan.mohinterpret, v->value, sizeof(confp->chan.mohinterpret));
 		} else if (!strcasecmp(v->name, "mohsuggest")) {
 			ast_copy_string(confp->chan.mohsuggest, v->value, sizeof(confp->chan.mohsuggest));
-		} else if (!strcasecmp(v->name, "parkinglot")) {
-			ast_copy_string(parkinglot, v->value, sizeof(parkinglot));
 		} else if (!strcasecmp(v->name, "stripmsd")) {
 			ast_log(LOG_NOTICE, "Configuration option \"%s\" has been deprecated. Please use dialplan instead\n", v->name);
 			confp->chan.stripmsd = atoi(v->value);

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=329059&r1=329058&r2=329059
==============================================================================
--- team/rmudgett/parking/channels/chan_iax2.c (original)
+++ team/rmudgett/parking/channels/chan_iax2.c Wed Jul 20 16:58:43 2011
@@ -10692,6 +10692,7 @@
 					pbx_builtin_setvar_helper(owner, "BLINDTRANSFER", bridged_chan->name);
 					pbx_builtin_setvar_helper(bridged_chan, "BLINDTRANSFER", owner->name);
 
+/* BUGBUG c cannot be right.  C is likely NULL.  owner should probably be used instead. */
 					if (ast_parking_ext_valid(ies.called_number, c, iaxs[fr->callno]->context)) {
 						ast_debug(1, "Parking call '%s'\n", bridged_chan->name);
 						if (iax_park(bridged_chan, owner, ies.called_number)) {

Modified: team/rmudgett/parking/configs/chan_dahdi.conf.sample
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/parking/configs/chan_dahdi.conf.sample?view=diff&rev=329059&r1=329058&r2=329059
==============================================================================
--- team/rmudgett/parking/configs/chan_dahdi.conf.sample (original)
+++ team/rmudgett/parking/configs/chan_dahdi.conf.sample Wed Jul 20 16:58:43 2011
@@ -579,6 +579,13 @@
 ; ('canpark=no' is overridden by 'transfer=yes')
 ;
 canpark=yes
+
+; Sets the default parking lot for call parking.
+; This is setable per channel.
+; Parkinglots are configured in features.conf
+;
+;parkinglot=plaza
+
 ;
 ; Support call forward variable
 ;

Modified: team/rmudgett/parking/configs/features.conf.sample
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/parking/configs/features.conf.sample?view=diff&rev=329059&r1=329058&r2=329059
==============================================================================
--- team/rmudgett/parking/configs/features.conf.sample (original)
+++ team/rmudgett/parking/configs/features.conf.sample Wed Jul 20 16:58:43 2011
@@ -53,8 +53,6 @@
                                 ; one of: callee, caller, both, no (default is no)
 ;parkeddynamic = yes            ; Enables dynamically created parkinglots. (default is no)
 ;adsipark = yes			; if you want ADSI parking announcements
-;findslot => next		; Continue to the 'next' free parking space.
-				; Defaults to 'first' available
 ;parkedmusicclass=default	; This is the MOH class to use for the parked channel
 				; as long as the class is not set on the channel directly
 				; using Set(CHANNEL(musicclass)=whatever) in the dialplan
@@ -94,7 +92,6 @@
 ;context => edvinapark
 ;parkext => 799
 ;parkpos => 800-850
-;findslot => next
 
 ; Note that the DTMF features listed below only work when two channels have answered and are bridged together.
 ; They can not be used while the remote party is ringing or in progress. If you require this feature you can use

Modified: team/rmudgett/parking/main/asterisk.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/parking/main/asterisk.c?view=diff&rev=329059&r1=329058&r2=329059
==============================================================================
--- team/rmudgett/parking/main/asterisk.c (original)
+++ team/rmudgett/parking/main/asterisk.c Wed Jul 20 16:58:43 2011
@@ -3799,7 +3799,10 @@
 		exit(1);
 	}
 
-	ast_features_init();
+	if (ast_features_init()) {
+		printf("%s", term_quit());
+		exit(1);
+	}
 
 	if (init_framer()) {
 		printf("%s", term_quit());

Modified: team/rmudgett/parking/main/features.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/parking/main/features.c?view=diff&rev=329059&r1=329058&r2=329059
==============================================================================
--- team/rmudgett/parking/main/features.c (original)
+++ team/rmudgett/parking/main/features.c Wed Jul 20 16:58:43 2011
@@ -402,35 +402,94 @@
 	unsigned int options_specified:1;
 	char peername[1024];
 	unsigned char moh_trys;
+	/*! Parking lot this entry belongs to.  Holds a parking lot reference. */
 	struct ast_parkinglot *parkinglot;
 	AST_LIST_ENTRY(parkeduser) list;
 };
 
+/*! Parking lot configuration options. */
+struct parkinglot_cfg {
+	/*! Music class used for parking */
+	char mohclass[MAX_MUSICCLASS];
+	/*! Extension to park calls in this parking lot. */
+	char parkext[AST_MAX_EXTENSION];
+	/*! Context for which parking is made accessible */
+	char parking_con[AST_MAX_EXTENSION];
+	/*! Context for dialback for parking (KLUDGE) */
+	char parking_con_dial[AST_MAX_EXTENSION];
+	/*! First available extension for parking */
+	int parking_start;
+	/*! Last available extension for parking */
+	int parking_stop;
+	/*! Default parking time in ms. */
+	int parkingtime;
+	/*!
+	 * \brief Enable DTMF based transfers on bridge when picking up parked calls.
+	 *
+	 * \details
+	 * none(0)
+	 * AST_FEATURE_FLAG_BYCALLEE
+	 * AST_FEATURE_FLAG_BYCALLER
+	 * AST_FEATURE_FLAG_BYBOTH
+	 */
+	int parkedcalltransfers;
+	/*!
+	 * \brief Enable DTMF based parking on bridge when picking up parked calls.
+	 *
+	 * \details
+	 * none(0)
+	 * AST_FEATURE_FLAG_BYCALLEE
+	 * AST_FEATURE_FLAG_BYCALLER
+	 * AST_FEATURE_FLAG_BYBOTH
+	 */
+	int parkedcallreparking;
+	/*!
+	 * \brief Enable DTMF based hangup on a bridge when pickup up parked calls.
+	 *
+	 * \details
+	 * none(0)
+	 * AST_FEATURE_FLAG_BYCALLEE
+	 * AST_FEATURE_FLAG_BYCALLER
+	 * AST_FEATURE_FLAG_BYBOTH
+	 */
+	int parkedcallhangup;
+	/*!
+	 * \brief Enable DTMF based recording on a bridge when picking up parked calls.
+	 *
+	 * \details
+	 * none(0)
+	 * AST_FEATURE_FLAG_BYCALLEE
+	 * AST_FEATURE_FLAG_BYCALLER
+	 * AST_FEATURE_FLAG_BYBOTH
+	 */
+	int parkedcallrecording;
+
+	/*! Add parking hints automatically */
+	unsigned int parkaddhints:1;
+/* BUGBUG need to make use is_invalid to prevent use of parking lot. */
+	/*! TRUE if configuration is invalid and the parking lot should not be used. */
+	unsigned int is_invalid:1;
+};
+
 /*! \brief Structure for parking lots which are put in a container. */
 struct ast_parkinglot {
+	/*! Name of the parking lot. */
 	char name[AST_MAX_CONTEXT];
-	char parkext[AST_MAX_EXTENSION];				/*!< Parkingextension */
-	char parking_con[AST_MAX_EXTENSION];		/*!< Context for which parking is made accessible */
-	char parking_con_dial[AST_MAX_EXTENSION];	/*!< Context for dialback for parking (KLUDGE) */
-	int parking_start;				/*!< First available extension for parking */
-	int parking_stop;				/*!< Last available extension for parking */
-	int parking_offset;
-	int parkfindnext;
-	int parkingtime;				/*!< Default parking time */
-	char mohclass[MAX_MUSICCLASS];                  /*!< Music class used for parking */
-	int parkaddhints;                               /*!< Add parking hints automatically */
-	int parkedcalltransfers;                        /*!< Enable DTMF based transfers on bridge when picking up parked calls */
-	int parkedcallreparking;                        /*!< Enable DTMF based parking on bridge when picking up parked calls */
-	int parkedcallhangup;                           /*!< Enable DTMF based hangup on a bridge when pickup up parked calls */
-	int parkedcallrecording;                        /*!< Enable DTMF based recording on a bridge when picking up parked calls */
-	unsigned short the_mark:1;                      /*!< Used during reloads, that which bears the_mark shall be deleted! */
-	AST_LIST_HEAD(parkinglot_parklist, parkeduser) parkings; /*!< List of active parkings in this parkinglot */
+	/*! 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! */
+	unsigned int the_mark:1;
+
+	/*! List of active parkings in this parkinglot */
+	AST_LIST_HEAD(parkinglot_parklist, parkeduser) parkings;
 };
 
 /*! \brief The list of parking lots configured. Always at least one  - the default parking lot */
 static struct ao2_container *parkinglots;
  
-struct ast_parkinglot *default_parkinglot;
+static struct ast_parkinglot *default_parkinglot;
 char parking_ext[AST_MAX_EXTENSION];            /*!< Extension you type to park the call */
 
 static char courtesytone[256];                             /*!< Courtesy tone */
@@ -578,9 +637,7 @@
 /* Forward declarations */
 static struct ast_parkinglot *parkinglot_addref(struct ast_parkinglot *parkinglot);
 static void parkinglot_unref(struct ast_parkinglot *parkinglot);
-static void parkinglot_destroy(void *obj);
-int manage_parkinglot(struct ast_parkinglot *curlot, const struct pollfd *pfds, const int nfds, struct pollfd **new_pfds, int *new_nfds, int *fs);
-struct ast_parkinglot *find_parkinglot(const char *name);
+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);
 
@@ -589,7 +646,7 @@
 	struct ast_parkinglot *parkinglot = obj;
 	int *parkpos = args;
 
-	if (*parkpos >= parkinglot->parking_start && *parkpos <= parkinglot->parking_stop) {
+	if (*parkpos >= parkinglot->cfg.parking_start && *parkpos <= parkinglot->cfg.parking_stop) {
 		return CMP_MATCH | CMP_STOP;
 	}
 
@@ -601,7 +658,7 @@
 	struct ast_parkinglot *parkinglot = obj;
 	const char *parkext = args;
 
-	if (!strcmp(parkinglot->parkext, parkext)) {
+	if (!strcmp(parkinglot->cfg.parkext, parkext)) {
 		return CMP_MATCH | CMP_STOP;
 	}
 
@@ -620,7 +677,7 @@
 	}
 
 	app_at_exten = ast_get_extension_app(exten);
-	if (!app_at_exten || strcmp(PARK_APP_NAME, app_at_exten)) {
+	if (!app_at_exten || strcasecmp(PARK_APP_NAME, app_at_exten)) {
 		return 0;
 	}
 
@@ -649,7 +706,8 @@
 
 static int parkinglot_cmp_cb(void *obj, void *arg, int flags)
 {
-	struct ast_parkinglot *parkinglot = obj, *parkinglot2 = arg;
+	struct ast_parkinglot *parkinglot = obj;
+	struct ast_parkinglot *parkinglot2 = arg;
 
 	return !strcasecmp(parkinglot->name, parkinglot2->name) ? CMP_MATCH | CMP_STOP : 0;
 }
@@ -802,20 +860,21 @@
 	return ast_adsi_print(chan, message, justify, 1);
 }
 
-/*! \brief Find parking lot name from channel */
+/*!
+ * \brief Find parking lot name from channel
+ * \note Channel needs to be locked while the returned string is in use.
+ */
 static const char *findparkinglotname(struct ast_channel *chan)
 {
-	const char *temp, *parkinglot = NULL;
-
-	/* Check if the channel has a parking lot */
-	if (!ast_strlen_zero(chan->parkinglot))
+	const char *parkinglot;
+
+	/* The channel variable overrides everything */
+	parkinglot = pbx_builtin_getvar_helper(chan, "PARKINGLOT");
+	if (!parkinglot
+		&& !ast_strlen_zero(chan->parkinglot)) {
+		/* Use the channel's parking lot. */
 		parkinglot = chan->parkinglot;
-
-	/* Channel variables override everything */
-
-	if ((temp  = pbx_builtin_getvar_helper(chan, "PARKINGLOT")))
-		return temp;
-
+	}
 	return parkinglot;
 }
 
@@ -874,9 +933,24 @@
 	uint32_t flags;
 	/*! Parked user that has already obtained a parking space */
 	struct parkeduser *pu;
-	struct ast_parkinglot *parkinglot; /*! parkinglot to be parked in, based on parkext */
+	/*!
+	 * \brief Parkinglot to be parked in, based on parkext
+	 * \note BUGBUG check reference use!
+	 */
+	struct ast_parkinglot *parkinglot;
 };
 
+/*!
+ * \internal
+ * \brief Reserve a parking space in a parking lot for a call being parked.
+ *
+ * \param chan Channel being parked.
+ * \param peer Channel parking the call.
+ * \param args BUGBUG
+ *
+ * \return Parked call descriptor or NULL if failed.
+ * \note The parking lot list is locked if successful.
+ */
 static struct parkeduser *park_space_reserve(struct ast_channel *chan, struct ast_channel *peer, struct ast_park_call_args *args)
 {
 	struct parkeduser *pu;
@@ -894,7 +968,7 @@
 		parkinglotname = findparkinglotname(chan);
 	}
 
-	if (!args->parkinglot) {
+	if (!parkinglot) {
 		if (parkinglotname) {
 			parkinglot = find_parkinglot(parkinglotname);
 		} else {
@@ -919,6 +993,11 @@
 
 		if (!ast_strlen_zero(parkinglotname_copy)) {
 			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;
+			}
 		}
 		if (!parkinglot_copy) {
 			parkinglot_copy = parkinglot_addref(default_parkinglot);
@@ -928,16 +1007,17 @@
 			ast_log(LOG_ERROR, "Could not build dynamic parking lot!\n");
 		} else {
 			if (!ast_strlen_zero(dyn_context)) {
-				ast_copy_string(parkinglot->parking_con, dyn_context, sizeof(parkinglot->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");
 				} else {
-					parkinglot->parking_start = dyn_start;
-					parkinglot->parking_stop = dyn_end;
+					parkinglot->cfg.parking_start = dyn_start;
+					parkinglot->cfg.parking_stop = dyn_end;
 				}
 			}
+/* BUGBUG need to create the dynamic parking lot context and park extension if they do not already exist! */
 			ao2_link(parkinglots, parkinglot);
 		}
 
@@ -962,10 +1042,9 @@
 
 	/* Lock parking list */
 	AST_LIST_LOCK(&parkinglot->parkings);
+
 	/* Check for channel variable PARKINGEXTEN */
-	ast_channel_lock(chan);
 	parkingexten = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGEXTEN"), ""));
-	ast_channel_unlock(chan);
 	if (!ast_strlen_zero(parkingexten)) {
 		/*!
 		 * \note The API forces us to specify a numeric parking slot, even
@@ -975,39 +1054,40 @@
 		 * 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);
-            free(pu);
-            ast_log(LOG_WARNING, "PARKINGEXTEN does not indicate a valid parking slot: '%s'.\n", parkingexten);
+			ast_free(pu);
             return NULL;
         }
         snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", parking_space);
 
-		if (ast_exists_extension(NULL, parkinglot->parking_con, pu->parkingexten, 1, NULL)) {
-			ast_log(LOG_WARNING, "Requested parking extension already exists: %s@%s\n", parkingexten, parkinglot->parking_con);
+		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);
 			AST_LIST_UNLOCK(&parkinglot->parkings);
 			parkinglot_unref(parkinglot);
 			ast_free(pu);
 			return NULL;
 		}
-	} else { /* parkingexten not length zero, so find a usable extension in the lot to park the call */
+	} else {
+		/* 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->parking_stop - parkinglot->parking_start + 1);
-			start+=parkinglot->parking_start;
+			start = ast_random() % (parkinglot->cfg.parking_stop - parkinglot->cfg.parking_start + 1);
+			start+=parkinglot->cfg.parking_start;
 		} else { /* Otherwise, just set it to the start position. */
-			start = parkinglot->parking_start;
+			start = parkinglot->cfg.parking_start;
 		}
 
 		/* free parking extension linear search: O(n^2) */
-		for (i = start; 1; i++) {
+		for (i = start; ; i++) {
 			/* If we are past the end, wrap around to the first parking slot*/
-			if (i == parkinglot->parking_stop + 1) {
-				i = parkinglot->parking_start;
+			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. */
@@ -1036,15 +1116,12 @@
 		/* 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");
-			ast_free(pu);
 			AST_LIST_UNLOCK(&parkinglot->parkings);
 			parkinglot_unref(parkinglot);
+			ast_free(pu);
 			return NULL;
 		}
 
-		/* Set pointer for next parking */
-		if (parkinglot->parkfindnext)
-			parkinglot->parking_offset = parking_space - parkinglot->parking_start + 1;
 		snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", parking_space);
 	}
 
@@ -1081,13 +1158,13 @@
 			ast_indicate(pu->chan, AST_CONTROL_RINGING);
 		} else {
 			ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 
-				S_OR(pu->parkinglot->mohclass, NULL),
-				!ast_strlen_zero(pu->parkinglot->mohclass) ? strlen(pu->parkinglot->mohclass) + 1 : 0);
+				S_OR(pu->parkinglot->cfg.mohclass, NULL),
+				!ast_strlen_zero(pu->parkinglot->cfg.mohclass) ? strlen(pu->parkinglot->cfg.mohclass) + 1 : 0);
 		}
 	}
 	
 	pu->start = ast_tvnow();
-	pu->parkingtime = (args->timeout > 0) ? args->timeout : pu->parkinglot->parkingtime;
+	pu->parkingtime = (args->timeout > 0) ? args->timeout : pu->parkinglot->cfg.parkingtime;
 	if (args->extout)
 		*(args->extout) = pu->parkingnum;
 
@@ -1136,7 +1213,7 @@
 	pu->priority = args->return_pri ? args->return_pri : 
 		(chan->macropriority ? chan->macropriority : chan->priority);
 
-	/* If parking a channel directly, don't quiet yet get parking running on it.
+	/* 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;
@@ -1178,12 +1255,12 @@
 		ast_adsi_unload_session(peer);
 	}
 
-	con = ast_context_find_or_create(NULL, NULL, pu->parkinglot->parking_con, registrar);
+	con = ast_context_find_or_create(NULL, NULL, pu->parkinglot->cfg.parking_con, registrar);
 	if (!con)	/* Still no context? Bad */
-		ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", pu->parkinglot->parking_con);
+		ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", pu->parkinglot->cfg.parking_con);
 	if (con) {
 		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->parking_con, AST_DEVICE_INUSE);
+			notify_metermaids(pu->parkingexten, pu->parkinglot->cfg.parking_con, AST_DEVICE_INUSE);
 	}
 
 	AST_LIST_UNLOCK(&pu->parkinglot->parkings);
@@ -1199,8 +1276,8 @@
 	if (peer == chan) { /* pu->notquiteyet = 1 */
 		/* Wake up parking thread if we're really done */
 		ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 
-			S_OR(pu->parkinglot->mohclass, NULL),
-			!ast_strlen_zero(pu->parkinglot->mohclass) ? strlen(pu->parkinglot->mohclass) + 1 : 0);
+			S_OR(pu->parkinglot->cfg.mohclass, NULL),
+			!ast_strlen_zero(pu->parkinglot->cfg.mohclass) ? strlen(pu->parkinglot->cfg.mohclass) + 1 : 0);
 		pu->notquiteyet = 0;
 		pthread_kill(parking_thread, SIGURG);
 	}
@@ -1210,7 +1287,8 @@
 /*! \brief Park a call */
 int ast_park_call(struct ast_channel *chan, struct ast_channel *peer, int timeout, const char *parkexten, int *extout)
 {
-	struct ast_parkinglot *found_lot = ao2_callback(parkinglots, 0, find_parkinglot_by_exten_cb, (void *) parkexten);
+/* 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,
@@ -1324,13 +1402,13 @@
 	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->parking_con);
+		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->parking_con, AST_DEVICE_NOT_INUSE);
+				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");
@@ -1876,6 +1954,7 @@
 		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 = {
@@ -2072,6 +2151,7 @@
 
 	/* If we are attended transfering to parking, just use parkcall_helper instead of trying to track all of
 	 * the different variables for handling this properly with a builtin_atxfer */
+/* BUGBUG the next line breaks named parking lots. */
 	parkinglot = ao2_callback(parkinglots, 0, find_parkinglot_by_exten_cb, &xferto);
 	if (parkinglot) {
 		struct ast_park_call_args args = {
@@ -4105,7 +4185,7 @@
 }
 
 /*! \brief Run management on parkinglots, called once per parkinglot */
-int manage_parkinglot(struct ast_parkinglot *curlot, const struct pollfd *pfds, const int nfds, struct pollfd **new_pfds, int *new_nfds, int *ms)
+static int manage_parkinglot(struct ast_parkinglot *curlot, const struct pollfd *pfds, const int nfds, struct pollfd **new_pfds, int *new_nfds, int *ms)
 {
 	struct parkeduser *pu;
 	int res = 0;
@@ -4124,10 +4204,12 @@
 		}
 		tms = ast_tvdiff_ms(ast_tvnow(), pu->start);
 		if (tms > pu->parkingtime) {
+/* BUGBUG stop MOH or RINGING depending on what was configured */
 			/* Stop music on hold */
 			ast_indicate(pu->chan, AST_CONTROL_UNHOLD);
 			/* Get chan, exten from derived kludge */
 			if (pu->peername[0]) {
+/* BUGBUG allocating from the stack within a loop here! */
 				char *peername = ast_strdupa(pu->peername);
 				char *dash = strrchr(peername, '-');
 				char *peername_flat; /* using something like DAHDI/52 for an extension name is NOT a good idea */
@@ -4137,16 +4219,17 @@
 					*dash = '\0';
 				}
 
+/* BUGBUG again allocating from the stack within a loop here! */
 				peername_flat = ast_strdupa(peername);
 				for (i = 0; peername_flat[i]; i++) {
 					if (peername_flat[i] == '/') {
-						peername_flat[i]= '_';
+						peername_flat[i] = '_';
 					}
 				}
 
-				con = ast_context_find_or_create(NULL, NULL, pu->parkinglot->parking_con_dial, registrar);
+				con = ast_context_find_or_create(NULL, NULL, pu->parkinglot->cfg.parking_con_dial, registrar);
 				if (!con) {
-					ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", pu->parkinglot->parking_con_dial);
+					ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", pu->parkinglot->cfg.parking_con_dial);
 				} else {
 					char returnexten[AST_MAX_EXTENSION];
 					struct ast_datastore *features_datastore;
@@ -4173,12 +4256,12 @@
 
 					ast_add_extension2(con, 1, peername_flat, 1, NULL, NULL, "Dial", ast_strdup(returnexten), ast_free_ptr, registrar);
 				}
-				if (pu->options_specified == 1) {
+				if (pu->options_specified) {
 					/* Park() was called with overriding return arguments, respect those arguments */
 					set_c_e_p(chan, pu->context, pu->exten, pu->priority);
 				} else {
 					if (comebacktoorigin) {
-						set_c_e_p(chan, pu->parkinglot->parking_con_dial, peername_flat, 1);
+						set_c_e_p(chan, pu->parkinglot->cfg.parking_con_dial, peername_flat, 1);
 					} else {
 						snprintf(parkingslot, sizeof(parkingslot), "%d", pu->parkingnum);
 						pbx_builtin_setvar_helper(chan, "PARKINGSLOT", parkingslot);
@@ -4200,16 +4283,17 @@
 				ast_hangup(chan);
 			}
 			/* And take them out of the parking lot */
-			con = ast_context_find(pu->parkinglot->parking_con);
+			con = ast_context_find(pu->parkinglot->cfg.parking_con);
 			if (con) {
 				if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 0))
 					ast_log(LOG_WARNING, "Whoa, failed to remove the parking extension!\n");
 				else
-					notify_metermaids(pu->parkingexten, curlot->parking_con, AST_DEVICE_NOT_INUSE);
+					notify_metermaids(pu->parkingexten, curlot->cfg.parking_con, AST_DEVICE_NOT_INUSE);
 			} else
 				ast_log(LOG_WARNING, "Whoa, no parking context?\n");
 			AST_LIST_REMOVE_CURRENT(list);
-			free(pu);
+			parkinglot_unref(pu->parkinglot);
+			ast_free(pu);
 		} else {	/* still within parking time, process descriptors */
 			for (x = 0; x < AST_MAX_FDS; x++) {
 				struct ast_frame *f;
@@ -4255,17 +4339,17 @@
 					ast_verb(2, "%s got tired of being parked\n", chan->name);
 					ast_hangup(chan);
 					/* And take them out of the parking lot */
-					con = ast_context_find(curlot->parking_con);
+					con = ast_context_find(curlot->cfg.parking_con);
 					if (con) {
 						if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 0))
 							ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
 						else
-							notify_metermaids(pu->parkingexten, curlot->parking_con, AST_DEVICE_NOT_INUSE);
+							notify_metermaids(pu->parkingexten, curlot->cfg.parking_con, AST_DEVICE_NOT_INUSE);
 					} else
 						ast_log(LOG_WARNING, "Whoa, no parking context for parking lot %s?\n", curlot->name);
 					AST_LIST_REMOVE_CURRENT(list);
 					parkinglot_unref(pu->parkinglot);
-					free(pu);
+					ast_free(pu);
 					break;
 				} else {
 					/* XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */
@@ -4273,8 +4357,8 @@
 					if (pu->moh_trys < 3 && !chan->generatordata) {
 						ast_debug(1, "MOH on parked call stopped by outside source.  Restarting on channel %s.\n", chan->name);
 						ast_indicate_data(chan, AST_CONTROL_HOLD, 
-							S_OR(curlot->mohclass, NULL),
-							(!ast_strlen_zero(curlot->mohclass) ? strlen(curlot->mohclass) + 1 : 0));
+							S_OR(curlot->cfg.mohclass, NULL),
+							(!ast_strlen_zero(curlot->cfg.mohclass) ? strlen(curlot->cfg.mohclass) + 1 : 0));
 						pu->moh_trys++;
 					}
 					goto std;	/* XXX Ick: jumping into an else statement??? XXX */
@@ -4324,8 +4408,8 @@
 		struct ao2_iterator iter;
 		struct ast_parkinglot *curlot;
 		int ms = -1;	/* poll2 timeout, uninitialized */
+
 		iter = ao2_iterator_init(parkinglots, 0);
-
 		while ((curlot = ao2_iterator_next(&iter))) {
 			manage_parkinglot(curlot, pfds, nfds, &new_pfds, &new_nfds, &ms);
 			ao2_ref(curlot, -1);
@@ -4348,7 +4432,7 @@
 }
 
 /*! \brief Find parkinglot by name */
-struct ast_parkinglot *find_parkinglot(const char *name)
+static struct ast_parkinglot *find_parkinglot(const char *name)
 {
 	struct ast_parkinglot *parkinglot;
 
@@ -4365,25 +4449,24 @@
 }
 
 /*! \brief Copy parkinglot and store it with new name */
-struct ast_parkinglot *copy_parkinglot(const char *name, const struct ast_parkinglot *parkinglot) {
+static struct ast_parkinglot *copy_parkinglot(const char *name, const struct ast_parkinglot *parkinglot)
+{
 	struct ast_parkinglot *copylot;
 
-	if (ast_strlen_zero(name)) { /* No name specified */
+	if ((copylot = find_parkinglot(name))) { /* Parkinglot with that name already exists */
+		ao2_ref(copylot, -1);
 		return NULL;
 	}
-	if ((copylot = find_parkinglot(name))) { /* Parkinglot with that name already exists */
-		if (copylot) {
-			ao2_ref(copylot, -1);
-		}
+
+	copylot = create_parkinglot(name);
+	if (!copylot) {
 		return NULL;
 	}
 
-	copylot = create_parkinglot(name);
 	ast_debug(1, "Building parking lot %s\n", name);
 
-	memcpy(copylot, parkinglot, sizeof(struct ast_parkinglot));
-	ast_copy_string(copylot->name, name, sizeof(copylot->name));
-	AST_LIST_HEAD_INIT(&copylot->parkings);
+	/* Copy the source parking lot configuration. */
+	copylot->cfg = parkinglot->cfg;
 
 	return copylot;
 }
@@ -4466,6 +4549,7 @@
 		ast_app_parse_options(park_call_options, &flags, NULL, app_args.options);
 		args.flags = flags.flags;
 
+/* BUGBUG the next line breaks named parking lots. */
 		args.parkinglot = ao2_callback(parkinglots, 0, find_parkinglot_by_exten_cb, &orig_exten);
 		res = masq_park_call_announce(chan, chan, &args);
 		/* Continue on in the dialplan */
@@ -4482,31 +4566,34 @@
 }
 
 /*! \brief Pickup parked call */
-static int park_exec_full(struct ast_channel *chan, const char *data)
+static int parked_call_exec(struct ast_channel *chan, const char *data)
 {
 	int res = 0;
-	struct ast_channel *peer=NULL;
+	struct ast_channel *peer = NULL;
 	struct parkeduser *pu;
 	struct ast_context *con;
 	int park = 0;
 	struct ast_bridge_config config;
 	struct ast_parkinglot *parkinglot;
 
-	if (data) {
-		park = atoi((char *) data);
-	}
-
+	if (!ast_strlen_zero(data)) {
+		if (sscanf(data, "%30u", &park) != 1) {
+			ast_log(LOG_WARNING, "Specified parking extension not a number: %s\n", data);
+			park = -1;
+		}
+	}
+
+/* BUGBUG the next line breaks named parking lots. (it used to just use the chan->parkinglot) */
 	parkinglot = ao2_callback(parkinglots, 0, find_parkinglot_by_position_cb, (void *) &park);
-	if (!parkinglot)
-		parkinglot = default_parkinglot;
+	if (!parkinglot) {
+		parkinglot = parkinglot_addref(default_parkinglot);
+	}
 
 	AST_LIST_LOCK(&parkinglot->parkings);
 	AST_LIST_TRAVERSE_SAFE_BEGIN(&parkinglot->parkings, pu, list) {
-		if (!pu->notquiteyet && (!data || pu->parkingnum == park)) {
-			if (pu->chan->pbx) { /* do not allow call to be picked up until the PBX thread is finished */
-				AST_LIST_UNLOCK(&parkinglot->parkings);
-				return -1;
-			}
+		if ((ast_strlen_zero(data) || pu->parkingnum == park)
+			&& !pu->notquiteyet && !pu->chan->pbx) {
+			/* The parking space has a call and can be picked up now. */
 			AST_LIST_REMOVE_CURRENT(list);
 			break;
 		}
@@ -4516,14 +4603,16 @@
 
 	if (pu) {
 		peer = pu->chan;
-		con = ast_context_find(parkinglot->parking_con);
+		con = ast_context_find(parkinglot->cfg.parking_con);
 		if (con) {
-			if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 0))
+			if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 0)) {
 				ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
-			else
-				notify_metermaids(pu->parkingexten, parkinglot->parking_con, AST_DEVICE_NOT_INUSE);
-		} else
+			} else {
+				notify_metermaids(pu->parkingexten, parkinglot->cfg.parking_con, AST_DEVICE_NOT_INUSE);
+			}
+		} else {
 			ast_log(LOG_WARNING, "Whoa, no parking context?\n");
+		}
 
 		ast_cel_report_event(pu->chan, AST_CEL_PARK_END, NULL, "UnParkedCall", chan);
 		ast_manager_event(pu->chan, EVENT_FLAG_CALL, "UnParkedCall",
@@ -4541,52 +4630,61 @@
 			S_COR(pu->chan->connected.id.name.valid, pu->chan->connected.id.name.str, "<unknown>")
 			);
 
+		parkinglot_unref(pu->parkinglot);
 		ast_free(pu);
 	}
+
+/* BUGBUG we need to update connected line for this connection. */
+
 	/* JK02: it helps to answer the channel if not already up */
-	if (chan->_state != AST_STATE_UP)
+	if (chan->_state != AST_STATE_UP) {
 		ast_answer(chan);
-
-	//XXX Why do we unlock here ?
-	// uncomment it for now, till my setup with debug_threads and detect_deadlocks starts to complain
-	//ASTOBJ_UNLOCK(parkinglot);
+	}
 
 	if (peer) {
 		struct ast_datastore *features_datastore;
 		struct ast_dial_features *dialfeatures = NULL;
 
+/* BUGBUG we should unhold or stop ringing as configured. */
+		ast_indicate(peer, AST_CONTROL_UNHOLD);
+
 		/* Play a courtesy to the source(s) configured to prefix the bridge connecting */
-
 		if (!ast_strlen_zero(courtesytone)) {
 			int error = 0;
-			ast_indicate(peer, AST_CONTROL_UNHOLD);
+
+/* BUGBUG we should autoservice the channel not getting the courtesy tone. */
 			if (parkedplay == 0) {
 				error = ast_stream_and_wait(chan, courtesytone, "");
 			} else if (parkedplay == 1) {
 				error = ast_stream_and_wait(peer, courtesytone, "");
 			} else if (parkedplay == 2) {
-				if (!ast_streamfile(chan, courtesytone, chan->language) &&
-						!ast_streamfile(peer, courtesytone, chan->language)) {
+				if (!ast_streamfile(chan, courtesytone, chan->language)
+					&& !ast_streamfile(peer, courtesytone, peer->language)) {
 					/*! \todo XXX we would like to wait on both! */
 					res = ast_waitstream(chan, "");
-					if (res >= 0)
+					if (res >= 0) {
 						res = ast_waitstream(peer, "");
-					if (res < 0)
+					}
+					if (res < 0) {
 						error = 1;
+					}
+				} else {
+					error = 1;
 				}
 			}
 			if (error) {
 				ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
 				ast_hangup(peer);
+				parkinglot_unref(parkinglot);
 				return -1;
 			}
-		} else
-			ast_indicate(peer, AST_CONTROL_UNHOLD);
+		}
 
 		res = ast_channel_make_compatible(chan, peer);
 		if (res < 0) {
 			ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
 			ast_hangup(peer);
+			parkinglot_unref(parkinglot);
 			return -1;
 		}
 		/* This runs sorta backwards, since we give the incoming channel control, as if it
@@ -4602,42 +4700,45 @@
 		if ((features_datastore = ast_channel_datastore_find(peer, &dial_features_info, NULL))) {
 			dialfeatures = features_datastore->data;
 		}
-		ast_channel_unlock(peer);
-
-		/* When the datastores for both caller and callee are created, both the callee and caller channels
-		 * use the features_caller flag variable to represent themselves. With that said, the config.features_callee
-		 * flags should be copied from the datastore's caller feature flags regardless if peer was a callee
-		 * or caller. */
+
+		/*
+		 * When the datastores for both caller and callee are created,
+		 * both the callee and caller channels use the features_caller
+		 * flag variable to represent themselves.  With that said, the
+		 * config.features_callee flags should be copied from the
+		 * datastore's caller feature flags regardless if peer was a
+		 * callee or caller.
+		 */
 		if (dialfeatures) {
 			ast_copy_flags(&(config.features_callee), &(dialfeatures->features_caller), AST_FLAGS_ALL);
 		}
-
-		if ((parkinglot->parkedcalltransfers == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) {
+		ast_channel_unlock(peer);
+
+		if ((parkinglot->cfg.parkedcalltransfers == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->cfg.parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) {
 			ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
 		}
-		if ((parkinglot->parkedcalltransfers == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) {
+		if ((parkinglot->cfg.parkedcalltransfers == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->cfg.parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) {
 			ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
 		}
-		if ((parkinglot->parkedcallreparking == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) {
+		if ((parkinglot->cfg.parkedcallreparking == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->cfg.parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) {
 			ast_set_flag(&(config.features_callee), AST_FEATURE_PARKCALL);
 		}
-		if ((parkinglot->parkedcallreparking == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) {
+		if ((parkinglot->cfg.parkedcallreparking == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->cfg.parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) {
 			ast_set_flag(&(config.features_caller), AST_FEATURE_PARKCALL);
 		}
-		if ((parkinglot->parkedcallhangup == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) {
+		if ((parkinglot->cfg.parkedcallhangup == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->cfg.parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) {
 			ast_set_flag(&(config.features_callee), AST_FEATURE_DISCONNECT);
 		}
-		if ((parkinglot->parkedcallhangup == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) {
+		if ((parkinglot->cfg.parkedcallhangup == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->cfg.parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) {
 			ast_set_flag(&(config.features_caller), AST_FEATURE_DISCONNECT);
 		}
-		if ((parkinglot->parkedcallrecording == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) {
+		if ((parkinglot->cfg.parkedcallrecording == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->cfg.parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) {
 			ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON);
 		}
-		if ((parkinglot->parkedcallrecording == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) {
+		if ((parkinglot->cfg.parkedcallrecording == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->cfg.parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) {
 			ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON);
 		}
 
-		parkinglot_unref(parkinglot);
 		res = ast_bridge_call(chan, peer, &config);
 
 		pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
@@ -4645,21 +4746,18 @@
 
 		/* Simulate the PBX hanging up */
 		ast_hangup(peer);
-		return -1;
 	} else {
 		/*! \todo XXX Play a message XXX */
-		if (ast_stream_and_wait(chan, "pbx-invalidpark", ""))
-			ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name);
-		ast_verb(3, "Channel %s tried to talk to nonexistent parked call %d\n", chan->name, park);
-		res = -1;
-	}
-
+		if (ast_stream_and_wait(chan, "pbx-invalidpark", "")) {
+			ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark",
+				chan->name);
+		}
+		ast_verb(3, "Channel %s tried to talk to nonexistent parked call %d\n",
+			chan->name, park);
+	}
+
+	parkinglot_unref(parkinglot);
 	return -1;
-}
-
-static int park_exec(struct ast_channel *chan, const char *data) 
-{

[... 840 lines stripped ...]



More information about the asterisk-commits mailing list