From 1fb2eaabf39561a716a7201bbfbb734a381809ea Mon Sep 17 00:00:00 2001
From: Mark Spencer <markster@digium.com>
Date: Sat, 2 Aug 2003 21:10:06 +0000
Subject: [PATCH] Implement remaining queue strategies, ADSI fixes, and queue
 config updates

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@1252 65c4cc65-6c06-0410-ace0-fbb531ad65f3
---
 CHANGES                    |  2 ++
 apps/app_queue.c           | 70 +++++++++++++++++++++++++++++++-------
 apps/app_voicemail2.c      | 31 ++++++++++++++++-
 configs/queues.conf.sample |  4 +--
 4 files changed, 91 insertions(+), 16 deletions(-)

diff --git a/CHANGES b/CHANGES
index b02852d298..df2fecdef5 100755
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,5 @@
+ -- Merge voicemail enhancements (app_voicemail2)
+ -- Add multiple queueing strategies
  -- Merge support for 'T'
  -- Allow pending agent calling (Agent/:1)
  -- Add groupings to agents.conf
diff --git a/apps/app_queue.c b/apps/app_queue.c
index 6fec751a2c..cddf31165a 100755
--- a/apps/app_queue.c
+++ b/apps/app_queue.c
@@ -111,7 +111,6 @@ struct localuser {
 	char numsubst[256];
 	char tech[40];
 	int stillgoing;
-	int penalty;
 	int metric;
 	int allowredirect_in;
 	int allowredirect_out;
@@ -119,6 +118,7 @@ struct localuser {
 	int musiconhold;
 	int dataquality;
 	int allowdisconnect;
+	struct member *member;
 	struct localuser *next;
 };
 
@@ -139,7 +139,8 @@ struct member {
 	char tech[80];				/* Technology */
 	char loc[256];				/* Location */
 	int penalty;				/* Are we a last resort? */
-	struct timeval lastcall;	/* When last successful call was hungup */
+	int calls;
+	time_t lastcall;	/* When last successful call was hungup */
 	struct member *next;		/* Next member */
 };
 
@@ -429,7 +430,7 @@ static int valid_exit(struct queue_ent *qe, char digit)
 
 #define MAX 256
 
-static struct ast_channel *wait_for_answer(struct queue_ent *qe, struct localuser *outgoing, int *to, int *allowredir_in, int *allowredir_out, int *allowdisconnect, char *digit)
+static struct localuser *wait_for_answer(struct queue_ent *qe, struct localuser *outgoing, int *to, int *allowredir_in, int *allowredir_out, int *allowdisconnect, char *digit)
 {
 	char *queue = qe->parent->name;
 	struct localuser *o;
@@ -439,7 +440,7 @@ static struct ast_channel *wait_for_answer(struct queue_ent *qe, struct localuse
 	int numbusies = 0;
 	int orig = *to;
 	struct ast_frame *f;
-	struct ast_channel *peer = NULL;
+	struct localuser *peer = NULL;
 	struct ast_channel *watchers[MAX];
 	int pos;
 	struct ast_channel *winner;
@@ -476,7 +477,7 @@ static struct ast_channel *wait_for_answer(struct queue_ent *qe, struct localuse
 				if (!peer) {
 					if (option_verbose > 2)
 						ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
-					peer = o->chan;
+					peer = o;
 					*allowredir_in = o->allowredirect_in;
 					*allowredir_out = o->allowredirect_out;
 					*allowdisconnect = o->allowdisconnect;
@@ -491,7 +492,7 @@ static struct ast_channel *wait_for_answer(struct queue_ent *qe, struct localuse
 							if (!peer) {
 								if (option_verbose > 2)
 									ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
-								peer = o->chan;
+								peer = o;
 								*allowredir_in = o->allowredirect_in;
 								*allowredir_out = o->allowredirect_out;
 								*allowdisconnect = o->allowdisconnect;
@@ -604,7 +605,26 @@ static int wait_our_turn(struct queue_ent *qe)
 	return res;
 }
 
-static int calc_metric(struct ast_call_queue *q, int pos, struct queue_ent *qe, struct localuser *tmp)
+static int update_queue(struct ast_call_queue *q, struct localuser *user)
+{
+	struct member *cur;
+	/* Since a reload could have taken place, we have to traverse the list to
+		be sure it's still valid */
+	ast_pthread_mutex_lock(&q->lock);
+	cur = q->members;
+	while(cur) {
+		if (user->member == cur) {
+			time(&cur->lastcall);
+			cur->calls++;
+			break;
+		}
+		cur = cur->next;
+	}
+	ast_pthread_mutex_unlock(&q->lock);
+	return 0;
+}
+
+static int calc_metric(struct ast_call_queue *q, struct member *mem, int pos, struct queue_ent *qe, struct localuser *tmp)
 {
 	switch (q->strategy) {
 	case QUEUE_STRATEGY_RINGALL:
@@ -626,11 +646,22 @@ static int calc_metric(struct ast_call_queue *q, int pos, struct queue_ent *qe,
 				q->wrapped = 1;
 			tmp->metric = pos;
 		}
-		tmp->metric += tmp->penalty * 1000000;
+		tmp->metric += mem->penalty * 1000000;
 		break;
 	case QUEUE_STRATEGY_RANDOM:
 		tmp->metric = rand() % 1000;
-		tmp->metric += tmp->penalty * 1000000;
+		tmp->metric += mem->penalty * 1000000;
+		break;
+	case QUEUE_STRATEGY_FEWESTCALLS:
+		tmp->metric = mem->calls;
+		tmp->metric += mem->penalty * 1000000;
+		break;
+	case QUEUE_STRATEGY_LEASTRECENT:
+		if (!mem->lastcall)
+			tmp->metric = 0;
+		else
+			tmp->metric = 1000000 - (time(NULL) - mem->lastcall);
+		tmp->metric += mem->penalty * 1000000;
 		break;
 	default:
 		ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy);
@@ -650,6 +681,7 @@ static int try_calling(struct queue_ent *qe, char *options, char *announceoverri
 	char restofit[AST_MAX_EXTENSION];
 	char *newnum;
 	struct ast_channel *peer;
+	struct localuser *lpeer;
 	int res = 0, bridge = 0;
 	int zapx = 2;
 	int x=0;
@@ -690,9 +722,9 @@ static int try_calling(struct queue_ent *qe, char *options, char *announceoverri
 		} 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);
 		strncpy(tmp->numsubst, cur->loc, sizeof(tmp->numsubst)-1);
-		tmp->penalty = cur->penalty;
 		/* If we're dialing by extension, look at the extension to know what to dial */
 		if ((newnum = strstr(tmp->numsubst, "BYEXTENSION"))) {
 			strncpy(restofit, newnum + strlen("BYEXTENSION"), sizeof(restofit)-1);
@@ -705,7 +737,7 @@ static int try_calling(struct queue_ent *qe, char *options, char *announceoverri
 		if (!qe->parent->strategy)
 			ring_entry(qe, tmp);
 		else
-			calc_metric(qe->parent, x++, qe, tmp);
+			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 */
@@ -724,7 +756,11 @@ static int try_calling(struct queue_ent *qe, char *options, char *announceoverri
 	if (qe->parent->strategy)
 		ring_one(qe, outgoing);
 	ast_pthread_mutex_unlock(&qe->parent->lock);
-	peer = wait_for_answer(qe, outgoing, &to, &allowredir_in, &allowredir_out, &allowdisconnect, &digit);
+	lpeer = wait_for_answer(qe, outgoing, &to, &allowredir_in, &allowredir_out, &allowdisconnect, &digit);
+	if (lpeer)
+		peer = lpeer->chan;
+	else
+		peer = NULL;
 	if (!peer) {
 		if (to) {
 			/* Musta gotten hung up */
@@ -750,6 +786,8 @@ static int try_calling(struct queue_ent *qe, char *options, char *announceoverri
 			if (tmp->dataquality) zapx = 0;
 			ast_channel_setoption(peer,AST_OPTION_TONE_VERIFY,&zapx,sizeof(char),0);
 		}
+		/* Update parameters for the queue */
+		update_queue(qe->parent, lpeer);
 		hanguptree(outgoing, peer);
 		/* Stop music on hold */
 		ast_moh_stop(qe->chan);
@@ -1270,6 +1308,7 @@ static int queues_show(int fd, int argc, char **argv)
 	int pos;
 	time_t now;
 	char max[80];
+	char calls[80];
 	
 	time(&now);
 	if (argc != 2)
@@ -1293,7 +1332,12 @@ static int queues_show(int fd, int argc, char **argv)
 					snprintf(max, sizeof(max), " with penalty %d", mem->penalty);
 				else
 					strcpy(max, "");
-				ast_cli(fd, "      %s/%s%s\n", mem->tech, mem->loc, max);
+				if (mem->calls) {
+					snprintf(calls, sizeof(calls), " has taken %d calls (last was %ld secs ago)",
+							mem->calls, 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 Members\n");
diff --git a/apps/app_voicemail2.c b/apps/app_voicemail2.c
index 3d1010ae41..54c9e2de14 100755
--- a/apps/app_voicemail2.c
+++ b/apps/app_voicemail2.c
@@ -1303,7 +1303,7 @@ static int adsi_load_vmail(struct ast_channel *chan, int *useadsi)
 	bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 0, "Listen", "Listen", "1", 1);
 	bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 1, "Folder", "Folder", "2", 1);
 	bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 2, "Advanced", "Advnced", "3", 1);
-	bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Options", "Options", "4", 1);
+	bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Options", "Options", "0", 1);
 	bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 4, "Help", "Help", "*", 1);
 	bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 5, "Exit", "Exit", "#", 1);
  	adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
@@ -1446,6 +1446,7 @@ static void adsi_password(struct ast_channel *chan)
 	bytes += adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Password: ******", "");
 	bytes += adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 0, 1, ADSI_JUST_LEFT);
 	bytes += adsi_set_keys(buf + bytes, keys);
+	bytes += adsi_voice_mode(buf + bytes, 0);
 	adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
 }
 
@@ -1473,6 +1474,8 @@ static void adsi_folders(struct ast_channel *chan, int start, char *label)
 	bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, " ", "");
 	bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
 	bytes += adsi_set_keys(buf + bytes, keys);
+	bytes += adsi_voice_mode(buf + bytes, 0);
+
 	adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
 }
 
@@ -1559,6 +1562,8 @@ static void adsi_message(struct ast_channel *chan, char *folder, int msg, int la
 	bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, datetime, "");
 	bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
 	bytes += adsi_set_keys(buf + bytes, keys);
+	bytes += adsi_voice_mode(buf + bytes, 0);
+
 	adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
 }
 
@@ -1602,6 +1607,8 @@ static void adsi_delete(struct ast_channel *chan, int msg, int last, int deleted
 	/* Except "Exit" */
 	keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
 	bytes += adsi_set_keys(buf + bytes, keys);
+	bytes += adsi_voice_mode(buf + bytes, 0);
+
 	adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
 }
 
@@ -1645,6 +1652,8 @@ static void adsi_status(struct ast_channel *chan, int new, int old, int lastmsg)
 		keys[0] = 1;
 	bytes += adsi_set_keys(buf + bytes, keys);
 
+	bytes += adsi_voice_mode(buf + bytes, 0);
+
 	adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
 }
 
@@ -1683,6 +1692,8 @@ static void adsi_status2(struct ast_channel *chan, char *folder, int messages)
 	bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
 	bytes += adsi_set_keys(buf + bytes, keys);
 
+	bytes += adsi_voice_mode(buf + bytes, 0);
+
 	adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
 	
 }
@@ -1694,6 +1705,8 @@ static void adsi_clear(struct ast_channel *chan)
 	if (!adsi_available(chan))
 		return;
 	bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
+	bytes += adsi_voice_mode(buf + bytes, 0);
+
 	adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
 }
 
@@ -1708,6 +1721,8 @@ static void adsi_goodbye(struct ast_channel *chan)
 	bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, " ", "");
 	bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Goodbye", "");
 	bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
+	bytes += adsi_voice_mode(buf + bytes, 0);
+
 	adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
 }
 
@@ -2399,6 +2414,18 @@ static int vm_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct
 	char newpassword[80] = "";
 	char newpassword2[80] = "";
 	char prefile[256]="";
+	char buf[256];
+	int bytes=0;
+
+	if (adsi_available(chan))
+	{
+		bytes += adsi_logo(buf + bytes);
+		bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Options Menu", "");
+		bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
+		bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
+		bytes += adsi_voice_mode(buf + bytes, 0);
+		adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
+	}
 	while((cmd >= 0) && (cmd != 't')) {
 		if (cmd)
 			retries = 0;
@@ -2723,6 +2750,8 @@ static int vm_execmain(struct ast_channel *chan, void *data)
 				break;
 			case '0':
 				cmd = vm_options(chan, vmu, &vms, vmfmts);
+				if (useadsi)
+					adsi_status(chan, vms.newmessages, vms.oldmessages, vms.lastmsg);
 				break;
 			default:	/* Nothing */
 				cmd = vm_instructions(chan, &vms);
diff --git a/configs/queues.conf.sample b/configs/queues.conf.sample
index 3e7341ac24..dff5da17e2 100755
--- a/configs/queues.conf.sample
+++ b/configs/queues.conf.sample
@@ -29,8 +29,8 @@
 ;
 ; ringall - ring all available channels until one answers (default)
 ; roundrobin - take turns ringing each available interface 
-; leastrecent - ring interface which least recently had a call
-; fewestcalls - ring interface which has had fewest completed calls
+; leastrecent - ring interface which was least recently called by this queue
+; fewestcalls - ring the one with fewest completed calls from this queue
 ; random - ring random interface
 ;
 ;strategy = ringall
-- 
GitLab