[svn-commits] mvanbaak: branch group/multiparking r104047 - /team/group/multiparking/

SVN commits to the Digium repositories svn-commits at lists.digium.com
Sat Feb 23 05:48:09 CST 2008


Author: mvanbaak
Date: Sat Feb 23 05:48:08 2008
New Revision: 104047

URL: http://svn.digium.com/view/asterisk?view=rev&rev=104047
Log:
add patchfile so both me and oej can have a look at it

Added:
    team/group/multiparking/multipark_clean.diff   (with props)

Added: team/group/multiparking/multipark_clean.diff
URL: http://svn.digium.com/view/asterisk/team/group/multiparking/multipark_clean.diff?view=auto&rev=104047
==============================================================================
--- team/group/multiparking/multipark_clean.diff (added)
+++ team/group/multiparking/multipark_clean.diff Sat Feb 23 05:48:08 2008
@@ -1,0 +1,1860 @@
+diff -ruN trunk/channels/chan_iax2.c multiparking/channels/chan_iax2.c
+--- trunk/channels/chan_iax2.c	2007-05-25 00:07:50.000000000 +0200
++++ multiparking/channels/chan_iax2.c	2007-05-25 01:13:02.000000000 +0200
+@@ -149,6 +151,7 @@
+ 
+ 
+ static char context[80] = "default";
++static char default_parkinglot[AST_MAX_EXTENSION];
+ 
+ static char language[MAX_LANGUAGE] = "";
+ static char regcontext[AST_MAX_CONTEXT] = "";
+@@ -313,6 +316,8 @@
+ 	
+ 	int authmethods;
+ 	int encmethods;
++	char parkinglot[AST_MAX_EXTENSION];		/*!< Default parkinglot for device */
++			/* XXX Needs to be a string field */
+ 	int amaflags;
+ 	int adsi;
+ 	unsigned int flags;
+@@ -346,6 +351,7 @@
+ 		AST_STRING_FIELD(cid_name);		/*!< Default context (for transfer really) */
+ 		AST_STRING_FIELD(zonetag);		/*!< Time Zone */
+ 	);
++	char parkinglot[AST_MAX_EXTENSION];		/*!< Default parkinglot for device */
+ 	struct ast_codec_pref prefs;
+ 	struct ast_dnsmgr_entry *dnsmgr;		/*!< DNS refresh manager */
+ 	struct sockaddr_in addr;
+@@ -634,6 +640,7 @@
+ 	int calling_ton;
+ 	int calling_tns;
+ 	int calling_pres;
++	char parkinglot[AST_MAX_EXTENSION];		/*!< Default parkinglot for device */
+ 	int amaflags;
+ 	AST_LIST_HEAD_NOLOCK(, iax2_dpcache) dpentries;
+ 	struct ast_variable *vars;
+@@ -1376,6 +1383,7 @@
+ 			ast_string_field_set(iaxs[x], accountcode, accountcode);
+ 			ast_string_field_set(iaxs[x], mohinterpret, mohinterpret);
+ 			ast_string_field_set(iaxs[x], mohsuggest, mohsuggest);
++			ast_copy_string(iaxs[x]->parkinglot, default_parkinglot, sizeof(iaxs[x]->parkinglot));
+ 		} else {
+ 			ast_log(LOG_WARNING, "Out of resources\n");
+ 			ast_mutex_unlock(&iaxsl[x]);
+@@ -2104,6 +2112,7 @@
+ 		ast_cli(fd, "  * Name       : %s\n", peer->name);
+ 		ast_cli(fd, "  Secret       : %s\n", ast_strlen_zero(peer->secret)?"<Not set>":"<Set>");
+ 		ast_cli(fd, "  Context      : %s\n", peer->context);
++		ast_cli(fd, "  Parking lot  : %s\n", peer->parkinglot);
+ 		ast_cli(fd, "  Mailbox      : %s\n", peer->mailbox);
+ 		ast_cli(fd, "  Dynamic      : %s\n", ast_test_flag(peer, IAX_DYNAMIC) ? "Yes":"No");
+ 		ast_cli(fd, "  Callerid     : %s\n", ast_callerid_merge(cbuf, sizeof(cbuf), peer->cid_name, peer->cid_num, "<unspecified>"));
+@@ -3449,6 +3458,8 @@
+ 	tmp->writeformat = ast_best_codec(capability);
+ 	tmp->tech_pvt = CALLNO_TO_PTR(i->callno);
+ 
++	if (!ast_strlen_zero(i->parkinglot))
++		ast_string_field_set(tmp, parkinglot, i->parkinglot);
+ 	/* Don't use ast_set_callerid() here because it will
+ 	 * generate a NewCallerID event before the NewChannel event */
+ 	tmp->cid.cid_num = ast_strdup(i->cid_num);
+@@ -4927,6 +4938,8 @@
+ 			ast_string_field_set(iaxs[callno], mohinterpret, user->mohinterpret);
+ 		if (!ast_strlen_zero(user->mohsuggest))
+ 			ast_string_field_set(iaxs[callno], mohsuggest, user->mohsuggest);
++		if (!ast_strlen_zero(user->parkinglot))
++			ast_copy_string(iaxs[callno]->parkinglot, user->parkinglot, sizeof(iaxs[callno]->parkinglot));
+ 		if (user->amaflags)
+ 			iaxs[callno]->amaflags = user->amaflags;
+ 		if (!ast_strlen_zero(user->language))
+@@ -9021,6 +9034,8 @@
+ 				ast_string_field_set(user, mohinterpret, v->value);
+ 			} else if (!strcasecmp(v->name, "mohsuggest")) {
+ 				ast_string_field_set(user, mohsuggest, v->value);
++			} else if (!strcasecmp(v->name, "parkinglot")) {
++				ast_copy_string(user->parkinglot, v->value, sizeof(user->parkinglot));
+ 			} else if (!strcasecmp(v->name, "language")) {
+ 				ast_string_field_set(user, language, v->value);
+ 			} else if (!strcasecmp(v->name, "amaflags")) {
+@@ -9225,6 +9240,8 @@
+ #ifdef SO_NO_CHECK
+ 	nochecksums = 0;
+ #endif
++	/* Reset default parking lot */
++	default_parkinglot[0] = '\0';
+ 
+ 	min_reg_expire = IAX_DEFAULT_REG_EXPIRE;
+ 	max_reg_expire = IAX_DEFAULT_REG_EXPIRE;
+@@ -9424,6 +9441,8 @@
+ 		} else if (!strcasecmp(v->name, "cos")) {
+ 			if (ast_str2cos(v->value, &cos))
+ 				ast_log(LOG_WARNING, "Invalid cos value at line %d, see doc/qos.tex for more information.'\n", v->lineno);
++		} else if (!strcasecmp(v->name, "parkinglot")) {
++			ast_copy_string(default_parkinglot, v->value, sizeof(default_parkinglot));
+ 		} else if (!strcasecmp(v->name, "accountcode")) {
+ 			ast_copy_string(accountcode, v->value, sizeof(accountcode));
+ 		} else if (!strcasecmp(v->name, "mohinterpret")) {
+diff -ruN trunk/channels/chan_zap.c multiparking/channels/chan_zap.c
+--- trunk/channels/chan_zap.c	2007-05-30 18:11:57.000000000 +0200
++++ multiparking/channels/chan_zap.c	2007-05-30 19:14:45.000000000 +0200
+@@ -214,6 +214,7 @@
+ static char defaultcic[64] = "";
+ static char defaultozz[64] = "";
+ 
++static char parkinglot[AST_MAX_EXTENSION] = "";		/*!< Default parking lot for this channel */
+ static char progzone[10] = "";
+ 
+ static int usedistinctiveringdetection = 0;
+@@ -556,6 +557,7 @@
+ 	char language[MAX_LANGUAGE];
+ 	char mohinterpret[MAX_MUSICCLASS];
+ 	char mohsuggest[MAX_MUSICCLASS];
++		AST_STRING_FIELD(parkinglot);		/*!< Parking lot for this channel */
+ #ifdef PRI_ANI
+ 	char cid_ani[AST_MAX_EXTENSION];
+ #endif
+@@ -5638,6 +5640,8 @@
+ 		tmp->callgroup = i->callgroup;
+ 		tmp->pickupgroup = i->pickupgroup;
+ 	}
++	if (!ast_strlen_zero(i->parkinglot))
++		ast_string_field_set(tmp, parkinglot, i->parkinglot);
+ 	if (!ast_strlen_zero(i->language))
+ 		ast_string_field_set(tmp, language, i->language);
+ 	if (!i->owner)
+@@ -7886,6 +7890,7 @@
+ 		ast_copy_string(tmp->mohsuggest, conf.chan.mohsuggest, sizeof(tmp->mohsuggest));
+ 		ast_copy_string(tmp->context, conf.chan.context, sizeof(tmp->context));
+ 		ast_copy_string(tmp->cid_num, conf.chan.cid_num, sizeof(tmp->cid_num));
++		ast_string_field_set((tmp->parkinglot, parkinglot, sizeof(tmp->parkinglot));
+ 		tmp->cid_ton = 0;
+ 		ast_copy_string(tmp->cid_name, conf.chan.cid_name, sizeof(tmp->cid_name));
+ 		ast_copy_string(tmp->mailbox, conf.chan.mailbox, sizeof(tmp->mailbox));
+@@ -12054,6 +12059,8 @@
+ 			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")) {
+ 			confp->chan.stripmsd = atoi(v->value);
+ 		} else if (!strcasecmp(v->name, "jitterbuffers")) {
+diff -ruN trunk/configs/features.conf.sample multiparking/configs/features.conf.sample
+--- trunk/configs/features.conf.sample	2007-05-31 16:52:30.000000000 +0200
++++ multiparking/configs/features.conf.sample	2007-05-14 19:46:53.000000000 +0200
+@@ -3,10 +3,11 @@
+ ;
+ 
+ [general]
+-parkext => 700			; What extension to dial to park
+-parkpos => 701-720		; What extensions to park calls on. These needs to be
+-				; numeric, as Asterisk starts from the start position
++parkext => 700			; What extension to dial to park	(all parking lots)
++parkpos => 701-720		; What extensions to park calls on. (defafult parking lot)
++				; These needs to be numeric, as Asterisk starts from the start position
+ 				; and increments with one for the next parked call.
++context => parkedcalls		; Which context parked calls are in (default parking lot)
+ context => parkedcalls		; Which context parked calls are in
+ ;parkingtime => 45		; Number of seconds a call can be parked for 
+ 				; (default is 45 seconds)
+@@ -42,6 +43,7 @@
+ ;atxfercallbackretries = 2  ; Number of times to attempt to send the call back to the transferer.
+                             ; By default, this is 2.
+ 
++
+ [featuremap]
+ ;blindxfer => #1		; Blind transfer  (default is #)
+ ;disconnect => *0		; Disconnect  (default is *)
+@@ -56,6 +58,7 @@
+ ;
+ ;    Set(DYNAMIC_FEATURES=myfeature1#myfeature2#myfeature3)
+ ;
++
+ ;
+ ; The syntax for declaring a dynamic feature is the following:
+ ;
+@@ -100,20 +103,15 @@
+ ;unpauseMonitor => #3,self/callee,UnPauseMonitor   ;Allow the callee to unpause monitoring
+ ;                                                  ;on their channel
+ ;
+-; GROUPS
+-;   Groups are groupings of features defined in [applicationmap]
+-;   that can have their own key mappings.
+-;
+-;   Groups are defined as a configuration section,
+-;   and can be set as part of DYNAMIC_FEATURES in
+-;   the same way that a normal feature can... 
+-;	etc:	
+-;
+-;	  Set(DYNAMIC_FEATURES=myGroupName);
+-;
+-; example:
+-; [myGroupName]        ; defines the group named myGroupName
+-; testfeature => #9    ; associates testfeature with the group and the keycode #9
+-; pauseMonitor         ; associates pauseMonitor with the group and the keycode
+-;                      ; defined in [applicationmap]
+ 
++
++
++;*** Define another parking lot
++;
++; You can set parkinglot with the CHANNEL dialplan function
++; or configure it in the device configuration in the channel
++;
++;[parkinglot_edvina]
++;context => edvinapark
++;parkpos => 800-850
++;findslot => next
+diff -ruN trunk/configs/iax.conf.sample multiparking/configs/iax.conf.sample
+--- trunk/configs/iax.conf.sample	2007-04-30 18:16:26.000000000 +0200
++++ multiparking/configs/iax.conf.sample	2007-05-14 19:46:53.000000000 +0200
+@@ -286,6 +286,10 @@
+ 			; has expired based on its registration interval, used the stored
+ 			; address information regardless. (yes|no)
+ 
++;parkinglot=edvina		; Default parkinglot for IAX peers and users
++				; This can also be configured per device
++				; Parkinglots are defined in features.conf
++
+ ; Guest sections for unauthenticated connection attempts.  Just specify an
+ ; empty secret, or provide no secret section.
+ ;
+diff -ruN trunk/configs/sip.conf.sample multiparking/configs/sip.conf.sample
+--- trunk/configs/sip.conf.sample	2007-05-16 09:35:56.000000000 +0200
++++ multiparking/configs/sip.conf.sample	2007-05-16 10:06:18.000000000 +0200
+@@ -100,6 +100,9 @@
+ ;
+ ;mohsuggest=default
+ ;
++;parkinglot=plaza		; Sets the default parking lot for call parking
++				; This may also be set for individual users/peers
++				; Parkinglots are configured in features.conf
+ ;language=en			; Default language setting for all users/peers
+ 				; This may also be set for individual users/peers
+ ;relaxdtmf=yes			; Relax dtmf handling
+diff -ruN trunk/funcs/func_channel.c multiparking/funcs/func_channel.c
+--- trunk/funcs/func_channel.c	2007-04-20 23:12:53.000000000 +0200
++++ multiparking/funcs/func_channel.c	2007-05-14 19:46:53.000000000 +0200
+@@ -83,6 +83,8 @@
+ 		locked_copy_string(chan, buf, chan->language, len);
+ 	else if (!strcasecmp(data, "musicclass"))
+ 		locked_copy_string(chan, buf, chan->musicclass, len);
++	else if (!strcasecmp(data, "parkinglot"))
++		locked_copy_string(chan, buf, chan->parkinglot, len);
+ 	else if (!strcasecmp(data, "state"))
+ 		locked_copy_string(chan, buf, ast_state2str(chan->_state), len);
+ 	else if (!strcasecmp(data, "channeltype"))
+@@ -109,6 +111,8 @@
+ 
+ 	if (!strcasecmp(data, "language"))
+ 		locked_string_field_set(chan, language, value);
++	else if (!strcasecmp(data, "parkinglot"))
++		locked_string_field_set(chan, parkinglot, value);
+ 	else if (!strcasecmp(data, "musicclass"))
+ 		locked_string_field_set(chan, musicclass, value);
+ 	else if (!strcasecmp(data, "tonezone")) {
+@@ -157,6 +161,7 @@
+ 		"R/O	channeltype        technology used for channel\n"
+ 		"R/W	language           language for sounds played\n"
+ 		"R/W	musicclass         class (from musiconhold.conf) for hold music\n"
++		"R/W	parkinglot         parkinglot for parking\n"
+ 		"R/W	rxgain             set rxgain level on channel drivers that support it\n"
+ 		"R/O	state              state for channel\n"
+ 		"R/W	tonezone           zone for indications played\n"
+diff -ruN trunk/include/asterisk/channel.h multiparking/include/asterisk/channel.h
+--- trunk/include/asterisk/channel.h	2007-05-22 20:52:59.000000000 +0200
++++ multiparking/include/asterisk/channel.h	2007-05-22 21:11:13.000000000 +0200
+@@ -394,6 +394,7 @@
+ 		AST_STRING_FIELD(accountcode);		/*!< Account code for billing */
+ 		AST_STRING_FIELD(call_forward);		/*!< Where to forward to if asked to dial on this interface */
+ 		AST_STRING_FIELD(uniqueid);		/*!< Unique Channel Identifier */
++		AST_STRING_FIELD(parkinglot);		/*! Default parking lot, if empty, default parking lot  */
+ 	);
+ 	
+ 	/*! \brief File descriptor for channel -- Drivers will poll on these file descriptors, so at least one must be non -1.  See \ref AstFileDesc */
+diff -ruN trunk/res/res_features.c multiparking/res/res_features.c
+--- trunk/res/res_features.c	2007-05-31 16:52:30.000000000 +0200
++++ multiparking/res/res_features.c	2007-05-22 15:05:38.000000000 +0200
+@@ -58,10 +58,12 @@
+ #include "asterisk/adsi.h"
+ #include "asterisk/devicestate.h"
+ #include "asterisk/monitor.h"
++#include "asterisk/astobj.h"
+ 
+-#define DEFAULT_PARK_TIME 45000
+-#define DEFAULT_TRANSFER_DIGIT_TIMEOUT 3000
++#define DEFAULT_PARK_TIME 45000				/*!< Default parking time */
++#define DEFAULT_TRANSFER_DIGIT_TIMEOUT 3000		
+ #define DEFAULT_FEATURE_DIGIT_TIMEOUT 500
++#define DEFAULT_PARKINGLOT "default"			/*!< Default parking lot */
+ #define DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER 15000
+ #define DEFAULT_ATXFER_DROP_CALL 0
+ #define DEFAULT_ATXFER_LOOP_DELAY 10000
+@@ -69,6 +71,7 @@
+ 
+ #define AST_MAX_WATCHERS 256
+ 
++/*! \bug Why isn't these flags documented? */
+ enum {
+ 	AST_FEATURE_FLAG_NEEDSDTMF = (1 << 0),
+ 	AST_FEATURE_FLAG_ONPEER =    (1 << 1),
+@@ -78,48 +81,49 @@
+ 	AST_FEATURE_FLAG_BYBOTH	 =   (3 << 3),
+ };
+ 
+-struct feature_group_exten {
+-	AST_LIST_ENTRY(feature_group_exten) entry;
+-	char exten[FEATURE_MAX_LEN];
+-	struct ast_call_feature *feature;
+-};
+-
+-struct feature_group {
+-	AST_LIST_ENTRY(feature_group) entry;
+-	char gname[80];
+-	AST_LIST_HEAD_NOLOCK(, feature_group_exten) features;
+-};
+-
+-static AST_RWLIST_HEAD_STATIC(feature_groups, feature_group);
+-
+ static char *parkedcall = "ParkedCall";
+ 
+ static int parkaddhints = 0;                               /*!< Add parking hints automatically */
+ static int parkedcalltransfers = 0;                        /*!< Enable DTMF based transfers on bridge when picking up parked calls */
+ static int parkedcallreparking = 0;                        /*!< Enable DTMF based parking on bridge when picking up parked calls */
+ static int parkingtime = DEFAULT_PARK_TIME;                /*!< No more than 45 seconds parked before you do something with them */
+-static char parking_con[AST_MAX_EXTENSION];                /*!< Context for which parking is made accessible */
+-static char parking_con_dial[AST_MAX_EXTENSION];           /*!< Context for dialback for parking (KLUDGE) */
+-static char parking_ext[AST_MAX_EXTENSION];                /*!< Extension you type to park the call */
+ static char pickup_ext[AST_MAX_EXTENSION];                 /*!< Call pickup extension */
+ static char parkmohclass[MAX_MUSICCLASS];                  /*!< Music class used for parking */
+-static int parking_start;                                  /*!< First available extension for parking */
+-static int parking_stop;                                   /*!< Last available extension for parking */
+ 
++/* XXX This is used in many modules, so for now it's the same for all parking lots */
++static char parking_ext[AST_MAX_EXTENSION] = "700";	/*!< Extension you type to park the call */
++
++/* Default sounds */
+ static char courtesytone[256];                             /*!< Courtesy tone */
+ static int parkedplay = 0;                                 /*!< Who to play the courtesy tone to */
+ static char xfersound[256];                                /*!< Call transfer sound */
+ static char xferfailsound[256];                            /*!< Call transfer failure sound */
+ 
+-static int parking_offset;
+-static int parkfindnext;
++/*! \brief Structure for parking lots in a linked list. */
++struct ast_parkinglot {
++	ASTOBJ_COMPONENTS(struct ast_parkinglot);	/*!< various object stuff, including ->name */
++	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 */
++	struct parkeduser *occupiedlots;
++};
+ 
+-static int adsipark;
++struct ast_parkinglot_list {
++	ASTOBJ_CONTAINER_COMPONENTS(struct ast_parkinglot);
++} parkinglots;
+ 
+-static int transferdigittimeout;
+-static int featuredigittimeout;
++struct ast_parkinglot *default_parkinglot;
+ static int comebacktoorigin = 1;
+ 
++static int adsipark = 0;
++
++static int transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
++static int featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
++
+ static int atxfernoanswertimeout;
+ static unsigned int atxferdropcall;
+ static unsigned int atxferloopdelay;
+@@ -154,6 +158,7 @@
+ static struct ast_app *monitor_app = NULL;
+ static int monitor_ok = 1;
+ 
++/*! \brief Structure to handle one parked user */ 
+ struct parkeduser {
+ 	struct ast_channel *chan;                   /*!< Parking channel */
+ 	struct timeval start;                       /*!< Time the parking started */
+@@ -167,14 +172,24 @@
+ 	char peername[1024];
+ 	unsigned char moh_trys;
+ 	struct parkeduser *next;
++	struct ast_parkinglot *parkinglot;
+ };
+ 
+-static struct parkeduser *parkinglot;
+ 
++/*!  Lock for parking */
+ AST_MUTEX_DEFINE_STATIC(parking_lock);	/*!< protects all static variables above */
+ 
+ static pthread_t parking_thread;
+ 
++/* Forward declarations */
++static struct ast_parkinglot *parkinglot_addref(struct ast_parkinglot *parkinglot);
++static void parkinglot_unref(struct ast_parkinglot *parkinglot);
++static void parkinglot_destroy(struct ast_parkinglot *ruin);
++int manage_parkinglot(struct ast_parkinglot *curlot, fd_set *rfds, fd_set *efds, fd_set *nrfds, fd_set *nefds);
++int ast_park_call_full(struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout, struct ast_parkinglot *parkinglot);
++struct ast_parkinglot *find_parkinglot(const char *name);
++
++
+ char *ast_parking_ext(void)
+ {
+ 	return parking_ext;
+@@ -203,6 +218,7 @@
+ 	chan->priority = pri;
+ }
+ 
++/*! If GOTO_ON_BLINDXFR is set, transferer in a blind transfer will be sent there. */
+ static void check_goto_on_transfer(struct ast_channel *chan) 
+ {
+ 	struct ast_channel *xferchan;
+@@ -261,6 +277,7 @@
+ 		ast_cdr_setdestchan(tobj->peer->cdr, tobj->chan->name);
+ 	}
+ 
++
+ 	ast_bridge_call(tobj->peer, tobj->chan, &tobj->bconfig);
+ 
+ 	if (tobj->return_to_pbx) {
+@@ -288,6 +305,7 @@
+ 	return NULL;
+ }
+ 
++
+ static void ast_bridge_call_thread_launch(void *data) 
+ {
+ 	pthread_t thread;
+@@ -317,6 +335,23 @@
+ 	return ast_adsi_print(chan, message, justify, 1);
+ }
+ 
++/*! \brief Find parking lot name from channel */
++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))
++		parkinglot = chan->parkinglot;
++
++	/* Channel variables override everything */
++
++	if ((temp  = pbx_builtin_getvar_helper(chan, "PARKINGLOT")))
++		return temp;
++
++	return parkinglot;
++}
++
+ /*! \brief Notify metermaids that we've changed an extension */
+ static void notify_metermaids(char *exten, char *context)
+ {
+@@ -353,36 +388,55 @@
+ /*! \brief Park a call 
+  	\note We put the user in the parking list, then wake up the parking thread to be sure it looks
+ 	after these channels too */
+-int ast_park_call(struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout)
++int ast_park_call_full(struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout, struct ast_parkinglot *parkinglot)
+ {
+ 	struct parkeduser *pu, *cur;
+ 	int i, x = -1, parking_range;
+ 	struct ast_context *con;
++	const char *parkinglotname;
+ 	const char *parkingexten;
+ 	
++	parkinglotname = findparkinglotname(peer);
++
++	if (parkinglotname) {
++		if (option_debug)
++			ast_log(LOG_DEBUG, "Found chanvar Parkinglot: %s\n", parkinglotname);
++		parkinglot = find_parkinglot(parkinglotname);	
++	}
++	if (!parkinglot)
++		parkinglot = default_parkinglot;
++
++	parkinglot_addref(parkinglot);
++	if (option_debug)
++		ast_log(LOG_DEBUG, "Parkinglot: %s\n", parkinglot->name);
++
++	
+ 	/* Allocate memory for parking data */
+-	if (!(pu = ast_calloc(1, sizeof(*pu)))) 
++	if (!(pu = ast_calloc(1, sizeof(*pu)))) {
++		parkinglot_unref(parkinglot);
+ 		return -1;
++	}
++	ASTOBJ_WRLOCK(parkinglot);
+ 
+-	/* Lock parking lot */
+-	ast_mutex_lock(&parking_lock);
+ 	/* Check for channel variable PARKINGEXTEN */
+ 	parkingexten = pbx_builtin_getvar_helper(chan, "PARKINGEXTEN");
+ 	if (!ast_strlen_zero(parkingexten)) {
+-		if (ast_exists_extension(NULL, parking_con, parkingexten, 1, NULL)) {
++		if (ast_exists_extension(NULL, parkinglot->parking_con, parkingexten, 1, NULL)) {
+ 			ast_mutex_unlock(&parking_lock);
++			parkinglot_unref(parkinglot);
++			ASTOBJ_UNLOCK(parkinglot);
+ 			free(pu);
+-			ast_log(LOG_WARNING, "Requested parking extension already exists: %s@%s\n", parkingexten, parking_con);
++			ast_log(LOG_WARNING, "Requested parking extension already exists: %s@%s\n", parkingexten, parkinglot->parking_con);
+ 			return 0;	/* Continue execution if possible */
+ 		}
+ 		ast_copy_string(pu->parkingexten, parkingexten, sizeof(pu->parkingexten));
+ 		x = atoi(parkingexten);
+ 	} else {
+ 		/* Select parking space within range */
+-		parking_range = parking_stop - parking_start+1;
++		parking_range = parkinglot->parking_stop - parkinglot->parking_start + 1;
+ 		for (i = 0; i < parking_range; i++) {
+-			x = (i + parking_offset) % parking_range + parking_start;
+-			cur = parkinglot;
++			x = (i + parkinglot->parking_offset) % parking_range + parkinglot->parking_start;
++			cur = parkinglot->occupiedlots;
+ 			while(cur) {
+ 				if (cur->parkingnum == x) 
+ 					break;
+@@ -393,16 +447,17 @@
+ 		}
+ 
+ 		if (!(i < parking_range)) {
+-			ast_log(LOG_WARNING, "No more parking spaces\n");
++			ast_log(LOG_WARNING, "No more parking spaces in parking lot \"%s\"\n", parkinglot->name);
+ 			free(pu);
+ 			ast_mutex_unlock(&parking_lock);
++			parkinglot_unref(parkinglot);
++			ASTOBJ_UNLOCK(parkinglot);
+ 			return -1;
+ 		}
+ 		/* Set pointer for next parking */
+-		if (parkfindnext) 
+-			parking_offset = x - parking_start + 1;
++		if (parkinglot->parkfindnext) 
++			parkinglot->parking_offset = x - parkinglot->parking_start + 1;
+ 	}
+-	
+ 	chan->appl = "Parked Call";
+ 	chan->data = NULL; 
+ 
+@@ -417,11 +472,13 @@
+ 	
+ 	pu->start = ast_tvnow();
+ 	pu->parkingnum = x;
++	pu->parkinglot = parkinglot;
+ 	pu->parkingtime = (timeout > 0) ? timeout : parkingtime;
++
+ 	if (extout)
+ 		*extout = x;
+ 
+-	if (peer) 
++	if (peer) 	/* Parking channel */
+ 		ast_copy_string(pu->peername, peer->name, sizeof(pu->peername));
+ 
+ 	/* Remember what had been dialed, so that if the parking
+@@ -429,8 +486,9 @@
+ 	ast_copy_string(pu->context, S_OR(chan->macrocontext, chan->context), sizeof(pu->context));
+ 	ast_copy_string(pu->exten, S_OR(chan->macroexten, chan->exten), sizeof(pu->exten));
+ 	pu->priority = chan->macropriority ? chan->macropriority : chan->priority;
+-	pu->next = parkinglot;
+-	parkinglot = pu;
++	pu->next = parkinglot->occupiedlots;
++	parkinglot->occupiedlots = pu;
++	ASTOBJ_UNLOCK(parkinglot);
+ 
+ 	/* If parking a channel directly, don't quiet yet get parking running on it */
+ 	if (peer == chan) 
+@@ -439,18 +497,19 @@
+ 	/* Wake up the (presumably select()ing) thread */
+ 	pthread_kill(parking_thread, SIGURG);
+ 	if (option_verbose > 1) 
+-		ast_verbose(VERBOSE_PREFIX_2 "Parked %s on %d@%s. Will timeout back to extension [%s] %s, %d in %d seconds\n", pu->chan->name, pu->parkingnum, parking_con, pu->context, pu->exten, pu->priority, (pu->parkingtime/1000));
++		ast_verbose(VERBOSE_PREFIX_2 "Parked %s on %d (lot %s). Will timeout back to extension [%s] %s, %d in %d seconds\n", pu->chan->name, pu->parkingnum, parkinglot->name, pu->context, pu->exten, pu->priority, (pu->parkingtime/1000));
+ 
+ 	if (pu->parkingnum != -1)
+ 		snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", x);
+ 	manager_event(EVENT_FLAG_CALL, "ParkedCall",
+ 		"Exten: %s\r\n"
+ 		"Channel: %s\r\n"
++		"Parkinglot: %s\r\n"
+ 		"From: %s\r\n"
+ 		"Timeout: %ld\r\n"
+ 		"CallerIDNum: %s\r\n"
+ 		"CallerIDName: %s\r\n",
+-		pu->parkingexten, pu->chan->name, peer ? peer->name : "",
++		pu->parkingexten, pu->chan->name, pu->parkinglot->name, peer ? peer->name : "",
+ 		(long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL),
+ 		S_OR(pu->chan->cid.cid_num, "<unknown>"),
+ 		S_OR(pu->chan->cid.cid_name, "<unknown>")
+@@ -460,15 +519,15 @@
+ 		adsi_announce_park(peer, pu->parkingexten);	/* Only supports parking numbers */
+ 		ast_adsi_unload_session(peer);
+ 	}
+-
+-	con = ast_context_find(parking_con);
++	con = ast_context_find(parkinglot->parking_con);
+ 	if (!con) 
+-		con = ast_context_create(NULL, parking_con, registrar);
++		con = ast_context_create(NULL, parkinglot->parking_con, registrar);
+ 	if (!con)	/* Still no context? Bad */
+-		ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
++		ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parkinglot->parking_con);
+ 	else {		/* Add extension to context */
+ 		if (!ast_add_extension2(con, 1, pu->parkingexten, 1, NULL, NULL, parkedcall, strdup(pu->parkingexten), ast_free, registrar))
+-			notify_metermaids(pu->parkingexten, parking_con);
++			notify_metermaids(pu->parkingexten, parkinglot->parking_con);
++
+ 	}
+ 	/* Tell the peer channel the number of the parking space */
+ 	if (peer && pu->parkingnum != -1) /* Only say number if it's a number */
+@@ -484,6 +543,11 @@
+ 	return 0;
+ }
+ 
++int ast_park_call(struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout)
++{
++	return ast_park_call_full(chan, peer, timeout, extout, NULL);
++}
++
+ int ast_masq_park_call(struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout)
+ {
+ 	struct ast_channel *chan;
+@@ -1024,7 +1088,7 @@
+ AST_RWLOCK_DEFINE_STATIC(features_lock);
+ 
+ static struct ast_call_feature builtin_features[] = 
+-{
++ {
+ 	{ AST_FEATURE_REDIRECT, "Blind Transfer", "blindxfer", "#", "#", builtin_blindtransfer, AST_FEATURE_FLAG_NEEDSDTMF, "" },
+ 	{ AST_FEATURE_REDIRECT, "Attended Transfer", "atxfer", "", "", builtin_atxfer, AST_FEATURE_FLAG_NEEDSDTMF, "" },
+ 	{ AST_FEATURE_AUTOMON, "One Touch Monitor", "automon", "", "", builtin_automonitor, AST_FEATURE_FLAG_NEEDSDTMF, "" },
+@@ -1051,64 +1115,6 @@
+ 		ast_verbose(VERBOSE_PREFIX_2 "Registered Feature '%s'\n",feature->sname);
+ }
+ 
+-/*! \brief This function must be called while feature_groups is locked... */
+-static struct feature_group* register_group(const char *fgname)
+-{
+-	struct feature_group *fg;
+-
+-	if (!fgname) {
+-		ast_log(LOG_NOTICE, "You didn't pass a new group name!\n");
+-		return NULL;
+-	}
+-
+-	fg = ast_calloc(1, sizeof(*fg));
+-
+-	if (!fg) {
+-		ast_log(LOG_ERROR, "Failed to allocate memory for group '%s'\n", fgname);
+-		return NULL;
+-	}
+-
+-	ast_copy_string(fg->gname, fgname, sizeof(fg->gname));
+-
+-	AST_LIST_INSERT_HEAD(&feature_groups, fg, entry);
+-
+-	if (option_verbose >= 2) 
+-		ast_verbose(VERBOSE_PREFIX_2 "Registered group '%s'\n", fg->gname);
+-
+-	return fg;
+-}
+-
+-/*! \brief This function must be called while feature_groups is locked... */
+-
+-static void register_group_feature(struct feature_group *fg, const char *exten, struct ast_call_feature *feature) 
+-{
+-	struct feature_group_exten *fge;
+-
+-	fge = ast_calloc(1, sizeof(*fge));
+-
+-	if (!fge) return;
+-
+-	if (!fg) {
+-		ast_log(LOG_NOTICE, "You didn't pass a group!\n");
+-		return;
+-	}
+-
+-	if (!feature) {
+-		ast_log(LOG_NOTICE, "You didn't pass a feature!\n");
+-		return;
+-	}
+-
+-	ast_copy_string(fge->exten, (ast_strlen_zero(exten) ? feature->exten : exten), sizeof(fge->exten));
+-
+-	fge->feature = feature;
+-
+-	AST_LIST_INSERT_HEAD(&fg->features, fge, entry);		
+-
+-	if (option_verbose >= 2)
+-		ast_verbose(VERBOSE_PREFIX_2 "Registered feature '%s' for group '%s' at exten '%s'\n", 
+-					feature->sname, fg->gname, exten);
+-}
+-
+ /*! \brief unregister feature from feature_list */
+ void ast_unregister_feature(struct ast_call_feature *feature)
+ {
+@@ -1145,44 +1151,6 @@
+ 	return tmp;
+ }
+ 
+-/*! \brief Remove all groups in the list */
+-static void ast_unregister_groups(void)
+-{
+-	struct feature_group *fg;
+-	struct feature_group_exten *fge;
+-
+-	AST_RWLIST_WRLOCK(&feature_groups);
+-	while ((fg = AST_LIST_REMOVE_HEAD(&feature_groups, entry))) {
+-		while ((fge = AST_LIST_REMOVE_HEAD(&fg->features, entry)))
+-			free(fge);
+-		free(fg);
+-	}
+-	AST_RWLIST_UNLOCK(&feature_groups);
+-}
+-
+-/*! \brief Find a group by name */
+-static struct feature_group *find_group(const char *name) {
+-	struct feature_group *fg = NULL;
+-
+-	AST_LIST_TRAVERSE(&feature_groups, fg, entry) {
+-		if (!strcasecmp(fg->gname, name))
+-			break;
+-	}
+-
+-	return fg;
+-}
+-
+-static struct feature_group_exten *find_group_exten(struct feature_group *fg, const char *code) {
+-	struct feature_group_exten *fge = NULL;
+-
+-	AST_LIST_TRAVERSE(&fg->features, fge, entry) {
+-		if(!strcasecmp(fge->exten, code))
+-			break;
+-	}
+-
+-	return fge;
+-}
+-
+ void ast_rdlock_call_features(void)
+ {
+ 	ast_rwlock_rdlock(&features_lock);
+@@ -1307,15 +1275,13 @@
+ 	struct ast_flags features;
+ 	int res = FEATURE_RETURN_PASSDIGITS;
+ 	struct ast_call_feature *feature;
+-	struct feature_group *fg = NULL;
+-	struct feature_group_exten *fge;
+ 	const char *dynamic_features=pbx_builtin_getvar_helper(chan,"DYNAMIC_FEATURES");
+ 	char *tmp, *tok;
+ 
+ 	if (sense == FEATURE_SENSE_CHAN)
+-		ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL);
++		ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL);	
+ 	else
+-		ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL);
++		ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL);	
+ 	if (option_debug > 2)
+ 		ast_log(LOG_DEBUG, "Feature interpret: chan=%s, peer=%s, sense=%d, features=%d\n", chan->name, peer->name, sense, features.flags);
+ 
+@@ -1341,23 +1307,9 @@
+ 	tmp = ast_strdupa(dynamic_features);
+ 
+ 	while ((tok = strsep(&tmp, "#"))) {
+-		AST_RWLIST_RDLOCK(&feature_groups);
+-
+-		fg = find_group(tok);
+-
+-		if (fg && (fge = find_group_exten(fg, code))) {
+-			res = fge->feature->operation(chan, peer, config, code, sense);
+-			AST_RWLIST_UNLOCK(&feature_groups);
++		AST_LIST_LOCK(&feature_list);	
++		if (!(feature = find_dynamic_feature(tok)))
+ 			continue;
+-		}
+-
+-		AST_RWLIST_UNLOCK(&feature_groups);
+-		AST_LIST_LOCK(&feature_list);
+-
+-		if(!(feature = find_dynamic_feature(tok))) {
+-			AST_LIST_UNLOCK(&feature_list);
+-			continue;
+-		}
+ 			
+ 		/* Feature is up for consideration */
+ 		if (!strcmp(feature->exten, code)) {
+@@ -1430,7 +1382,8 @@
+ 	
+ 	if ((chan = ast_request(type, format, data, &cause))) {
+ 		ast_set_callerid(chan, cid_num, cid_name, cid_num);
+-		ast_channel_inherit_variables(caller, chan);	
++		ast_channel_inherit_variables(caller, chan);
++		
+ 		pbx_builtin_setvar_helper(chan, "TRANSFERERNAME", caller->name);
+ 		if (!chan->cdr) {
+ 			chan->cdr=ast_cdr_alloc();
+@@ -1874,180 +1827,204 @@
+ 	manager_event(EVENT_FLAG_CALL, s,
+ 		"Exten: %s\r\n"
+ 		"Channel: %s\r\n"
++		"Parkinglot: %s\r\n"
+ 		"CallerIDNum: %s\r\n"
+ 		"CallerIDName: %s\r\n\r\n",
+ 		pu->parkingexten, 
+ 		pu->chan->name,
++		pu->parkinglot->name,
+ 		S_OR(pu->chan->cid.cid_num, "<unknown>"),
+ 		S_OR(pu->chan->cid.cid_name, "<unknown>")
+ 		);
+ }
+ 
+-/*! \brief Take care of parked calls and unpark them if needed */
+-static void *do_parking_thread(void *ignore)
++/*! \brief Run management on parkinglots, called once per parkinglot */
++int manage_parkinglot(struct ast_parkinglot *curlot, fd_set *rfds, fd_set *efds, fd_set *nrfds, fd_set *nefds)
+ {
+-	char parkingslot[AST_MAX_EXTENSION];
+-	fd_set rfds, efds;	/* results from previous select, to be preserved across loops. */
++	int ms = -1;	/* select timeout, uninitialized */
++	int max = -1;	/* max fd, none there yet */
++	struct parkeduser *pu, *pl = NULL, *pt = NULL;
++	int res = 0;
+ 
+-	FD_ZERO(&rfds);
+-	FD_ZERO(&efds);
++	parkinglot_addref(curlot);
++	pu = curlot->occupiedlots;
++		
++	while(pu) {
++		struct ast_channel *chan = pu->chan;	/* shorthand */
++		int tms;        /* timeout for this item */
++		int x;          /* fd index in channel */
++		struct ast_context *con;
++
++		if (pu->notquiteyet) { /* Pretend this one isn't here yet */
++			pl = pu;
++			pu = pu->next;
++			continue;
++		}
++		tms = ast_tvdiff_ms(ast_tvnow(), pu->start);
++		if (tms > pu->parkingtime) {
++			/* Stop music on hold */
++			ast_indicate(pu->chan, AST_CONTROL_UNHOLD);
++			/* Get chan, exten from derived kludge */
++			if (pu->peername[0]) {
++				char *peername = ast_strdupa(pu->peername);
++				char *cp = strrchr(peername, '-');
++
++				if (cp) 
++					*cp = 0;
++				con = ast_context_find(pu->parkinglot->parking_con_dial);
++				if (!con)
++					con = ast_context_create(NULL, pu->parkinglot->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);
++				if (con) {
++					char returnexten[AST_MAX_EXTENSION];
+ 
+-	for (;;) {
+-		struct parkeduser *pu, *pl, *pt = NULL;
+-		int ms = -1;	/* select timeout, uninitialized */
+-		int max = -1;	/* max fd, none there yet */
+-		fd_set nrfds, nefds;	/* args for the next select */
+-		FD_ZERO(&nrfds);
+-		FD_ZERO(&nefds);
++					snprintf(returnexten, sizeof(returnexten), "%s||t", peername);
++					ast_add_extension2(con, 1, peername, 1, NULL, NULL, "Dial", strdup(returnexten), ast_free, registrar);
++				}
++				if (comebacktoorigin)
++					set_c_e_p(chan, pu->parkinglot->parking_con_dial, peername, 1);
++				else {
++					char parkingslot[AST_MAX_EXTENSION];
++					ast_log(LOG_WARNING, "now going to parkedcallstimeout,s,1 | ps is %d\n",pu->parkingnum);
++					snprintf(parkingslot, sizeof(parkingslot), "%d", pu->parkingnum);
++					pbx_builtin_setvar_helper(chan, "PARKINGSLOT", parkingslot);
++					set_c_e_p(chan, "parkedcallstimeout", peername, 1);
++				}
+ 
+-		ast_mutex_lock(&parking_lock);
+-		pl = NULL;
+-		pu = parkinglot;
+-		/* navigate the list with prev-cur pointers to support removals */
+-		while (pu) {
+-			struct ast_channel *chan = pu->chan;	/* shorthand */
+-			int tms;        /* timeout for this item */
+-			int x;          /* fd index in channel */
+-			struct ast_context *con;
++			} else {
++				/* They've been waiting too long, send them back to where they came.  Theoretically they
++			   	should have their original extensions and such, but we copy to be on the safe side */
++				set_c_e_p(chan, pu->context, pu->exten, pu->priority);
+ 
+-			if (pu->notquiteyet) { /* Pretend this one isn't here yet */
+-				pl = pu;
+-				pu = pu->next;
+-				continue;
+ 			}
+-			tms = ast_tvdiff_ms(ast_tvnow(), pu->start);
+-			if (tms > pu->parkingtime) {
+-				ast_indicate(chan, AST_CONTROL_UNHOLD);
+-				/* Get chan, exten from derived kludge */
+-				if (pu->peername[0]) {
+-					char *peername = ast_strdupa(pu->peername);
+-					char *cp = strrchr(peername, '-');
+-					if (cp) 
+-						*cp = 0;
+-					con = ast_context_find(parking_con_dial);
+-					if (!con) {
+-						con = ast_context_create(NULL, parking_con_dial, registrar);
+-						if (!con)
+-							ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", parking_con_dial);
+-					}
+-					if (con) {
+-						char returnexten[AST_MAX_EXTENSION];
+-						snprintf(returnexten, sizeof(returnexten), "%s||t", peername);
+-						ast_add_extension2(con, 1, peername, 1, NULL, NULL, "Dial", strdup(returnexten), ast_free, registrar);
+-					}
+-					if (comebacktoorigin) { 
+-						set_c_e_p(chan, parking_con_dial, peername, 1);
+-					} else {
+-						ast_log(LOG_WARNING, "now going to parkedcallstimeout,s,1 | ps is %d\n",pu->parkingnum);
+-						snprintf(parkingslot, sizeof(parkingslot), "%d", pu->parkingnum);
+-						pbx_builtin_setvar_helper(pu->chan, "PARKINGSLOT", parkingslot);
+-						set_c_e_p(chan, "parkedcallstimeout", peername, 1);
+-					}
+-				} else {
+-					/* They've been waiting too long, send them back to where they came.  Theoretically they
+-					   should have their original extensions and such, but we copy to be on the safe side */
+-					set_c_e_p(chan, pu->context, pu->exten, pu->priority);
+-				}
+-
+-				post_manager_event("ParkedCallTimeOut", pu);
++			post_manager_event("ParkedCallTimeOut", pu);
+ 
+-				if (option_verbose > 1) 
+-					ast_verbose(VERBOSE_PREFIX_2 "Timeout for %s parked on %d. Returning to %s,%s,%d\n", chan->name, pu->parkingnum, chan->context, chan->exten, chan->priority);
+-				/* Start up the PBX, or hang them up */
+-				if (ast_pbx_start(chan))  {
+-					ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", chan->name);
+-					ast_hangup(chan);
+-				}
+-				/* And take them out of the parking lot */
+-				if (pl) 
+-					pl->next = pu->next;
++			if (option_verbose > 1) 
++				ast_verbose(VERBOSE_PREFIX_2 "Timeout for %s parked on %d (%s). Returning to %s,%s,%d\n", pu->chan->name, pu->parkingnum, pu->parkinglot->name, pu->chan->context, pu->chan->exten, pu->chan->priority);
++			/* Start up the PBX, or hang them up */
++			if (ast_pbx_start(chan))  {
++				ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", pu->chan->name);
++				ast_hangup(chan);
++			}
++			/* And take them out of the parking lot */
++			if (pl) 
++				pl->next = pu->next;
++			else
++				curlot->occupiedlots = pu->next;
++			pt = pu;
++			pu = pu->next;
++			con = ast_context_find(pt->parkinglot->parking_con);
++			if (con) {
++				if (ast_context_remove_extension2(con, pt->parkingexten, 1, NULL))
++					ast_log(LOG_WARNING, "Whoa, failed to remove the parking extension!\n");
+ 				else
+-					parkinglot = pu->next;
+-				pt = pu;
+-				pu = pu->next;
+-				con = ast_context_find(parking_con);
+-				if (con) {
+-					if (ast_context_remove_extension2(con, pt->parkingexten, 1, NULL))
+-						ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
+-					else
+-						notify_metermaids(pt->parkingexten, parking_con);
+-				} else
+-					ast_log(LOG_WARNING, "Whoa, no parking context?\n");
+-				free(pt);
+-			} else {	/* still within parking time, process descriptors */
+-				for (x = 0; x < AST_MAX_FDS; x++) {
+-					struct ast_frame *f;
++					notify_metermaids(pt->parkingexten, curlot->parking_con);
++			} else
++				ast_log(LOG_WARNING, "Whoa, no parking context?\n");
++			free(pt);
++			parkinglot_unref(curlot);
++		} else {	/* still within parking time, process descriptors */
++			for (x = 0; x < AST_MAX_FDS; x++) {
++				struct ast_frame *f;

[... 884 lines stripped ...]



More information about the svn-commits mailing list