--- apps/app_queue.c	2009-02-06 12:10:44.000000000 +0100
+++ apps/app_queue.c	2009-02-06 12:14:49.000000000 +0100
@@ -119,7 +119,8 @@
 	QUEUE_STRATEGY_LEASTRECENT,
 	QUEUE_STRATEGY_FEWESTCALLS,
 	QUEUE_STRATEGY_RANDOM,
-	QUEUE_STRATEGY_RRMEMORY
+	QUEUE_STRATEGY_RRMEMORY,
+	QUEUE_STRATEGY_LINEAR
 };
 
 static struct strategy {
@@ -132,6 +133,7 @@
 	{ QUEUE_STRATEGY_FEWESTCALLS, "fewestcalls" },
 	{ QUEUE_STRATEGY_RANDOM, "random" },
 	{ QUEUE_STRATEGY_RRMEMORY, "rrmemory" },
+	{ QUEUE_STRATEGY_LINEAR, "linear" }
 };
 
 #define DEFAULT_RETRY		5
@@ -346,6 +348,8 @@
 	int handled;                        /*!< Whether our call was handled */
 	int pending;                        /*!< Non-zero if we are attempting to call a member */
 	int max_penalty;                    /*!< Limit the members that can take this call to this penalty or lower */
+	int linpos;                         /*!< If using linear strategy, position in queue */
+	int linwrapped;                     /*!< Is the linpos wrapped? */
 	time_t start;                       /*!< When we started holding */
 	time_t expire;                      /*!< When this entry should expire (time out of queue) */
 	struct ast_channel *chan;           /*!< Our channel */
@@ -841,8 +845,16 @@
 	q->eventwhencalled = 0;
 	q->weight = 0;
 	q->timeoutrestart = 0;
-	if (!q->members)
-		q->members = ao2_container_alloc(37, member_hash_fn, member_cmp_fn);
+	if(!q->members) {
+		if(q->strategy == QUEUE_STRATEGY_LINEAR) {
+			/*linear strategy depnds on order, so only use one hash bucket */
+			q->members = ao2_container_alloc(1, member_hash_fn, member_cmp_fn);
+			ast_log(LOG_NOTICE, "Using linear strategy.\n");
+		} else {
+			q->members = ao2_container_alloc(37, member_hash_fn, member_cmp_fn);
+			ast_log(LOG_NOTICE, "Strategy is NOT linear.\n");
+		}
+	}
 	q->membercount = 0;
 	q->found = 1;
 	ast_copy_string(q->sound_next, "queue-youarenext", sizeof(q->sound_next));
@@ -1239,6 +1251,30 @@
 		ast_mutex_lock(&q->lock);
 		clear_queue(q);
 		q->realtime = 1;
+
+		/* manwe & saghul FTW!!*/
+
+		/*Before we initialize the queue, we need to set the strategy, so that linear strategy
+		* will allocate the members properly
+		*/
+		struct ast_variable *tmpvar = NULL; 
+		for (tmpvar = queue_vars; tmpvar; tmpvar = tmpvar->next) {
+			if (!strcasecmp(tmpvar->name, "strategy")) {
+				q->strategy = strat2int(tmpvar->value);
+				if (q->strategy < 0) {
+					ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
+					tmpvar->value, q->name);
+					q->strategy = QUEUE_STRATEGY_RINGALL;
+				}
+				break;
+			}
+		}
+		/* We traversed all variables and didn't find a strategy */
+		if (!tmpvar)
+			q->strategy = QUEUE_STRATEGY_RINGALL;
+
+		/* /manwe & saghul FTW!! */
+
 		AST_LIST_INSERT_HEAD(&queues, q, list);
 	}
 	init_queue(q);		/* Ensure defaults for all parameters not set explicitly. */
@@ -1857,6 +1893,8 @@
 		qe->parent->rrpos++;
 		ast_mutex_unlock(&qe->parent->lock);
 
+		qe->linpos++;
+
 		(*busies)++;
 		return 0;
 	}
@@ -1987,7 +2025,7 @@
 	return ret;
 }
 
-static int store_next(struct queue_ent *qe, struct callattempt *outgoing)
+static int store_next_rr(struct queue_ent *qe, struct callattempt *outgoing)
 {
 	struct callattempt *best = find_best(outgoing);
 
@@ -2011,6 +2049,30 @@
 	return 0;
 }
 
+static int store_next_lin(struct queue_ent *qe, struct callattempt *outgoing)
+{
+	struct callattempt *best = find_best(outgoing);
+
+	if (best) {
+		/* Ring just the best channel */
+		if (option_debug)
+			ast_log(LOG_DEBUG, "Next is '%s' with metric %d\n", best->interface, best->metric);
+		qe->linpos = best->metric % 1000;
+	} else {
+		/* Just increment rrpos */
+		if (qe->linwrapped) {
+			/* No more channels, start over */
+			qe->linpos = 0;
+		} else {
+			/* Prioritize next entry */
+			qe->linpos++;
+		}
+	}
+	qe->linwrapped = 0;
+
+	return 0;
+}
+
 static int say_periodic_announcement(struct queue_ent *qe)
 {
 	int res = 0;
@@ -2553,6 +2615,17 @@
 		}
 		tmp->metric += mem->penalty * 1000000;
 		break;
+	case QUEUE_STRATEGY_LINEAR:
+		if (pos < qe->linpos) {
+			tmp->metric = 1000 + pos;
+		} else {
+			if (pos > qe->linpos)
+				/* Indicate there is another priority */
+				qe->linwrapped = 1;
+			tmp->metric = pos;
+		}
+		tmp->metric += mem->penalty * 1000000;
+		break;
 	case QUEUE_STRATEGY_RANDOM:
 		tmp->metric = ast_random() % 1000;
 		tmp->metric += mem->penalty * 1000000;
@@ -2774,7 +2847,7 @@
 			ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT);
 			break;
 		case 'n':
-			if (qe->parent->strategy == QUEUE_STRATEGY_ROUNDROBIN || qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY)
+			if (qe->parent->strategy == QUEUE_STRATEGY_ROUNDROBIN || qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY || qe->parent->strategy == QUEUE_STRATEGY_LINEAR)
 				(*tries)++;
 			else
 				*tries = qe->parent->membercount;
@@ -2916,7 +2989,10 @@
 	ast_channel_unlock(qe->chan);
 	ast_mutex_lock(&qe->parent->lock);
 	if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY) {
-		store_next(qe, outgoing);
+		store_next_rr(qe, outgoing);
+	}
+	if (qe->parent->strategy == QUEUE_STRATEGY_LINEAR) {
+		store_next_lin(qe, outgoing);
 	}
 	ast_mutex_unlock(&qe->parent->lock);
 	peer = lpeer ? lpeer->chan : NULL;
@@ -4351,6 +4427,23 @@
 						ast_mutex_unlock(&q->lock);
 					continue;
 				}
+				/* manwe & saghul FTW!! */
+
+				/* Due to the fact that the "linear" strategy will have a different allocation
+				* scheme for queue members, we must devise the queue's strategy before other initializations
+				*/
+				const char *tmpvar = NULL;
+				if ((tmpvar = ast_variable_retrieve(cfg, cat, "strategy"))) {
+					q->strategy = strat2int(tmpvar);
+					if (q->strategy < 0) {
+						ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
+						tmpvar, q->name);
+						q->strategy = QUEUE_STRATEGY_RINGALL;
+					}
+				} else
+					q->strategy = QUEUE_STRATEGY_RINGALL; 
+				/* /manwe & saghul FTW!! */
+
 				/* Re-initialize the queue, and clear statistics */
 				init_queue(q);
 				clear_queue(q);
