[svn-commits] irroot: branch irroot/patches r344958 - /team/irroot/patches/

SVN commits to the Digium repositories svn-commits at lists.digium.com
Sat Nov 12 08:28:33 CST 2011


Author: irroot
Date: Sat Nov 12 08:28:29 2011
New Revision: 344958

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=344958
Log:
Distrotech patch for 10.0.0-rc1 [342951]

Added:
    team/irroot/patches/distrotech-10.0.patch   (with props)

Added: team/irroot/patches/distrotech-10.0.patch
URL: http://svnview.digium.com/svn/asterisk/team/irroot/patches/distrotech-10.0.patch?view=auto&rev=344958
==============================================================================
--- team/irroot/patches/distrotech-10.0.patch (added)
+++ team/irroot/patches/distrotech-10.0.patch Sat Nov 12 08:28:29 2011
@@ -1,0 +1,9132 @@
+Index: channels/chan_sip.c
+===================================================================
+--- channels/chan_sip.c	(.../digium/10)	(revision 900)
++++ channels/chan_sip.c	(.../distrotech/10/10.1.0)	(revision 900)
+@@ -5601,17 +5601,23 @@
+ 
+ 		if (p->rtp && !p->srtp && setup_srtp(&p->srtp) < 0) {
+ 			ast_log(LOG_WARNING, "SRTP audio setup failed\n");
+-			return -1;
++			if (!ast_test_flag(&p->flags[2], SIP_PAGE3_SRTP_TRY)) {
++				return -1;
++			}
+ 		}
+ 
+ 		if (p->vrtp && !p->vsrtp && setup_srtp(&p->vsrtp) < 0) {
+ 			ast_log(LOG_WARNING, "SRTP video setup failed\n");
+-			return -1;
++			if (!ast_test_flag(&p->flags[2], SIP_PAGE3_SRTP_TRY)) {
++				return -1;
++			}
+ 		}
+ 
+ 		if (p->trtp && !p->tsrtp && setup_srtp(&p->tsrtp) < 0) {
+ 			ast_log(LOG_WARNING, "SRTP text setup failed\n");
+-			return -1;
++			if (!ast_test_flag(&p->flags[2], SIP_PAGE3_SRTP_TRY)) {
++				return -1;
++			}
+ 		}
+ 	}
+ 
+@@ -9205,32 +9211,48 @@
+ 
+ 	if (secure_audio && !(p->srtp && (ast_test_flag(p->srtp, SRTP_CRYPTO_OFFER_OK)))) {
+ 		ast_log(LOG_WARNING, "Can't provide secure audio requested in SDP offer\n");
+-		res = -4;
+-		goto process_sdp_cleanup;
++		if (!ast_test_flag(&p->flags[2], SIP_PAGE3_SRTP_TRY)) {
++			res = -4;
++			goto process_sdp_cleanup;
++		}
+ 	}
+ 
+ 	if (!secure_audio && p->srtp) {
+ 		ast_log(LOG_WARNING, "We are requesting SRTP, but they responded without it!\n");
+-		res = -4;
+-		goto process_sdp_cleanup;
++		if (ast_test_flag(&p->flags[2], SIP_PAGE3_SRTP_TRY)) {
++			sip_srtp_destroy(p->srtp);
++			p->srtp = NULL;
++		} else {
++			res = -4;
++			goto process_sdp_cleanup;
++		}
+ 	}
+ 
+ 	if (secure_video && !(p->vsrtp && (ast_test_flag(p->vsrtp, SRTP_CRYPTO_OFFER_OK)))) {
+ 		ast_log(LOG_WARNING, "Can't provide secure video requested in SDP offer\n");
+-		res = -4;
+-		goto process_sdp_cleanup;
++		if (!ast_test_flag(&p->flags[2], SIP_PAGE3_SRTP_TRY)) {
++			res = -4;
++			goto process_sdp_cleanup;
++		}
+ 	}
+ 
+ 	if (!p->novideo && !secure_video && p->vsrtp) {
+ 		ast_log(LOG_WARNING, "We are requesting SRTP, but they responded without it!\n");
+-		res = -4;
+-		goto process_sdp_cleanup;
++		if (ast_test_flag(&p->flags[2], SIP_PAGE3_SRTP_TRY)) {
++			sip_srtp_destroy(p->vsrtp);
++			p->vsrtp = NULL;
++		} else {
++			res = -4;
++			goto process_sdp_cleanup;
++		}
+ 	}
+ 
+ 	if (!(secure_audio || secure_video) && ast_test_flag(&p->flags[1], SIP_PAGE2_USE_SRTP)) {
+ 		ast_log(LOG_WARNING, "Matched device setup to use SRTP, but request was not!\n");
+-		res = -4;
+-		goto process_sdp_cleanup;
++		if (!ast_test_flag(&p->flags[2], SIP_PAGE3_SRTP_TRY)) {
++			res = -4;
++			goto process_sdp_cleanup;
++		}
+ 	}
+ 
+ 	if (udptlportno == -1) {
+@@ -23194,7 +23216,8 @@
+ 				transmit_response_with_t38_sdp(p, "200 OK", req, (reinvite ? XMIT_RELIABLE : (req->ignore ?  XMIT_UNRELIABLE : XMIT_CRITICAL)));
+ 			} else if ((p->t38.state == T38_DISABLED) || (p->t38.state == T38_REJECTED)) {
+ 				/* If this is not a re-invite or something to ignore - it's critical */
+-				if (p->srtp && !ast_test_flag(p->srtp, SRTP_CRYPTO_OFFER_OK)) {
++				if (p->srtp && !ast_test_flag(p->srtp, SRTP_CRYPTO_OFFER_OK) &&
++				    !ast_test_flag(&p->flags[2], SIP_PAGE3_SRTP_TRY)) {
+ 					ast_log(LOG_WARNING, "Target does not support required crypto\n");
+ 					transmit_response_reliable(p, "488 Not Acceptable Here (crypto)", req);
+ 				} else {
+@@ -27422,6 +27445,11 @@
+ 		int duplicate = 0;
+ 		/* remove leading/trailing whitespace from mailbox string */
+ 		mbox = ast_strip(mbox);
++		if (strstr("@",context) == NULL) {
++			strncat(context,"@",sizeof(context)-2);
++			strncat(context,peer->context,sizeof(context)-strlen(peer->context)-1);
++		}
++
+ 		strsep(&context, "@");
+ 
+ 		if (ast_strlen_zero(mbox)) {
+@@ -27898,7 +27926,13 @@
+ 			} else if (!strcasecmp(v->name, "use_q850_reason")) {
+ 				ast_set2_flag(&peer->flags[1], ast_true(v->value), SIP_PAGE2_Q850_REASON);
+ 			} else if (!strcasecmp(v->name, "encryption")) {
+-				ast_set2_flag(&peer->flags[1], ast_true(v->value), SIP_PAGE2_USE_SRTP);
++				if (!strcasecmp(v->value, "try")) {
++					ast_set_flag(&peer->flags[1], SIP_PAGE2_USE_SRTP);
++					ast_set_flag(&peer->flags[2], SIP_PAGE3_SRTP_TRY);
++				} else {
++					ast_set2_flag(&peer->flags[1], ast_true(v->value), SIP_PAGE2_USE_SRTP);
++					ast_clear_flag(&peer->flags[2], SIP_PAGE3_SRTP_TRY);
++				}
+ 			} else if (!strcasecmp(v->name, "encryption_taglen")) {
+ 				ast_set2_flag(&peer->flags[2], !strcasecmp(v->value, "32"), SIP_PAGE3_SRTP_TAG_32);
+ 			} else if (!strcasecmp(v->name, "snom_aoc_enabled")) {
+Index: channels/chan_misdn.c
+===================================================================
+--- channels/chan_misdn.c	(.../digium/10)	(revision 900)
++++ channels/chan_misdn.c	(.../distrotech/10/10.1.0)	(revision 900)
+@@ -7891,6 +7891,7 @@
+ 			int port_up;
+ 			int check;
+ 			int maxbchans;
++			int wraped = 0;
+ 
+ 			if (!rr->port) {
+ 				rr->port = misdn_cfg_get_next_port_spin(0);
+@@ -7926,6 +7927,11 @@
+ 					maxbchans = misdn_lib_get_maxchans(rr->port);
+ 
+ 					for (;rr->channel <= maxbchans;rr->channel++) {
++						/* ive come full circle and can stop now */
++						if (wraped && (rr->port == port_start) && (rr->channel == bchan_start)) {
++							break;
++						}
++
+ 						chan_misdn_log(4, rr->port, "Checking channel %d\n",  rr->channel);
+ 
+ 						if ((newbc = misdn_lib_get_free_bc(rr->port, rr->channel, 0, 0))) {
+@@ -7940,9 +7946,9 @@
+ 					}
+ 
+ 				}
++				wraped = 1;
+ 			} while (!newbc && (rr->port > 0) &&
+ 				 ((rr->port != port_start) || ((rr->port == port_start) && (rr->channel < bchan_start))));
+-
+ 		} else {
+ 			for (port = misdn_cfg_get_next_port(0); port > 0;
+ 				port = misdn_cfg_get_next_port(port)) {
+Index: channels/sip/include/sip.h
+===================================================================
+--- channels/sip/include/sip.h	(.../digium/10)	(revision 900)
++++ channels/sip/include/sip.h	(.../distrotech/10/10.1.0)	(revision 900)
+@@ -354,9 +354,10 @@
+ 
+ #define SIP_PAGE3_SNOM_AOC               (1 << 0)  /*!< DPG: Allow snom aoc messages */
+ #define SIP_PAGE3_SRTP_TAG_32            (1 << 1)  /*!< DP: Use a 32bit auth tag in INVITE not 80bit */
++#define SIP_PAGE3_SRTP_TRY               (1 << 2)  /*!< DP: Attempt SRTP / do not enforce it */
+ 
+ #define SIP_PAGE3_FLAGS_TO_COPY \
+-	(SIP_PAGE3_SNOM_AOC | SIP_PAGE3_SRTP_TAG_32)
++	(SIP_PAGE3_SNOM_AOC | SIP_PAGE3_SRTP_TAG_32 | SIP_PAGE3_SRTP_TRY)
+ 
+ #define CHECK_AUTH_BUF_INITLEN   256
+ 
+Index: channels/chan_local.c
+===================================================================
+--- channels/chan_local.c	(.../digium/10)	(revision 900)
++++ channels/chan_local.c	(.../distrotech/10/10.1.0)	(revision 900)
+@@ -649,9 +649,10 @@
+ static int local_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
+ {
+ 	struct local_pvt *p = ast->tech_pvt;
++	struct ast_channel *bridge;
+ 	int res = 0;
+ 	struct ast_frame f = { AST_FRAME_CONTROL, };
+-	int isoutbound;
++	int isoutbound = IS_OUTBOUND(ast, p);
+ 
+ 	if (!p)
+ 		return -1;
+@@ -674,7 +675,6 @@
+ 		 * happens to be in this control frame. The same applies for redirecting information, which
+ 		 * is why it is handled here as well.*/
+ 		ao2_lock(p);
+-		isoutbound = IS_OUTBOUND(ast, p);
+ 		if (isoutbound) {
+ 			this_channel = p->chan;
+ 			the_other_channel = p->owner;
+@@ -697,10 +697,33 @@
+ 			res = local_queue_frame(p, isoutbound, &f, ast, 1);
+ 		}
+ 		ao2_unlock(p);
++	} else if (!isoutbound && (condition == AST_CONTROL_SRCUPDATE)) {
++		bridge = ast_bridged_channel(ast);
++		ao2_lock(p);
++		/* fixup audio formats nativeformat might have changed we must adjust.
++		 * ast is p->owner and is locked here*/
++		if (p->chan && bridge && (bridge != p->chan) &&
++		    !ast_format_cap_identical(bridge->nativeformats, ast->nativeformats)) {
++			if (!ast_channel_trylock(p->chan)) {
++				ast_format_cap_copy(ast->nativeformats, bridge->nativeformats);
++				ast_set_read_format(ast, &ast->readformat);
++				ast_set_write_format(ast, &ast->writeformat);
++				ast_format_cap_copy(p->chan->nativeformats, bridge->nativeformats);
++				ast_set_read_format(p->chan, &p->chan->readformat);
++				ast_set_write_format(p->chan, &p->chan->writeformat);
++				ast_channel_unlock(p->chan);
++			} else {
++				ast_verb(3, "Tried to get lock on %s to set audio format but failed\n", p->chan->name);
++			}
++		}
++		f.subclass.integer = condition;
++		f.data.ptr = (void*)data;
++		f.datalen = datalen;
++		res = local_queue_frame(p, isoutbound, &f, ast, 1);
++		ao2_unlock(p);
+ 	} else {
+ 		/* Queue up a frame representing the indication as a control frame */
+ 		ao2_lock(p);
+-		isoutbound = IS_OUTBOUND(ast, p);
+ 		f.subclass.integer = condition;
+ 		f.data.ptr = (void*)data;
+ 		f.datalen = datalen;
+Index: channels/misdn/Makefile
+===================================================================
+--- channels/misdn/Makefile	(.../digium/10)	(revision 900)
++++ channels/misdn/Makefile	(.../distrotech/10/10.1.0)	(revision 900)
+@@ -11,7 +11,7 @@
+ 	$(CC) $(CFLAGS) -c -o $@ $<
+ 
+ portinfo: portinfo.o
+-	$(CC) -o $@ $^ -lisdnnet -lmISDN -lpthread
++	$(CC) -o $@ $^ -lisdnnet-1 -lmISDN -lpthread
+ 
+ clean:
+ 	rm -rf *.a *.o *.so portinfo *.i
+Index: configure.ac
+===================================================================
+--- configure.ac	(.../digium/10)	(revision 900)
++++ configure.ac	(.../distrotech/10/10.1.0)	(revision 900)
+@@ -389,7 +389,8 @@
+ AST_EXT_LIB_SETUP([IMAP_TK], [UW IMAP Toolkit], [imap])
+ AST_EXT_LIB_SETUP([INOTIFY], [inotify support], [inotify])
+ AST_EXT_LIB_SETUP([IODBC], [iODBC], [iodbc])
+-AST_EXT_LIB_SETUP([ISDNNET], [ISDN4Linux], [isdnnet])
++AST_EXT_LIB_SETUP([ISDNNET], [ISDN4Linux], [isdnnet-1])
++AST_EXT_LIB_SETUP([SUPPSERV], [mISDN Supplemental Services], [suppserv-1])
+ AST_EXT_LIB_SETUP([JACK], [Jack Audio Connection Kit], [jack])
+ AST_EXT_LIB_SETUP([KQUEUE], [kqueue support], [kqueue])
+ AST_EXT_LIB_SETUP([LDAP], [OpenLDAP], [ldap])
+@@ -453,7 +454,6 @@
+ AST_EXT_LIB_SETUP([SQLITE3], [SQLite], [sqlite3])
+ AST_EXT_LIB_SETUP([SRTP], [Secure RTP], [srtp])
+ AST_EXT_LIB_SETUP([OPENSSL], [OpenSSL Secure Sockets Layer], [ssl])
+-AST_EXT_LIB_SETUP([SUPPSERV], [mISDN Supplemental Services], [suppserv])
+ AST_EXT_LIB_SETUP([FREETDS], [FreeTDS], [tds])
+ AST_EXT_LIB_SETUP([TERMCAP], [Termcap], [termcap])
+ AST_EXT_LIB_SETUP([TIMERFD], [timerfd], [timerfd])
+@@ -1737,11 +1737,11 @@
+ AST_EXT_LIB_CHECK([MISDN], [mISDN], [mISDN_open], [mISDNuser/mISDNlib.h])
+ 
+ if test "${PBX_MISDN}" = 1; then
+-   AST_EXT_LIB_CHECK([ISDNNET], [isdnnet], [init_manager], [mISDNuser/isdn_net.h], [-lmISDN -lpthread])
+-   AST_EXT_LIB_CHECK([SUPPSERV], [suppserv], [encodeFac], [mISDNuser/suppserv.h])
++   AST_EXT_LIB_CHECK([ISDNNET], [isdnnet-1], [init_manager], [mISDNuser/isdn_net.h], [-lmISDN -lpthread])
++   AST_EXT_LIB_CHECK([SUPPSERV], [suppserv-1], [encodeFac], [mISDNuser/suppserv.h])
+    AST_C_DEFINE_CHECK([MISDN_FAC_RESULT], [Fac_RESULT], [mISDNuser/suppserv.h])
+    AST_C_DEFINE_CHECK([MISDN_FAC_ERROR], [Fac_ERROR], [mISDNuser/suppserv.h])
+-   AC_CHECK_HEADER([linux/mISDNdsp.h], [AC_DEFINE_UNQUOTED([MISDN_1_2], 1, [Build chan_misdn for mISDN 1.2 or later.])])
++   AC_CHECK_HEADER([mISDN/mISDNdsp.h], [AC_DEFINE_UNQUOTED([MISDN_1_2], 1, [Build chan_misdn for mISDN 1.2 or later.])])
+    AC_CHECK_MEMBER([Q931_info_t.redirect_dn], [], [PBX_MISDN=0], [#include <mISDNuser/mISDNlib.h>])
+ fi
+ 
+Index: apps/app_directed_pickup.c
+===================================================================
+--- apps/app_directed_pickup.c	(.../digium/10)	(revision 900)
++++ apps/app_directed_pickup.c	(.../distrotech/10/10.1.0)	(revision 900)
+@@ -73,7 +73,10 @@
+ 			tries to find a channel which has defined a <variable>PICKUPMARK</variable>
+ 			channel variable with the same value as <replaceable>extension</replaceable>
+ 			(in this example, <literal>10</literal>). When no parameter is specified, the application
+-			will pickup a channel matching the pickup group of the active channel.</para>
++			will pickup a channel matching the pickup group of the active channel.
++			If the channel variable <variable>PICKUP_BRIDGE_MACRO</variable> is set this macro will run
++			on the picked up channel using the channel variable <variable>PICKUP_BRIDGE_MACRO_ARGS</variable>
++			as arguments.</para>
+ 		</description>
+ 	</application>
+ 	<application name="PickupChan" language="en_US">
+@@ -94,7 +97,10 @@
+ 			</parameter>
+ 		</syntax>
+ 		<description>
+-			<para>This will pickup a specified <replaceable>channel</replaceable> if ringing.</para>
++			<para>This will pickup a specified <replaceable>channel</replaceable> if ringing.
++			If the channel variable <variable>PICKUP_BRIDGE_MACRO</variable> is set this macro will run
++			on the picked up channel using the channel variable <variable>PICKUP_BRIDGE_MACRO_ARGS</variable>
++			as arguments.</para>
+ 		</description>
+ 	</application>
+  ***/
+Index: apps/app_queue.c
+===================================================================
+--- apps/app_queue.c	(.../digium/10)	(revision 900)
++++ apps/app_queue.c	(.../distrotech/10/10.1.0)	(revision 900)
+@@ -25,6 +25,18 @@
+  * \arg Config in \ref Config_qu queues.conf
+  *
+  * \par Development notes
++ * \note 2011-11-01: Made application more thread safe
++ *		Distrotech PTY (LTD) (www.distrotech.co.za)
++ *		Gregory Nietsky (irroot) <gregory at distrotech.co.za>
++ *
++ *		Split away from locking queues/queue to having locks per
++ *		Queue/Member/Device.
++ *		Added device state struct to mange device states shared
++ *		for multiple members sharing same device.
++ *
++ *		Made all functions work with realtime/dynamic/static members.
++ *		Added missing CLI/AMI functions for handling callinuse.
++ *
+  * \note 2004-11-25: Persistent Dynamic Members added by:
+  *             NetNation Communications (www.netnation.com)
+  *             Kevin Lindsay <kevinl at netnation.com>
+@@ -99,22 +111,31 @@
+ #include "asterisk/callerid.h"
+ #include "asterisk/cel.h"
+ #include "asterisk/data.h"
++#include "asterisk/time.h"
+ 
+-/* Define, to debug reference counts on queues, without debugging reference counts on queue members */
+-/* #define REF_DEBUG_ONLY_QUEUES */
+-
+ /*!
+  * \par Please read before modifying this file.
+- * There are three locks which are regularly used
+- * throughout this file, the queue list lock, the lock
+- * for each individual queue, and the interface list lock.
++ * There are locks which are regularly used
++ * throughout this file, the lock
++ * for each individual queue, the individual member lock ,
++ * and the device state lock.
++ * there are container locks for the queues list, the member
++ * list on each queue and the devices container.
+  * Please be extra careful to always lock in the following order
+- * 1) queue list lock
+- * 2) individual queue lock
+- * 3) interface list lock
++ *
++ * 1) queues container lock (ao2 functions that lock the container)
++ * 2) queue lock
++ * 3) queue member lock
++ * 4) member lock
++ * 5) devices container lock
++ * 6) member device lock
+  * This order has sort of "evolved" over the lifetime of this
+  * application, but it is now in place this way, so please adhere
+  * to this order!
++ *
++ * the only elements that do not require a read lock (ie will not change)
++ * the queue name and members container, the member interface and
++ * device state_interface as they are never altered after been linked.
+  */
+ 
+ /*** DOCUMENTATION
+@@ -264,9 +285,10 @@
+ 			<parameter name="queuename" required="true" />
+ 			<parameter name="interface" />
+ 			<parameter name="penalty" />
+-			<parameter name="options" />
++			<parameter name="paused" />
+ 			<parameter name="membername" />
+ 			<parameter name="stateinterface" />
++			<parameter name="callinuse" />
+ 		</syntax>
+ 		<description>
+ 			<para>Dynamically adds interface to an existing queue. If the interface is
+@@ -530,8 +552,8 @@
+ 					<enum name="paused">
+ 						<para>Gets or sets queue member paused status.</para>
+ 					</enum>
+-					<enum name="ignorebusy">
+-						<para>Gets or sets queue member ignorebusy.</para>
++					<enum name="callinuse">
++						<para>Gets or sets queue member callinuse.</para>
+ 					</enum>
+ 				</enumlist>
+ 			</parameter>
+@@ -846,6 +868,19 @@
+ 		<description>
+ 		</description>
+ 	</manager>
++	<manager name="QueueCallInuse" language="en_US">
++		<synopsis>
++			Set interface to allow multiple calls
++		</synopsis>
++		<syntax>
++			<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++			<parameter name="Interface" required="true" />
++			<parameter name="CallInuse" required="true" />
++			<parameter name="Queue" required="true" />
++		</syntax>
++		<description>
++		</description>
++	</manager>
+  ***/
+ 
+ enum {
+@@ -870,8 +905,15 @@
+ 	QUEUE_RELOAD_MEMBER = (1 << 1),
+ 	QUEUE_RELOAD_RULES = (1 << 2),
+ 	QUEUE_RESET_STATS = (1 << 3),
++	QUEUE_RELOAD_REALTIME = (1 << 4),
+ };
+ 
++enum member_type {
++	QUEUE_ADD_MEMBER_STATIC = (1 << 0),
++	QUEUE_ADD_MEMBER_REALTIME = (1 << 1),
++	QUEUE_ADD_MEMBER_DYNAMIC = (1 << 2),
++};
++
+ static const struct strategy {
+ 	int strategy;
+ 	const char *name;
+@@ -912,7 +954,7 @@
+ #define	RES_OUTOFMEMORY	(-2)		/*!< Out of memory */
+ #define	RES_NOSUCHQUEUE	(-3)		/*!< No such queue */
+ #define RES_NOT_DYNAMIC (-4)		/*!< Member is not dynamic */
+-
++#define RES_ERROR	(-5)		/*!< Member is mis configured */
+ static char *app = "Queue";
+ 
+ static char *app_aqm = "AddQueueMember" ;
+@@ -955,7 +997,7 @@
+ static int negative_penalty_invalid = 0;
+ 
+ /*! \brief queues.conf [general] option */
+-static int check_state_unknown = 0;
++static int log_membername_as_agent = 0;
+ 
+ enum queue_result {
+ 	QUEUE_UNKNOWN = 0,
+@@ -991,48 +1033,32 @@
+  *  use it not only for keeping track of what is in use but
+  *  also for keeping track of who we're dialing.
+  *
+- *  There are two "links" defined in this structure, q_next and call_next.
+- *  q_next links ALL defined callattempt structures into a linked list. call_next is
+- *  a link which allows for a subset of the callattempts to be traversed. This subset
+- *  is used in wait_for_answer so that irrelevant callattempts are not traversed. This
+- *  also is helpful so that queue logs are always accurate in the case where a call to 
+- *  a member times out, especially if using the ringall strategy. 
+ */
+ 
+ struct callattempt {
+-	struct callattempt *q_next;
+-	struct callattempt *call_next;
+-	struct ast_channel *chan;
+-	char interface[256];
+-	int stillgoing;
+-	int metric;
+-	time_t lastcall;
+-	struct call_queue *lastqueue;
+-	struct member *member;
+-	/*! Saved connected party info from an AST_CONTROL_CONNECTED_LINE. */
+-	struct ast_party_connected_line connected;
+-	/*! TRUE if an AST_CONTROL_CONNECTED_LINE update was saved to the connected element. */
+-	unsigned int pending_connected_update:1;
+-	/*! TRUE if caller id is not available for connected line */
+-	unsigned int dial_callerid_absent:1;
++	struct ast_channel *chan;                  /*! Channel called */
++	int stillgoing;                            /*! This attempt is valid and active */
++	int metric;                                /*! Metric calculated according to strategy */
++	struct member *member;                     /*! Member assosiated with this attempt */
++	struct ast_party_connected_line connected; /*! Saved connected party info from an AST_CONTROL_CONNECTED_LINE. */
++	unsigned int reserved:1;                   /*! Is this attempt been attempted*/
++	unsigned int active:1;                     /*! Is this attempt active in a call*/
++	unsigned int pending_connected_update:1;   /*! TRUE if caller id is not available for connected line*/
++	unsigned int dial_callerid_absent:1;       /*! TRUE if caller id is not available for connected line */
+ 	struct ast_aoc_decoded *aoc_s_rate_list;
+ };
+ 
+-
+ struct queue_ent {
+ 	struct call_queue *parent;             /*!< What queue is our parent */
+-	char moh[80];                          /*!< Name of musiconhold to be used */
+-	char announce[PATH_MAX];               /*!< Announcement to play for member when call is answered */
+-	char context[AST_MAX_CONTEXT];         /*!< Context when user exits queue */
+ 	char digits[AST_MAX_EXTENSION];        /*!< Digits entered while in queue */
+ 	int valid_digits;                      /*!< Digits entered correspond to valid extension. Exited */
+ 	int pos;                               /*!< Where we are in the queue */
+ 	int prio;                              /*!< Our priority */
+ 	int last_pos_said;                     /*!< Last position we told the user */
+ 	int ring_when_ringing;                 /*!< Should we only use ring indication when a channel is ringing? */
+-	time_t last_periodic_announce_time;    /*!< The last time we played a periodic announcement */
++	struct timeval last_pannounce_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 */
++	struct timeval 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 */
+ 	int pending;                           /*!< Non-zero if we are attempting to call a member */
+@@ -1040,33 +1066,40 @@
+ 	int min_penalty;                       /*!< Limit the members that can take this call to this penalty or higher */
+ 	int linpos;                            /*!< If using linear strategy, what position are we at? */
+ 	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 timeval start;                  /*!< When we started holding */
++	struct timeval expire;                 /*!< When this entry should expire (time out of queue) */
+ 	int cancel_answered_elsewhere;	       /*!< Whether we should force the CAE flag on this call (C) option*/
++	struct ao2_container *attempts;        /*!< Container holding all call attempts*/
+ 	struct ast_channel *chan;              /*!< Our channel */
+-	AST_LIST_HEAD_NOLOCK(,penalty_rule) qe_rules; /*!< Local copy of the queue's penalty rules */
+-	struct penalty_rule *pr;               /*!< Pointer to the next penalty rule to implement */
+-	struct queue_ent *next;                /*!< The next queue entry */
++	struct rule_list *rules;               /*!< Pointer holding the ref for the queue penalty rules */
++	struct penalty_rule *pr;               /*!< Active penalty rule */
++	AST_LIST_ENTRY(queue_ent) next;        /*!< The next queue entry */
+ };
+ 
++/*! \brief keep track of device state changes */
++struct mem_state {
++	char state_interface[80];              /*!< Technology/Location from which to read devicestate changes */
++	int reserved;                          /*!< This interface is reserved for pending call */
++	int active;                            /*!< This interface is active on a call */
++	int status;                            /*!< Status of queue member */
++};
++
+ struct member {
+-	char interface[80];                  /*!< Technology/Location to dial to reach this member*/
+-	char state_exten[AST_MAX_EXTENSION]; /*!< Extension to get state from (if using hint) */
+-	char state_context[AST_MAX_CONTEXT]; /*!< Context to use when getting state (if using hint) */
+-	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 */
+-	int dynamic;                         /*!< Are we dynamically added? */
+-	int realtime;                        /*!< Is this member realtime? */
+-	int status;                          /*!< Status of queue member */
+-	int paused;                          /*!< Are we paused (not accepting calls)? */
+-	time_t lastcall;                     /*!< When last successful call was hungup */
+-	struct call_queue *lastqueue;	     /*!< Last queue we received a call */
+-	unsigned int dead:1;                 /*!< Used to detect members deleted in realtime */
+-	unsigned int delme:1;                /*!< Flag to delete entry on reload */
+-	char rt_uniqueid[80];                /*!< Unique id of realtime member entry */
+-	unsigned int ignorebusy:1;           /*!< Flag to ignore member if the status is not available */
++	AST_DECLARE_STRING_FIELDS(
++		AST_STRING_FIELD(interface);   /*!< Technology/Location to dial to reach this member*/
++		AST_STRING_FIELD(membername);  /*!< Member name to use in queue logs */
++		AST_STRING_FIELD(rt_uniqueid); /*!< Unique id of realtime member entry */
++	);
++	int penalty;                           /*!< Are we a last resort? */
++	int calls;                             /*!< Number of calls serviced by this member */
++	struct timeval lastcall;               /*!< When last successful call was hungup */
++	int lastwrapup;                        /*!< Last wrapuptime */
++	unsigned int dynamic:1;                /*!< Is this member dynamic? */
++	unsigned int realtime:1;               /*!< Is this member realtime? */
++	unsigned int paused:1;                 /*!< Are we paused (not accepting calls)? */
++	unsigned int dead:1;                   /*!< Used to detect members deleted in realtime */
++	unsigned int callinuse:1;              /*!< Are we dynamically added? */
++	struct mem_state *device;              /*!< Device information */
+ };
+ 
+ enum empty_conditions {
+@@ -1149,7 +1182,6 @@
+ 	unsigned int setqueuevar:1;
+ 	unsigned int setqueueentryvar:1;
+ 	unsigned int reportholdtime:1;
+-	unsigned int wrapped:1;
+ 	unsigned int timeoutrestart:1;
+ 	unsigned int announceholdtime:2;
+ 	unsigned int announceposition:3;
+@@ -1158,6 +1190,8 @@
+ 	unsigned int realtime:1;
+ 	unsigned int found:1;
+ 	unsigned int relativeperiodicannounce:1;
++	unsigned int autopausebusy:1;
++	unsigned int autopauseunavail:1;
+ 	enum empty_conditions joinempty;
+ 	enum empty_conditions leavewhenempty;
+ 	int announcepositionlimit;          /*!< How many positions we announce? */
+@@ -1167,52 +1201,57 @@
+ 	int numperiodicannounce;            /*!< The number of periodic announcements configured */
+ 	int randomperiodicannounce;         /*!< Are periodic announcments randomly chosen */
+ 	int roundingseconds;                /*!< How many seconds do we round to? */
+-	int holdtime;                       /*!< Current avg holdtime, based on an exponential average */
+-	int talktime;                       /*!< Current avg talktime, based on the same exponential average */
+-	int callscompleted;                 /*!< Number of queue calls completed */
+-	int callsabandoned;                 /*!< Number of queue calls abandoned */
+ 	int servicelevel;                   /*!< seconds setting for servicelevel*/
+-	int callscompletedinsl;             /*!< Number of calls answered with servicelevel*/
+ 	char monfmt[8];                     /*!< Format to use when recording calls */
+ 	int montype;                        /*!< Monitor type  Monitor vs. MixMonitor */
+-	int count;                          /*!< How many entries */
+ 	int maxlen;                         /*!< Max number of entries */
+ 	int wrapuptime;                     /*!< Wrapup Time */
+ 	int penaltymemberslimit;            /*!< Disregard penalty when queue has fewer than this many members */
+-
+ 	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 */
+ 	int autopausedelay;                 /*!< Delay auto pause for autopausedelay seconds since last call */
+ 	int timeoutpriority;                /*!< Do we allow a fraction of the timeout to occur for a ring? */
+-
+ 	/* 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 ao2_container *members;             /*!< Head of the list of members */
+-	struct queue_ent *head;             /*!< Head of the list of callers */
+-	AST_LIST_ENTRY(call_queue) list;    /*!< Next call queue */
+-	AST_LIST_HEAD_NOLOCK(, penalty_rule) rules; /*!< The list of penalty rules to invoke */
++	struct timeval reload;              /*!< Time the queue will be reloaded from RT */
++	struct queue_data *data;            /*!< Queue statistics */
+ };
+ 
++struct queue_data {
++	int qhash;                          /*!< Hash for queue */
++	unsigned int wrapped:1;
++	int count;                          /*!< How many entries */
++	int holdtime;                       /*!< Current avg holdtime, based on an exponential average */
++	int talktime;                       /*!< Current avg talktime, based on the same exponential average */
++	int callscompleted;                 /*!< Number of queue calls completed */
++	int callsabandoned;                 /*!< Number of queue calls abandoned */
++	int callscompletedinsl;             /*!< Number of calls answered with servicelevel*/
++	int rrpos;                          /*!< Round Robin - position */
++	AST_LIST_HEAD(, queue_ent)  *head;  /*!< Head of the list of callers */
++	struct ao2_container *members;      /*!< Head of the list of members */
++};
++
+ struct rule_list {
+ 	char name[80];
+-	AST_LIST_HEAD_NOLOCK(,penalty_rule) rules;
+-	AST_LIST_ENTRY(rule_list) list;
++	struct ao2_container *rules;
+ };
+ 
+-static AST_LIST_HEAD_STATIC(rule_lists, rule_list);
+-
+ static struct ao2_container *queues;
++static struct ao2_container *devices;
++static struct ao2_container *rules;
++static struct ao2_container *qdata;
+ 
+-static void update_realtime_members(struct call_queue *q);
++static int do_set_member_penalty_paused(struct call_queue *q, struct member *mem, int pause, int value, const char *reason);
++static void pm_load_member_config(struct call_queue *q);
++static char *queue_refshow(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
+ static struct member *interface_exists(struct call_queue *q, const char *interface);
+ static int set_member_paused(const char *queuename, const char *interface, const char *reason, int paused);
+ 
+ static void queue_transfer_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan);
++
+ /*! \brief sets the QUEUESTATUS channel variable */
+ static void set_queue_result(struct ast_channel *chan, enum queue_result res)
+ {
+@@ -1226,6 +1265,7 @@
+ 	}
+ }
+ 
++/*! \brief return strategy name from strategy*/
+ static const char *int2strat(int strategy)
+ {
+ 	int x;
+@@ -1238,6 +1278,7 @@
+ 	return "<unknown>";
+ }
+ 
++/*! brief return strategy from strategy name*/
+ static int strat2int(const char *strategy)
+ {
+ 	int x;
+@@ -1250,6 +1291,7 @@
+ 	return -1;
+ }
+ 
++/*! brief return a autopause setting from name*/
+ static int autopause2int(const char *autopause)
+ {
+ 	int x;
+@@ -1270,92 +1312,125 @@
+ 	return QUEUE_AUTOPAUSE_OFF;
+ }
+ 
++/*!
++ * \brief ao2 callback to calculate hash of a queue by name
++ */
+ static int queue_hash_cb(const void *obj, const int flags)
+ {
+ 	const struct call_queue *q = obj;
++	const char *name = q->name;
+ 
+-	return ast_str_case_hash(q->name);
++	return ast_str_case_hash(name);
+ }
+ 
++
++/*!
++ * \brief ao2 callback to find queue by name
++ * \note this is the default function used by ao2_find
++ */
+ static int queue_cmp_cb(void *obj, void *arg, int flags)
+ {
+-	struct call_queue *q = obj, *q2 = arg;
+-	return !strcasecmp(q->name, q2->name) ? CMP_MATCH | CMP_STOP : 0;
++	const struct call_queue *q = obj, *q2 = arg;
++	const char *name = (flags & OBJ_POINTER) ? q2->name : arg;
++
++	return !strcasecmp(q->name, name) ? CMP_MATCH | CMP_STOP : 0;
+ }
+ 
+-#ifdef REF_DEBUG_ONLY_QUEUES
+-#define queue_ref(a)	__ao2_ref_debug(a,1,"",__FILE__,__LINE__,__PRETTY_FUNCTION__)
+-#define queue_unref(a)	__ao2_ref_debug(a,-1,"",__FILE__,__LINE__,__PRETTY_FUNCTION__)
+-#define queue_t_ref(a,b)	__ao2_ref_debug(a,1,b,__FILE__,__LINE__,__PRETTY_FUNCTION__)
+-#define queue_t_unref(a,b)	__ao2_ref_debug(a,-1,b,__FILE__,__LINE__,__PRETTY_FUNCTION__)
+-#define queues_t_link(c,q,tag)	__ao2_link_debug(c,q,tag,__FILE__,__LINE__,__PRETTY_FUNCTION__)
+-#define queues_t_unlink(c,q,tag)	__ao2_unlink_debug(c,q,tag,__FILE__,__LINE__,__PRETTY_FUNCTION__)
+-#else
+-#define queue_t_ref(a,b)	queue_ref(a)
+-#define queue_t_unref(a,b)	queue_unref(a)
+-#define queues_t_link(c,q,tag)	ao2_t_link(c,q,tag)
+-#define queues_t_unlink(c,q,tag)	ao2_t_unlink(c,q,tag)
+-static inline struct call_queue *queue_ref(struct call_queue *q)
++/*!
++ * \brief ao2 callback to calculate hash of a queue by name
++ */
++static int qdata_hash_cb(const void *obj, const int flags)
+ {
+-	ao2_ref(q, 1);
+-	return q;
++	const struct queue_data *d = obj;
++	int qhash = d->qhash;
++
++	return qhash;
+ }
+ 
+-static inline struct call_queue *queue_unref(struct call_queue *q)
++
++/*!
++ * \brief ao2 callback to find queue by name
++ * \note this is the default function used by ao2_find
++ */
++static int qdata_cmp_cb(void *obj, void *arg, int flags)
+ {
+-	ao2_ref(q, -1);
+-	return NULL;
++	const struct queue_data *d = obj, *d2 = arg;
++	const char *name = arg;
++	int qhash = (flags & OBJ_POINTER) ? d2->qhash : ast_str_case_hash(name);
++
++	return  (d->qhash == qhash) ? CMP_MATCH | CMP_STOP : 0;
+ }
+-#endif
+ 
+-/*! \brief Set variables of queue */
++/*! \brief Set channel variables of queue */
+ static void set_queue_variables(struct call_queue *q, struct ast_channel *chan)
+ {
+ 	char interfacevar[256]="";
+ 	float sl = 0;
++	struct queue_data *data = q->data;
+ 
+-	ao2_lock(q);
+-
+ 	if (q->setqueuevar) {
+ 		sl = 0;
+-		if (q->callscompleted > 0) 
+-			sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
++		ao2_lock(data);
++		if (data->callscompleted > 0) {
++			sl = 100 * ((float) data->callscompletedinsl / (float) data->callscompleted);
++		}
+ 
+ 		snprintf(interfacevar, sizeof(interfacevar),
+ 			"QUEUENAME=%s,QUEUEMAX=%d,QUEUESTRATEGY=%s,QUEUECALLS=%d,QUEUEHOLDTIME=%d,QUEUETALKTIME=%d,QUEUECOMPLETED=%d,QUEUEABANDONED=%d,QUEUESRVLEVEL=%d,QUEUESRVLEVELPERF=%2.1f",
+-			q->name, q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->talktime, q->callscompleted, q->callsabandoned,  q->servicelevel, sl);
++			q->name, q->maxlen, int2strat(q->strategy), data->count, data->holdtime, data->talktime,
++			data->callscompleted, data->callsabandoned,  q->servicelevel, sl);
+ 
+-		ao2_unlock(q);
+-	
+-		pbx_builtin_setvar_multiple(chan, interfacevar); 
+-	} else {
+-		ao2_unlock(q);
++		pbx_builtin_setvar_multiple(chan, interfacevar);
++		ao2_unlock(data);
+ 	}
+ }
+ 
+-/*! \brief Insert the 'new' entry after the 'prev' entry of queue 'q' */
+-static inline void insert_entry(struct call_queue *q, struct queue_ent *prev, struct queue_ent *new, int *pos)
++/*! \brief Insert the 'new' callattempt entry after the 'prev' entry of queue 'q' */
++static inline void insert_entry(struct queue_ent *new, int *pos)
+ {
+-	struct queue_ent *cur;
++	new->pos = ++(*pos);
++	new->opos = *pos;
++	ao2_lock(new->parent->data);
++	new->parent->data->count++;
++	ao2_unlock(new->parent->data);
++}
+ 
+-	if (!q || !new)
+-		return;
+-	if (prev) {
+-		cur = prev->next;
+-		prev->next = new;
+-	} else {
+-		cur = q->head;
+-		q->head = new;
++/*! \brief return the device state for a member*/
++static int get_device_status(struct member *m)
++{
++	int ret;
++	struct mem_state *s = m->device;
++
++	ao2_lock(s);
++
++	ret = s->status;
++	switch (s->status) {
++		case AST_DEVICE_INVALID:
++		case AST_DEVICE_UNAVAILABLE:
++		case AST_DEVICE_BUSY:
++			break;
++		case AST_DEVICE_INUSE:
++		case AST_DEVICE_RINGING:
++		case AST_DEVICE_RINGINUSE:
++		case AST_DEVICE_ONHOLD:
++			/* if im active and may not place calls when INUSE im actually BUSY */
++			if ((s->reserved || s->active) && !m->callinuse) {
++				ret = AST_DEVICE_BUSY;
++				break;
++			}
++			break;
++		case AST_DEVICE_NOT_INUSE:
++		case AST_DEVICE_UNKNOWN:
++			/* it seems that i have this device active but the system does not */
++			if (s->active) {
++				ret = (m->callinuse) ? AST_DEVICE_INUSE : AST_DEVICE_BUSY;
++			} else if (s->reserved) {
++				ret = (m->callinuse) ? AST_DEVICE_RINGING : AST_DEVICE_BUSY;
++			}
+ 	}
+-	new->next = cur;
++        ao2_unlock(s);
+ 
+-	/* every queue_ent must have a reference to it's parent call_queue, this
+-	 * reference does not go away until the end of the queue_ent's life, meaning
+-	 * that even when the queue_ent leaves the call_queue this ref must remain. */
+-	queue_ref(q);
+-	new->parent = q;
+-	new->pos = ++(*pos);
+-	new->opos = *pos;
++        return ret;
+ }
+ 
+ /*! \brief Check if members are available
+@@ -1364,22 +1439,34 @@
+  * is available, the function immediately returns 0. If no members are available,
+  * then -1 is returned.
+  */
+-static int get_member_status(struct call_queue *q, int max_penalty, int min_penalty, enum empty_conditions conditions)
++static int get_member_status(const struct queue_ent *qe, int join)
+ {
+ 	struct member *member;
+ 	struct ao2_iterator mem_iter;
++	struct call_queue *q = qe->parent;
++	int max_penalty = qe->max_penalty;
++	int min_penalty = qe->min_penalty;
++	enum empty_conditions conditions;
+ 
+-	ao2_lock(q);
+-	mem_iter = ao2_iterator_init(q->members, 0);
+-	for (; (member = ao2_iterator_next(&mem_iter)); ao2_ref(member, -1)) {
++	conditions = (join) ? q->joinempty : q->leavewhenempty;
++
++	if (!conditions) {
++		return 0;
++	}
++
++	mem_iter = ao2_iterator_init(q->data->members, 0);
++	while((member = ao2_iterator_next(&mem_iter))) {
++		ao2_lock(member);
+ 		if ((max_penalty && (member->penalty > max_penalty)) || (min_penalty && (member->penalty < min_penalty))) {
+ 			if (conditions & QUEUE_EMPTY_PENALTY) {
+ 				ast_debug(4, "%s is unavailable because his penalty is not between %d and %d\n", member->membername, min_penalty, max_penalty);
++				ao2_unlock(member);
++				ao2_ref(member, -1);
+ 				continue;
+ 			}
+ 		}
+ 
+-		switch (member->status) {
++		switch (get_device_status(member)) {
+ 		case AST_DEVICE_INVALID:
+ 			if (conditions & QUEUE_EMPTY_INVALID) {
+ 				ast_debug(4, "%s is unavailable because his device state is 'invalid'\n", member->membername);
+@@ -1393,6 +1480,7 @@
+ 			}
+ 			goto default_case;
+ 		case AST_DEVICE_INUSE:
++		case AST_DEVICE_BUSY:
+ 			if (conditions & QUEUE_EMPTY_INUSE) {

[... 8224 lines stripped ...]



More information about the svn-commits mailing list