[asterisk-commits] branch oej/metermaids r8743 - in /team/oej/metermaids: ./ apps/ channels/ utils/

asterisk-commits at lists.digium.com asterisk-commits at lists.digium.com
Thu Jan 26 13:43:57 MST 2006


Author: oej
Date: Thu Jan 26 14:43:49 2006
New Revision: 8743

URL: http://svn.digium.com/view/asterisk?rev=8743&view=rev
Log:
Updates to current trunk

Modified:
    team/oej/metermaids/   (props changed)
    team/oej/metermaids/apps/app_dial.c
    team/oej/metermaids/apps/app_queue.c
    team/oej/metermaids/ast_expr2.fl
    team/oej/metermaids/ast_expr2.y
    team/oej/metermaids/asterisk.c
    team/oej/metermaids/channel.c
    team/oej/metermaids/channels/chan_features.c
    team/oej/metermaids/channels/chan_iax2.c
    team/oej/metermaids/channels/chan_zap.c
    team/oej/metermaids/pbx.c
    team/oej/metermaids/utils/astman.c

Propchange: team/oej/metermaids/
------------------------------------------------------------------------------
--- svnmerge-integrated (original)
+++ svnmerge-integrated Thu Jan 26 14:43:49 2006
@@ -1,1 +1,1 @@
-/branches/1.2:1-7496,7498-8265
+/branches/1.2:1-7496,7498-8741

Modified: team/oej/metermaids/apps/app_dial.c
URL: http://svn.digium.com/view/asterisk/team/oej/metermaids/apps/app_dial.c?rev=8743&r1=8742&r2=8743&view=diff
==============================================================================
--- team/oej/metermaids/apps/app_dial.c (original)
+++ team/oej/metermaids/apps/app_dial.c Thu Jan 26 14:43:49 2006
@@ -652,6 +652,7 @@
 					ast_hangup(o->chan);
 					o->chan = NULL;
 					ast_clear_flag(o, DIAL_STILLGOING);
+					HANDLE_CAUSE(in->hangupcause, in);
 				}
 			}
 			o = o->next;

Modified: team/oej/metermaids/apps/app_queue.c
URL: http://svn.digium.com/view/asterisk/team/oej/metermaids/apps/app_queue.c?rev=8743&r1=8742&r2=8743&view=diff
==============================================================================
--- team/oej/metermaids/apps/app_queue.c (original)
+++ team/oej/metermaids/apps/app_queue.c Thu Jan 26 14:43:49 2006
@@ -114,6 +114,7 @@
 #define DEFAULT_RETRY		5
 #define DEFAULT_TIMEOUT		15
 #define RECHECK			1		/* Recheck every second to see we we're at the top yet */
+#define MAX_PERIODIC_ANNOUNCEMENTS 10 /* The maximum periodic announcements we can have */
 
 #define	RES_OKAY	0		/* Action completed */
 #define	RES_EXISTS	(-1)		/* Entry already exists */
@@ -223,7 +224,7 @@
 
 /*! \brief Persistent Members astdb family */
 static const char *pm_family = "/Queue/PersistentMembers";
-/* The maximum lengh of each persistent member queue database entry */
+/* The maximum length of each persistent member queue database entry */
 #define PM_MAX_LEN 2048
 
 /*! \brief queues.conf [general] option */
@@ -282,7 +283,8 @@
 	int pos;			/*!< Where we are in the queue */
 	int prio;			/*!< Our priority */
 	int last_pos_said;              /*!< Last position we told the user */
-	time_t last_periodic_announce_time;	/*!< The last time we played a periodic anouncement */
+	time_t last_periodic_announce_time;	/*!< The last time we played a periodic announcement */
+	int last_periodic_announce_sound;	/* The last periodic announcement we made */
 	time_t last_pos;                /*!< Last time we told the user their position */
 	int opos;			/*!< Where we started in the queue */
 	int handled;			/*!< Whether our call was handled */
@@ -317,18 +319,18 @@
 	char moh[80];			/*!< Music On Hold class to be used */
 	char announce[80];		/*!< Announcement to play when call is answered */
 	char context[AST_MAX_CONTEXT];	/*!< Exit context */
-		unsigned int monjoin:1;
-		unsigned int dead:1;
-		unsigned int joinempty:2;
-		unsigned int eventwhencalled:1;
-		unsigned int leavewhenempty:2;
-		unsigned int reportholdtime:1;
-		unsigned int wrapped:1;
-		unsigned int timeoutrestart:1;
-		unsigned int announceholdtime:2;
-		unsigned int strategy:3;
-		unsigned int maskmemberstatus:1;
-		unsigned int realtime:1;
+	unsigned int monjoin:1;
+	unsigned int dead:1;
+	unsigned int joinempty:2;
+	unsigned int eventwhencalled:1;
+	unsigned int leavewhenempty:2;
+	unsigned int reportholdtime:1;
+	unsigned int wrapped:1;
+	unsigned int timeoutrestart:1;
+	unsigned int announceholdtime:2;
+	unsigned int strategy:3;
+	unsigned int maskmemberstatus:1;
+	unsigned int realtime:1;
 	int announcefrequency;          /*!< How often to announce their position */
 	int periodicannouncefrequency;	/*!< How often to play periodic announcement */
 	int roundingseconds;            /*!< How many seconds do we round to? */
@@ -347,7 +349,7 @@
 	char sound_seconds[80];         /*!< Sound file: "seconds." (def. queue-seconds) */
 	char sound_thanks[80];          /*!< Sound file: "Thank you for your patience." (def. queue-thankyou) */
 	char sound_reporthold[80];	/*!< Sound file: "Hold time" (def. queue-reporthold) */
-	char sound_periodicannounce[80];/*!< Sound file: Custom announce, no default */
+	char sound_periodicannounce[MAX_PERIODIC_ANNOUNCEMENTS][80];/* Sound files: Custom announce, no default */
 
 	int count;			/*!< How many entries */
 	int maxlen;			/*!< Max number of entries */
@@ -356,18 +358,21 @@
 	int retry;			/*!< Retry calling everyone after this amount of time */
 	int timeout;			/*!< How long to wait for an answer */
 	int weight;                     /*!< Respective weight */
-	
+	int autopause;			/*!< Auto pause queue members if they fail to answer */
+
 	/* Queue strategy things */
 	int rrpos;			/*!< Round Robin - position */
 	int memberdelay;		/*!< Seconds to delay connecting member to caller */
-
+	int autofill;			/*!< Ignore the head call status and ring an available agent */
+	
 	struct member *members;		/*!< Head of the list of members */
 	struct queue_ent *head;		/*!< Head of the list of callers */
-	struct ast_call_queue *next;	/*!< Next call queue */
+	AST_LIST_ENTRY(ast_call_queue) list;	/*!< Next call queue */
 };
 
-static struct ast_call_queue *queues = NULL;
-AST_MUTEX_DEFINE_STATIC(qlock);
+static AST_LIST_HEAD_STATIC(queues, ast_call_queue);
+
+static int set_member_paused(char *queuename, char *interface, int paused);
 
 static void set_queue_result(struct ast_channel *chan, enum queue_result res)
 {
@@ -475,8 +480,8 @@
 	}
 	if (option_debug)
 		ast_log(LOG_DEBUG, "Device '%s/%s' changed to state '%d' (%s)\n", technology, loc, sc->state, devstate2str(sc->state));
-	ast_mutex_lock(&qlock);
-	for (q = queues; q; q = q->next) {
+	AST_LIST_LOCK(&queues);
+	AST_LIST_TRAVERSE(&queues, q, list) {
 		ast_mutex_lock(&q->lock);
 		cur = q->members;
 		while(cur) {
@@ -502,7 +507,7 @@
 		}
 		ast_mutex_unlock(&q->lock);
 	}
-	ast_mutex_unlock(&qlock);
+	AST_LIST_UNLOCK(&queues);
 	free(sc);
 	return NULL;
 }
@@ -514,9 +519,8 @@
 	struct statechange *sc;
 	pthread_t t;
 	pthread_attr_t attr;
-
-	sc = malloc(sizeof(struct statechange) + strlen(dev) + 1);
-	if (sc) {
+	
+	if ((sc = ast_calloc(1, sizeof(*sc) + strlen(dev) + 1))) {
 		sc->state = state;
 		strcpy(sc->dev, dev);
 		pthread_attr_init(&attr);
@@ -535,10 +539,7 @@
 	
 	/* Add a new member */
 
-	cur = malloc(sizeof(struct member));
-
-	if (cur) {
-		memset(cur, 0, sizeof(struct member));
+	if ((cur = ast_calloc(1, sizeof(*cur)))) {
 		cur->penalty = penalty;
 		cur->paused = paused;
 		ast_copy_string(cur->interface, interface, sizeof(cur->interface));
@@ -554,9 +555,7 @@
 {
 	struct ast_call_queue *q;
 
-	q = malloc(sizeof(*q));
-	if (q) {
-		memset(q, 0, sizeof(*q));
+	if ((q = ast_calloc(1, sizeof(*q)))) {
 		ast_mutex_init(&q->lock);
 		ast_copy_string(q->name, queuename, sizeof(q->name));
 	}
@@ -565,6 +564,7 @@
 
 static void init_queue(struct ast_call_queue *q)
 {
+	int i;
 	q->dead = 0;
 	q->retry = DEFAULT_RETRY;
 	q->timeout = -1;
@@ -587,7 +587,10 @@
 	ast_copy_string(q->sound_thanks, "queue-thankyou", sizeof(q->sound_thanks));
 	ast_copy_string(q->sound_lessthan, "queue-less-than", sizeof(q->sound_lessthan));
 	ast_copy_string(q->sound_reporthold, "queue-reporthold", sizeof(q->sound_reporthold));
-	ast_copy_string(q->sound_periodicannounce, "queue-periodic-announce", sizeof(q->sound_periodicannounce));
+	ast_copy_string(q->sound_periodicannounce[0], "queue-periodic-announce", sizeof(q->sound_periodicannounce[0]));
+	for (i=1;i<MAX_PERIODIC_ANNOUNCEMENTS;i++) {
+		q->sound_periodicannounce[i][0]='\0';
+	}
 }
 
 static void clear_queue(struct ast_call_queue *q)
@@ -608,6 +611,9 @@
    extra fields in the tables. */
 static void queue_set_param(struct ast_call_queue *q, const char *param, const char *val, int linenum, int failunknown)
 {
+	int i = 0;
+	char *c, *lastc;
+	char buff[80];
 	if (!strcasecmp(param, "music") || !strcasecmp(param, "musiconhold")) {
 		ast_copy_string(q->moh, val, sizeof(q->moh));
 	} else if (!strcasecmp(param, "announce")) {
@@ -662,8 +668,24 @@
 			q->announceholdtime = ANNOUNCEHOLDTIME_ALWAYS;
 		else
 			q->announceholdtime = 0;
-	 } else if (!strcasecmp(param, "periodic-announce")) {
-		ast_copy_string(q->sound_periodicannounce, val, sizeof(q->sound_periodicannounce));
+	} else if (!strcasecmp(param, "periodic-announce")) {
+		if (strchr(val,'|')) {
+			lastc = (char *)val;
+			while ((c = strchr(lastc,'|'))) {
+				if (i > MAX_PERIODIC_ANNOUNCEMENTS)
+					break;
+				strncpy(buff, lastc, abs(lastc - c));
+				buff[abs(lastc - c)] = '\0';
+				ast_copy_string(q->sound_periodicannounce[i], buff, sizeof(q->sound_periodicannounce[i]));
+				lastc = (c + 1);
+				i++;
+			}
+			if (strlen(lastc)) {
+				ast_copy_string(q->sound_periodicannounce[i], lastc, sizeof(q->sound_periodicannounce[i]));
+			}
+		} else {
+			ast_copy_string(q->sound_periodicannounce[i], val, sizeof(q->sound_periodicannounce[i]));
+		}
 	} else if (!strcasecmp(param, "periodic-announce-frequency")) {
 		q->periodicannouncefrequency = atoi(val);
 	} else if (!strcasecmp(param, "retry")) {
@@ -672,6 +694,10 @@
 			q->retry = DEFAULT_RETRY;
 	} else if (!strcasecmp(param, "wrapuptime")) {
 		q->wrapuptime = atoi(val);
+	} else if (!strcasecmp(param, "autofill")) {
+		q->autofill = ast_true(val);
+	} else if (!strcasecmp(param, "autopause")) {
+		q->autopause = ast_true(val);
 	} else if (!strcasecmp(param, "maxlen")) {
 		q->maxlen = atoi(val);
 		if (q->maxlen < 0)
@@ -761,29 +787,48 @@
 	}
 }
 
+static void free_members(struct ast_call_queue *q, int all)
+{
+	/* Free non-dynamic members */
+	struct member *curm, *next, *prev = NULL;
+
+	for (curm = q->members; curm; curm = next) {
+		next = curm->next;
+		if (all || !curm->dynamic) {
+			if (prev)
+				prev->next = next;
+			else
+				q->members = next;
+			free(curm);
+		} else 
+			prev = curm;
+	}
+}
+
+static void destroy_queue(struct ast_call_queue *q)
+{
+	free_members(q, 1);
+	ast_mutex_destroy(&q->lock);
+	free(q);
+}
 
 /*!\brief Reload a single queue via realtime.
    \return Return the queue, or NULL if it doesn't exist.
-   \note Should be called with the global qlock locked.
-   When found, the queue is returned with q->lock locked. */
+   \note Should be called with the global qlock locked. */
 static struct ast_call_queue *find_queue_by_name_rt(const char *queuename, struct ast_variable *queue_vars, struct ast_config *member_config)
 {
 	struct ast_variable *v;
-	struct ast_call_queue *q, *prev_q;
+	struct ast_call_queue *q;
 	struct member *m, *prev_m, *next_m;
 	char *interface;
 	char *tmp, *tmp_name;
 	char tmpbuf[64];	/* Must be longer than the longest queue param name. */
 
 	/* Find the queue in the in-core list (we will create a new one if not found). */
-	q = queues;
-	prev_q = NULL;
-	while (q) {
+	AST_LIST_TRAVERSE(&queues, q, list) {
 		if (!strcasecmp(q->name, queuename)) {
 			break;
 		}
-		q = q->next;
-		prev_q = q;
 	}
 
 	/* Static queues override realtime. */
@@ -794,6 +839,7 @@
 				ast_mutex_unlock(&q->lock);
 				return NULL;
 			} else {
+				ast_mutex_unlock(&q->lock);
 				return q;
 			}
 		}
@@ -814,13 +860,9 @@
 			/* Delete if unused (else will be deleted when last caller leaves). */
 			if (!q->count) {
 				/* Delete. */
-				if (!prev_q) {
-					queues = q->next;
-				} else {
-					prev_q->next = q->next;
-				}
+				AST_LIST_REMOVE(&queues, q, list);
 				ast_mutex_unlock(&q->lock);
-				free(q);
+				destroy_queue(q);
 			} else
 				ast_mutex_unlock(&q->lock);
 		}
@@ -829,14 +871,12 @@
 
 	/* Create a new queue if an in-core entry does not exist yet. */
 	if (!q) {
-		q = alloc_queue(queuename);
-		if (!q)
+		if (!(q = alloc_queue(queuename)))
 			return NULL;
 		ast_mutex_lock(&q->lock);
 		clear_queue(q);
 		q->realtime = 1;
-		q->next = queues;
-		queues = q;
+		AST_LIST_INSERT_HEAD(&queues, q, list);
 	}
 	init_queue(q);		/* Ensure defaults for all parameters not set explicitly. */
 
@@ -888,13 +928,60 @@
 		m = next_m;
 	}
 
+	ast_mutex_unlock(&q->lock);
+
 	return q;
 }
 
-static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *reason)
+static struct ast_call_queue *load_realtime_queue(char *queuename)
 {
 	struct ast_variable *queue_vars = NULL;
 	struct ast_config *member_config = NULL;
+	struct ast_call_queue *q;
+
+	/* Find the queue in the in-core list first. */
+	AST_LIST_LOCK(&queues);
+	AST_LIST_TRAVERSE(&queues, q, list) {
+		if (!strcasecmp(q->name, queuename)) {
+			break;
+		}
+	}
+	AST_LIST_UNLOCK(&queues);
+
+	if (!q) {
+		/*! \note Load from realtime before taking the global qlock, to avoid blocking all
+		   queue operations while waiting for the DB.
+
+		   This will be two separate database transactions, so we might
+		   see queue parameters as they were before another process
+		   changed the queue and member list as it was after the change.
+		   Thus we might see an empty member list when a queue is
+		   deleted. In practise, this is unlikely to cause a problem. */
+
+		queue_vars = ast_load_realtime("queues", "name", queuename, NULL);
+		if (queue_vars) {
+			member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", queuename, NULL);
+			if (!member_config) {
+				ast_log(LOG_ERROR, "no queue_members defined in your config (extconfig.conf).\n");
+				return NULL;
+			}
+		}
+
+		AST_LIST_LOCK(&queues);
+
+		q = find_queue_by_name_rt(queuename, queue_vars, member_config);
+		if (member_config)
+			ast_config_destroy(member_config);
+		if (queue_vars)
+			ast_variables_destroy(queue_vars);
+
+		AST_LIST_UNLOCK(&queues);
+	}
+	return q;
+}
+
+static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *reason)
+{
 	struct ast_call_queue *q;
 	struct queue_ent *cur, *prev = NULL;
 	int res = -1;
@@ -902,35 +989,12 @@
 	int inserted = 0;
 	enum queue_member_status stat;
 
-	/*! \note Load from realtime before taking the global qlock, to avoid blocking all
-	   queue operations while waiting for the DB.
-
-	   This will be two separate database transactions, so we might
-	   see queue parameters as they were before another process
-	   changed the queue and member list as it was after the change.
-	   Thus we might see an empty member list when a queue is
-	   deleted. In practise, this is unlikely to cause a problem. */
-	queue_vars = ast_load_realtime("queues", "name", queuename, NULL);
-	if (queue_vars) {
-		member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", queuename, NULL);
-		if (!member_config) {
-			ast_log(LOG_ERROR, "no queue_members defined in your config (extconfig.conf).\n");
-			return res;
-		}
-	}
-
-	ast_mutex_lock(&qlock);
-	q = find_queue_by_name_rt(queuename, queue_vars, member_config);
-	/* Note: If found, find_queue_by_name_rt() returns with q->lock locked. */
-	if(member_config)
-		ast_config_destroy(member_config);
-	if(queue_vars)
-		ast_variables_destroy(queue_vars);
-
-	if (!q) {
-		ast_mutex_unlock(&qlock);
+	q = load_realtime_queue(queuename);
+	if (!q)
 		return res;
-	}
+
+	AST_LIST_LOCK(&queues);
+	ast_mutex_lock(&q->lock);
 
 	/* This is our one */
 	stat = get_member_status(q, qe->max_penalty);
@@ -978,50 +1042,8 @@
 #endif
 	}
 	ast_mutex_unlock(&q->lock);
-	ast_mutex_unlock(&qlock);
+	AST_LIST_UNLOCK(&queues);
 	return res;
-}
-
-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;
-	}
-}
-
-static void destroy_queue(struct ast_call_queue *q)
-{
-	struct ast_call_queue *cur, *prev = NULL;
-
-	ast_mutex_lock(&qlock);
-	for (cur = queues; cur; cur = cur->next) {
-		if (cur == q) {
-			if (prev)
-				prev->next = cur->next;
-			else
-				queues = cur->next;
-		} else {
-			prev = cur;
-		}
-	}
-	ast_mutex_unlock(&qlock);
-	free_members(q, 1);
-        ast_mutex_destroy(&q->lock);
-	free(q);
 }
 
 static int play_file(struct ast_channel *chan, char *filename)
@@ -1231,6 +1253,9 @@
 	ast_mutex_unlock(&q->lock);
 	if (q->dead && !q->count) {	
 		/* It's dead and nobody is in it, so kill it */
+		AST_LIST_LOCK(&queues);
+		AST_LIST_REMOVE(&queues, q, list);
+		AST_LIST_UNLOCK(&queues);
 		destroy_queue(q);
 	}
 }
@@ -1305,7 +1330,7 @@
 	
 	/* &qlock and &rq->lock already set by try_calling()
 	 * to solve deadlock */
-	for (q = queues; q; q = q->next) {
+	AST_LIST_TRAVERSE(&queues, q, list) {
 		if (q == rq) /* don't check myself, could deadlock */
 			continue; 
 		ast_mutex_lock(&q->lock);
@@ -1325,7 +1350,6 @@
 		if (found) 
 			break;
 	}
-	ast_mutex_unlock(&qlock);
 	return found;
 }
 
@@ -1570,8 +1594,13 @@
 	if (option_verbose > 2)
 		ast_verbose(VERBOSE_PREFIX_3 "Playing periodic announcement\n");
 
+	/* Check to make sure we have a sound file. If not, reset to the first sound file */
+	if (qe->last_periodic_announce_sound >= MAX_PERIODIC_ANNOUNCEMENTS || !strlen(qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound])) {
+		qe->last_periodic_announce_sound = 0;
+	}
+	
 	/* play the announcement */
-	res = background_file(qe, qe->chan, qe->parent->sound_periodicannounce);
+	res = background_file(qe, qe->chan, qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound]);
 
 	/* Resume Music on Hold */
 	ast_moh_start(qe->chan, qe->moh);
@@ -1579,6 +1608,9 @@
 	/* update last_periodic_announce_time */
 	qe->last_periodic_announce_time = now;
 
+	/* Update the current periodic announcement to the next announcement */
+	qe->last_periodic_announce_sound++;
+	
 	return res;
 }
 
@@ -1615,6 +1647,7 @@
 static struct localuser *wait_for_answer(struct queue_ent *qe, struct localuser *outgoing, int *to, char *digit, int prebusies, int caller_disconnect)
 {
 	char *queue = qe->parent->name;
+	char on[256] = "";
 	struct localuser *o;
 	int found;
 	int numlines;
@@ -1658,6 +1691,7 @@
 					peer = o;
 				}
 			} else if (o->chan && (o->chan == winner)) {
+				ast_copy_string(on, o->member->interface, sizeof(on));
 				if (!ast_strlen_zero(o->chan->call_forward)) {
 					char tmpchan[256]="";
 					char *stuff;
@@ -1707,11 +1741,7 @@
 						if (in->cid.cid_ani) {
 							if (o->chan->cid.cid_ani)
 								free(o->chan->cid.cid_ani);
-							o->chan->cid.cid_ani = malloc(strlen(in->cid.cid_ani) + 1);
-							if (o->chan->cid.cid_ani)
-								strncpy(o->chan->cid.cid_ani, in->cid.cid_ani, strlen(in->cid.cid_ani) + 1);
-							else
-								ast_log(LOG_WARNING, "Out of memory\n");
+							o->chan->cid.cid_ani = ast_strdup(in->cid.cid_ani);
 						}
 						if (o->chan->cid.cid_rdnis) 
 							free(o->chan->cid.cid_rdnis);
@@ -1836,8 +1866,19 @@
 			}
 			ast_frfree(f);
 		}
-		if (!*to && (option_verbose > 2))
-			ast_verbose( VERBOSE_PREFIX_3 "Nobody picked up in %d ms\n", orig);
+		if (!*to) {
+			if (option_verbose > 2)
+				ast_verbose( VERBOSE_PREFIX_3 "Nobody picked up in %d ms\n", orig);
+			if (qe->parent->autopause) {
+				if (!set_member_paused(qe->parent->name, on, 1)) {
+					if (option_verbose > 2)
+						ast_verbose( VERBOSE_PREFIX_3 "Auto-Pausing Queue Member %s in queue %s since they failed to answer.\n", on, qe->parent->name);
+				} else {
+					if (option_verbose > 2)
+						ast_verbose( VERBOSE_PREFIX_3 "Failed to pause Queue Member %s in queue %s!\n", on, qe->parent->name);
+				}
+			}
+		}
 	}
 
 	return peer;
@@ -1852,7 +1893,7 @@
 	/* 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 (ch == qe) {
+	if ((ch == qe) || (qe->parent->autofill)) {
 		if (option_debug)
 			ast_log(LOG_DEBUG, "It's our turn (%s).\n", qe->chan->name);
 		res = 1;
@@ -2050,7 +2091,7 @@
 
 	/* Hold the lock while we setup the outgoing calls */
 	if (use_weight) 
-		ast_mutex_lock(&qlock);
+		AST_LIST_LOCK(&queues);
 	ast_mutex_lock(&qe->parent->lock);
 	if (option_debug)
 		ast_log(LOG_DEBUG, "%s is trying to call a queue member.\n", 
@@ -2063,15 +2104,12 @@
 		announce = announceoverride;
 
 	while(cur) {
-		tmp = malloc(sizeof(*tmp));
-		if (!tmp) {
+		if (!(tmp = ast_calloc(1, sizeof(*tmp)))) {
 			ast_mutex_unlock(&qe->parent->lock);
 			if (use_weight) 
-				ast_mutex_unlock(&qlock);
-			ast_log(LOG_WARNING, "Out of memory\n");
+				AST_LIST_UNLOCK(&queues);
 			goto out;
 		}
-		memset(tmp, 0, sizeof(*tmp));
 		tmp->stillgoing = -1;
 		if (option_debug) {
 			if (url)
@@ -2116,7 +2154,7 @@
 	ring_one(qe, outgoing, &numbusies);
 	ast_mutex_unlock(&qe->parent->lock);
 	if (use_weight) 
-		ast_mutex_unlock(&qlock);
+		AST_LIST_UNLOCK(&queues);
 	lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies, ast_test_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT));
 	ast_mutex_lock(&qe->parent->lock);
 	if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY) {
@@ -2129,7 +2167,7 @@
 		peer = NULL;
 	if (!peer) {
 		if (to) {
-			/* Musta gotten hung up */
+			/* Must gotten hung up */
 			record_abandoned(qe);
 			res = -1;
 		} else {
@@ -2296,7 +2334,7 @@
 			ast_hangup(peer);
 		update_queue(qe->parent, member);
 		if (bridge == 0) 
-			res = 1; /* JDG: bridge successfull, leave app_queue */
+			res = 1; /* JDG: bridge successfully, leave app_queue */
 		else 
 			res = bridge; /* bridge error, stay in the queue */
 	}	
@@ -2326,7 +2364,7 @@
 }
 
 
-/* Dump all members in a specific queue to the databse
+/* Dump all members in a specific queue to the database
  *
  * <pm_family>/<queuename> = <interface>;<penalty>;<paused>[|...]
  *
@@ -2371,8 +2409,8 @@
 	struct member *last_member, *look;
 	int res = RES_NOSUCHQUEUE;
 
-	ast_mutex_lock(&qlock);
-	for (q = queues ; q ; q = q->next) {
+	AST_LIST_LOCK(&queues);
+	AST_LIST_TRAVERSE(&queues, q, list) {
 		ast_mutex_lock(&q->lock);
 		if (!strcmp(q->name, queuename)) {
 			if ((last_member = interface_exists(q, interface))) {
@@ -2406,7 +2444,7 @@
 		}
 		ast_mutex_unlock(&q->lock);
 	}
-	ast_mutex_unlock(&qlock);
+	AST_LIST_UNLOCK(&queues);
 	return res;
 }
 
@@ -2416,45 +2454,46 @@
 	struct member *new_member;
 	int res = RES_NOSUCHQUEUE;
 
-	ast_mutex_lock(&qlock);
-	for (q = queues ; q ; q = q->next) {
+	/* \note Ensure the appropriate realtime queue is loaded.  Note that this
+	 * short-circuits if the queue is already in memory. */
+	q = load_realtime_queue(queuename);
+
+	AST_LIST_LOCK(&queues);
+
+	if (q) {
 		ast_mutex_lock(&q->lock);
-		if (!strcmp(q->name, queuename)) {
-			if (interface_exists(q, interface) == NULL) {
-				new_member = create_queue_member(interface, penalty, paused);
-
-				if (new_member != NULL) {
-					new_member->dynamic = 1;
-					new_member->next = q->members;
-					q->members = new_member;
-					manager_event(EVENT_FLAG_AGENT, "QueueMemberAdded",
-						"Queue: %s\r\n"
-						"Location: %s\r\n"
-						"Membership: %s\r\n"
-						"Penalty: %d\r\n"
-						"CallsTaken: %d\r\n"
-						"LastCall: %d\r\n"
-						"Status: %d\r\n"
-						"Paused: %d\r\n",
-					q->name, new_member->interface, new_member->dynamic ? "dynamic" : "static",
-					new_member->penalty, new_member->calls, (int)new_member->lastcall, new_member->status, new_member->paused);
+		if (interface_exists(q, interface) == NULL) {
+			new_member = create_queue_member(interface, penalty, paused);
+
+			if (new_member != NULL) {
+				new_member->dynamic = 1;
+				new_member->next = q->members;
+				q->members = new_member;
+				manager_event(EVENT_FLAG_AGENT, "QueueMemberAdded",
+					"Queue: %s\r\n"
+					"Location: %s\r\n"
+					"Membership: %s\r\n"
+					"Penalty: %d\r\n"
+					"CallsTaken: %d\r\n"
+					"LastCall: %d\r\n"
+					"Status: %d\r\n"
+					"Paused: %d\r\n",
+				q->name, new_member->interface, new_member->dynamic ? "dynamic" : "static",
+				new_member->penalty, new_member->calls, (int)new_member->lastcall, new_member->status, new_member->paused);
 					
-					if (dump)
-						dump_queue_members(q);
-
-					res = RES_OKAY;
-				} else {
-					res = RES_OUTOFMEMORY;
-				}
+				if (dump)
+					dump_queue_members(q);
+
+				res = RES_OKAY;
 			} else {
-				res = RES_EXISTS;
-			}
-			ast_mutex_unlock(&q->lock);
-			break;
+				res = RES_OUTOFMEMORY;
+			}
+		} else {
+			res = RES_EXISTS;
 		}
 		ast_mutex_unlock(&q->lock);
 	}
-	ast_mutex_unlock(&qlock);
+	AST_LIST_UNLOCK(&queues);
 	return res;
 }
 
@@ -2469,8 +2508,8 @@
 	if (ast_strlen_zero(queuename))
 		ast_queue_log("NONE", "NONE", interface, (paused ? "PAUSEALL" : "UNPAUSEALL"), "%s", "");
 
-	ast_mutex_lock(&qlock);
-	for (q = queues ; q ; q = q->next) {
+	AST_LIST_LOCK(&queues);
+	AST_LIST_TRAVERSE(&queues, q, list) {
 		ast_mutex_lock(&q->lock);
 		if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) {
 			if ((mem = interface_exists(q, interface))) {
@@ -2493,7 +2532,7 @@
 		}
 		ast_mutex_unlock(&q->lock);
 	}
-	ast_mutex_unlock(&qlock);
+	AST_LIST_UNLOCK(&queues);
 
 	if (found)
 		return RESULT_SUCCESS;
@@ -2517,7 +2556,7 @@
 	struct ast_call_queue *cur_queue;
 	char queue_data[PM_MAX_LEN];
 
-	ast_mutex_lock(&qlock);
+	AST_LIST_LOCK(&queues);
 
 	/* Each key in 'pm_family' is the name of a queue */
 	db_tree = ast_db_gettree(pm_family, NULL);
@@ -2525,13 +2564,11 @@
 
 		queue_name = entry->key + strlen(pm_family) + 2;
 
-		cur_queue = queues;
-		while (cur_queue) {
+		AST_LIST_TRAVERSE(&queues, cur_queue, list) {
 			ast_mutex_lock(&cur_queue->lock);
 			if (!strcmp(queue_name, cur_queue->name))
 				break;
 			ast_mutex_unlock(&cur_queue->lock);
-			cur_queue = cur_queue->next;
 		}
 
 		if (!cur_queue) {
@@ -2555,7 +2592,7 @@
 			paused_tok = strsep(&member, ";");
 
 			if (!penalty_tok) {
-				ast_log(LOG_WARNING, "Error parsing persisent member string for '%s' (penalty)\n", queue_name);
+				ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (penalty)\n", queue_name);
 				break;
 			}
 			penalty = strtol(penalty_tok, NULL, 10);
@@ -2584,9 +2621,9 @@
 		}
 	}
 
-	ast_mutex_unlock(&qlock);
+	AST_LIST_UNLOCK(&queues);
 	if (db_tree) {
-		ast_log(LOG_NOTICE, "Queue members sucessfully reloaded from database.\n");
+		ast_log(LOG_NOTICE, "Queue members successfully reloaded from database.\n");
 		ast_db_freetree(db_tree);
 	}
 }
@@ -2607,15 +2644,12 @@
 		return -1;
 	}
 
+	if (!(parse = ast_strdupa(data)))
+		return -1;
+
+	AST_STANDARD_APP_ARGS(args, parse);
+
 	LOCAL_USER_ADD(u);
-
-	if (!(parse = ast_strdupa(data))) {
-		ast_log(LOG_WARNING, "Memory Error!\n");
-		LOCAL_USER_REMOVE(u);
-		return -1;
-	}
-
-	AST_STANDARD_APP_ARGS(args, parse);
 
 	if (args.options) {
 		if (strchr(args.options, 'j'))
@@ -2663,15 +2697,12 @@
 		return -1;
 	}
 
+	if (!(parse = ast_strdupa(data))) 
+		return -1;	
+
+	AST_STANDARD_APP_ARGS(args, parse);
+
 	LOCAL_USER_ADD(u);
-
-	if (!(parse = ast_strdupa(data))) {
-		ast_log(LOG_WARNING, "Memory Error!\n");
-		LOCAL_USER_REMOVE(u);
-		return -1;
-	}
-
-	AST_STANDARD_APP_ARGS(args, parse);
 
 	if (args.options) {
 		if (strchr(args.options, 'j'))
@@ -2721,15 +2752,12 @@
 		return -1;
 	}
 
+	if (!(parse = ast_strdupa(data)))
+		return -1;
+
+	AST_STANDARD_APP_ARGS(args, parse);
+
 	LOCAL_USER_ADD(u);
-
-	if (!(parse = ast_strdupa(data))) {
-		ast_log(LOG_WARNING, "Memory Error!\n");
-		LOCAL_USER_REMOVE(u);
-		return -1;
-	}
-
-	AST_STANDARD_APP_ARGS(args, parse);
 
 	if (ast_strlen_zero(args.interface)) {
 		args.interface = ast_strdupa(chan->name);
@@ -2789,15 +2817,12 @@
 		return -1;
 	}
 
+	if (!(parse = ast_strdupa(data)))
+		return -1;
+
+	AST_STANDARD_APP_ARGS(args, parse);
+
 	LOCAL_USER_ADD(u);
-
-	if (!(parse = ast_strdupa(data))) {
-		ast_log(LOG_WARNING, "Memory Error!\n");
-		LOCAL_USER_REMOVE(u);
-		return -1;
-	}
-
-	AST_STANDARD_APP_ARGS(args, parse);
 
 	if (ast_strlen_zero(args.interface)) {
 		args.interface = ast_strdupa(chan->name);
@@ -2851,22 +2876,24 @@
 	int res=-1;
 	int ringing=0;
 	struct localuser *u;
-	char *queuename;
-	char info[512];
-	char *info_ptr = info;
-	char *options = NULL;
-	char *url = NULL;
-	char *announceoverride = NULL;
 	const char *user_priority;
 	const char *max_penalty_str;
 	int prio;
 	int max_penalty;
-	char *queuetimeoutstr = NULL;
 	enum queue_result reason = QUEUE_UNKNOWN;
 
 	/* whether to exit Queue application after the timeout hits */
 	int go_on = 0;
 
+	char *parse;
+	AST_DECLARE_APP_ARGS(args,
+		 AST_APP_ARG(queuename);
+		 AST_APP_ARG(options);
+		 AST_APP_ARG(url);
+		 AST_APP_ARG(announceoverride);
+		 AST_APP_ARG(queuetimeoutstr);
+	);
+	
 	/* Our queue entry */
 	struct queue_ent qe;
 	
@@ -2874,24 +2901,23 @@
 		ast_log(LOG_WARNING, "Queue requires an argument: queuename[|options[|URL][|announceoverride][|timeout]]\n");
 		return -1;
 	}
+	
+	parse = ast_strdupa(data);
+	if (!parse) {
+		ast_log(LOG_ERROR, "Out of memory!\n");
+		return -1;
+	}
+	AST_STANDARD_APP_ARGS(args, parse);
 
 	LOCAL_USER_ADD(u);
 
 	/* Setup our queue entry */
 	memset(&qe, 0, sizeof(qe));
 	qe.start = time(NULL);
-	
-	/* Parse our arguments XXX Check for failure XXX */
-	ast_copy_string(info, (char *) data, sizeof(info));
-	queuename = strsep(&info_ptr, "|");
-	options = strsep(&info_ptr, "|");
-	url = strsep(&info_ptr, "|");
-	announceoverride = strsep(&info_ptr, "|");
-	queuetimeoutstr = info_ptr;
 
 	/* set the expire time based on the supplied timeout; */
-	if (queuetimeoutstr)
-		qe.expire = qe.start + atoi(queuetimeoutstr);
+	if (args.queuetimeoutstr)
+		qe.expire = qe.start + atoi(args.queuetimeoutstr);
 	else
 		qe.expire = 0;
 
@@ -2928,12 +2954,12 @@
 		max_penalty = 0;
 	}
 
-	if (options && (strchr(options, 'r')))
+	if (args.options && (strchr(args.options, 'r')))
 		ringing = 1;
 
 	if (option_debug)  
 		ast_log(LOG_DEBUG, "queue: %s, options: %s, url: %s, announce: %s, expires: %ld, priority: %d\n",
-			queuename, options, url, announceoverride, (long)qe.expire, prio);
+			args.queuename, args.options, args.url, args.announceoverride, (long)qe.expire, prio);
 
 	qe.chan = chan;
 	qe.prio = prio;
@@ -2941,8 +2967,9 @@
 	qe.last_pos_said = 0;
 	qe.last_pos = 0;
 	qe.last_periodic_announce_time = time(NULL);
-	if (!join_queue(queuename, &qe, &reason)) {
-		ast_queue_log(queuename, chan->uniqueid, "NONE", "ENTERQUEUE", "%s|%s", url ? url : "",
+	qe.last_periodic_announce_sound = 0;
+	if (!join_queue(args.queuename, &qe, &reason)) {
+		ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ENTERQUEUE", "%s|%s", args.url ? args.url : "",
 			      chan->cid.cid_num ? chan->cid.cid_num : "");
 check_turns:
 		if (ringing) {
@@ -2958,9 +2985,9 @@
 			if (res < 0) {
 				/* Record this abandoned call */
 				record_abandoned(&qe);
-				ast_queue_log(queuename, chan->uniqueid, "NONE", "ABANDON", "%d|%d|%ld", qe.pos, qe.opos, (long)time(NULL) - qe.start);
+				 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ABANDON", "%d|%d|%ld", qe.pos, qe.opos, (long)time(NULL) - qe.start);
 				if (option_verbose > 2) {
-					ast_verbose(VERBOSE_PREFIX_3 "User disconnected from queue %s while waiting their turn\n", queuename);
+					ast_verbose(VERBOSE_PREFIX_3 "User disconnected from queue %s while waiting their turn\n", args.queuename);
 					res = -1;
 				}
 				break;
@@ -2968,7 +2995,7 @@
 			if (!res) 
 				break;
 			if (valid_exit(&qe, res)) {
-				ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%s|%d", qe.digits, qe.pos);
+				ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%s|%d", qe.digits, qe.pos);
 				break;
 			}
 		}
@@ -2987,7 +3014,7 @@
                                         record_abandoned(&qe);
 					reason = QUEUE_TIMEOUT;
 					res = 0;
-					ast_queue_log(queuename, chan->uniqueid,"NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
+					ast_queue_log(args.queuename, chan->uniqueid,"NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
 					break;
 				}
 
@@ -2996,7 +3023,7 @@
 					if (qe.parent->announcefrequency && !ringing)
 						res = say_position(&qe);
 					if (res && valid_exit(&qe, res)) {
-						ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%s|%d", qe.digits, qe.pos);
+						 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%s|%d", qe.digits, qe.pos);
 						break;
 					}
 
@@ -3008,20 +3035,21 @@
 					res = say_periodic_announcement(&qe);
 
 				if (res && valid_exit(&qe, res)) {
-					ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%c|%d", res, qe.pos);
+					ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%c|%d", res, qe.pos);
 					break;
 				}
 
 				/* Try calling all queue members for 'timeout' seconds */
-				res = try_calling(&qe, options, announceoverride, url, &go_on);
+				res = try_calling(&qe, args.options, args.announceoverride, args.url, &go_on);
+
 				if (res) {
 					if (res < 0) {
 						if (!qe.handled) {
 							record_abandoned(&qe);
-							ast_queue_log(queuename, chan->uniqueid, "NONE", "ABANDON", "%d|%d|%ld", qe.pos, qe.opos, (long)time(NULL) - qe.start);
+							ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ABANDON", "%d|%d|%ld", qe.pos, qe.opos, (long)time(NULL) - qe.start);
 						}
 					} else if (res > 0)
-						ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%s|%d", qe.digits, qe.pos);
+						 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%s|%d", qe.digits, qe.pos);
 					break;
 				}
 
@@ -3048,7 +3076,7 @@
 					record_abandoned(&qe);
 					reason = QUEUE_TIMEOUT;
 					res = 0;
-					ast_queue_log(queuename, chan->uniqueid,"NONE", "EXITWITHTIMEOUT", "%d", qe.pos);	
+					ast_queue_log(args.queuename, chan->uniqueid,"NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
 					break;
 				}
 
@@ -3056,15 +3084,15 @@
 				res = wait_a_bit(&qe);
 				if (res < 0) {
 					record_abandoned(&qe);
-					ast_queue_log(queuename, chan->uniqueid, "NONE", "ABANDON", "%d|%d|%ld", qe.pos, qe.opos, (long)time(NULL) - qe.start);
+					ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ABANDON", "%d|%d|%ld", qe.pos, qe.opos, (long)time(NULL) - qe.start);
 					if (option_verbose > 2) {
-						ast_verbose(VERBOSE_PREFIX_3 "User disconnected from queue %s when they almost made it\n", queuename);
+						ast_verbose(VERBOSE_PREFIX_3 "User disconnected from queue %s when they almost made it\n", args.queuename);
 						res = -1;
 					}
 					break;
 				}
 				if (res && valid_exit(&qe, res)) {
-					ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%s|%d", qe.digits, qe.pos);
+					ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%s|%d", qe.digits, qe.pos);
 					break;
 				}
 				/* exit after 'timeout' cycle if 'n' option enabled */
@@ -3073,7 +3101,7 @@
 						ast_verbose(VERBOSE_PREFIX_3 "Exiting on time-out cycle\n");
 						res = -1;
 					}
-					ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
+					ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
                                         record_abandoned(&qe);
 					reason = QUEUE_TIMEOUT;
 					res = 0;
@@ -3105,7 +3133,7 @@
 		if (reason != QUEUE_UNKNOWN)
 			set_queue_result(chan, reason);
 	} else {
-		ast_log(LOG_WARNING, "Unable to join queue '%s'\n", queuename);
+		ast_log(LOG_WARNING, "Unable to join queue '%s'\n", args.queuename);
 		set_queue_result(chan, reason);
 		res = 0;
 	}
@@ -3120,27 +3148,27 @@
 	struct localuser *u;
 	struct member *m;
 
-	LOCAL_USER_ACF_ADD(u);
 
 	ast_copy_string(buf, "0", len);
 	
 	if (ast_strlen_zero(data)) {
-		ast_log(LOG_ERROR, "QUEUEAGENTCOUNT requires an argument: queuename\n");
-		LOCAL_USER_REMOVE(u);
+		ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
 		return buf;
 	}
 
-	ast_mutex_lock(&qlock);
+	LOCAL_USER_ACF_ADD(u);
+	
+	AST_LIST_LOCK(&queues);
 
 	/* Find the right queue */
-	for (q = queues; q; q = q->next) {
+	AST_LIST_TRAVERSE(&queues, q, list) {
 		if (!strcasecmp(q->name, data)) {
 			ast_mutex_lock(&q->lock);
 			break;
 		}
 	}
 
-	ast_mutex_unlock(&qlock);
+	AST_LIST_UNLOCK(&queues);
 
 	if (q) {
 		for (m = q->members; m; m = m->next) {
@@ -3157,16 +3185,90 @@
 	return buf;
 }
 
+static char *queue_function_queuememberlist(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
+{
+	struct localuser *u;
+	struct ast_call_queue *q;
+	struct member *m;
+
+	/* Ensure an otherwise empty list doesn't return garbage */
+	buf[0] = '\0';
+
+	if (ast_strlen_zero(data)) {
+		ast_log(LOG_ERROR, "QUEUE_MEMBER_LIST requires an argument: queuename\n");
+		return buf;
+	}
+	
+	LOCAL_USER_ACF_ADD(u);
+
+	AST_LIST_LOCK(&queues);
+
+	/* Find the right queue */
+	AST_LIST_TRAVERSE(&queues, q, list) {
+		if (!strcasecmp(q->name, data)) {
+			ast_mutex_lock(&q->lock);
+			break;
+		}
+	}
+
+	AST_LIST_UNLOCK(&queues);
+
+	if (q) {
+		int buflen = 0, count = 0;
+		for (m = q->members; m; m = m->next) {
+			/* strcat() is always faster than printf() */
+			if (count++) {
+				strncat(buf + buflen, ",", len - buflen - 1);
+				buflen++;
+			}
+			strncat(buf + buflen, m->interface, len - buflen - 1);
+			buflen += strlen(m->interface);
+			/* Safeguard against overflow (negative length) */
+			if (buflen >= len - 2) {
+				ast_log(LOG_WARNING, "Truncating list\n");
+				break;
+			}
+		}
+		ast_mutex_unlock(&q->lock);
+	}
+
+	/* We should already be terminated, but let's make sure. */
+	buf[len - 1] = '\0';
+	LOCAL_USER_REMOVE(u);
+	return buf;
+}
+
 static struct ast_custom_function queueagentcount_function = {
 	.name = "QUEUEAGENTCOUNT",
 	.synopsis = "Count number of agents answering a queue",
 	.syntax = "QUEUEAGENTCOUNT(<queuename>)",
+	.desc =
+"Returns the number of members currently associated with the specified queue.\n"
+"This function is deprecated.  You should use QUEUE_MEMBER_COUNT() instead.\n",
 	.read = queue_function_qac,
 };
 
+static struct ast_custom_function queuemembercount_function = {
+	.name = "QUEUE_MEMBER_COUNT",
+	.synopsis = "Count number of members answering a queue",
+	.syntax = "QUEUE_MEMBER_COUNT(<queuename>)",
+	.desc =
+"Returns the number of members currently associated with the specified queue.\n",
+	.read = queue_function_qac,
+};
+
+static struct ast_custom_function queuememberlist_function = {
+	.name = "QUEUE_MEMBER_LIST",
+	.synopsis = "Returns a list of interfaces on a queue",
+	.syntax = "QUEUE_MEMBER_LIST(<queuename>)",
+	.desc =
+"Returns a comma-separated list of members associated with the specified queue.\n",
+	.read = queue_function_queuememberlist,
+};
+
 static void reload_queues(void)
 {
-	struct ast_call_queue *q, *ql, *qn;
+	struct ast_call_queue *q;
 	struct ast_config *cfg;
 	char *cat, *tmp;
 	struct ast_variable *var;
@@ -3182,13 +3284,11 @@
 		return;
 	}
 	memset(interface, 0, sizeof(interface));
-	ast_mutex_lock(&qlock);
+	AST_LIST_LOCK(&queues);
 	use_weight=0;
 	/* Mark all queues as dead for the moment */
-	q = queues;
-	while(q) {
+	AST_LIST_TRAVERSE(&queues, q, list) {
 		q->dead = 1;
-		q = q->next;
 	}
 	/* Chug through config file */
 	cat = ast_category_browse(cfg, NULL);
@@ -3200,15 +3300,15 @@
 				queue_persistent_members = ast_true(general_val);
 		} else {	/* Define queue */
 			/* Look for an existing one */
-			q = queues;
-			while(q) {
+			AST_LIST_TRAVERSE(&queues, q, list) {
 				if (!strcmp(q->name, cat))
 					break;
-				q = q->next;
 			}
 			if (!q) {
 				/* Make one then */
-				q = alloc_queue(cat);
+				if (!(q = alloc_queue(cat))) {

[... 656 lines stripped ...]


More information about the asterisk-commits mailing list