[svn-commits] mmichelson: trunk r97203 - in /trunk: ./ apps/ configs/

SVN commits to the Digium repositories svn-commits at lists.digium.com
Tue Jan 8 15:18:33 CST 2008


Author: mmichelson
Date: Tue Jan  8 15:18:32 2008
New Revision: 97203

URL: http://svn.digium.com/view/asterisk?view=rev&rev=97203
Log:
Adding the option of specifying a second interface in a member definition for a queue. app_queue
will monitor this second device's state for the member, even though it actually calls the first
interface. This ability has been added for statically defined queue members, realtime queue members,
and dynamic queue members added through the CLI, dialplan, or manager.

(closes issue #11603, reported by acidv)


Modified:
    trunk/CHANGES
    trunk/apps/app_queue.c
    trunk/configs/queues.conf.sample

Modified: trunk/CHANGES
URL: http://svn.digium.com/view/asterisk/trunk/CHANGES?view=diff&rev=97203&r1=97202&r2=97203
==============================================================================
--- trunk/CHANGES (original)
+++ trunk/CHANGES Tue Jan  8 15:18:32 2008
@@ -265,6 +265,9 @@
   * Added new channel variable QUEUE_MIN_PENALTY
   * QUEUE_MAX_PENALTY and QUEUE_MIN_PENALTY may be adjusted in mid-call by defining
      rules in queuerules.conf. See configs/queuerules.conf.sample for details
+  * Added a new parameter for member definition, called state_interface. This may be
+    used so that a member may be called via one interface but have a different interface's
+	device state reported.
 
 MeetMe Changes
 --------------

Modified: trunk/apps/app_queue.c
URL: http://svn.digium.com/view/asterisk/trunk/apps/app_queue.c?view=diff&rev=97203&r1=97202&r2=97203
==============================================================================
--- trunk/apps/app_queue.c (original)
+++ trunk/apps/app_queue.c Tue Jan  8 15:18:32 2008
@@ -352,7 +352,8 @@
 };
 
 struct member {
-	char interface[80];                 /*!< Technology/Location */
+	char interface[80];                 /*!< Technology/Location to dial to reach this member*/
+	char state_interface[80];           /*!< Technology/Location from which to read devicestate changes */
 	char membername[80];                /*!< Member name to use in queue logs */
 	int penalty;                        /*!< Are we a last resort? */
 	int calls;                          /*!< Number of calls serviced by this member */
@@ -690,7 +691,7 @@
 		while ((cur = ao2_iterator_next(&mem_iter))) {
 			char *interface;
 			char *slash_pos;
-			interface = ast_strdupa(cur->interface);
+			interface = ast_strdupa(cur->state_interface);
 			if ((slash_pos = strchr(interface, '/')))
 				if ((slash_pos = strchr(slash_pos + 1, '/')))
 					*slash_pos = '\0';
@@ -815,7 +816,7 @@
 	statechange_queue(device, state);
 }
 
-static struct member *create_queue_member(const char *interface, const char *membername, int penalty, int paused)
+static struct member *create_queue_member(const char *interface, const char *membername, int penalty, int paused, const char *state_interface)
 {
 	struct member *cur;
 	
@@ -823,6 +824,10 @@
 		cur->penalty = penalty;
 		cur->paused = paused;
 		ast_copy_string(cur->interface, interface, sizeof(cur->interface));
+		if (!ast_strlen_zero(state_interface))
+			ast_copy_string(cur->state_interface, state_interface, sizeof(cur->state_interface));
+		else
+			ast_copy_string(cur->state_interface, interface, sizeof(cur->state_interface));
 		if (!ast_strlen_zero(membername))
 			ast_copy_string(cur->membername, membername, sizeof(cur->membername));
 		else
@@ -958,20 +963,20 @@
 {
 	struct call_queue *q;
 	struct member *mem, tmpmem;
-	struct ao2_iterator queue_iter;
+	struct ao2_iterator queue_iter, mem_iter;
 	int ret = 0;
 
 	ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
 	queue_iter = ao2_iterator_init(queues, 0);
 	while ((q = ao2_iterator_next(&queue_iter))) {
-
 		ao2_lock(q);
-		if ((mem = ao2_find(q->members, &tmpmem, OBJ_POINTER))) {
-			ao2_ref(mem, -1);
-			ao2_unlock(q);
-			queue_unref(q);
-			ret = 1;
-			break;
+		mem_iter = ao2_iterator_init(q->members, 0);
+		while ((mem = ao2_iterator_next(&mem_iter))) { 
+			if (!strcasecmp(mem->state_interface, interface)) {
+				ao2_ref(mem, -1);
+				ret = 1;
+				break;
+			}
 		}
 		ao2_unlock(q);
 		queue_unref(q);
@@ -991,7 +996,7 @@
 				ast_debug(1, "Removing %s from the list of interfaces that make up all of our queue members.\n", interface);
 				AST_LIST_REMOVE_CURRENT(list);
 				ast_free(curint);
-			}
+			} 
 			break;
 		}
 	}
@@ -1256,7 +1261,7 @@
 	}
 }
 
-static void rt_handle_member_record(struct call_queue *q, char *interface, const char *membername, const char *penalty_str, const char *paused_str)
+static void rt_handle_member_record(struct call_queue *q, char *interface, const char *membername, const char *penalty_str, const char *paused_str, const char* state_interface)
 {
 	struct member *m, tmpmem;
 	int penalty = 0;
@@ -1280,10 +1285,10 @@
 
 	/* Create a new one if not found, else update penalty */
 	if (!m) {
-		if ((m = create_queue_member(interface, membername, penalty, paused))) {
+		if ((m = create_queue_member(interface, membername, penalty, paused, state_interface))) {
 			m->dead = 0;
 			m->realtime = 1;
-			add_to_interfaces(interface);
+			add_to_interfaces(state_interface);
 			ao2_link(q->members, m);
 			ao2_ref(m, -1);
 			m = NULL;
@@ -1293,6 +1298,11 @@
 		m->dead = 0;	/* Do not delete this one. */
 		if (paused_str)
 			m->paused = paused;
+		if (strcasecmp(state_interface, m->state_interface)) {
+			remove_from_interfaces(m->state_interface);
+			ast_copy_string(m->state_interface, state_interface, sizeof(m->state_interface));
+			add_to_interfaces(m->state_interface);
+		}
 		m->penalty = penalty;
 		ao2_ref(m, -1);
 	}
@@ -1307,7 +1317,7 @@
 	while ((cur = ao2_iterator_next(&mem_iter))) {
 		if (all || !cur->dynamic) {
 			ao2_unlink(q->members, cur);
-			remove_from_interfaces(cur->interface);
+			remove_from_interfaces(cur->state_interface);
 			q->membercount--;
 		}
 		ao2_ref(cur, -1);
@@ -1436,7 +1446,8 @@
 		rt_handle_member_record(q, interface,
 			ast_variable_retrieve(member_config, interface, "membername"),
 			ast_variable_retrieve(member_config, interface, "penalty"),
-			ast_variable_retrieve(member_config, interface, "paused"));
+			ast_variable_retrieve(member_config, interface, "paused"),
+			ast_variable_retrieve(member_config, interface, "state_interface"));
 	}
 
 	/* Delete all realtime members that have been deleted in DB. */
@@ -1444,9 +1455,7 @@
 	while ((m = ao2_iterator_next(&mem_iter))) {
 		if (m->dead) {
 			ao2_unlink(q->members, m);
-			ao2_unlock(q);
-			remove_from_interfaces(m->interface);
-			ao2_lock(q);
+			remove_from_interfaces(m->state_interface);
 			q->membercount--;
 		}
 		ao2_ref(m, -1);
@@ -1549,7 +1558,8 @@
 		rt_handle_member_record(q, interface,
 			S_OR(ast_variable_retrieve(member_config, interface, "membername"), interface),
 			ast_variable_retrieve(member_config, interface, "penalty"),
-			ast_variable_retrieve(member_config, interface, "paused"));
+			ast_variable_retrieve(member_config, interface, "paused"),
+			ast_variable_retrieve(member_config, interface, "state_interface"));
 	}
 
 	/* Delete all realtime members that have been deleted in DB. */
@@ -1557,9 +1567,7 @@
 	while ((m = ao2_iterator_next(&mem_iter))) {
 		if (m->dead) {
 			ao2_unlink(q->members, m);
-			ao2_unlock(q);
-			remove_from_interfaces(m->interface);
-			ao2_lock(q);
+			remove_from_interfaces(m->state_interface);
 			q->membercount--;
 		}
 		ao2_ref(m, -1);
@@ -3578,6 +3586,7 @@
 				"MemberName: %s\r\n",
 				q->name, mem->interface, mem->membername);
 			ao2_unlink(q->members, mem);
+			remove_from_interfaces(mem->state_interface);
 			ao2_ref(mem, -1);
 
 			if (queue_persistent_members)
@@ -3591,14 +3600,11 @@
 		queue_unref(q);
 	}
 
-	if (res == RES_OKAY)
-		remove_from_interfaces(interface);
-
 	return res;
 }
 
 
-static int add_to_queue(const char *queuename, const char *interface, const char *membername, int penalty, int paused, int dump)
+static int add_to_queue(const char *queuename, const char *interface, const char *membername, int penalty, int paused, int dump, const char *state_interface)
 {
 	struct call_queue *q;
 	struct member *new_member, *old_member;
@@ -3613,8 +3619,8 @@
 
 	ao2_lock(q);
 	if ((old_member = interface_exists(q, interface)) == NULL) {
-		add_to_interfaces(interface);
-		if ((new_member = create_queue_member(interface, membername, penalty, paused))) {
+		if ((new_member = create_queue_member(interface, membername, penalty, paused, state_interface))) {
+			add_to_interfaces(state_interface);
 			new_member->dynamic = 1;
 			ao2_link(q->members, new_member);
 			q->membercount++;
@@ -3797,6 +3803,7 @@
 	char *member;
 	char *interface;
 	char *membername = NULL;
+	char *state_interface;
 	char *penalty_tok;
 	int penalty = 0;
 	char *paused_tok;
@@ -3846,6 +3853,7 @@
 			penalty_tok = strsep(&member, ";");
 			paused_tok = strsep(&member, ";");
 			membername = strsep(&member, ";");
+			state_interface = strsep(&member, ";");
 
 			if (!penalty_tok) {
 				ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (penalty)\n", queue_name);
@@ -3866,12 +3874,10 @@
 				ast_log(LOG_WARNING, "Error converting paused: %s: Expected 0 or 1.\n", paused_tok);
 				break;
 			}
-			if (ast_strlen_zero(membername))
-				membername = interface;
 
 			ast_debug(1, "Reload Members: Queue: %s  Member: %s  Name: %s  Penalty: %d  Paused: %d\n", queue_name, interface, membername, penalty, paused);
 			
-			if (add_to_queue(queue_name, interface, membername, penalty, paused, 0) == RES_OUTOFMEMORY) {
+			if (add_to_queue(queue_name, interface, membername, penalty, paused, 0, state_interface) == RES_OUTOFMEMORY) {
 				ast_log(LOG_ERROR, "Out of Memory when reloading persistent queue member\n");
 				break;
 			}
@@ -4020,6 +4026,7 @@
 		AST_APP_ARG(penalty);
 		AST_APP_ARG(options);
 		AST_APP_ARG(membername);
+		AST_APP_ARG(state_interface);
 	);
 	int penalty = 0;
 
@@ -4046,7 +4053,7 @@
 		}
 	}
 
-	switch (add_to_queue(args.queuename, args.interface, args.membername, penalty, 0, queue_persistent_members)) {
+	switch (add_to_queue(args.queuename, args.interface, args.membername, penalty, 0, queue_persistent_members, args.state_interface)) {
 	case RES_OKAY:
 		ast_queue_log(args.queuename, chan->uniqueid, args.interface, "ADDMEMBER", "%s", "");
 		ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", args.interface, args.queuename);
@@ -4803,7 +4810,7 @@
 	int new;
 	const char *general_val = NULL;
 	char parse[80];
-	char *interface;
+	char *interface, *state_interface;
 	char *membername = NULL;
 	int penalty;
 	struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
@@ -4812,6 +4819,7 @@
 		AST_APP_ARG(interface);
 		AST_APP_ARG(penalty);
 		AST_APP_ARG(membername);
+		AST_APP_ARG(state_interface);
 	);
 
 	/*First things first. Let's load queuerules.conf*/
@@ -4880,8 +4888,10 @@
 				/* Check if a queue with this name already exists */
 				if (q->found) {
 					ast_log(LOG_WARNING, "Queue '%s' already defined! Skipping!\n", cat);
-					if (!new)
+					if (!new) {
 						ao2_unlock(q);
+						queue_unref(q);
+					}
 					continue;
 				}
 				/* Due to the fact that the "linear" strategy will have a different allocation
@@ -4933,11 +4943,22 @@
 							while (*membername && *membername < 33) membername++;
 						}
 
+						if (!ast_strlen_zero(args.state_interface)) {
+							state_interface = args.state_interface;
+							while (*state_interface && *state_interface < 33) state_interface++;
+						} else
+							state_interface = interface;
+
 						/* Find the old position in the list */
 						ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
 						cur = ao2_find(q->members, &tmpmem, OBJ_POINTER | OBJ_UNLINK);
-
-						newm = create_queue_member(interface, membername, penalty, cur ? cur->paused : 0);
+						/* Only attempt removing from interfaces list if the new state_interface is different than the old one */
+						if (cur && strcasecmp(cur->state_interface, state_interface)) {
+							remove_from_interfaces(cur->state_interface);
+						}
+						newm = create_queue_member(interface, membername, penalty, cur ? cur->paused : 0, state_interface);
+						if (!cur || (cur && strcasecmp(cur->state_interface, state_interface)))
+							add_to_interfaces(state_interface);
 						ao2_link(q->members, newm);
 						ao2_ref(newm, -1);
 						newm = NULL;
@@ -4945,8 +4966,6 @@
 						if (cur)
 							ao2_ref(cur, -1);
 						else {
-							/* Add them to the master int list if necessary */
-							add_to_interfaces(interface);
 							q->membercount++;
 						}
 					} else {
@@ -4961,16 +4980,16 @@
 						ao2_ref(cur, -1);
 						continue;
 					}
-
-					remove_from_interfaces(cur->interface);
+					ast_log(LOG_DEBUG, "%s in queue marked as delme, we should be deleting...\n", cur->interface);
 					q->membercount--;
 					ao2_unlink(q->members, cur);
+					remove_from_interfaces(cur->interface);
 					ao2_ref(cur, -1);
 				}
 
 				if (new) {
 					ao2_link(queues, q);
-				} else
+				} else 
 					ao2_unlock(q);
 				queue_unref(q);
 			}
@@ -5352,7 +5371,7 @@
 
 static int manager_add_queue_member(struct mansession *s, const struct message *m)
 {
-	const char *queuename, *interface, *penalty_s, *paused_s, *membername;
+	const char *queuename, *interface, *penalty_s, *paused_s, *membername, *state_interface;
 	int paused, penalty = 0;
 
 	queuename = astman_get_header(m, "Queue");
@@ -5360,6 +5379,7 @@
 	penalty_s = astman_get_header(m, "Penalty");
 	paused_s = astman_get_header(m, "Paused");
 	membername = astman_get_header(m, "MemberName");
+	state_interface = astman_get_header(m, "StateInterface");
 
 	if (ast_strlen_zero(queuename)) {
 		astman_send_error(s, m, "'Queue' not specified.");
@@ -5381,7 +5401,7 @@
 	else
 		paused = abs(ast_true(paused_s));
 
-	switch (add_to_queue(queuename, interface, membername, penalty, paused, queue_persistent_members)) {
+	switch (add_to_queue(queuename, interface, membername, penalty, paused, queue_persistent_members, state_interface)) {
 	case RES_OKAY:
 		ast_queue_log(queuename, "MANAGER", interface, "ADDMEMBER", "%s", "");
 		astman_send_ack(s, m, "Added interface to queue");
@@ -5537,26 +5557,28 @@
 
 static char *handle_queue_add_member(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
-	char *queuename, *interface, *membername = NULL;
+	char *queuename, *interface, *membername = NULL, *state_interface;
 	int penalty;
 
 	switch ( cmd ) {
 	case CLI_INIT:
 		e->command = "queue add member";
 		e->usage =
-			"Usage: queue add member <channel> to <queue> [penalty <penalty>]\n"; 
+			"Usage: queue add member <channel> to <queue> [[[penalty <penalty>] as <membername>] state_interface <interface>]\n"; 
 		return NULL;
 	case CLI_GENERATE:
 		return complete_queue_add_member(a->line, a->word, a->pos, a->n);
 	}
 
-	if ((a->argc != 6) && (a->argc != 8) && (a->argc != 10)) {
+	if ((a->argc != 6) && (a->argc != 8) && (a->argc != 10) && (a->argc != 12)) {
 		return CLI_SHOWUSAGE;
 	} else if (strcmp(a->argv[4], "to")) {
 		return CLI_SHOWUSAGE;
-	} else if ((a->argc == 8) && strcmp(a->argv[6], "penalty")) {
+	} else if ((a->argc >= 8) && strcmp(a->argv[6], "penalty")) {
 		return CLI_SHOWUSAGE;
-	} else if ((a->argc == 10) && strcmp(a->argv[8], "as")) {
+	} else if ((a->argc >= 10) && strcmp(a->argv[8], "as")) {
+		return CLI_SHOWUSAGE;
+	} else if ((a->argc == 12) && strcmp(a->argv[10], "state_interface")) {
 		return CLI_SHOWUSAGE;
 	}
 
@@ -5580,7 +5602,11 @@
 		membername = a->argv[9];
 	}
 
-	switch (add_to_queue(queuename, interface, membername, penalty, 0, queue_persistent_members)) {
+	if (a->argc >= 12) {
+		state_interface = a->argv[11];
+	}
+
+	switch (add_to_queue(queuename, interface, membername, penalty, 0, queue_persistent_members, state_interface)) {
 	case RES_OKAY:
 		ast_queue_log(queuename, "CLI", interface, "ADDMEMBER", "%s", "");
 		ast_cli(a->fd, "Added interface '%s' to queue '%s'\n", interface, queuename);

Modified: trunk/configs/queues.conf.sample
URL: http://svn.digium.com/view/asterisk/trunk/configs/queues.conf.sample?view=diff&rev=97203&r1=97202&r2=97203
==============================================================================
--- trunk/configs/queues.conf.sample (original)
+++ trunk/configs/queues.conf.sample Tue Jan  8 15:18:32 2008
@@ -375,7 +375,10 @@
 ; entries with higher penalties are considered last.  An optional member
 ; name may also be specified after a second comma, which is used in log
 ; messages as a "friendly name".  Multiple interfaces may share a single
-; member name.
+; member name. An optional state interface may be specified after a third
+; comma. This interface will be the one for which app_queue receives device
+; state notifications, even though the first interface specified is the one
+; that is actually called.
 ;
 ; It is important to ensure that channel drivers used for members are loaded
 ; before app_queue.so itself or they may be marked invalid until reload. This
@@ -386,6 +389,7 @@
 ;member => Zap/3,10,Bob Johnson
 ;member => Agent/1001
 ;member => Agent/1002
+;member => Local/1000 at default,0,John Smith,SIP/1000
 
 ;
 ; Note that using agent groups is probably not what you want.  Strategies do




More information about the svn-commits mailing list