--- clean_asterisk/apps/app_queue.c	2003-11-19 16:56:45.000000000 -0500
+++ asterisk/apps/app_queue.c	2003-12-17 10:45:14.000000000 -0500
@@ -2,7 +2,7 @@
  * Asterisk -- A telephony toolkit for Linux.
  *
  * True call queues with optional send URL on answer
- * 
+ *
  * Copyright (C) 1999, Mark Spencer
  *
  * Mark Spencer <markster@linux-support.net>
@@ -34,14 +34,18 @@
 #include <sys/time.h>
 #include <sys/signal.h>
 #include <netinet/in.h>
-
+#include <asthash.h>
 #include <pthread.h>
 
+#define DEFAULT_CHIMEREPS               20
+#define AST_QUEUE_TIMEOUT               100
 #define QUEUE_STRATEGY_RINGALL		0
 #define QUEUE_STRATEGY_ROUNDROBIN	1
 #define QUEUE_STRATEGY_LEASTRECENT	2
 #define QUEUE_STRATEGY_FEWESTCALLS	3
 #define QUEUE_STRATEGY_RANDOM		4
+#define QUEUE_STRATEGY_SKILLBASED       5
+#define MAX_CHIMELIST                   40
 
 static struct strategy {
 	int strategy;
@@ -52,6 +56,7 @@
 	{ QUEUE_STRATEGY_LEASTRECENT, "leastrecent" },
 	{ QUEUE_STRATEGY_FEWESTCALLS, "fewestcalls" },
 	{ QUEUE_STRATEGY_RANDOM, "random" },
+	{ QUEUE_STRATEGY_SKILLBASED, "skillbased" }
 };
 
 #define DEFAULT_RETRY		5
@@ -61,12 +66,20 @@
 static char *tdesc = "True Call Queueing";
 
 static char *app = "Queue";
+static char *dapp = "DynaQueue";
+static char *dsynopsis = "Build a Queue on the fly";
 
 static char *synopsis = "Queue a call for a call queue";
 
+static char *ddescrip =
+"  DynaQueue \n"
+;
+
 static char *descrip =
-"  Queue(queuename[|options[|URL][|announceoverride]]):\n"
+"  Queue(queuename[|options[|skillmask][|toolong][|URL][|announceoverride]]):\n"
 "Queues an incoming call in a particular call queue as defined in queues.conf.\n"
+"skillmask is a bitmask representing the skills of the agent.\n"
+"toolong is a specified timeout 0 = endless where the call will quit the queue returning 2\n"
 "  This application returns -1 if the originating channel hangs up, or if the\n"
 "call is bridged and  either of the parties in the bridge terminate the call.\n"
 "Returns 0 if the queue is full, nonexistant, or has no members.\n"
@@ -75,7 +88,6 @@
 "      'T' -- to allow the calling user to transfer the call.\n"
 "      'd' -- data-quality (modem) call (minimum delay).\n"
 "      'H' -- allow caller to hang up by hitting *.\n"
-"      'n' -- no retries on the timeout; will exit this application and go to the next step.\n"
 "  In addition to transferring the call, a call may be parked and then picked\n"
 "up by another user.\n"
 "  The optionnal URL will be sent to the called party if the channel supports\n"
@@ -85,11 +97,14 @@
 static char *app_aqm = "AddQueueMember" ;
 static char *app_aqm_synopsis = "Dynamically adds queue members" ;
 static char *app_aqm_descrip =
-"   AddQueueMember(queuename[|interface]):\n"
+"   AddQueueMember(queuename[|penalty][|skillmask][|interface]):\n"
 "Dynamically adds interface to an existing queue\n"
 "Returns -1 if there is an error.\n"
+""
 "Example: AddQueueMember(techsupport|SIP/3000)\n"
-"";
+"Example: AddQueueMember(techsupport|100|SIP/3001)\n"
+"skillmask is a bitmask representing the skills of the agent.\n";
+
 
 static char *app_rqm = "RemoveQueueMember" ;
 static char *app_rqm_synopsis = "Dynamically removes queue members" ;
@@ -100,8 +115,7 @@
 "Example: RemoveQueueMember(techsupport|SIP/3000)\n"
 "";
 
-/* whether to exit Queue application after the timeout hits */
-static int go_on = 0;
+
 
 
 /* We define a customer "local user" structure because we
@@ -132,7 +146,12 @@
 	char announce[80];		/* Announcement to play */
 	char context[80];		/* Context when user exits queue */
 	int pos;					/* Where we are in the queue */
-	time_t start;				/* When we started holding */
+        int chimerep;                              /* how may revolutions in the q have we made*/
+        int chimepos;                              /* which chime element are we on */
+        time_t toolong;                              /* too long to wait */
+        long skillmask;                          /* skill bit mask */
+        int ok_secondary;             /* ok for secondary?*/
+	time_t start;                      /* When we started holding */
 	struct ast_channel *chan;	/* Our channel */
 	struct queue_ent *next;		/* The next queue entry */
 };
@@ -141,6 +160,7 @@
 	char tech[80];				/* Technology */
 	char loc[256];				/* Location */
 	int penalty;				/* Are we a last resort? */
+        long skillmask;                         /* skill bitmask */
 	int calls;
 	int dynamic;				/* Are we dynamically added? */
 	time_t lastcall;	/* When last successful call was hungup */
@@ -148,7 +168,7 @@
 };
 
 struct ast_call_queue {
-	ast_mutex_t	lock;	
+	ast_mutex_t	lock;
 	char name[80];			/* Name of the queue */
 	char moh[80];			/* Name of musiconhold to be used */
 	char announce[80];		/* Announcement to play */
@@ -157,17 +177,28 @@
 	int announcetimeout;	/* How often to announce their position */
 	int count;				/* How many entries are in the queue */
 	int maxlen;				/* Max number of entries in queue */
-
 	int dead;				/* Whether this queue is dead or not */
+        int dynamic;                            /* Whether this queue is dynamic or not */
 	int retry;				/* Retry calling everyone after this amount of time */
+        int maxwait;                            /* longest wait time in this q */
+        char q_pos_is[80];
+        char q_wait_time[80];
+        char q_min[80];
+        int loopmin;
+        char chimedata[255];
+        char *chimelist[MAX_CHIMELIST];           /* comma sep list of chime-in sound files */
+        int chimelistlen;
+        time_t allow_secondary;             /* how many seconds to make em wait till we let secondary agent answer */
+        int chimereps;
 	int timeout;			/* How long to wait for an answer */
-	
+
 	/* Queue strategy things */
-	
+
 	int rrpos;				/* Round Robin - position */
 	int wrapped;			/* Round Robin - wrapped around? */
 
 	struct member *members;	/* Member channels to be tried */
+	struct member *secondary_members;	/* Member channels to be tried */
 	struct queue_ent *head;	/* Start of the actual queue */
 	struct ast_call_queue *next;	/* Next call queue */
 };
@@ -195,12 +226,39 @@
 	return -1;
 }
 
+static int intcompare(const void *p1, const void *p2)
+{
+  int i = *((int *)p1);
+  int j = *((int *)p2);
+
+  if (i > j)
+    return (1);
+  if (i < j)
+    return (-1);
+  return (0);
+}
+
+
+static struct queue_ent *pull_member(struct queue_ent *qe,int y) {
+  int x=0;
+  struct queue_ent *cur = NULL;
+
+  for(cur=qe;cur;cur=cur->next) {
+    if(x==y)
+      return cur;
+    x++;
+    
+  }
+}
+
 static int join_queue(char *queuename, struct queue_ent *qe)
 {
 	struct ast_call_queue *q;
-	struct queue_ent *cur, *prev = NULL;
+	struct queue_ent *cur, *prev= NULL;
 	int res = -1;
 	int pos = 0;
+
+
 	ast_mutex_lock(&qlock);
 	q = queues;
 	while(q) {
@@ -212,9 +270,9 @@
 				prev = NULL;
 				cur = q->head;
 				while(cur) {
-					cur->pos = ++pos;
-					prev = cur;
-					cur = cur->next;
+				  cur->pos = ++pos;
+				  prev = cur;
+				  cur = cur->next;
 				}
 				if (prev)
 					prev->next = qe;
@@ -228,9 +286,17 @@
 				strncpy(qe->moh, q->moh, sizeof(qe->moh));
 				strncpy(qe->announce, q->announce, sizeof(qe->announce));
 				strncpy(qe->context, q->context, sizeof(qe->context));
+				qe->chimepos = 0;
+				qe->chimerep = 0;
 				q->count++;
 				res = 0;
-				manager_event(EVENT_FLAG_CALL, "Join", 
+
+				
+				
+				
+
+
+				manager_event(EVENT_FLAG_CALL, "Join",
         	                                               	"Channel: %s\r\nCallerID: %s\r\nQueue: %s\r\nPosition: %d\r\nCount: %d\r\n",
 	                                                       	qe->chan->name, (qe->chan->callerid ? qe->chan->callerid : "unknown"), q->name, qe->pos, q->count );
 #if 0
@@ -249,21 +315,37 @@
 static void free_members(struct ast_call_queue *q, int all)
 {
 	/* Free non-dynamic members */
-	struct member *curm, *next, *prev;
-	curm = q->members;
-	prev = NULL;
-	while(curm) {
-		next = curm->next;
-		if (all || !curm->dynamic) {
-			if (prev)
-				prev->next = next;
-			else
-				q->members = next;
-			free(curm);
-		} else 
-			prev = curm;
-		curm = next;
-	}
+  struct member *curm, *next, *prev;
+  curm = q->members;
+  prev = NULL;
+  while(curm) {
+    next = curm->next;
+    if (all || !curm->dynamic) {
+      if (prev)
+	prev->next = next;
+      else
+	q->members = next;
+      free(curm);
+    } else
+      prev = curm;
+    curm = next;
+  }
+  
+  curm = q->secondary_members;
+  prev = NULL;
+  while(curm) {
+    next = curm->next;
+    if (all || !curm->dynamic) {
+      if (prev)
+	prev->next = next;
+      else
+	q->secondary_members = next;
+      free(curm);
+    } else
+      prev = curm;
+    curm = next;
+  }
+  
 }
 
 static void destroy_queue(struct ast_call_queue *q)
@@ -322,7 +404,7 @@
 		cur = cur->next;
 	}
 	ast_mutex_unlock(&q->lock);
-	if (q->dead && !q->count) {	
+	if (q->dead && !q->count) {
 		/* It's dead and nobody is in it, so kill it */
 		destroy_queue(q);
 	}
@@ -350,7 +432,7 @@
 	if (!tmp->chan) {			/* If we can't, just go on to the next call */
 #if 0
 		ast_log(LOG_NOTICE, "Unable to create channel of type '%s'\n", cur->tech);
-#endif			
+#endif
 		if (qe->chan->cdr)
 			ast_cdr_busy(qe->chan->cdr);
 		tmp->stillgoing = 0;
@@ -466,7 +548,7 @@
 	int pos;
 	struct ast_channel *winner;
 	struct ast_channel *in = qe->chan;
-	
+
 	while(*to && !peer) {
 		o = outgoing;
 		found = -1;
@@ -549,7 +631,7 @@
 							if (!sentringing) {
 #if 0
 								ast_indicate(in, AST_CONTROL_RINGING);
-#endif								
+#endif
 								sentringing++;
 							}
 							break;
@@ -603,23 +685,151 @@
 	}
 
 	return peer;
-	
+
 }
 
+
+
+
+
+
+
+
+static int announce_loop(struct queue_ent *qe) {
+  time_t now;
+  int res=0;
+
+  time(&now);
+
+
+  time(&now);
+  if((qe->toolong > 0) && (now - qe->start) > qe->toolong) {
+    /* timeout fall to another option in dialplan */ 
+    ast_log(LOG_WARNING,"timeout waiting for reply [%ld] > [%ld] seconds.\n",(now - qe->start),qe->toolong);
+    res = AST_QUEUE_TIMEOUT;
+    return(res);
+  }
+
+
+
+
+
+
+  if(qe->parent->chimelistlen > 0 && qe->parent->chimereps > 0 && qe->chimerep > 0 && (qe->chimerep % qe->parent->chimereps == 0)) {
+
+
+	  if( qe->parent->chimelist[qe->chimepos] && strcmp(qe->parent->chimelist[qe->chimepos],"skip")) {
+	    
+	    if(qe->parent->chimelist[qe->chimepos] && (! strcmp(qe->parent->chimelist[qe->chimepos],"announce_pos") || ! strcmp(qe->parent->chimelist[qe->chimepos],"announce_only"))) {
+
+
+	ast_moh_stop(qe->chan);
+	ast_safe_sleep(qe->chan, 1000);	      	      
+			
+			
+	res = ast_streamfile(qe->chan,qe->parent->q_pos_is, qe->chan->language);
+	if(! res)
+	  ast_waitstream(qe->chan, "");
+			
+	res = ast_say_number(qe->chan, qe->pos, "", qe->chan->language);
+			
+	if(! strcmp(qe->parent->chimelist[qe->chimepos],"announce_pos")) {
+		res = ast_streamfile(qe->chan,qe->parent->q_wait_time, qe->chan->language);
+		if(! res)
+			ast_waitstream(qe->chan, "");
+			
+	      
+		res = ast_say_number(qe->chan,qe->parent->maxwait, "", qe->chan->language);
+			
+		res = ast_streamfile(qe->chan,qe->parent->q_min, qe->chan->language);
+		if(! res)
+			ast_waitstream(qe->chan, "");
+	}
+	ast_safe_sleep(qe->chan, 1000);
+	ast_moh_start(qe->chan, qe->moh);
+
+			
+
+      }
+      else {
+
+	ast_moh_stop(qe->chan);
+	ast_safe_sleep(qe->chan, 1000);	      	      
+	res = ast_streamfile(qe->chan,qe->parent->chimelist[qe->chimepos], qe->chan->language);
+	if(! res)
+	  ast_waitstream(qe->chan, "");
+			
+	ast_safe_sleep(qe->chan, 1000);
+	ast_moh_start(qe->chan, qe->moh);  
+			
+	      
+      }
+	    
+
+	  
+    }
+	  
+
+		    
+    qe->chimepos++;
+    if(qe->parent->chimelistlen > 0) {
+      if(qe->chimepos >= qe->parent->chimelistlen)
+	qe->chimepos = qe->parent->loopmin - 1;
+      if(qe->chimepos >= qe->parent->chimelistlen)
+	qe->chimepos = 0;
+    }
+		    
+		    
+  }
+		  
+		  
+		  
+  if(qe->chimerep == 2147483647) {
+    qe->chimerep = 0;
+  }
+		  
+		  
+  qe->chimerep++;
+
+  ast_mutex_lock(&qe->parent->lock);
+  qe->parent->maxwait = (long) (now - qe->start) / 60;
+  ast_mutex_unlock(&qe->parent->lock);
+  
+
+  return res;
+}
+
+
 static int wait_our_turn(struct queue_ent *qe)
 {
 	struct queue_ent *ch;
 	int res = 0;
+	time_t now;
+	
+	
 	for (;;) {
-		/* Atomically read the parent head -- does not need a lock */
-		ch = qe->parent->head;
-		/* If we are now at the top of the head, break out */
-		if (qe->parent->head == qe)
-			break;
-		/* Wait a second before checking again */
-		res = ast_waitfordigit(qe->chan, RECHECK * 1000);
-		if (res)
-			break;
+
+	  /* handle any chimein or position announcement */
+	  res = announce_loop(qe);
+	  if (res == AST_QUEUE_TIMEOUT) {
+	    break;
+	  }
+	  time(&now);
+	  if(qe->ok_secondary != 1 && qe->parent->allow_secondary >= 0 && (((now - qe->start) > qe->parent->allow_secondary))) {
+	    /* cut the nap short to let secondary agents have a chance */
+	    qe->ok_secondary = 1;
+	    break;
+	  }
+
+	  /* Atomically read the parent head -- no lock needed */
+	  ch = qe->parent->head;
+	  /* If we are now at the top of the head, break out */
+	  if (qe->parent->head == qe)
+	    break;
+	  /* Wait a second before checking again */
+	  res = ast_waitfordigit(qe->chan, RECHECK * 1000);
+	  if (res)
+	    break;
 	}
 	return res;
 }
@@ -645,7 +855,29 @@
 
 static int calc_metric(struct ast_call_queue *q, struct member *mem, int pos, struct queue_ent *qe, struct localuser *tmp)
 {
+  int yes=0;
+
 	switch (q->strategy) {
+
+
+	case QUEUE_STRATEGY_SKILLBASED:
+		/* penalty and skill 'it's all in the wrist'*/
+
+	  if(((qe->skillmask & mem->skillmask) == qe->skillmask) || mem->skillmask == 0 || qe->skillmask == 0 ) {
+	    tmp->metric = mem->penalty * 1000000;
+	    yes=1;
+	  }
+	  else {
+	    tmp->metric = -1;
+
+	  }
+
+	  ast_log(LOG_WARNING,"skillmask %ld & %ld = %ld [%s]\n",qe->skillmask,mem->skillmask,(qe->skillmask & mem->skillmask),yes ? "qualify" : "disqualify");
+
+
+
+		break;
+
 	case QUEUE_STRATEGY_RINGALL:
 		/* Everyone equal, except for penalty */
 		tmp->metric = mem->penalty * 1000000;
@@ -694,7 +926,7 @@
 	return 0;
 }
 
-static int try_calling(struct queue_ent *qe, char *options, char *announceoverride, char *url)
+static int try_calling(struct queue_ent *qe, char *options, char *announceoverride, char *url,struct member *members)
 {
 	struct member *cur;
 	struct localuser *outgoing=NULL, *tmp = NULL;
@@ -711,18 +943,22 @@
 	int x=0;
 	char *announce = NULL;
 	char digit = 0;
+
+
 	/* Hold the lock while we setup the outgoing calls */
+
 	ast_mutex_lock(&qe->parent->lock);
-	cur = qe->parent->members;
+	cur = members;
 	if (strlen(qe->announce))
 		announce = qe->announce;
 	if (announceoverride && strlen(announceoverride))
 		announce = announceoverride;
 	while(cur) {
+
+
 		/* Get a technology/[device:]number pair */
 		tmp = malloc(sizeof(struct localuser));
 		if (!tmp) {
-			ast_mutex_unlock(&qe->parent->lock);
 			ast_log(LOG_WARNING, "Out of memory\n");
 			goto out;
 		}
@@ -741,12 +977,10 @@
 				tmp->dataquality = 1;
 			if (strchr(options, 'H'))
 				tmp->allowdisconnect = 1;
-			if (strchr(options, 'n'))
-				go_on = 1;
 		}
 		if (url) {
 			ast_log(LOG_DEBUG, "Queue with URL=%s_\n", url);
-		} else 
+		} else
 			ast_log(LOG_DEBUG, "Simple queue (no URL)\n");
 
 		tmp->member = cur;		/* Never directly dereference!  Could change on reload */
@@ -762,23 +996,36 @@
 		/* Special case: If we ring everyone, go ahead and ring them, otherwise
 		   just calculate their metric for the appropriate strategy */
 		calc_metric(qe->parent, cur, x++, qe, tmp);
-		/* Put them in the list of outgoing thingies...  We're ready now. 
-		   XXX If we're forcibly removed, these outgoing calls won't get
-		   hung up XXX */
-		tmp->next = outgoing;
-		outgoing = tmp;		
-		/* If this line is up, don't try anybody else */
-		if (outgoing->chan && (outgoing->chan->_state == AST_STATE_UP))
+
+
+
+		    if(tmp->metric >= 0) {
+		      /* Put them in the list of outgoing thingies...  We're ready now.
+			 XXX If we're forcibly removed, these outgoing calls won't get
+			 hung up XXX */
+		      tmp->next = outgoing;
+		      outgoing = tmp;
+		      /* If this line is up, don't try anybody else */
+		      if (outgoing->chan && (outgoing->chan->_state == AST_STATE_UP)) {
 			break;
+		      }
+		    }
+		    
+		    cur = cur->next;
 
-		cur = cur->next;
 	}
+
+
+
+
+
 	if (qe->parent->timeout)
 		to = qe->parent->timeout * 1000;
 	else
 		to = -1;
 	ring_one(qe, outgoing);
 	ast_mutex_unlock(&qe->parent->lock);
+
 	lpeer = wait_for_answer(qe, outgoing, &to, &allowredir_in, &allowredir_out, &allowdisconnect, &digit);
 	if (lpeer)
 		peer = lpeer->chan;
@@ -795,16 +1042,17 @@
 				/* Nobody answered, next please? */
 				res=0;
 		}
+
 		goto out;
 	}
 	if (peer) {
 		/* Ah ha!  Someone answered within the desired timeframe.  Of course after this
-		   we will always return with -1 so that it is hung up properly after the 
+		   we will always return with -1 so that it is hung up properly after the
 		   conversation.  */
 		if (!strcmp(qe->chan->type,"Zap")) {
 			if (tmp->dataquality) zapx = 0;
 			ast_channel_setoption(qe->chan,AST_OPTION_TONE_VERIFY,&zapx,sizeof(char),0);
-		}			
+		}
 		if (!strcmp(peer->type,"Zap")) {
 			if (tmp->dataquality) zapx = 0;
 			ast_channel_setoption(peer,AST_OPTION_TONE_VERIFY,&zapx,sizeof(char),0);
@@ -815,13 +1063,23 @@
 		/* Stop music on hold */
 		ast_moh_stop(qe->chan);
 		outgoing = NULL;
+		
 		if (announce) {
 			int res2;
 			res2 = ast_autoservice_start(qe->chan);
+
+			if (!res2)
+			  res2 = ast_streamfile(peer, "agent_beep", peer->language);
+			if (!res2)
+			  res2 = ast_waitstream(peer, "");
+
+
 			if (!res2)
 				res2 = ast_streamfile(peer, announce, peer->language);
 			if (!res2)
 				res2 = ast_waitstream(peer, "");
+
+
 			res2 |= ast_autoservice_stop(qe->chan);
 			if (res2) {
 				/* Agent must have hung up */
@@ -830,6 +1088,7 @@
 				return -1;
 			}
 		}
+
 		/* If appropriate, log that we have a destination channel */
 		if (qe->chan->cdr)
 			ast_cdr_setdestchan(qe->chan->cdr, peer->name);
@@ -841,20 +1100,22 @@
 			return -1;
 		}
 		/* Drop out of the queue at this point, to prepare for next caller */
-		leave_queue(qe);			
+		leave_queue(qe);
  		/* JDG: sendurl */
  		if( url && strlen(url) && ast_channel_supports_html(peer) ) {
  			ast_log(LOG_DEBUG, "app_queue: sendurl=%s.\n", url);
  			ast_channel_sendurl( peer, url );
  		} /* /JDG */
+
 		bridge = ast_bridge_call(qe->chan, peer, allowredir_in, allowredir_out, allowdisconnect);
 
+
 		if(bridge != AST_PBX_NO_HANGUP_PEER)
 			ast_hangup(peer);
 
 		if( bridge == 0 ) res=1; /* JDG: bridge successfull, leave app_queue */
 		else res = bridge; /* bridge error, stay in the queue */
-	}	
+	}
 out:
 	hanguptree(outgoing, NULL);
 	return res;
@@ -862,9 +1123,33 @@
 
 static int wait_a_bit(struct queue_ent *qe)
 {
-	/* Don't need to hold the lock while we setup the outgoing calls */
-	int retrywait = qe->parent->retry * 1000;
-	return ast_waitfordigit(qe->chan, retrywait);
+  /* We do not need to hold the lock while we setup the outgoing calls */
+  int retrywait,res,res2;
+  time_t now;
+
+  retrywait=res=res2=0;
+
+
+
+  for(retrywait=0;retrywait < qe->parent->retry ; retrywait++) {
+    res2 = ast_waitfordigit(qe->chan, 1000);
+    /* handle any chimein or position announcement */
+    res = announce_loop(qe);
+    if (res == AST_QUEUE_TIMEOUT) {
+      return res;
+    }
+    if(res2 != 0) {
+      return res2;
+    }
+    time(&now);
+    if(qe->ok_secondary != 1 && qe->parent->allow_secondary >= 0 && (((now - qe->start) > qe->parent->allow_secondary))) {
+      /* cut the nap short to let secondary agents have a chance */
+      qe->ok_secondary = 1;
+      return 0;
+    }
+
+  }
+  return res2;
 }
 
 // [PHM 06/26/03]
@@ -899,7 +1184,7 @@
 {
 	struct member * cur ;
 	char * tmp ;
-	
+
 	/* Add a new member */
 
 	cur = malloc(sizeof(struct member));
@@ -937,9 +1222,9 @@
 		ast_log(LOG_WARNING, "RemoveQueueMember requires an argument (queuename|optional interface)\n");
 		return -1;
 	}
-	
+
 	LOCAL_USER_ADD(u); // not sure if we need this, but better be safe than sorry ;-)
-	
+
 	/* Parse our arguments XXX Check for failure XXX */
 	strncpy(info, (char *)data, strlen((char *)data) + AST_MAX_EXTENSION-1);
 	queuename = info;
@@ -960,7 +1245,7 @@
 
 	if( ( q = queues) != NULL )
 	{
-		while( q && ( res != 0 ) && (!found) ) 
+		while( q && ( res != 0 ) && (!found) )
 		{
 			ast_mutex_lock(&q->lock);
 			if( strcmp( q->name, queuename) == 0 )
@@ -989,7 +1274,7 @@
 
 					free( node ) ;
 
-					ast_log(LOG_NOTICE, "Removed interface '%s' to queue '%s'\n", 
+					ast_log(LOG_NOTICE, "Removed interface '%s' to queue '%s'\n",
 						interface, queuename);
 					res = 0 ;
 				}
@@ -1012,46 +1297,93 @@
 
 
 
+static int parse_list(char *str, char delim,char *alist[]) {
+  char *args,*p;
+  int x = 1;
+  alist[0] = args = str;
+  while((p = strchr(args,delim))) {
+    *p = '\0';
+    p++;
+    alist[x++] = p;
+    args = p;
+    p = NULL;
+  }
+
+  return(x);
+}
+
+
+
 static int aqm_exec(struct ast_channel *chan, void *data)
 {
 	int res=-1;
 	struct localuser *u;
-	char *queuename;
+	char *args,*queuename,*penalty,*skillmask,*interface,*secondary,*p;
+
 	char info[512];
 	char tmpchan[512]="";
-	char *interface=NULL;
 	struct ast_call_queue *q;
-	struct member *save;
+	struct member *save,*member;
 	int found=0 ;
+	int arg_count;
+	struct string_hash_table *arghash = (struct string_hash_table *) init_string_hash("args");
+
+
+
 
 	if (!data) {
-		ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename|optional interface)\n");
+		ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename|penalty|skillmask|optional interface)\n");
 		return -1;
 	}
-	
+
+
 	LOCAL_USER_ADD(u); // not sure if we need this, but better be safe than sorry ;-)
-	
+
+
+	args = queuename = penalty = skillmask = interface = p = NULL;
+
 	/* Parse our arguments XXX Check for failure XXX */
 	strncpy(info, (char *)data, strlen((char *)data) + AST_MAX_EXTENSION-1);
-	queuename = info;
-	if (queuename) {
-		interface = strchr(queuename, '|');
-		if (interface) {
+
+
+
+
+        arg_count = named_args(arghash,info,'|');
+
+	queuename = string_hash_read(arghash,"0");
+	if(queuename) {
+	  penalty = string_hash_read(arghash,"1");
+	  skillmask = string_hash_read(arghash,"2");
+	  interface = string_hash_read(arghash,"3");
+	  secondary = string_hash_read(arghash,"4");
+	}
+	else { /* named args yay! */
+	  queuename = string_hash_read(arghash,"queuename");
+	  penalty = string_hash_read(arghash,"penalty");
+          skillmask = string_hash_read(arghash,"skillmask");
+          interface = string_hash_read(arghash,"interface");
+	  secondary = string_hash_read(arghash,"secondary");
+	}
+
+
+
+
+
+	if(! interface || (interface && !(strlen(interface)))) {
+		strncpy(tmpchan, chan->name, sizeof(tmpchan) - 1);
+		interface = strrchr(tmpchan, '-');
+		if (interface)
 			*interface = '\0';
-			interface++;
-		}
-		else {
-			strncpy(tmpchan, chan->name, sizeof(tmpchan) - 1);
-			interface = strrchr(tmpchan, '-');
-			if (interface)
-				*interface = '\0';
-			interface = tmpchan;
-		}
+		interface = tmpchan;
 	}
 
+	if(secondary && !strlen(secondary))
+		secondary=NULL;
+
+
 	if( ( q = queues) != NULL )
 	{
-		while( q && ( res != 0 ) && (!found) ) 
+		while( q && ( res != 0 ) && (!found) )
 		{
 			ast_mutex_lock(&q->lock);
 			if( strcmp( q->name, queuename) == 0 )
@@ -1061,15 +1393,28 @@
 
 				if( interface_exists( q, interface ) == NULL )
 				{
-					save = q->members ;
-					q->members = create_queue_node( interface ) ;
 
-					if( q->members != NULL ) {
-						q->members->dynamic = 1;
-						q->members->next = save ;
+					save = secondary ? q->secondary_members : q->members ;
+					
+					member = create_queue_node( interface ) ;
+					
+					if( member != NULL ) {
+						member->dynamic = 1;
+						if(penalty)
+						  member->penalty = atoi(penalty);
+
+						member->skillmask = skillmask ? atol(skillmask) : 0;
+
+						member->next = save ;
 					} else
-						q->members = save ;
+						member = save ;
 
+					if(member) {
+						if(secondary)
+							q->secondary_members = member;
+						else
+							q->members = member;
+					}
 					ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", interface, queuename);
 					res = 0 ;
 				}
@@ -1091,57 +1436,312 @@
 }
 
 
+
+static int dynaqueue_exec(struct ast_channel *chan, void *data) {
+  int res=-1;
+  struct localuser *u;
+  char *queuename,*skillmask,*toolong;
+  char info[512];
+  int arg_count;
+  struct string_hash_table *arghash = (struct string_hash_table *) init_string_hash("args");
+
+  struct ast_call_queue *q, *ql, *qn;
+  queuename = skillmask = toolong = NULL;
+  int new = 0;
+  struct member *cur,*memb;
+  char *tmp,*mtmp;
+
+  char i[10];
+  int x;
+
+  cur=memb=NULL;
+
+  if (!data) {
+    ast_log(LOG_WARNING, "DynaQueue requires arguments\n");
+    return res;
+  }
+
+  LOCAL_USER_ADD(u);
+
+  /* Parse our arguments XXX Check for failure XXX */
+  strncpy(info, (char *)data, strlen((char *)data) + AST_MAX_EXTENSION-1);
+
+  arg_count = named_args(arghash,info,'|');
+
+
+  queuename = string_hash_read(arghash,"queuename");
+
+
+
+
+  q = queues;
+
+  while(q) {
+    if (!strcmp(q->name, queuename))
+      break;
+    q = q->next;
+  }
+  
+
+
+  if (!q) {
+    ast_mutex_lock(&qlock);
+    /* Make one then */
+    q = malloc(sizeof(struct ast_call_queue));
+    if (q) {
+      /* Initialize it */
+      memset(q, 0, sizeof(struct ast_call_queue));
+      ast_mutex_init(&q->lock);
+
+      strncpy(q->name,queuename,sizeof(q->name));
+
+      new = 1;
+    } else new = 0;
+  } 
+  else
+    return -1; /* nevermind its here already */
+    
+	
+      if (q) {
+	if (!new)
+	  ast_mutex_lock(&q->lock);
+	/* Re-initialize the queue */
+
+
+	q->dead = 0;
+	q->dynamic = 1;
+	tmp = string_hash_read(arghash,"retry");
+	q->retry =  tmp ? atoi(tmp) : 5;
+	
+	tmp = string_hash_read(arghash,"maxwait");
+	q->maxwait = tmp ? atoi(tmp) : 0;
+	
+	tmp = string_hash_read(arghash,"timeout");
+	q->timeout = tmp ? atoi(tmp) : -1;
+	
+	tmp = string_hash_read(arghash,"maxlen");
+	q->maxlen = tmp ? atoi(tmp) : 0;
+	
+	tmp = string_hash_read(arghash,"chimereps");
+	q->chimereps = tmp ? atoi(tmp) : DEFAULT_CHIMEREPS;
+
+
+	q->chimelistlen = 0;
+	
+	tmp = string_hash_read(arghash,"loopmin");
+	q->loopmin = tmp ? atoi(tmp) : 1;
+	
+	tmp = string_hash_read(arghash,"allow_secondary");
+	q->allow_secondary = tmp ? atoi(tmp) : -1;
+	
+	
+	strncpy(q->q_wait_time,"q_wait_time",sizeof(q->q_wait_time));
+	
+	strncpy(q->q_pos_is,"q_pos_is",sizeof(q->q_pos_is));
+	
+	strncpy(q->q_min,"q_min",sizeof(q->q_min));
+
+
+
+	for(x=0;;x++) {
+	  sprintf(i,"%d",x);
+	  tmp=string_hash_read(arghash,i);
+	  if(!tmp)
+	    break;
+
+	  /* Add a new member */
+	  memb = malloc(sizeof(struct member));
+	  if (memb) {
+	    memset(memb, 0, sizeof(struct member));
+	    strncpy(memb->tech,tmp, sizeof(memb->tech) - 1);
+	    if ((mtmp = strchr(memb->tech, ','))) {
+	      *mtmp = '\0';
+	      mtmp++;
+	      memb->penalty = atoi(mtmp);
+	      if (memb->penalty < 0)
+		memb->penalty = 0;
+	      if ((mtmp = strchr(mtmp, ','))) {
+		*mtmp = '\0';
+		mtmp++;
+		memb->skillmask = atol(mtmp);
+	      }
+	      
+	    }
+	    if ((mtmp = strchr(memb->tech, '/')))
+	      *mtmp = '\0';
+	    if ((mtmp = strchr(tmp, '/'))) {
+	      mtmp++;
+	      strncpy(memb->loc, mtmp, sizeof(memb->loc) - 1);
+	      if ((mtmp = strchr(memb->loc, ',')))
+		*mtmp = '\0';
+	    }
+	    else
+	      ast_log(LOG_WARNING, "No location in dynamic addition\n");
+	  }
+
+	  if(!x) 
+	    cur = q->members = memb;
+	  else 
+	    cur = cur->next = memb;
+
+	}
+	
+
+	tmp = string_hash_read(arghash,"chimelist");
+	if(tmp) {
+	  strncpy(q->chimedata,tmp, sizeof(q->chimedata) - 1);
+	  q->chimelistlen = parse_list(q->chimedata,',',q->chimelist);
+	}
+
+
+
+	tmp = string_hash_read(arghash,"moh");
+	strncpy(q->moh, tmp ? tmp : "default" ,sizeof(q->moh));
+	
+	tmp = string_hash_read(arghash,"announce");
+	if(tmp)
+	  strncpy(q->announce,tmp,sizeof(q->announce));
+	
+	tmp = string_hash_read(arghash,"context");
+	if(tmp)
+	  strncpy(q->context,tmp,sizeof(q->context));
+	
+
+	
+	
+
+	if (!new)
+	  ast_mutex_unlock(&q->lock);
+
+	if (new) {
+	  q->next = queues;
+	  queues = q;
+	}
+
+      }
+  
+  
+  q = queues;
+  ql = NULL;
+  while(q) {
+    qn = q->next;
+    if (q->dead) {
+      if (ql)
+	ql->next = q->next;
+      else
+	queues = q->next;
+      if (!q->count) {
+	free(q);
+      } else
+	ast_log(LOG_WARNING, "XXX Leaking a litttle memory :( XXX\n");
+    } else
+      ql = q;
+    q = qn;
+  }
+  ast_mutex_unlock(&qlock);
+
+
+  
+  return 0;
+}
+
+
 static int queue_exec(struct ast_channel *chan, void *data)
 {
+
+
 	int res=-1;
 	struct localuser *u;
-	char *queuename;
+	char *queuename,*skillmask,*toolong;
 	char info[512];
 	char *options = NULL;
 	char *url = NULL;
 	char *announceoverride = NULL;
-	
+	int arg_count;
+	time_t now;
 	/* Our queue entry */
 	struct queue_ent qe;
-	
+	struct string_hash_table *arghash = (struct string_hash_table *) init_string_hash("args");
+
+
+
+	queuename = skillmask = toolong = NULL;
+
+
+
+
 	if (!data) {
 		ast_log(LOG_WARNING, "Queue requires an argument (queuename|optional timeout|optional URL)\n");
 		return -1;
 	}
-	
+
 	LOCAL_USER_ADD(u);
-	
+
 	/* Parse our arguments XXX Check for failure XXX */
 	strncpy(info, (char *)data, strlen((char *)data) + AST_MAX_EXTENSION-1);
-	queuename = info;
-	if (queuename) {
-		options = strchr(queuename, '|');
-		if (options) {
-			*options = '\0';
-			options++;
-			url = strchr(options, '|');
-			if (url) {
-				*url = '\0';
-				url++;
-				announceoverride = strchr(url, '|');
-				if (announceoverride) {
-					*announceoverride = '\0';
-					announceoverride++;
-				}
-			}
-		}
+
+	/* old way
+	arg_count = parse_list(info,'|',alist);
+	*/
+
+
+	arg_count = named_args(arghash,info,'|');
+	
+
+	queuename = string_hash_read(arghash,"0");
+	if(queuename) {
+	  options = string_hash_read(arghash,"1");
+	  skillmask = string_hash_read(arghash,"2");
+	  toolong = string_hash_read(arghash,"3");
+	  url = string_hash_read(arghash,"4");
+	  announceoverride = string_hash_read(arghash,"5");
+	}
+	else { /* named args */
+	  queuename = string_hash_read(arghash,"queuename");
+	  options = string_hash_read(arghash,"options");
+          skillmask = string_hash_read(arghash,"skillmask");
+          toolong = string_hash_read(arghash,"toolong");
+          url = string_hash_read(arghash,"url");
+          announceoverride = string_hash_read(arghash,"announceoverride");
 	}
-	printf("queue: %s, options: %s, url: %s, announce: %s\n",
-		queuename, options, url, announceoverride);
+
+
+
+
+	if (!skillmask)
+	  skillmask = "0";
+
+
+	printf("queue: %s, options: %s, skillmask: %s toolong: %s url: %s, announce: %s\n",
+		queuename, options, skillmask,toolong, url, announceoverride);
 	/* Setup our queue entry */
 	memset(&qe, 0, sizeof(qe));
 	qe.chan = chan;
+
 	qe.start = time(NULL);
+	qe.toolong = toolong ? atol(toolong) : 0;
+	
+	qe.skillmask = skillmask ? atol(skillmask) : 0;
+
+
+	qe.ok_secondary = 0;
+	qe.chimepos = 0;
+	qe.chimerep = 0;
+
+
 	if (!join_queue(queuename, &qe)) {
 		/* Start music on hold */
 		ast_moh_start(chan, qe.moh);
 		for (;;) {
-			res = wait_our_turn(&qe);
+		  
+
+		  /* let all the calls flood to the try calling staging area in skillbased routing otherwise, get in line*/
+		  res = (qe.parent->strategy == QUEUE_STRATEGY_SKILLBASED) ? 0 : wait_our_turn(&qe);
+
+
+
+
+
 			/* If they hungup, return immediately */
 			if (res < 0) {
 				if (option_verbose > 2) {
@@ -1156,16 +1756,45 @@
 				break;
 		}
 		if (!res) {
-			for (;;) {
-				res = try_calling(&qe, options, announceoverride, url);
-				if (res)
-					break;
-				/* exit after a timeout if 'n' option enabled */
-				if (go_on) {
-					res = 0;
-					break;
-				}
-				res = wait_a_bit(&qe);
+		  /* handle any chimein or position announcement */
+		  res = announce_loop(&qe);
+		  while (res != AST_QUEUE_TIMEOUT) {
+
+
+
+
+		    res = try_calling(&qe, options, announceoverride, url,qe.parent->members);
+		    if (res)
+		      break;
+
+		    time(&now);
+
+		    /* secondary agents */
+
+		    if(qe.ok_secondary !=1 && (qe.parent->allow_secondary >= 0 && (((now - qe.start) > qe.parent->allow_secondary)))) {
+		      qe.ok_secondary = 1;
+		    }
+
+
+		    if(qe.ok_secondary == 1) {
+		      res = try_calling(&qe, options, announceoverride, url,qe.parent->secondary_members);
+		      if (res)
+			break;
+		    }
+
+
+
+		       res = wait_a_bit(&qe);
+		       
+		       if (res == AST_QUEUE_TIMEOUT) {
+			 break;
+		       }
+
+				
+
+
+
+
 				if (res < 0) {
 					if (option_verbose > 2) {
 						ast_verbose(VERBOSE_PREFIX_3 "User disconnected when they almost made it\n");
@@ -1179,7 +1808,7 @@
 		}
 		/* Don't allow return code > 0 */
 		if (res > 0 && res != AST_PBX_KEEPALIVE) {
-			res = 0;	
+			res = 0;
 			ast_moh_stop(chan);
 		}
 		leave_queue(&qe);
@@ -1196,8 +1825,10 @@
 	struct ast_call_queue *q, *ql, *qn;
 	struct ast_config *cfg;
 	char *cat, *tmp;
+
+	
 	struct ast_variable *var;
-	struct member *prev, *cur;
+	struct member *prev, *cur,*sprev;
 	int new;
 	cfg = ast_load("queues.conf");
 	if (!cfg) {
@@ -1205,11 +1836,12 @@
 		return;
 	}
 	ast_mutex_lock(&qlock);
+
 	/* Mark all queues as dead for the moment */
 	q = queues;
 	while(q) {
-		q->dead = 1;
-		q = q->next;
+	  q->dead = 1;
+	  q = q->next;
 	}
 	/* Chug through config file */
 	cat = ast_category_browse(cfg, NULL);
@@ -1235,13 +1867,22 @@
 			} else
 					new = 0;
 			if (q) {
-				if (!new) 
+				if (!new)
 					ast_mutex_lock(&q->lock);
 				/* Re-initialize the queue */
 				q->dead = 0;
 				q->retry = 0;
+				q->maxwait = 0;
 				q->timeout = -1;
+				q->dynamic = 0;
 				q->maxlen = 0;
+				q->chimereps = DEFAULT_CHIMEREPS;
+				q->chimelistlen = 0;
+				q->loopmin = 1;
+                                q->allow_secondary = -1;
+				strncpy(q->q_wait_time,"q_wait_time",sizeof(q->q_wait_time));
+				strncpy(q->q_pos_is,"q_pos_is",sizeof(q->q_pos_is));
+				strncpy(q->q_min,"q_min",sizeof(q->q_min));
 				free_members(q, 0);
 				strcpy(q->moh, "");
 				strcpy(q->announce, "");
@@ -1252,9 +1893,17 @@
 					while(prev->next)
 						prev = prev->next;
 				}
+
+
+				sprev = q->secondary_members;
+				if (sprev) {
+					/* find the end of any dynamic secondary members */
+					while(sprev->next)
+						sprev = sprev->next;
+				}
 				var = ast_variable_browse(cfg, cat);
 				while(var) {
-					if (!strcasecmp(var->name, "member")) {
+					if (!strcasecmp(var->name, "member") || !strcasecmp(var->name, "secondary_member")) {
 						/* Add a new member */
 						cur = malloc(sizeof(struct member));
 						if (cur) {
@@ -1266,32 +1915,69 @@
 								cur->penalty = atoi(tmp);
 								if (cur->penalty < 0)
 									cur->penalty = 0;
+								if ((tmp = strchr(tmp, ','))) {
+								  *tmp = '\0';
+								  tmp++;
+								  cur->skillmask = atol(tmp);
+								}
+
 							}
 							if ((tmp = strchr(cur->tech, '/')))
-								*tmp = '\0';
+							  *tmp = '\0';
 							if ((tmp = strchr(var->value, '/'))) {
 								tmp++;
 								strncpy(cur->loc, tmp, sizeof(cur->loc) - 1);
 								if ((tmp = strchr(cur->loc, ',')))
 									*tmp = '\0';
-							} else
-								ast_log(LOG_WARNING, "No location at line %d of queue.conf\n", var->lineno);
-							if (prev)
-								prev->next = cur;
+							}
 							else
-								q->members = cur;
-							prev = cur;
+							  ast_log(LOG_WARNING, "No location at line %d of queue.conf\n", var->lineno);
+
+
+							if(!strcasecmp(var->name, "member")) {
+							  if (prev)
+							    prev->next = cur;
+							  else
+							    q->members = cur;
+							  prev = cur;
+							}
+							   
+							else {
+							     
+							  if (sprev)
+							    sprev->next = cur;
+							  else
+							    q->secondary_members = cur;
+							  sprev = cur;
+							}
+
 						}
 					} else if (!strcasecmp(var->name, "music")) {
 						strncpy(q->moh, var->value, sizeof(q->moh) - 1);
 					} else if (!strcasecmp(var->name, "announce")) {
 						strncpy(q->announce, var->value, sizeof(q->announce) - 1);
+
+					} else if (!strcasecmp(var->name, "q_min")) {
+						strncpy(q->q_min, var->value, sizeof(q->q_min) - 1);
+					} else if (!strcasecmp(var->name, "q_pos_is")) {
+						strncpy(q->q_pos_is, var->value, sizeof(q->q_pos_is) - 1);
+					} else if (!strcasecmp(var->name, "q_wait_time")) {
+						strncpy(q->q_wait_time, var->value, sizeof(q->q_wait_time) - 1);
 					} else if (!strcasecmp(var->name, "context")) {
 						strncpy(q->context, var->value, sizeof(q->context) - 1);
 					} else if (!strcasecmp(var->name, "timeout")) {
 						q->timeout = atoi(var->value);
+					} else if (!strcasecmp(var->name, "loopmin")) {
+						q->loopmin = atoi(var->value);
 					} else if (!strcasecmp(var->name, "retry")) {
 						q->retry = atoi(var->value);
+					} else if (!strcasecmp(var->name, "allow_secondary")) {
+						q->allow_secondary = atol(var->value);
+					} else if (!strcasecmp(var->name, "chimereps")) {
+						q->chimereps = atoi(var->value) || DEFAULT_CHIMEREPS;
+					} else if (!strcasecmp(var->name, "chimelist")) {
+					  strncpy(q->chimedata, var->value, sizeof(q->chimedata) - 1);
+					  q->chimelistlen = parse_list(q->chimedata,',',q->chimelist);
 					} else if (!strcasecmp(var->name, "maxlen")) {
 						q->maxlen = atoi(var->value);
 					} else if (!strcasecmp(var->name, "strategy")) {
@@ -1311,7 +1997,7 @@
 					q->timeout = DEFAULT_TIMEOUT;
 				if (q->maxlen < 0)
 					q->maxlen = 0;
-				if (!new) 
+				if (!new)
 					ast_mutex_unlock(&q->lock);
 				if (new) {
 					q->next = queues;
@@ -1351,13 +2037,13 @@
 	time_t now;
 	char max[80];
 	char calls[80];
-	
+
 	time(&now);
 	if (argc != 2)
 		return RESULT_SHOWUSAGE;
 	ast_mutex_lock(&qlock);
 	q = queues;
-	if (!q) {	
+	if (!q) {
 		ast_mutex_unlock(&qlock);
 		ast_cli(fd, "No queues.\n");
 		return RESULT_SUCCESS;
@@ -1368,12 +2054,12 @@
 			snprintf(max, sizeof(max), "%d", q->maxlen);
 		else
 			strcpy(max, "unlimited");
-		ast_cli(fd, "%-12.12s has %d calls (max %s) in '%s' strategy\n", q->name, q->count, max, int2strat(q->strategy));
+		ast_cli(fd, "%s has %d calls (max %s) in '%s' strategy; allow secondary after '%ld' seconds\n", q->name, q->count, max, int2strat(q->strategy),q->allow_secondary);
 		if (q->members) {
 			ast_cli(fd, "   Members: \n");
 			for (mem = q->members; mem; mem = mem->next) {
 				if (mem->penalty)
-					snprintf(max, sizeof(max) - 20, " with penalty %d", mem->penalty);
+					snprintf(max, sizeof(max) - 20, " with penalty %d and skillmask %ld", mem->penalty,mem->skillmask);
 				else
 					strcpy(max, "");
 				if (mem->dynamic)
@@ -1385,14 +2071,38 @@
 					strcpy(calls, " has taken no calls yet");
 				ast_cli(fd, "      %s/%s%s%s\n", mem->tech, mem->loc, max, calls);
 			}
-		} else
-			ast_cli(fd, "   No Members\n");
+		} 
+		else
+		  ast_cli(fd, "   No Members\n");
+
+
+		if (q->secondary_members) {
+			ast_cli(fd, "   Secondary Members: \n");
+			for (mem = q->secondary_members; mem; mem = mem->next) {
+				if (mem->penalty)
+					snprintf(max, sizeof(max) - 20, " with penalty %d and skillmask %ld", mem->penalty,mem->skillmask);
+				else
+					strcpy(max, "");
+				if (mem->dynamic)
+					strcat(max, " (dynamic)");
+				if (mem->calls) {
+					snprintf(calls, sizeof(calls), " has taken %d calls (last was %ld secs ago)",
+							mem->calls, (long)(time(NULL) - mem->lastcall));
+				} else
+					strcpy(calls, " has taken no calls yet");
+				ast_cli(fd, "      %s/%s%s%s\n", mem->tech, mem->loc, max, calls);
+			}
+		} 
+		else
+		  ast_cli(fd, "   No Secondary Members\n");
+
+
 		if (q->head) {
 			pos = 1;
 			ast_cli(fd, "   Callers: \n");
-			for (qe = q->head; qe; qe = qe->next) 
-				ast_cli(fd, "      %d. %s (wait: %ld:%2.2ld)\n", pos++, qe->chan->name,
-								(long)(now - qe->start) / 60, (long)(now - qe->start) % 60);
+			for (qe = q->head; qe; qe = qe->next)
+				ast_cli(fd, "      %d. %s (wait: %ld:%2.2ld) skillmask:%ld\n", pos++, qe->chan->name,
+								(long)(now - qe->start) / 60, (long)(now - qe->start) % 60,qe->skillmask);
 		} else
 			ast_cli(fd, "   No Callers\n");
 		ast_cli(fd, "\n");
@@ -1437,21 +2147,22 @@
 					"\r\n",
 						q->name, q->maxlen, q->count,idText);
 #if 0
-		/* Do we care about queue members? */					
-		for (mem = q->members; mem; mem = mem->next) 
+		/* Do we care about queue members? */
+		for (mem = q->members; mem; mem = mem->next)
 			ast_cli(fd, "      %s/%s\n", mem->tech, mem->loc);
-#endif			
+#endif
 		pos = 1;
-		for (qe = q->head; qe; qe = qe->next) 
+		for (qe = q->head; qe; qe = qe->next)
 			ast_cli(s->fd, "Event: QueueMember\r\n"
 				"Queue: %s\r\n"
+				"Skillmask: %ld\r\n"
 				"Position: %d\r\n"
 				"Channel: %s\r\n"
 				"CallerID: %s\r\n"
 				"Wait: %ld\r\n"
 				"%s"
-				"\r\n", 
-					q->name, pos++, qe->chan->name, (qe->chan->callerid ? qe->chan->callerid : ""), (long)(now - qe->start), idText);
+				"\r\n",
+					q->name, qe->skillmask,pos++, qe->chan->name, (qe->chan->callerid ? qe->chan->callerid : ""), (long)(now - qe->start), idText);
 		ast_mutex_unlock(&q->lock);
 		q = q->next;
 	}
@@ -1459,16 +2170,17 @@
 	return RESULT_SUCCESS;
 }
 
-static char show_queues_usage[] = 
+static char show_queues_usage[] =
 "Usage: show queues\n"
 "       Provides summary information on call queues.\n";
 
 static struct ast_cli_entry cli_show_queues = {
-	{ "show", "queues", NULL }, queues_show, 
+	{ "show", "queues", NULL }, queues_show,
 	"Show status of queues", show_queues_usage, NULL };
 
 int unload_module(void)
 {
+
 	STANDARD_HANGUP_LOCALUSERS;
 	ast_cli_unregister(&cli_show_queues);
 	ast_manager_unregister( "Queues" );
@@ -1488,6 +2200,8 @@
 		// [PHM 06/26/03]
 		ast_register_application(app_aqm, aqm_exec, app_aqm_synopsis, app_aqm_descrip) ;
 		ast_register_application(app_rqm, rqm_exec, app_rqm_synopsis, app_rqm_descrip) ;
+		res = ast_register_application(dapp, dynaqueue_exec, dsynopsis, ddescrip);
+
 	}
 	reload_queues();
 	return res;
