5c5
<  * 
---
>  *
37c37
< 
---
> #include <asthash.h>
39a40,41
> #define DEFAULT_CHIMEREPS               20
> #define AST_QUEUE_TIMEOUT               100
44a47,48
> #define QUEUE_STRATEGY_SKILLBASED       5
> #define MAX_CHIMELIST                   40
54a59
> 	{ QUEUE_STRATEGY_SKILLBASED, "skillbased" }
63a69,70
> static char *dapp = "DynaQueue";
> static char *dsynopsis = "Build a Queue on the fly";
66a74,77
> static char *ddescrip =
> "  DynaQueue \n"
> ;
> 
68c79
< "  Queue(queuename[|options[|URL][|announceoverride]]):\n"
---
> "  Queue(queuename[|options[|skillmask][|toolong][|URL][|announceoverride]]):\n"
69a81,82
> "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"
78d90
< "      'n' -- no retries on the timeout; will exit this application and go to the next step.\n"
88c100
< "   AddQueueMember(queuename[|interface]):\n"
---
> "   AddQueueMember(queuename[|penalty][|skillmask][|interface]):\n"
90a103
> ""
92c105,107
< "";
---
> "Example: AddQueueMember(techsupport|100|SIP/3001)\n"
> "skillmask is a bitmask representing the skills of the agent.\n";
> 
103,104c118
< /* whether to exit Queue application after the timeout hits */
< static int go_on = 0;
---
> 
135c149,154
< 	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 */
143a163
>         long skillmask;                         /* skill bitmask */
151c171
< 	ast_mutex_t	lock;	
---
> 	ast_mutex_t	lock;
160d179
< 
161a181
>         int dynamic;                            /* Whether this queue is dynamic or not */
162a183,192
>         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;
164c194
< 	
---
> 
166c196
< 	
---
> 
170a201
> 	struct member *secondary_members;	/* Member channels to be tried */
197a229,253
> 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++;
>     
>   }
> }
> 
201c257
< 	struct queue_ent *cur, *prev = NULL;
---
> 	struct queue_ent *cur, *prev= NULL;
203a260,261
> 
> 
210c268,270
< 			if (q->members && (!q->maxlen || (q->count < q->maxlen))) {
---
> 
> 
> 			if ((q->members || q->secondary_members) && (!q->maxlen || (q->count < q->maxlen))) {
215,217c275,277
< 					cur->pos = ++pos;
< 					prev = cur;
< 					cur = cur->next;
---
> 				  cur->pos = ++pos;
> 				  prev = cur;
> 				  cur = cur->next;
230a291,292
> 				qe->chimepos = 0;
> 				qe->chimerep = 0;
233c295,301
< 				manager_event(EVENT_FLAG_CALL, "Join", 
---
> 
> 				
> 				
> 				
> 
> 
> 				manager_event(EVENT_FLAG_CALL, "Join",
252,266c320,350
< 	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;
>   }
>   
325c409
< 	if (q->dead && !q->count) {	
---
> 	if (q->dead && !q->count) {
353c437
< #endif			
---
> #endif
469c553
< 	
---
> 
552c636
< #endif								
---
> #endif
606c690
< 	
---
> 
608a693,799
> 
> 
> 
> 
> 
> 
> 
> 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 % 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;
> }
> 
> 
612a804,806
> 	time_t now;
> 	
> 	
614,622c808,829
< 		/* 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)
> 
> 	  /* Wait a second before checking again */
> 	  res = ast_waitfordigit(qe->chan, RECHECK * 1000);
> 	  if (res)
> 	    break;
647a855,856
>   int yes=0;
> 
648a858,877
> 
> 
> 	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;
> 
697c926
< 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)
713a943,944
> 
> 
714a946
> 
716c948
< 	cur = qe->parent->members;
---
> 	cur = members;
721a954,955
> 
> 
725d958
< 			ast_mutex_unlock(&qe->parent->lock);
744,745d976
< 			if (strchr(options, 'n'))
< 				go_on = 1;
749c980
< 		} else 
---
> 		} else
765,771c996,1006
< 		/* 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)) {
772a1008,1011
> 		      }
> 		    }
> 		    
> 		    cur = cur->next;
774d1012
< 		cur = cur->next;
775a1014,1018
> 
> 
> 
> 
> 
781a1025
> 
797a1042
> 
802c1047
< 		   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
807c1052
< 		}			
---
> 		}
817a1063
> 		
820a1067,1073
> 
> 			if (!res2)
> 			  res2 = ast_streamfile(peer, "agent_beep", peer->language);
> 			if (!res2)
> 			  res2 = ast_waitstream(peer, "");
> 
> 
824a1078,1079
> 
> 
832a1088
> 
844c1100
< 		leave_queue(qe);			
---
> 		leave_queue(qe);
849a1106
> 
851a1109
> 
857c1115
< 	}	
---
> 	}
865,867c1123,1149
< 	/* 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;
872c1154
< static struct member * interface_exists( struct ast_call_queue * q, char * interface )
---
> static struct member * interface_exists( struct ast_call_queue * q, char * interface , int secondary)
880c1162,1165
< 		mem = q->members ;
---
> 		if(secondary)
> 			mem = q->secondary_members ;
> 		else
> 			mem = q->members ;
891a1177,1181
> 
> 
> 
> 
> 
902c1192
< 	
---
> 
928c1218
< 	struct member * node ;
---
> 	struct member * node;
934c1224,1226
< 	int found=0 ;
---
> 	int found=0,arg_count=0;
> 	struct string_hash_table *arghash = (struct string_hash_table *) init_string_hash("args");
> 	char *secondary=NULL;
940c1232,1234
< 	
---
> 
> 
> 
942c1236
< 	
---
> 
945,948c1239,1257
< 	queuename = info;
< 	if (queuename) {
< 		interface = strchr(queuename, '|');
< 		if (interface) {
---
> 
> 	arg_count = named_args(arghash,info,'|');
> 	
> 	queuename = string_hash_read(arghash,"0");
>      if(queuename) {
> 		interface = string_hash_read(arghash,"1");
> 		secondary = string_hash_read(arghash,"2");
> 	}
> 	else {
> 		queuename = string_hash_read(arghash,"queuename");
> 		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)
950,958c1259
< 			interface++;
< 		}
< 		else {
< 			strncpy(tmpchan, chan->name, sizeof(tmpchan) - 1);
< 			interface = strrchr(tmpchan, '-');
< 			if (interface)
< 				*interface = '\0';
< 			interface = tmpchan;
< 		}
---
> 		interface = tmpchan;
959a1261,1264
> 	
> 	if(secondary && !strlen(secondary))
>           secondary=NULL;
> 
963c1268
< 		while( q && ( res != 0 ) && (!found) ) 
---
> 		while( q && ( res != 0 ) && (!found) )
971,973c1276
< 				if( ( node = interface_exists( q, interface ) ) != NULL )
< 				{
< 					if( ( look = q->members ) == node )
---
> 				if( ( node = interface_exists( q, interface,secondary ?1:0 ) ) != NULL )
975,981c1278
< 						// 1st
< 						q->members = node->next;
< 					}
< 					else
< 					{
< 						while( look != NULL )
< 							if( look->next == node )
---
> 						if( ( look = secondary ? q->secondary_members  : q->members ) == node )
983,984c1280,1292
< 								look->next = node->next ;
< 								break ;
---
> 								// 1st
> 								secondary ? q->secondary_members  : q->members = node->next;
> 							}
> 						else
> 							{
> 								while( look != NULL )
> 									if( look->next == node )
> 										{
> 											look->next = node->next ;
> 											break ;
> 										}
> 									else
> 										look = look->next ;
986,988d1293
< 							else
< 								look = look->next ;
< 					}
990c1295,1300
< 					free( node ) ;
---
> 						free( node ) ;
> 
> 						ast_log(LOG_NOTICE, "Removed interface '%s' to queue '%s'\n",
> 							   interface, queuename);
> 						res = 0 ;
> 					}
992,995d1301
< 					ast_log(LOG_NOTICE, "Removed interface '%s' to queue '%s'\n", 
< 						interface, queuename);
< 					res = 0 ;
< 				}
1014a1321,1337
> 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);
> }
> 
> 
> 
1019c1342,1343
< 	char *queuename;
---
> 	char *args,*queuename,*penalty,*skillmask,*interface,*secondary,*p;
> 
1022d1345
< 	char *interface=NULL;
1024c1347
< 	struct member *save;
---
> 	struct member *save,*member;
1025a1349,1353
> 	int arg_count;
> 	struct string_hash_table *arghash = (struct string_hash_table *) init_string_hash("args");
> 
> 
> 
1028c1356
< 		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");
1031c1359,1360
< 	
---
> 
> 
1033c1362,1365
< 	
---
> 
> 
> 	args = queuename = penalty = skillmask = interface = p = NULL;
> 
1036,1039c1368,1396
< 	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)
1041,1049c1398
< 			interface++;
< 		}
< 		else {
< 			strncpy(tmpchan, chan->name, sizeof(tmpchan) - 1);
< 			interface = strrchr(tmpchan, '-');
< 			if (interface)
< 				*interface = '\0';
< 			interface = tmpchan;
< 		}
---
> 		interface = tmpchan;
1051a1401,1404
> 	if(secondary && !strlen(secondary))
> 		secondary=NULL;
> 
> 
1054c1407
< 		while( q && ( res != 0 ) && (!found) ) 
---
> 		while( q && ( res != 0 ) && (!found) )
1062c1415
< 				if( interface_exists( q, interface ) == NULL )
---
> 				if( interface_exists( q, interface,secondary ?1:0 ) == NULL )
1064,1065d1416
< 					save = q->members ;
< 					q->members = create_queue_node( interface ) ;
1067,1069c1418,1429
< 					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 ;
1071c1431
< 						q->members = save ;
---
> 						member = save ;
1072a1433,1438
> 					if(member) {
> 						if(secondary)
> 							q->secondary_members = member;
> 						else
> 							q->members = member;
> 					}
1093a1460,1669
> 
> 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;
> }
> 
> 
1095a1672,1673
> 
> 
1098c1676
< 	char *queuename;
---
> 	char *queuename,*skillmask,*toolong;
1103c1681,1682
< 	
---
> 	int arg_count;
> 	time_t now;
1106c1685,1693
< 	
---
> 	struct string_hash_table *arghash = (struct string_hash_table *) init_string_hash("args");
> 
> 
> 
> 	queuename = skillmask = toolong = NULL;
> 
> 
> 
> 
1111c1698
< 	
---
> 
1113c1700
< 	
---
> 
1116,1132c1703,1718
< 	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");
1134,1135c1720,1737
< 	printf("queue: %s, options: %s, url: %s, announce: %s\n",
< 		queuename, options, url, announceoverride);
---
> 	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");
> 	}
> 
> 
> 
> 
> 	if (!skillmask)
> 	  skillmask = "0";
> 
> 
> 	printf("queue: %s, options: %s, skillmask: %s toolong: %s url: %s, announce: %s\n",
> 		queuename, options, skillmask,toolong, url, announceoverride);
1138a1741
> 
1139a1743,1752
> 	qe.toolong = toolong ? atol(toolong) : 0;
> 	
> 	qe.skillmask = skillmask ? atol(skillmask) : 0;
> 
> 
> 	qe.ok_secondary = 0;
> 	qe.chimepos = 0;
> 	qe.chimerep = 0;
> 
> 
1144c1757,1765
< 			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);
> 
> 
> 
> 
> 
1159,1168c1780,1820
< 			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;
> 		       }
> 
> 				
> 
> 
> 
> 
1182c1834
< 			res = 0;	
---
> 			res = 0;
1198a1851,1852
> 
> 	
1200c1854
< 	struct member *prev, *cur;
---
> 	struct member *prev, *cur,*sprev;
1207a1862
> 
1211,1212c1866,1867
< 		q->dead = 1;
< 		q = q->next;
---
> 	  q->dead = 1;
> 	  q = q->next;
1238c1893
< 				if (!new) 
---
> 				if (!new)
1242a1898
> 				q->maxwait = 0;
1243a1900
> 				q->dynamic = 0;
1244a1902,1908
> 				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));
1254a1919,1926
> 
> 
> 				sprev = q->secondary_members;
> 				if (sprev) {
> 					/* find the end of any dynamic secondary members */
> 					while(sprev->next)
> 						sprev = sprev->next;
> 				}
1257c1929
< 					if (!strcasecmp(var->name, "member")) {
---
> 					if (!strcasecmp(var->name, "member") || !strcasecmp(var->name, "secondary_member")) {
1268a1941,1946
> 								if ((tmp = strchr(tmp, ','))) {
> 								  *tmp = '\0';
> 								  tmp++;
> 								  cur->skillmask = atol(tmp);
> 								}
> 
1271c1949
< 								*tmp = '\0';
---
> 							  *tmp = '\0';
1277,1280c1955
< 							} else
< 								ast_log(LOG_WARNING, "No location at line %d of queue.conf\n", var->lineno);
< 							if (prev)
< 								prev->next = cur;
---
> 							}
1282,1283c1957,1976
< 								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;
> 							}
> 
1288a1982,1988
> 
> 					} 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);
1292a1993,1994
> 					} else if (!strcasecmp(var->name, "loopmin")) {
> 						q->loopmin = atoi(var->value);
1294a1997,2003
> 					} else if (!strcasecmp(var->name, "allow_secondary")) {
> 						q->allow_secondary = atol(var->value);
> 					} else if (!strcasecmp(var->name, "chimereps")) {
> 						q->chimereps = atoi(var->value) ? 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);
1314c2023
< 				if (!new) 
---
> 				if (!new)
1354c2063
< 	
---
> 
1360c2069
< 	if (!q) {	
---
> 	if (!q) {
1371c2080
< 		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);
1376c2085
< 					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);
1388,1389c2097,2122
< 		} 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");
> 
> 
1393,1395c2126,2128
< 			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);
1440,1441c2173,2174
< 		/* 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)
1443c2176
< #endif			
---
> #endif
1445c2178
< 		for (qe = q->head; qe; qe = qe->next) 
---
> 		for (qe = q->head; qe; qe = qe->next)
1447a2181
> 				"Skillmask: %ld\r\n"
1453,1454c2187,2188
< 				"\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);
1462c2196
< static char show_queues_usage[] = 
---
> static char show_queues_usage[] =
1467c2201
< 	{ "show", "queues", NULL }, queues_show, 
---
> 	{ "show", "queues", NULL }, queues_show,
1471a2206
> 
1490a2226,2227
> 		res = ast_register_application(dapp, dynaqueue_exec, dsynopsis, ddescrip);
> 
