[Asterisk-cvs] asterisk/apps app_queue.c,1.72,1.73

markster at lists.digium.com markster at lists.digium.com
Wed Jun 23 16:19:24 CDT 2004


Update of /usr/cvsroot/asterisk/apps
In directory mongoose.digium.com:/tmp/cvs-serv30868/apps

Modified Files:
	app_queue.c 
Log Message:
Merge in-access updates for queue priorities (bug #1821)


Index: app_queue.c
===================================================================
RCS file: /usr/cvsroot/asterisk/apps/app_queue.c,v
retrieving revision 1.72
retrieving revision 1.73
diff -u -d -r1.72 -r1.73
--- app_queue.c	22 Jun 2004 19:32:52 -0000	1.72
+++ app_queue.c	23 Jun 2004 20:05:18 -0000	1.73
@@ -7,6 +7,8 @@
  *
  * Mark Spencer <markster at linux-support.net>
  *
+ * 2004-06-04: Priorities in queues added by inAccess Networks (work funded by Hellas On Line (HOL) www.hol.gr).
+ *
  * These features added by David C. Troy <dave at toad.net>:
  *    - Per-queue holdtime calculation
  *    - Estimated holdtime announcement
@@ -154,7 +156,8 @@
 	char moh[80];			/* Name of musiconhold to be used */
 	char announce[80];		/* Announcement to play for member when call is answered */
 	char context[80];		/* Context when user exits queue */
-	int pos;			/* Where we are in the queue */
+	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_pos;                /* Last time we told the user their position */
 	int opos;			/* Where we started in the queue */
@@ -166,12 +169,12 @@
 };
 
 struct member {
-	char tech[80];			/* Technology */
-	char loc[256];			/* Location */
-	int penalty;			/* Are we a last resort? */
-	int calls;
-	int dynamic;			/* Are we dynamically added? */
-	time_t lastcall;		/* When last successful call was hungup */
+	char tech[80];				/* Technology */
+	char loc[256];				/* Location */
+	int penalty;				/* Are we a last resort? */
+	int calls;					/* Number of calls serviced by this member */
+	int dynamic;				/* Are we dynamically added? */
+	time_t lastcall;			/* When last successful call was hungup */
 	struct member *next;		/* Next member */
 };
 
@@ -238,12 +241,35 @@
 	return -1;
 }
 
+/* Insert the 'new' entry after the 'prev' entry of queue 'q' */
+static inline void insert_entry(struct ast_call_queue *q, 
+					struct queue_ent *prev, struct queue_ent *new, int *pos)
+{
+	struct queue_ent *cur;
+
+	if (!q || !new)
+		return;
+	if (prev) {
+		cur = prev->next;
+		prev->next = new;
+	} else {
+		cur = q->head;
+		q->head = new;
+	}
+	new->next = cur;
+	new->parent = q;
+	new->pos = ++(*pos);
+	new->opos = *pos;
+}
+
 static int join_queue(char *queuename, struct queue_ent *qe)
 {
 	struct ast_call_queue *q;
 	struct queue_ent *cur, *prev = NULL;
 	int res = -1;
 	int pos = 0;
+	int inserted = 0;
+
 	ast_mutex_lock(&qlock);
 	q = queues;
 	while(q) {
@@ -251,32 +277,35 @@
 			/* This is our one */
 			ast_mutex_lock(&q->lock);
 			if (q->members && (!q->maxlen || (q->count < q->maxlen))) {
-				/* There's space for us, put us at the end */
+				/* There's space for us, put us at the right position inside
+				 * the queue. 
+				 * Take into account the priority of the calling user */
+				inserted = 0;
 				prev = NULL;
 				cur = q->head;
 				while(cur) {
+					/* We have higher priority than the current user, enter
+					 * before him, after all the other users with priority
+					 * higher or equal to our priority. */
+					if ((!inserted) && (qe->prio > cur->prio)) {
+						insert_entry(q, prev, qe, &pos);
+						inserted = 1;
+					}
 					cur->pos = ++pos;
 					prev = cur;
 					cur = cur->next;
 				}
-				if (prev)
-					prev->next = qe;
-				else
-					q->head = qe;
-				/* Fix additional pointers and
-				  information  */
-				qe->next = NULL;
-				qe->parent = q;
-				qe->pos = ++pos;
-				qe->opos = pos;
+				/* No luck, join at the end of the queue */
+				if (!inserted)
+					insert_entry(q, prev, qe, &pos);
 				strncpy(qe->moh, q->moh, sizeof(qe->moh));
 				strncpy(qe->announce, q->announce, sizeof(qe->announce));
 				strncpy(qe->context, q->context, sizeof(qe->context));
 				q->count++;
 				res = 0;
 				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 );
+					"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
 ast_log(LOG_NOTICE, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, qe->chan->name, qe->pos );
 #endif
@@ -448,8 +477,8 @@
 
 			/* Take us out of the queue */
 			manager_event(EVENT_FLAG_CALL, "Leave",
-                                 "Channel: %s\r\nQueue: %s\r\nCount: %d\r\n",
-				 qe->chan->name, q->name,  q->count);
+				"Channel: %s\r\nQueue: %s\r\nCount: %d\r\n",
+				qe->chan->name, q->name,  q->count);
 #if 0
 ast_log(LOG_NOTICE, "Queue '%s' Leave, Channel '%s'\n", q->name, qe->chan->name );
 #endif
@@ -565,13 +594,16 @@
 				}
 			} else {
 				/* Ring just the best channel */
-				ast_log(LOG_DEBUG, "Trying '%s/%s' with metric %d\n", best->tech, best->numsubst, best->metric);
+				if (option_debug)
+					ast_log(LOG_DEBUG, "Trying '%s/%s' with metric %d\n", 
+									best->tech, best->numsubst, best->metric);
 				ring_entry(qe, best);
 			}
 		}
 	} while (best && !best->chan);
 	if (!best) {
-		ast_log(LOG_DEBUG, "Nobody left to try ringing in queue\n");
+		if (option_debug)
+			ast_log(LOG_DEBUG, "Nobody left to try ringing in queue\n");
 		return 0;
 	}
 	return 1;
@@ -784,6 +816,26 @@
 	
 }
 
+static int is_our_turn(struct queue_ent *qe)
+{
+	struct queue_ent *ch;
+	int res;
+
+	/* 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 (option_debug)
+			ast_log(LOG_DEBUG, "It's our turn (%s).\n", qe->chan->name);
+		res = 1;
+	} else {
+		if (option_debug)
+			ast_log(LOG_DEBUG, "It's not our turn (%s).\n", qe->chan->name);
+		res = 0;
+	}
+	return res;
+}
+
 static int wait_our_turn(struct queue_ent *qe, int ringing)
 {
 	struct queue_ent *ch;
@@ -796,8 +848,11 @@
 		ch = qe->parent->head;
 
 		/* If we are now at the top of the head, break out */
-		if (qe == ch)
+		if (ch == qe) {
+			if (option_debug)
+				ast_log(LOG_DEBUG, "It's our turn (%s).\n", qe->chan->name);
 			break;
+		}
 
 		/* If we have timed out, break out */
 		if ( qe->queuetimeout ) {
@@ -810,7 +865,6 @@
 		if (qe->parent->announcefrequency && !ringing)
 			say_position(qe);
 
-
 		/* Wait a second before checking again */
 		res = ast_waitfordigit(qe->chan, RECHECK * 1000);
 		if (res)
@@ -919,6 +973,9 @@
 	struct ast_bridge_config config;
 	/* Hold the lock while we setup the outgoing calls */
 	ast_mutex_lock(&qe->parent->lock);
+	if (option_debug)
+		ast_log(LOG_DEBUG, "%s is trying to call a queue member.\n", 
+							qe->chan->name);
 	strncpy(queuename, qe->parent->name, sizeof(queuename) - 1);
 	time(&now);
 	cur = qe->parent->members;
@@ -952,10 +1009,12 @@
 			if ((strchr(options, 'n')) && (now - qe->start >= qe->parent->timeout))
 				*go_on = 1;
 		}
-		if (url) {
-			ast_log(LOG_DEBUG, "Queue with URL=%s_\n", url);
-		} else 
-			ast_log(LOG_DEBUG, "Simple queue (no URL)\n");
+		if (option_debug) {
+			if (url)
+				ast_log(LOG_DEBUG, "Queue with URL=%s_\n", url);
+			else 
+				ast_log(LOG_DEBUG, "Simple queue (no URL)\n");
+		}
 
 		tmp->member = cur;		/* Never directly dereference!  Could change on reload */
 		strncpy(tmp->tech, cur->tech, sizeof(tmp->tech)-1);
@@ -1009,6 +1068,8 @@
 				/* Nobody answered, next please? */
 				res=0;
 		}
+		if (option_debug)
+			ast_log(LOG_DEBUG, "%s: Nobody answered.\n", qe->chan->name);
 		goto out;
 	}
 	if (peer) {
@@ -1078,7 +1139,8 @@
 		/* Drop out of the queue at this point, to prepare for next caller */
 		leave_queue(qe);			
  		if( url && !ast_strlen_zero(url) && ast_channel_supports_html(peer) ) {
- 			ast_log(LOG_DEBUG, "app_queue: sendurl=%s.\n", url);
+			if (option_debug)
+	 			ast_log(LOG_DEBUG, "app_queue: sendurl=%s.\n", url);
  			ast_channel_sendurl( peer, url );
  		}
 		ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "CONNECT", "%ld", (long)time(NULL) - qe->start);
@@ -1382,12 +1444,13 @@
 	char *options = NULL;
 	char *url = NULL;
 	char *announceoverride = NULL;
+	char *user_priority;
+	int prio;
 	char *queuetimeoutstr = NULL;
+
 	/* whether to exit Queue application after the timeout hits */
 	int go_on = 0;
 
-
-
 	/* Our queue entry */
 	struct queue_ent qe;
 	
@@ -1424,29 +1487,49 @@
 						qe.queuetimeout = atoi(queuetimeoutstr);
 					} else {
 						qe.queuetimeout = 0;
+					}
 				}
 			}
 		}
 	}
+
+	/* Get the priority from the variable ${QUEUE_PRIO} */
+	user_priority = pbx_builtin_getvar_helper(chan, "QUEUE_PRIO");
+	if (user_priority) {
+		if (sscanf(user_priority, "%d", &prio) == 1) {
+			if (option_debug)
+				ast_log(LOG_DEBUG, "%s: Got priority %d from ${QUEUE_PRIO}.\n",
+								chan->name, prio);
+		} else {
+			ast_log(LOG_WARNING, "${QUEUE_PRIO}: Invalid value (%s), channel %s.\n",
+							user_priority, chan->name);
+			prio = 0;
+		}
+	} else {
+		if (option_debug)
+			ast_log(LOG_DEBUG, "NO QUEUE_PRIO variable found. Using default.\n");
+		prio = 0;
 	}
 
 	if (options) {
 		if (strchr(options, 'r')) {
 			ringing = 1;
-	  	}
-        }
-
-	printf("queue: %s, options: %s, url: %s, announce: %s, timeout: %d\n",
-		queuename, options, url, announceoverride, qe.queuetimeout);
+		}
+	}
 
+//	if (option_debug) 
+		ast_log(LOG_DEBUG, "queue: %s, options: %s, url: %s, announce: %s, timeout: %d, priority: %d\n",
+				queuename, options, url, announceoverride, qe.queuetimeout, (int)prio);
 
 	qe.chan = chan;
 	qe.start = time(NULL);
+	qe.prio = (int)prio;
 	qe.last_pos_said = 0;
 	qe.last_pos = 0;
 	if (!join_queue(queuename, &qe)) {
 		ast_queue_log(queuename, chan->uniqueid, "NONE", "ENTERQUEUE", "%s|%s", url ? url : "", chan->callerid ? chan->callerid : "");
 		/* Start music on hold */
+check_turns:
 		if (ringing) {
 			ast_indicate(chan, AST_CONTROL_RINGING);
 		} else {              
@@ -1532,7 +1615,15 @@
 					res = 0;
 					break;
 				}
-
+				/* Since this is a priority queue and 
+				 * it is not sure that we are still at the head
+				 * of the queue, go and check for our turn again.
+				 */
+				if (!is_our_turn(&qe)) {
+					ast_log(LOG_DEBUG, "Darn priorities, going back in queue (%s)!\n",
+								qe.chan->name);
+					goto check_turns;
+				}
 			}
 		}
 		/* Don't allow return code > 0 */
@@ -1733,7 +1824,7 @@
 			if (!q->count) {
 				free(q);
 			} else
-				ast_log(LOG_WARNING, "XXX Leaking a litttle memory :( XXX\n");
+				ast_log(LOG_WARNING, "XXX Leaking a little memory :( XXX\n");
 		} else
 			ql = q;
 		q = qn;
@@ -1809,8 +1900,8 @@
 			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);
+				ast_cli(fd, "      %d. %s (wait: %ld:%2.2ld, prio: %d)\n", pos++, qe->chan->name,
+								(long)(now - qe->start) / 60, (long)(now - qe->start) % 60, qe->prio);
 		} else
 			ast_cli(fd, "   No Callers\n");
 		ast_cli(fd, "\n");




More information about the svn-commits mailing list