[asterisk-commits] branch oej/multiparking - r7314 /team/oej/multiparking/res/res_features.c

asterisk-commits at lists.digium.com asterisk-commits at lists.digium.com
Sat Dec 3 15:01:44 CST 2005


Author: oej
Date: Sat Dec  3 15:01:42 2005
New Revision: 7314

URL: http://svn.digium.com/view/asterisk?rev=7314&view=rev
Log:
Actually adding the incomplete multi-parking code.

Modified:
    team/oej/multiparking/res/res_features.c

Modified: team/oej/multiparking/res/res_features.c
URL: http://svn.digium.com/view/asterisk/team/oej/multiparking/res/res_features.c?rev=7314&r1=7313&r2=7314&view=diff
==============================================================================
--- team/oej/multiparking/res/res_features.c (original)
+++ team/oej/multiparking/res/res_features.c Sat Dec  3 15:01:42 2005
@@ -16,9 +16,27 @@
  * at the top of the source tree.
  */
 
+/*----------------- BRANCH NOTE *------------------------------ 
+ * This code is under development 
+ *
+ * Input is appreciated, e-mail to oej at edvina.net
+ *
+ *	Goal:
+ *	 To implement multiple parking lots, so that if you
+ *	 run a virtual PBX with many customers in the same
+ * 	 Asterisk, you can set up multiple parking lots
+ *	 Or one for each group in your company
+ * 	 And maybe a special VIP parking lot for the boss :-)
+ *
+ *	 Todo:
+ *	  - Configuration would be nice. Configuring in source is
+ *	    strangeley enough not considered very user friendly...
+ *	  - Make parking lots AST_LIST
+ */
+
 /*! \file
  *
- * \brief Routines implementing call parking
+ * Routines implementing call parking and other call features
  * 
  */
 
@@ -77,36 +95,41 @@
 /* No more than 45 seconds parked before you do something with them */
 static int parkingtime = DEFAULT_PARK_TIME;
 
-/* Context for which parking is made accessible */
-static char parking_con[AST_MAX_EXTENSION];
-
-/* Context for dialback for parking (KLUDGE) */
-static char parking_con_dial[AST_MAX_EXTENSION];
-
 /* Extension you type to park the call */
-static char parking_ext[AST_MAX_EXTENSION];
-
-static char pickup_ext[AST_MAX_EXTENSION];
+/* 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";
+
+static char pickup_ext[AST_MAX_EXTENSION] = "*8";
 
 /* Default sounds */
-static char courtesytone[256];
+static char courtesytone[256] = "";
 static char xfersound[256];
 static char xferfailsound[256];
 
-/* First available extension for parking */
-static int parking_start;
-
-/* Last available extension for parking */
-static int parking_stop;
-
-static int parking_offset;
-
-static int parkfindnext;
-
-static int adsipark;
-
-static int transferdigittimeout;
-static int featuredigittimeout;
+/* Structure for parking lots in a linked list. */
+/* You set parkinglot by setting channel var PARKINGLOT for now */
+/* Maybe a channel setting later */
+struct ast_parkinglot {
+	char name[AST_MAX_EXTENSION];
+	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;
+	struct parkeduser *occupiedlots;
+	struct ast_parkinglot *next;		/* Kevin will hate me */
+};
+
+struct ast_parkinglot default_parkinglot = { "default", "parkedcalls", "park-dial", 701, 750, 0, 0, NULL, NULL};
+
+struct ast_parkinglot extra_parkinglot = { "edvina", "edvinapark", "edvina-dial", 501, 550, 0, 0, NULL, NULL };
+struct ast_parkinglot *parkinglots = &default_parkinglot;
+
+static int adsipark = 0;
+
+static int transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
+static int featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
 
 /* Default courtesy tone played when party joins conference */
 
@@ -125,7 +148,7 @@
 
 static char *synopsis2 = "Park yourself";
 
-static char *descrip2 = "Park(exten):"
+static char *descrip2 = "Park():"
 "Used to park yourself (typically in combination with a supervised\n"
 "transfer to know the parking space). This application is always\n"
 "registered internally and does not need to be explicitly added\n"
@@ -148,9 +171,9 @@
 	char peername[1024];
 	unsigned char moh_trys;
 	struct parkeduser *next;
+	struct ast_parkinglot *parkinglot;
 };
 
-static struct parkeduser *parkinglot;
 
 AST_MUTEX_DEFINE_STATIC(parking_lock);
 
@@ -176,6 +199,9 @@
 	struct ast_channel *chan;
 	struct ast_channel *peer;
 };
+/* Forward declarations */
+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(char *name);
 
 static void check_goto_on_transfer(struct ast_channel *chan) 
 {
@@ -217,7 +243,6 @@
 static void *ast_bridge_call_thread(void *data) 
 {
 	struct ast_bridge_thread_obj *tobj = data;
-
 	tobj->chan->appl = "Transferred Call";
 	tobj->chan->data = tobj->peer->name;
 	tobj->peer->appl = "Transferred Call";
@@ -231,6 +256,7 @@
 		ast_cdr_setdestchan(tobj->peer->cdr, tobj->chan->name);
 	}
 
+
 	ast_bridge_call(tobj->peer, tobj->chan, &tobj->bconfig);
 	ast_hangup(tobj->chan);
 	ast_hangup(tobj->peer);
@@ -240,6 +266,7 @@
 	return NULL;
 }
 
+
 static void ast_bridge_call_thread_launch(void *data) 
 {
 	pthread_t thread;
@@ -254,8 +281,6 @@
 	pthread_setschedparam(thread, SCHED_RR, &sched);
 }
 
-
-
 static int adsi_announce_park(struct ast_channel *chan, int parkingnum)
 {
 	int res;
@@ -273,14 +298,25 @@
 }
 
 /*--- ast_park_call: Park a call */
-/* 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)
+/* 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_full(struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout, struct ast_parkinglot *parkinglot)
 {
 	struct parkeduser *pu, *cur;
-	int i,x,parking_range;
+	int i, x, parking_range;
 	char exten[AST_MAX_EXTENSION];
 	struct ast_context *con;
+	char *parkinglotname;
+	
+
+	if (!parkinglot)
+		parkinglot = &default_parkinglot;
+	parkinglotname = pbx_builtin_getvar_helper(chan, "PARKINGLOT");
+	if (parkinglotname) {
+		ast_log(LOG_DEBUG, "---------**--------- Found chanvar Parkinglot: %s\n", parkinglotname);
+		parkinglot = find_parkinglot(parkinglotname);	
+	}
+	ast_log(LOG_DEBUG, "---------**--------- Parkinglot: %s\n", parkinglot->name);
 
 	pu = malloc(sizeof(struct parkeduser));
 	if (!pu) {
@@ -289,10 +325,10 @@
 	}
 	memset(pu, 0, sizeof(struct parkeduser));
 	ast_mutex_lock(&parking_lock);
-	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;
@@ -303,17 +339,19 @@
 	}
 
 	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);
 		return -1;
 	}
-	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; 
 
 	pu->chan = chan;
+
 	/* Start music on hold */
 	if (chan != peer) {
 		ast_indicate(pu->chan, AST_CONTROL_HOLD);
@@ -321,13 +359,17 @@
 	}
 	pu->start = ast_tvnow();
 	pu->parkingnum = x;
+	pu->parkinglot = parkinglot;
+
 	if (timeout > 0)
 		pu->parkingtime = timeout;
 	else
 		pu->parkingtime = 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
@@ -344,8 +386,8 @@
 		pu->priority = chan->macropriority;
 	else
 		pu->priority = chan->priority;
-	pu->next = parkinglot;
-	parkinglot = pu;
+	pu->next = parkinglot->occupiedlots;
+	parkinglot->occupiedlots = pu;
 	/* If parking a channel directly, don't quiet yet get parking running on it */
 	if (peer == chan) 
 		pu->notquiteyet = 1;
@@ -353,34 +395,31 @@
 	/* 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. Will timeout back to extension [%s] %s, %d in %d seconds\n", pu->chan->name, pu->parkingnum, 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));
 
 	manager_event(EVENT_FLAG_CALL, "ParkedCall",
 		"Exten: %d\r\n"
 		"Channel: %s\r\n"
+		"Parkinglot: %s\r\n"
 		"From: %s\r\n"
 		"Timeout: %ld\r\n"
 		"CallerID: %s\r\n"
 		"CallerIDName: %s\r\n\r\n"
-		,pu->parkingnum, pu->chan->name, peer->name
+		,pu->parkingnum, pu->chan->name, pu->parkinglot->name, peer->name
 		,(long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL)
 		,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>")
 		,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>")
 		);
 
-	if (peer) {
-		if (adsipark && adsi_available(peer)) {
+	if (peer && adsipark && adsi_available(peer)) {
 			adsi_announce_park(peer, pu->parkingnum);
-		}
-		if (adsipark && adsi_available(peer)) {
 			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) {
-			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);
 		}
 	}
 	if (con) {
@@ -396,6 +435,11 @@
 		pthread_kill(parking_thread, SIGURG);
 	}
 	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)
@@ -1089,7 +1133,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);
+		
 		if (!ast_call(chan, data, timeout)) {
 			struct timeval started;
 			int x, len = 0;
@@ -1464,6 +1509,7 @@
 	return res;
 }
 
+/*--- do_parking_thred: Take care of parked calls and unpark them if needed */
 static void *do_parking_thread(void *ignore)
 {
 	int ms, tms, max;
@@ -1474,6 +1520,7 @@
 	char *peername,*cp;
 	char returnexten[AST_MAX_EXTENSION];
 	struct ast_context *con;
+	struct ast_parkinglot *curlot = &default_parkinglot;
 	int x;
 	fd_set rfds, efds;
 	fd_set nrfds, nefds;
@@ -1485,153 +1532,158 @@
 		max = -1;
 		ast_mutex_lock(&parking_lock);
 		pl = NULL;
-		pu = parkinglot;
-		FD_ZERO(&nrfds);
-		FD_ZERO(&nefds);
-		while(pu) {
-			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_moh_stop(pu->chan);
-				ast_indicate(pu->chan, AST_CONTROL_UNHOLD);
-				/* Get chan, exten from derived kludge */
-				if (pu->peername[0]) {
-					peername = ast_strdupa(pu->peername);
-					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);
+		/* We need to do this for every parking lot */
+		while (curlot) {
+			pu = curlot->occupiedlots;
+			FD_ZERO(&nrfds);
+			FD_ZERO(&nefds);
+			while(pu) {
+				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_moh_stop(pu->chan);
+					ast_indicate(pu->chan, AST_CONTROL_UNHOLD);
+					/* Get chan, exten from derived kludge */
+					if (pu->peername[0]) {
+						peername = ast_strdupa(pu->peername);
+						cp = strrchr(peername, '-');
+						if (cp) 
+							*cp = 0;
+						con = ast_context_find(pu->parkinglot->parking_con_dial);
 						if (!con) {
-							ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", parking_con_dial);
+							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) {
+							snprintf(returnexten, sizeof(returnexten), "%s||t", peername);
+							ast_add_extension2(con, 1, peername, 1, NULL, NULL, "Dial", strdup(returnexten), FREE, registrar);
+						}
+						ast_copy_string(pu->chan->exten, peername, sizeof(pu->chan->exten));
+						ast_copy_string(pu->chan->context, pu->parkinglot->parking_con_dial, sizeof(pu->chan->context));
+						pu->chan->priority = 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 */
+						ast_copy_string(pu->chan->exten, pu->exten, sizeof(pu->chan->exten));
+						ast_copy_string(pu->chan->context, pu->context, sizeof(pu->chan->context));
+						pu->chan->priority = pu->priority;
+					}
+
+					manager_event(EVENT_FLAG_CALL, "ParkedCallTimeOut",
+						"Exten: %d\r\n"
+						"Channel: %s\r\n"
+						"Parkinglot: %s\r\n"
+						"CallerID: %s\r\n"
+						"CallerIDName: %s\r\n\r\n"
+						,pu->parkingnum, pu->chan->name, pu->parkinglot->name
+						,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>")
+						,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>")
+						);
+
+					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(pu->chan))  {
+						ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", pu->chan->name);
+						ast_hangup(pu->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) {
+						snprintf(exten, sizeof(exten), "%d", pt->parkingnum);
+						if (ast_context_remove_extension2(con, exten, 1, NULL))
+							ast_log(LOG_WARNING, "Whoa, failed to remove the parking extension!\n");
+					} else
+						ast_log(LOG_WARNING, "Whoa, no parking context?\n");
+					free(pt);
+				} else {
+					for (x = 0; x < AST_MAX_FDS; x++) {
+						if ((pu->chan->fds[x] > -1) && (FD_ISSET(pu->chan->fds[x], &rfds) || FD_ISSET(pu->chan->fds[x], &efds))) {
+							if (FD_ISSET(pu->chan->fds[x], &efds))
+								ast_set_flag(pu->chan, AST_FLAG_EXCEPTION);
+							else
+								ast_clear_flag(pu->chan, AST_FLAG_EXCEPTION);
+							pu->chan->fdno = x;
+							/* See if they need servicing */
+							f = ast_read(pu->chan);
+							if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass ==  AST_CONTROL_HANGUP))) {
+
+								manager_event(EVENT_FLAG_CALL, "ParkedCallGiveUp",
+									"Exten: %d\r\n"
+									"Channel: %s\r\n"
+									"CallerID: %s\r\n"
+									"CallerIDName: %s\r\n\r\n"
+									,pu->parkingnum, pu->chan->name
+									,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>")
+									,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>")
+									);
+
+								/* There's a problem, hang them up*/
+								if (option_verbose > 1) 
+									ast_verbose(VERBOSE_PREFIX_2 "%s got tired of being parked\n", pu->chan->name);
+								ast_hangup(pu->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(curlot->parking_con);
+								if (con) {
+									snprintf(exten, sizeof(exten), "%d", pt->parkingnum);
+									if (ast_context_remove_extension2(con, exten, 1, NULL))
+										ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
+								} else
+									ast_log(LOG_WARNING, "Whoa, no parking context for parking lot %s?\n", curlot->name);
+								free(pt);
+								break;
+							} else {
+								/* XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */
+								ast_frfree(f);
+								if (pu->moh_trys < 3 && !pu->chan->generatordata) {
+									ast_log(LOG_DEBUG, "MOH on parked call stopped by outside source.  Restarting.\n");
+									ast_moh_start(pu->chan, NULL);
+									pu->moh_trys++;
+								}
+								goto std;	/* XXX Ick: jumping into an else statement??? XXX */
+							}
 						}
 					}
-					if (con) {
-						snprintf(returnexten, sizeof(returnexten), "%s||t", peername);
-						ast_add_extension2(con, 1, peername, 1, NULL, NULL, "Dial", strdup(returnexten), FREE, registrar);
+					if (x >= AST_MAX_FDS) {
+	std:					for (x=0; x<AST_MAX_FDS; x++) {
+							/* Keep this one for next one */
+							if (pu->chan->fds[x] > -1) {
+								FD_SET(pu->chan->fds[x], &nrfds);
+								FD_SET(pu->chan->fds[x], &nefds);
+								if (pu->chan->fds[x] > max)
+									max = pu->chan->fds[x];
+							}
+						}
+						/* Keep track of our longest wait */
+						if ((tms < ms) || (ms < 0))
+							ms = tms;
+						pl = pu;
+						pu = pu->next;
 					}
-					ast_copy_string(pu->chan->exten, peername, sizeof(pu->chan->exten));
-					ast_copy_string(pu->chan->context, parking_con_dial, sizeof(pu->chan->context));
-					pu->chan->priority = 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 */
-					ast_copy_string(pu->chan->exten, pu->exten, sizeof(pu->chan->exten));
-					ast_copy_string(pu->chan->context, pu->context, sizeof(pu->chan->context));
-					pu->chan->priority = pu->priority;
-				}
-
-				manager_event(EVENT_FLAG_CALL, "ParkedCallTimeOut",
-					"Exten: %d\r\n"
-					"Channel: %s\r\n"
-					"CallerID: %s\r\n"
-					"CallerIDName: %s\r\n\r\n"
-					,pu->parkingnum, pu->chan->name
-					,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>")
-					,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>")
-					);
-
-				if (option_verbose > 1) 
-					ast_verbose(VERBOSE_PREFIX_2 "Timeout for %s parked on %d. Returning to %s,%s,%d\n", pu->chan->name, pu->parkingnum, pu->chan->context, pu->chan->exten, pu->chan->priority);
-				/* Start up the PBX, or hang them up */
-				if (ast_pbx_start(pu->chan))  {
-					ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", pu->chan->name);
-					ast_hangup(pu->chan);
-				}
-				/* And take them out of the parking lot */
-				if (pl) 
-					pl->next = pu->next;
-				else
-					parkinglot = pu->next;
-				pt = pu;
-				pu = pu->next;
-				con = ast_context_find(parking_con);
-				if (con) {
-					snprintf(exten, sizeof(exten), "%d", pt->parkingnum);
-					if (ast_context_remove_extension2(con, exten, 1, NULL))
-						ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
-				} else
-					ast_log(LOG_WARNING, "Whoa, no parking context?\n");
-				free(pt);
-			} else {
-				for (x = 0; x < AST_MAX_FDS; x++) {
-					if ((pu->chan->fds[x] > -1) && (FD_ISSET(pu->chan->fds[x], &rfds) || FD_ISSET(pu->chan->fds[x], &efds))) {
-						if (FD_ISSET(pu->chan->fds[x], &efds))
-							ast_set_flag(pu->chan, AST_FLAG_EXCEPTION);
-						else
-							ast_clear_flag(pu->chan, AST_FLAG_EXCEPTION);
-						pu->chan->fdno = x;
-						/* See if they need servicing */
-						f = ast_read(pu->chan);
-						if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass ==  AST_CONTROL_HANGUP))) {
-
-							manager_event(EVENT_FLAG_CALL, "ParkedCallGiveUp",
-								"Exten: %d\r\n"
-								"Channel: %s\r\n"
-								"CallerID: %s\r\n"
-								"CallerIDName: %s\r\n\r\n"
-								,pu->parkingnum, pu->chan->name
-								,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>")
-								,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>")
-								);
-
-							/* There's a problem, hang them up*/
-							if (option_verbose > 1) 
-								ast_verbose(VERBOSE_PREFIX_2 "%s got tired of being parked\n", pu->chan->name);
-							ast_hangup(pu->chan);
-							/* And take them out of the parking lot */
-							if (pl) 
-								pl->next = pu->next;
-							else
-								parkinglot = pu->next;
-							pt = pu;
-							pu = pu->next;
-							con = ast_context_find(parking_con);
-							if (con) {
-								snprintf(exten, sizeof(exten), "%d", pt->parkingnum);
-								if (ast_context_remove_extension2(con, exten, 1, NULL))
-									ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
-							} else
-								ast_log(LOG_WARNING, "Whoa, no parking context?\n");
-							free(pt);
-							break;
-						} else {
-							/* XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */
-							ast_frfree(f);
-							if (pu->moh_trys < 3 && !pu->chan->generatordata) {
-								ast_log(LOG_DEBUG, "MOH on parked call stopped by outside source.  Restarting.\n");
-								ast_moh_start(pu->chan, NULL);
-								pu->moh_trys++;
-							}
-							goto std;	/* XXX Ick: jumping into an else statement??? XXX */
-						}
-					}
-				}
-				if (x >= AST_MAX_FDS) {
-std:					for (x=0; x<AST_MAX_FDS; x++) {
-						/* Keep this one for next one */
-						if (pu->chan->fds[x] > -1) {
-							FD_SET(pu->chan->fds[x], &nrfds);
-							FD_SET(pu->chan->fds[x], &nefds);
-							if (pu->chan->fds[x] > max)
-								max = pu->chan->fds[x];
-						}
-					}
-					/* Keep track of our longest wait */
-					if ((tms < ms) || (ms < 0))
-						ms = tms;
-					pl = pu;
-					pu = pu->next;
 				}
 			}
+			curlot = curlot -> next;
 		}
 		ast_mutex_unlock(&parking_lock);
 		rfds = nrfds;
@@ -1644,13 +1696,38 @@
 	return NULL;	/* Never reached */
 }
 
+/*--- find_parkinglot: Find parkinglot by name */
+struct ast_parkinglot *find_parkinglot(char *name)
+{
+	struct ast_parkinglot *parkinglot = &default_parkinglot;
+
+	while(parkinglot) {
+		if (!strcasecmp(parkinglot->name, name)) {
+			ast_log(LOG_DEBUG, "---------**--------- Found Parkinglot: %s\n", parkinglot->name);
+			return parkinglot;
+		}
+		parkinglot = parkinglot->next;
+	}
+	/* We did not find a parking lot */
+	return &default_parkinglot;
+}
+
+/*--- park_call_exec: Park a call */
 static int park_call_exec(struct ast_channel *chan, void *data)
 {
 	/* Data is unused at the moment but could contain a parking
 	   lot context eventually */
 	int res=0;
 	struct localuser *u;
+	char *parkinglotname;
+	struct ast_parkinglot *parkinglot = &default_parkinglot;
+
 	LOCAL_USER_ADD(u);
+	parkinglotname = pbx_builtin_getvar_helper(chan, "PARKINGLOT");
+	if (parkinglotname) {
+		ast_log(LOG_DEBUG, "---------**--------- Found chanvar Parkinglot: %s\n", parkinglotname);
+		parkinglot = find_parkinglot(parkinglotname);	
+	}
 	/* Setup the exten/priority to be s/1 since we don't know
 	   where this call should return */
 	strcpy(chan->exten, "s");
@@ -1660,39 +1737,46 @@
 	if (!res)
 		res = ast_safe_sleep(chan, 1000);
 	if (!res)
-		res = ast_park_call(chan, chan, 0, NULL);
+		res = ast_park_call_full(chan, chan, 0, NULL, parkinglot);
 	LOCAL_USER_REMOVE(u);
 	if (!res)
 		res = AST_PBX_KEEPALIVE;
 	return res;
 }
 
-static int park_exec(struct ast_channel *chan, void *data)
+/*--- park_exec: Pick up parked call in dial plan */
+static int park_exec_full(struct ast_channel *chan, void *data, struct ast_parkinglot *parkinglot)
 {
 	int res=0;
 	struct localuser *u;
 	struct ast_channel *peer=NULL;
 	struct parkeduser *pu, *pl=NULL;
 	char exten[AST_MAX_EXTENSION];
+	char *parkinglotname;
 	struct ast_context *con;
 	int park;
 	int dres;
 	struct ast_bridge_config config;
 
 	if (!data) {
-		ast_log(LOG_WARNING, "Park requires an argument (extension number)\n");
+		ast_log(LOG_WARNING, "ParkedCall requires an argument (extension number)\n");
 		return -1;
 	}
 	LOCAL_USER_ADD(u);
 	park = atoi((char *)data);
 	ast_mutex_lock(&parking_lock);
-	pu = parkinglot;
+	parkinglotname = pbx_builtin_getvar_helper(chan, "PARKINGLOT");
+	if (parkinglotname) {
+		ast_log(LOG_DEBUG, "---------**--------- Found chanvar Parkinglot: %s\n", parkinglotname);
+		parkinglot = find_parkinglot(parkinglotname);	
+	}
+	pu = parkinglot->occupiedlots;
 	while(pu) {
 		if (pu->parkingnum == park) {
 			if (pl)
 				pl->next = pu->next;
 			else
-				parkinglot = pu->next;
+				parkinglot->occupiedlots = pu->next;
 			break;
 		}
 		pl = pu;
@@ -1701,7 +1785,7 @@
 	ast_mutex_unlock(&parking_lock);
 	if (pu) {
 		peer = pu->chan;
-		con = ast_context_find(parking_con);
+		con = ast_context_find(pu->parkinglot->parking_con);
 		if (con) {
 			snprintf(exten, sizeof(exten), "%d", pu->parkingnum);
 			if (ast_context_remove_extension2(con, exten, 1, NULL))
@@ -1712,10 +1796,11 @@
 		manager_event(EVENT_FLAG_CALL, "UnParkedCall",
 			"Exten: %d\r\n"
 			"Channel: %s\r\n"
+			"Parkinglot: %s\r\n"
 			"From: %s\r\n"
 			"CallerID: %s\r\n"
 			"CallerIDName: %s\r\n\r\n"
-			,pu->parkingnum, pu->chan->name, chan->name
+			,pu->parkingnum, pu->chan->name, pu->parkinglot->name, chan->name
 			,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>")
 			,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>")
 			);
@@ -1750,7 +1835,7 @@
 		/* This runs sorta backwards, since we give the incoming channel control, as if it
 		   were the person called. */
 		if (option_verbose > 2) 
-			ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to parked call %d\n", chan->name, park);
+			ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to parked call %d in lot %s\n", chan->name, park, parkinglot->name);
 
 		memset(&config, 0, sizeof(struct ast_bridge_config));
 		ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
@@ -1782,6 +1867,11 @@
 	return res;
 }
 
+static int park_exec(struct ast_channel *chan, void *data) 
+{
+	return park_exec_full(chan, data, &default_parkinglot);
+}
+
 static int handle_showfeatures(int fd, int argc, char *argv[])
 {
 	int i;
@@ -1813,11 +1903,12 @@
 		}
 		AST_LIST_UNLOCK(&feature_list);
 	}
+
 	ast_cli(fd, "\nCall parking\n");
 	ast_cli(fd, "------------\n");
 	ast_cli(fd,"%-20s:	%s\n", "Parking extension", parking_ext);
-	ast_cli(fd,"%-20s:	%s\n", "Parking context", parking_con);
-	ast_cli(fd,"%-20s:	%d-%d\n", "Parked call extensions", parking_start, parking_stop);
+	//OEJ FIX ast_cli(fd,"%-20s:	%s\n", "Parking context", parking_con);
+	//OEJ FIX ast_cli(fd,"%-20s:	%d-%d\n", "Parked call extensions", parking_start, parking_stop);
 	ast_cli(fd,"\n");
 	
 	return RESULT_SUCCESS;
@@ -1834,22 +1925,32 @@
 {
 	struct parkeduser *cur;
 	int numparked = 0;
+	struct ast_parkinglot *parkinglot = &default_parkinglot;
+	
 
 	ast_cli(fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel"
 		, "Context", "Extension", "Pri", "Timeout");
 
 	ast_mutex_lock(&parking_lock);
 
-	cur = parkinglot;
-	while(cur) {
-		ast_cli(fd, "%4d %25s (%-15s %-12s %-4d) %6lds\n"
-			,cur->parkingnum, cur->chan->name, cur->context, cur->exten
-			,cur->priority, cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL));
-
-		cur = cur->next;
-		numparked++;
-	}
-	ast_cli(fd, "%d parked call%s.\n", numparked, (numparked != 1) ? "s" : "");
+	while (parkinglot) {
+		int lotparked = 0;
+		cur = parkinglot->occupiedlots;
+		if (cur)
+			ast_cli(fd, "*** Parking lot: %s\n", parkinglot->name);
+		while(cur) {
+			ast_cli(fd, "%4d %25s (%-15s %-12s %-4d) %6lds\n"
+				,cur->parkingnum, cur->chan->name, cur->context, cur->exten
+				,cur->priority, cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL));
+
+			cur = cur->next;
+			lotparked++;
+		}
+		if (lotparked)
+			ast_cli(fd, "%d parked call%s in this parking lot.\n", lotparked, (numparked != 1) ? "s" : "");
+		parkinglot = parkinglot->next;
+	}
+	ast_cli(fd, "---\n%d parked call%s in total.\n", numparked, (numparked != 1) ? "s" : "");
 
 	ast_mutex_unlock(&parking_lock);
 
@@ -1863,38 +1964,46 @@
 static struct ast_cli_entry showparked =
 { { "show", "parkedcalls", NULL }, handle_parkedcalls, "Lists parked calls", showparked_help };
 
-/* Dump lot status */
+/*--- manager_parking_status: Dump lot status in manager */
 static int manager_parking_status( struct mansession *s, struct message *m )
 {
 	struct parkeduser *cur;
 	char *id = astman_get_header(m,"ActionID");
 	char idText[256] = "";
-
-	if (!ast_strlen_zero(id))
+	struct ast_parkinglot *parkinglot = &default_parkinglot;
+
+	if (id && !ast_strlen_zero(id))
 		snprintf(idText,256,"ActionID: %s\r\n",id);
 
 	astman_send_ack(s, m, "Parked calls will follow");
 
+	/* Do we need to lock all of parking? */
         ast_mutex_lock(&parking_lock);
 
-        cur=parkinglot;
-        while(cur) {
+	
+	while (parkinglot) {
+        	cur=parkinglot->occupiedlots;
+        	while(cur) {
 			ast_cli(s->fd, "Event: ParkedCall\r\n"
-			"Exten: %d\r\n"
-			"Channel: %s\r\n"
-			"Timeout: %ld\r\n"
-			"CallerID: %s\r\n"
-			"CallerIDName: %s\r\n"
-			"%s"
-			"\r\n"
-                        ,cur->parkingnum, cur->chan->name
-                        ,(long)cur->start.tv_sec + (long)(cur->parkingtime/1000) - (long)time(NULL)
-			,(cur->chan->cid.cid_num ? cur->chan->cid.cid_num : "")
-			,(cur->chan->cid.cid_name ? cur->chan->cid.cid_name : "")
-			,idText);
-
-            cur = cur->next;
-        }
+				"Exten: %d\r\n"
+				"Channel: %s\r\n"
+				"Parkinglot: %s\r\n"
+				"Timeout: %ld\r\n"
+				"CallerID: %s\r\n"
+				"CallerIDName: %s\r\n"
+				"%s"
+				"\r\n"
+                        	,cur->parkingnum, cur->chan->name
+				,parkinglot->name
+                        	,(long)cur->start.tv_sec + (long)(cur->parkingtime/1000) - (long)time(NULL)
+				,(cur->chan->cid.cid_num ? cur->chan->cid.cid_num : "")
+				,(cur->chan->cid.cid_name ? cur->chan->cid.cid_name : "")
+				,idText);
+
+			cur = cur->next;
+		}
+		parkinglot = parkinglot->next;
+	}
 
 	ast_cli(s->fd,
 	"Event: ParkedCallsComplete\r\n"
@@ -1948,28 +2057,16 @@
 	struct ast_context *con = NULL;
 	struct ast_config *cfg = NULL;
 	struct ast_variable *var = NULL;
-	char old_parking_ext[AST_MAX_EXTENSION];
-	char old_parking_con[AST_MAX_EXTENSION] = "";
-
-	if (!ast_strlen_zero(parking_con)) {
-		strcpy(old_parking_ext, parking_ext);
-		strcpy(old_parking_con, parking_con);
-	} 
-
-	/* Reset to defaults */
-	strcpy(parking_con, "parkedcalls");
-	strcpy(parking_con_dial, "park-dial");
-	strcpy(parking_ext, "700");
-	strcpy(pickup_ext, "*8");
-	courtesytone[0] = '\0';
+	struct ast_parkinglot *cur = &default_parkinglot;
+	
+	transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
+	featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
+	
+	// OEJ Make sure we remove old unused parking lots
+	// When reloading and resetting defaults as in res_features.c 
 	strcpy(xfersound, "beep");
 	strcpy(xferfailsound, "pbx-invalid");
-	parking_start = 701;
-	parking_stop = 750;
-	parkfindnext = 0;
-
-	transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
-	featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
+	courtesytone[0] = '\0';	/* No default setting */
 
 	cfg = ast_config_load("features.conf");
 	if (!cfg) {
@@ -1983,7 +2080,7 @@
 			if (!strcasecmp(var->name, "parkext")) {
 				ast_copy_string(parking_ext, var->value, sizeof(parking_ext));
 			} else if (!strcasecmp(var->name, "context")) {
-				ast_copy_string(parking_con, var->value, sizeof(parking_con));
+				ast_copy_string(cur->parking_con, var->value, sizeof(cur->parking_con));
 			} else if (!strcasecmp(var->name, "parkingtime")) {
 				if ((sscanf(var->value, "%d", &parkingtime) != 1) || (parkingtime < 1)) {
 					ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value);
@@ -1994,11 +2091,11 @@
 				if (sscanf(var->value, "%d-%d", &start, &end) != 2) {
 					ast_log(LOG_WARNING, "Format for parking positions is a-b, where a and b are numbers at line %d of parking.conf\n", var->lineno);
 				} else {
-					parking_start = start;
-					parking_stop = end;
+					cur->parking_start = start;
+					cur->parking_stop = end;
 				}
 			} else if (!strcasecmp(var->name, "findslot")) {
-				parkfindnext = (!strcasecmp(var->value, "next"));
+				cur->parkfindnext = (!strcasecmp(var->value, "next"));
 			} else if (!strcasecmp(var->name, "adsipark")) {
 				adsipark = ast_true(var->value);
 			} else if (!strcasecmp(var->name, "transferdigittimeout")) {
@@ -2105,15 +2202,13 @@
 	}
 	ast_config_destroy(cfg);
 
-	/* Remove the old parking extension */
-	if (!ast_strlen_zero(old_parking_con) && (con = ast_context_find(old_parking_con)))	{
-		ast_context_remove_extension2(con, old_parking_ext, 1, registrar);
-		ast_log(LOG_DEBUG, "Removed old parking extension %s@%s\n", old_parking_ext, old_parking_con);
-	}
-	
-	if (!(con = ast_context_find(parking_con))) {
-		if (!(con = ast_context_create(NULL, parking_con, registrar))) {
-			ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
+	
+	if (con)
+		ast_context_remove_extension2(con, ast_parking_ext(), 1, registrar);
+	
+	if (!(con = ast_context_find(cur->parking_con))) {
+		if (!(con = ast_context_create(NULL, cur->parking_con, registrar))) {
+			ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", cur->parking_con);
 			return -1;
 		}
 	}
@@ -2129,8 +2224,6 @@
 	int res;
 	
 	AST_LIST_HEAD_INIT(&feature_list);
-	memset(parking_ext, 0, sizeof(parking_ext));
-	memset(parking_con, 0, sizeof(parking_con));
 
 	if ((res = load_config()))
 		return res;
@@ -2143,6 +2236,7 @@
 	if (!res) {
 		ast_manager_register("ParkedCalls", 0, manager_parking_status, "List parked calls" );
 	}
+	default_parkinglot.next = &extra_parkinglot;	/* Just for testing */
 	return res;
 }
 
@@ -2166,7 +2260,7 @@
 int usecount(void)
 {
 	/* Never allow parking to be unloaded because it will
-	   unresolve needed symbols in the dialer */
+	   unresolve needed symbols in the dialer and chan_sip */
 #if 0
 	int res;
 	STANDARD_USECOUNT(res);



More information about the asterisk-commits mailing list