Index: apps/app_queue.c
===================================================================
--- apps/app_queue.c	(revision 46120)
+++ apps/app_queue.c	(working copy)
@@ -353,6 +353,8 @@
 	unsigned int leavewhenempty:2;
 	unsigned int ringinuse:1;
 	unsigned int setinterfacevar:1;
+	unsigned int setqueuevar:1;
+	unsigned int setqueueentryvar:1;
 	unsigned int reportholdtime:1;
 	unsigned int wrapped:1;
 	unsigned int timeoutrestart:1;
@@ -370,6 +372,7 @@
 	int callscompletedinsl;             /*!< Number of calls answered with servicelevel*/
 	char monfmt[8];                     /*!< Format to use when recording calls */
 	int montype;                        /*!< Monitor type  Monitor vs. MixMonitor */
+	char membermacro[32];               /*!< Macro to run upon member connection */
 	char sound_next[80];                /*!< Sound file: "Your call is now first in line" (def. queue-youarenext) */
 	char sound_thereare[80];            /*!< Sound file: "There are currently" (def. queue-thereare) */
 	char sound_calls[80];               /*!< Sound file: "calls waiting to speak to a representative." (def. queue-callswaiting)*/
@@ -646,8 +649,11 @@
 	q->servicelevel = 0;
 	q->ringinuse = 1;
 	q->setinterfacevar = 0;
+	q->setqueuevar = 0;
+	q->setqueueentryvar = 0;
 	q->autofill = autofill_default;
 	q->montype = montype_default;
+	q->membermacro[0] = '\0';
 	q->moh[0] = '\0';
 	q->announce[0] = '\0';
 	q->context[0] = '\0';
@@ -786,10 +792,16 @@
 		q->ringinuse = ast_true(val);
 	} else if (!strcasecmp(param, "setinterfacevar")) {
 		q->setinterfacevar = ast_true(val);
+	} else if (!strcasecmp(param, "setqueuevar")) {
+		q->setqueuevar = ast_true(val);
+	} else if (!strcasecmp(param, "setqueueentryvar")) {
+		q->setqueueentryvar = ast_true(val);
 	} else if (!strcasecmp(param, "monitor-join")) {
 		q->monjoin = ast_true(val);
 	} else if (!strcasecmp(param, "monitor-format")) {
 		ast_copy_string(q->monfmt, val, sizeof(q->monfmt));
+	} else if (!strcasecmp(param, "membermacro")) {
+		ast_copy_string(q->membermacro, val, sizeof(q->membermacro));
 	} else if (!strcasecmp(param, "queue-youarenext")) {
 		ast_copy_string(q->sound_next, val, sizeof(q->sound_next));
 	} else if (!strcasecmp(param, "queue-thereare")) {
@@ -2277,6 +2289,7 @@
 	char oldexten[AST_MAX_EXTENSION]="";
 	char oldcontext[AST_MAX_CONTEXT]="";
 	char queuename[256]="";
+	char interfacevar[256]="";
 	struct ast_channel *peer;
 	struct ast_channel *which;
 	struct callattempt *lpeer;
@@ -2303,7 +2316,7 @@
 	char *p;
 	char vars[2048];
 	int forwardsallowed = 1;
-
+	float sl = 0;
 	memset(&bridge_config, 0, sizeof(bridge_config));
 	time(&now);
 		
@@ -2586,10 +2599,63 @@
 				ast_log(LOG_DEBUG, "app_queue: sendurl=%s.\n", url);
 			ast_channel_sendurl(peer, url);
 		}
+		
+		/* if setinterfacevar is defined, make member variables available to the channel */
+		/* use  pbx_builtin_setvar to set a load of variables with one call */
 		if (qe->parent->setinterfacevar) {
-				pbx_builtin_setvar_helper(qe->chan, "MEMBERINTERFACE", member->interface);
-				pbx_builtin_setvar_helper(qe->chan, "MEMBERNAME", member->membername);
+			snprintf(interfacevar,sizeof(interfacevar), "MEMBERINTERFACE=%s|MEMBERNAME=%s|MEMBERCALLS=%d|MEMBERLASTCALL=%ld|MEMBERPENALTY=%d|MEMBERDYNAMIC=%d",
+				member->interface, member->membername, member->calls, member->lastcall, member->penalty, member->dynamic);
+		 	pbx_builtin_setvar(qe->chan, interfacevar);
 		}
+		
+		/* if setqueueentryvar is defined, make queue entry (i.e. the caller) variables available to the channel */
+		/* use  pbx_builtin_setvar to set a load of variables with one call */
+		if (qe->parent->setqueueentryvar) {
+			snprintf(interfacevar,sizeof(interfacevar), "QEHOLDTIME=%ld|QEORIGINALPOS=%d",
+				(long)time(NULL) - qe->start, qe->opos);
+			pbx_builtin_setvar(qe->chan, interfacevar);
+		}
+		
+		/* if setqueuevar is defined, make queue variables available to the channel */
+		/* use  pbx_builtin_setvar to set a load of variables with one call */
+		if (qe->parent->setqueuevar) {
+			sl = 0;
+			if (qe->parent->callscompleted > 0)
+				sl = 100 * ((float) qe->parent->callscompletedinsl / (float) qe->parent->callscompleted);
+			snprintf(interfacevar,sizeof(interfacevar),
+				"QUEUEMAX=%d|QUEUESTRATEGY=%s|QUEUECALLS=%d|QUEUEHOLDTIME=%d|QUEUECOMPLETED=%d|QUEUEABANDONED=%d|QUEUESRVLEVEL=%d|QUEUESRVLEVELPERF=%2.1f",
+				qe->parent->maxlen, int2strat(qe->parent->strategy), qe->parent->count, qe->parent->holdtime, qe->parent->callscompleted,
+				qe->parent->callsabandoned,  qe->parent->servicelevel, sl);
+		}
+		
+		/* run a macro for this connection if defined. The macro simply returns, no action is taken on the result */
+		if (qe->parent->membermacro) {
+			struct ast_app *theapp;
+			
+			res = ast_autoservice_start(qe->chan);
+			if (res) {
+				ast_log(LOG_ERROR, "Unable to start autoservice on calling channel\n");
+				res = -1;
+			}
+			
+			theapp = pbx_findapp("Macro");
+			
+			if (theapp) {
+				res = pbx_exec(qe->chan, theapp, qe->parent->membermacro);
+				if (option_debug)
+					ast_log(LOG_DEBUG, "Macro exited with status %d\n", res);
+				res = 0;
+			} else {
+				ast_log(LOG_ERROR, "Could not find application Macro\n");
+				res = -1;
+			}
+		
+			if (ast_autoservice_stop(qe->chan) < 0) {
+				ast_log(LOG_ERROR, "Could not stop autoservice on calling channel\n");
+				res = -1;
+			}
+		}
+
 		if (!ast_strlen_zero(agi)) {
 			if (option_debug)
 				ast_log(LOG_DEBUG, "app_queue: agi=%s.\n", agi);
Index: configs/queues.conf.sample
===================================================================
--- configs/queues.conf.sample	(revision 46120)
+++ configs/queues.conf.sample	(working copy)
@@ -128,13 +128,39 @@
 ;maxlen = 0
 ;
 ; If set to yes, just prior to the caller being bridged with a queue member 
-; the MEMBERINTERFACE variable will be set with the interface name (eg. Agent/1234)
-; and the MEMBERNAME variable will be set with the member name (eg. Joe Soap)
-; of the queue member that was chosen and is now connected to be bridged with
-; the caller
+; the following variables will be set
+; MEMBERINTERFACE is the interface name (eg. Agent/1234)
+; MEMBERNAME is the member name (eg. Joe Soap)
+; MEMBERCALLS is the number of calls that interface has taken, 
+; MEMBERLASTCALL is the last time the member took a call. 
+; MEMBERPENALTY is the penalty of the member 
+; MEMBERDYNAMIC indicates if a member is dynamic or not
 ;
 ;setinterfacevar=no
 ;
+; If set to yes, just prior to the caller being bridged with a queue member 
+; the following variables will be set:
+; QEHOLDTIME callers hold time 
+; QEORIGINALPOS original position of the caller in the queue
+;
+;setqueueentryvar=no
+;
+; If set to yes, just prior to the caller being bridged with a queue member 
+; the following variables will be set:
+; QUEUEMAX maxmimum number of calls allowed
+; QUEUESTRATEGY the strategy of the queue; 
+; QUEUECALLS number of calls currently in the queue
+; QUEUEHOLDTIME current average hold time
+; QUEUECOMPLETED number of completed calls for the queue
+; QUEUEABANDONED number of abandoned calls
+; QUEUESRVLEVEL queue service level
+; QUEUESRVLEVELPERF current service level performance
+;
+;setqueuevar=no
+;
+; if set, run this macro when connected to the queue member
+; membermacro=somemacro
+
 ; How often to announce queue position and/or estimated 
 ; holdtime to caller (0=off)
 ;
