[asterisk-commits] irroot: branch irroot/patches r337964 - /team/irroot/patches/

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Sun Sep 25 09:03:54 CDT 2011


Author: irroot
Date: Sun Sep 25 09:03:49 2011
New Revision: 337964

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=337964
Log:
Patches for older versions

Added:
    team/irroot/patches/distrotech-1.8.2.patch   (with props)
    team/irroot/patches/distrotech-1.8.3.patch   (with props)
    team/irroot/patches/distrotech-1.8.4.patch   (with props)
    team/irroot/patches/distrotech-1.8.5.patch   (with props)

Added: team/irroot/patches/distrotech-1.8.2.patch
URL: http://svnview.digium.com/svn/asterisk/team/irroot/patches/distrotech-1.8.2.patch?view=auto&rev=337964
==============================================================================
--- team/irroot/patches/distrotech-1.8.2.patch (added)
+++ team/irroot/patches/distrotech-1.8.2.patch Sun Sep 25 09:03:49 2011
@@ -1,0 +1,1914 @@
+Index: channels/chan_dahdi.c
+===================================================================
+--- channels/chan_dahdi.c	(revision 226)
++++ channels/chan_dahdi.c	(working copy)
+@@ -9178,6 +9178,9 @@
+ 		case AST_CONTROL_SRCUPDATE:
+ 			res = 0;
+ 			break;
++		case AST_CONTROL_T38_PARAMETERS:
++			res = -1;
++			break;
+ 		case -1:
+ 			res = tone_zone_play_tone(p->subs[idx].dfd, -1);
+ 			break;
+Index: channels/chan_sip.c
+===================================================================
+--- channels/chan_sip.c	(revision 226)
++++ channels/chan_sip.c	(working copy)
+@@ -4068,6 +4068,9 @@
+ 			case T38_ENABLED:
+ 				state = T38_STATE_NEGOTIATED;
+ 				break;
++			case T38_REJECTED:
++				state = T38_STATE_UNAVAILABLE;
++				break;
+ 			default:
+ 				state = T38_STATE_UNKNOWN;
+ 			}
+@@ -4729,6 +4732,7 @@
+ 		parameters.request_response = AST_T38_NEGOTIATED;
+ 		ast_udptl_set_tag(p->udptl, "SIP/%s", p->username);
+ 		break;
++	case T38_REJECTED:
+ 	case T38_DISABLED:
+ 		if (old == T38_ENABLED) {
+ 			parameters.request_response = AST_T38_TERMINATED;
+@@ -6269,7 +6273,7 @@
+ 	case AST_T38_REQUEST_NEGOTIATE:         /* Request T38 */
+ 		/* Negotiation can not take place without a valid max_ifp value. */
+ 		if (!parameters->max_ifp) {
+-			change_t38_state(p, T38_DISABLED);
++			change_t38_state(p, T38_REJECTED);
+ 			if (p->t38.state == T38_PEER_REINVITE) {
+ 				AST_SCHED_DEL_UNREF(sched, p->t38id, dialog_unref(p, "when you delete the t38id sched, you should dec the refcount for the stored dialog ptr"));
+ 				transmit_response_reliable(p, "488 Not acceptable here", &p->initreq);
+@@ -6311,7 +6315,7 @@
+ 	case AST_T38_REQUEST_TERMINATE:         /* Shutdown T38 */
+ 		if (p->t38.state == T38_PEER_REINVITE) {
+ 			AST_SCHED_DEL_UNREF(sched, p->t38id, dialog_unref(p, "when you delete the t38id sched, you should dec the refcount for the stored dialog ptr"));
+-			change_t38_state(p, T38_DISABLED);
++			change_t38_state(p, T38_REJECTED);
+ 			transmit_response_reliable(p, "488 Not acceptable here", &p->initreq);
+ 		} else if (p->t38.state == T38_ENABLED)
+ 			transmit_reinvite_with_sdp(p, FALSE, FALSE);
+@@ -6961,6 +6965,12 @@
+ 
+ 	sip_pvt_lock(p);
+ 	fr = sip_rtp_read(ast, p, &faxdetected);
++
++	if (((fr == &ast_null_frame) && p->rtp && !ast_rtp_instance_get_bridged(p->rtp)) || (!p->rtp)) {
++		sip_pvt_unlock(p);
++		return fr;
++	}
++
+ 	p->lastrtprx = time(NULL);
+ 
+ 	/* If we detect a CNG tone and fax detection is enabled then send us off to the fax extension */
+@@ -8607,7 +8617,7 @@
+ 		}
+ 	}
+ 
+-	if ((portno == -1) && (p->t38.state != T38_DISABLED)) {
++	if ((portno == -1) && (p->t38.state != T38_DISABLED) && (p->t38.state != T38_REJECTED)) {
+ 		ast_debug(3, "Have T.38 but no audio, accepting offer anyway\n");
+ 		return 0;
+         }
+@@ -18387,7 +18397,7 @@
+ 	} else  if (!strcasecmp(data, "peername")) {
+ 		ast_copy_string(buf, p->peername, len);
+ 	} else if (!strcasecmp(data, "t38passthrough")) {
+-		if (p->t38.state == T38_DISABLED) {
++		if ((p->t38.state == T38_DISABLED) || (p->t38.state == T38_REJECTED)) {
+ 			ast_copy_string(buf, "0", len);
+ 		} else { /* T38 is offered or enabled in this call */
+ 			ast_copy_string(buf, "1", len);
+@@ -19143,7 +19153,7 @@
+ 	case 606: /* Not Acceptable */
+ 		xmitres = transmit_request(p, SIP_ACK, seqno, XMIT_UNRELIABLE, FALSE);
+ 		if (p->udptl && p->t38.state == T38_LOCAL_REINVITE) {
+-			change_t38_state(p, T38_DISABLED);
++			change_t38_state(p, T38_REJECTED);
+ 			/* Try to reset RTP timers */
+ 			//ast_rtp_set_rtptimers_onhold(p->rtp);
+ 
+@@ -20807,7 +20817,7 @@
+ 	 * want to abort the negotiation process
+ 	 */
+ 	if (p->t38id != -1) {
+-		change_t38_state(p, T38_DISABLED);
++		change_t38_state(p, T38_REJECTED);
+ 		transmit_response_reliable(p, "488 Not acceptable here", &p->initreq);
+ 		p->t38id = -1;
+ 		dialog_unref(p, "unref the dialog ptr from sip_t38_abort, because it held a dialog ptr");
+@@ -21678,7 +21688,7 @@
+ 			} else if (p->t38.state == T38_ENABLED) {
+ 				ast_set_flag(&p->flags[1], SIP_PAGE2_DIALOG_ESTABLISHED);
+ 				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) {
++			} 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)) {
+ 					ast_log(LOG_WARNING, "Target does not support required crypto\n");
+@@ -24345,14 +24355,10 @@
+ 		if (!ast_test_flag(&dialog->flags[1], SIP_PAGE2_CALL_ONHOLD) || (ast_rtp_instance_get_hold_timeout(dialog->rtp) && (t > dialog->lastrtprx + ast_rtp_instance_get_hold_timeout(dialog->rtp)))) {
+ 			/* Needs a hangup */
+ 			if (ast_rtp_instance_get_timeout(dialog->rtp)) {
+-				while (dialog->owner && ast_channel_trylock(dialog->owner)) {
+-					sip_pvt_unlock(dialog);
+-					usleep(1);
+-					sip_pvt_lock(dialog);
+-				}
+-				if (!dialog->owner) {
+-					return; /* channel hangup can occur during deadlock avoidance. */
+-				}
++				/* Don't block the monitor thread.  This function is called often enough
++				 * that we can wait for the next time around. */
++				if ((!dialog->owner) || (dialog->owner && ast_channel_trylock(dialog->owner)))
++					return;
+ 				ast_log(LOG_NOTICE, "Disconnecting call '%s' for lack of RTP activity in %ld seconds\n",
+ 					dialog->owner->name, (long) (t - dialog->lastrtprx));
+ 				/* Issue a softhangup */
+@@ -25692,6 +25698,11 @@
+ 		struct sip_mailbox *mailbox;
+ 		int duplicate = 0;
+ 
++		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)) {
+Index: channels/chan_iax2.c
+===================================================================
+--- channels/chan_iax2.c	(revision 226)
++++ channels/chan_iax2.c	(working copy)
+@@ -5623,7 +5623,12 @@
+ 		if (!ast_test_flag64(pvt, IAX_SENDCONNECTEDLINE))
+ 			goto done;
+ 		break;
+-	}
++	case AST_CONTROL_T38_PARAMETERS:
++		/* Immediately signal back that T38 is not supported. Otherwise
++		 * the bridged channel has to wait until a timeout. */
++		res = -1;
++		goto done;
++        }
+ 
+ 	res = send_command(pvt, AST_FRAME_CONTROL, condition, 0, data, datalen, -1);
+ 
+Index: channels/sip/include/sip.h
+===================================================================
+--- channels/sip/include/sip.h	(revision 226)
++++ channels/sip/include/sip.h	(working copy)
+@@ -592,7 +592,8 @@
+ 	T38_DISABLED = 0,     /*!< Not enabled */
+ 	T38_LOCAL_REINVITE,   /*!< Offered from local - REINVITE */
+ 	T38_PEER_REINVITE,    /*!< Offered from peer - REINVITE */
+-	T38_ENABLED           /*!< Negotiated (enabled) */
++	T38_ENABLED,          /*!< Negotiated (enabled) */
++	T38_REJECTED          /*!< Refused */
+ };
+ 
+ /*! \brief Parameters to know status of transfer */
+Index: apps/app_faxgateway.c
+===================================================================
+--- apps/app_faxgateway.c	(revision 0)
++++ apps/app_faxgateway.c	(revision 0)
+@@ -0,0 +1,473 @@
++/*
++ * Asterisk -- An open source telephony toolkit.
++ *
++ * Copyright (C) 2008-2009, Digium, Inc.
++ *
++ * Initial T.38-gateway code
++ * 2008, Daniel Ferenci <daniel.ferenci at nethemba.com>
++ * Created by Nethemba s.r.o. http://www.nethemba.com
++ * Sponsored by IPEX a.s. http://www.ipex.cz
++ *
++ * T.38-gateway integration into asterisk app_fax and rework
++ * 2008, Gregory Hinton Nietsky <gregory at dnstelecom.co.za>
++ * dns Telecom http://www.dnstelecom.co.za
++ *
++ * Modified to make T.38-gateway compatible with Asterisk 1.6.2
++ * 2010, Anton Verevkin <mymail at verevkin.it>
++ * ViaNetTV http://www.vianettv.com
++ *
++ * Modified to make T.38-gateway work
++ * 2010, Klaus Darilion, IPCom GmbH, www.ipcom.at
++ *
++ * See http://www.asterisk.org for more information about
++ * the Asterisk project. Please do not directly contact
++ * any of the maintainers of this project for assistance;
++ * the project provides a web site, mailing lists and IRC
++ * channels for your use.
++ *
++ * This program is free software, distributed under the terms of
++ * the GNU General Public License Version 2. See the LICENSE file
++ * at the top of the source tree.
++ */
++
++/*! \file
++ *
++ * \brief Redundant fax gateway functions that are to be depricated
++ *
++ * \ingroup applications
++ */
++
++#include "asterisk.h"
++
++ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
++
++#include "asterisk/io.h"
++#include "asterisk/file.h"
++#include "asterisk/logger.h"
++#include "asterisk/module.h"
++#include "asterisk/app.h"
++#include "asterisk/lock.h"
++#include "asterisk/options.h"
++#include "asterisk/strings.h"
++#include "asterisk/cli.h"
++#include "asterisk/utils.h"
++#include "asterisk/config.h"
++#include "asterisk/astobj2.h"
++#include "asterisk/res_fax.h"
++#include "asterisk/file.h"
++#include "asterisk/channel.h"
++#include "asterisk/pbx.h"
++#include "asterisk/manager.h"
++#include "asterisk/dsp.h"
++#include "asterisk/indications.h"
++#include "asterisk/ast_version.h"
++#include "asterisk/features.h"
++
++/*** DOCUMENTATION
++	<application name="FaxGateway" language="en_US">   
++		<synopsis>
++			T.38 Gateway Handling
++		</synopsis>
++		<syntax>
++			<parameter name="dialstring" required="true">
++				<para>Dial string in format (technology/[device:]number1)</para>
++			</parameter>  
++			<parameter name="timeout" required="false">
++				<para>Specifies the number of seconds we attempt to dial the specified devices</para>
++				<para>If not specified, this defaults to 35 seconds.</para>
++			</parameter>
++		</syntax>
++		<description>
++			<para>Dials specified channel and bridges voice and fax. If both channels use voice or
++			T.38, then FaxGateway just acts as a dumb bridge. I one of the channels uses T.38 and
++			the other channel uses voice, then FaxGateway activates the T.38-Gateway and translates
++			between T.38 and voice.</para> + <para>Use instead of Dial application.</para>
++			<para>Note: This application is not yet complete as it does not forward indications (e.g. Rigning)
++			as long as the outgoing channel is not answered.</para> 
++		</description>
++	</application>
++	<application name="FaxDetect" language="en_US">
++		<synopsis>
++			Generic Fax Detect CED/CNG/T.38
++		</synopsis>
++		<syntax>
++			<parameter name="timeout" required="true">
++				<para>Specifies the number of seconds we attempt to detect a fax tone on the channel</para>
++			</parameter>
++		</syntax>
++		<description>
++			<para>This application sets the following channel variables upon completion</para>
++			<para>  FAXTONE - detected tone: CED | CNG | NONE</para>
++			<para>  T38STATUS - T.38 negotiated: 0 | 1</para>
++		</description>
++	</application>
++***/
++
++static const char app_faxgateway[] = "FaxGateway";
++static const char app_faxdetect[] = "FaxDetect";
++
++/*! \brief Generic bridge enableing faxdetect/T.38 Negotiation */
++static int ast_bridge_frames(struct ast_channel *chan, struct ast_channel *peer)
++{
++	struct ast_dsp *dsp = NULL;
++	struct ast_channel *active = NULL;
++	struct ast_channel *inactive = NULL;
++	struct ast_channel *channels[2]={chan, peer};
++	struct ast_frame *f;
++	int timeout;
++	struct ast_control_t38_parameters t38_parameters = { .version = 0,
++							     .max_ifp = 400,
++							     .rate = AST_T38_RATE_14400,
++							     .rate_management = AST_T38_RATE_MANAGEMENT_TRANSFERRED_TCF,
++							     .fill_bit_removal = 1,
++							     .transcoding_mmr = 1, 
++							     .transcoding_jbig = 1,
++	};
++
++	/* Setup DSP CNG/CED processing */
++	if ((dsp=ast_dsp_new())) {
++		ast_dsp_set_features(dsp, DSP_FEATURE_FAX_DETECT);
++		ast_dsp_set_faxmode(dsp, DSP_FAXMODE_DETECT_CNG | DSP_FAXMODE_DETECT_CED);
++	} else {
++		ast_debug(1, "Unable to allocate Fax Detect DSP This may lead to problems with T.38 switchover!\n");
++	}
++
++	ast_debug(1, "Bridging started chan %s peer %s\n", chan->name, peer->name);
++	
++	for(;;) {
++		timeout=1000;
++		if (!(active = ast_waitfor_n(channels, 2, &timeout))) {
++			if (!timeout) {
++				break;
++			}
++			continue;
++		}
++
++		if (!(f = ast_read(active))) {
++			ast_debug(1, "Error reading frame on %s, stop bridging as the call has finished.\n", active->name);
++			break;
++		}
++ 
++		if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass.integer == AST_CONTROL_T38_PARAMETERS)) {
++			if ((ast_t38_gateway_handle_parameters == NULL) || (!ast_t38_gateway_handle_parameters(chan, peer, active, f))) {
++				ast_frfree(f);
++				continue;
++			}
++		}
++
++		inactive = (active == chan)  ?   peer  :  chan;
++
++		/* tickle the channel if we have fax tone */
++		if (dsp && ((f = ast_dsp_process(active, dsp, f))) && (f->frametype == AST_FRAME_DTMF)) {
++			switch (f->subclass.integer) {
++				case '5':
++				case 'f':
++				case 'e':
++					if (ast_channel_get_t38_state(active) == T38_STATE_UNKNOWN) {
++						t38_parameters.request_response = AST_T38_REQUEST_NEGOTIATE;
++						ast_indicate_data(active, AST_CONTROL_T38_PARAMETERS, &t38_parameters, sizeof(t38_parameters));
++					}
++					if (ast_channel_get_t38_state(inactive) == T38_STATE_UNKNOWN) {
++						t38_parameters.request_response = AST_T38_REQUEST_NEGOTIATE;
++						ast_indicate_data(inactive, AST_CONTROL_T38_PARAMETERS, &t38_parameters, sizeof(t38_parameters));
++					}
++					ast_frfree(f);
++					continue;
++			}
++		}
++
++		ast_write(inactive, f);
++		ast_frfree(f);
++	}
++	if (dsp) {
++		ast_dsp_free(dsp);
++	}
++	return 0;
++}
++
++/*!
++ * \brief Helper function called from app_dial.c
++ * \param chan,peer
++ */
++static int __ast_bridge_t38(struct ast_channel *chan, struct ast_channel *peer)
++{
++	int res = 0;
++	struct ast_cdr *peer_cdr=peer->cdr;
++	union ast_frame_subclass expected_framesubclass = { .integer = -1 };
++	unsigned int expected_frametype = -1;
++
++	while (peer_cdr) {
++		if (!ast_test_flag(peer_cdr,AST_CDR_FLAG_LOCKED))
++			break;
++		peer_cdr = peer_cdr->next;
++	}
++
++	if (! peer_cdr) {
++		peer_cdr=peer->cdr;
++	}
++
++	if (!chan || !peer) {
++		ast_debug(1, "Fax channel is NULL Or No Fax Handler Possible. Giving up.\n");
++		return -1;
++	}
++
++	/* pick up originating call */
++	if (chan->_state != AST_STATE_UP) {
++		if (ast_answer(chan)) {
++			ast_debug(1, "Could not answer channel '%s'. Can not run a gateway on a down channel\n", chan->name);
++			return -1;
++		}
++	}
++
++	pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name);
++	pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name);
++
++	manager_event(EVENT_FLAG_CALL, "Dial",
++		"SubEvent: Begin\r\n"
++		"Channel: %s\r\n"
++		"Destination: %s\r\n"
++		"CallerIDNum: %s\r\n"
++		"CallerIDName: %s\r\n"
++		"UniqueID: %s\r\n"
++		"DestUniqueID: %s\r\n"
++		"Dialstring: %s\r\n",
++		chan->name, peer->name, 
++		S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, "<unknown>"),
++		S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, "<unknown>"),
++		chan->uniqueid,peer->uniqueid, "");
++
++	/* set the read format to slin to do fax detect*/
++	expected_frametype = AST_FRAME_VOICE;
++	expected_framesubclass.codec = AST_FORMAT_SLINEAR;
++	ast_set_read_format(chan, AST_FORMAT_SLINEAR);
++	ast_set_read_format(peer, AST_FORMAT_SLINEAR);
++	ast_channel_make_compatible(chan, peer);
++
++	/* start the gateway / switch over loop*/
++	/* Start bridging packets until all sides have negotiated T.38 capabilities and only one is capable*/
++	ast_bridge_frames(chan, peer);
++
++	if (peer) {
++		ast_cdr_specialized_reset(peer_cdr,0);
++		ast_hangup(peer);
++	}
++
++	return res;
++}
++
++static int faxgateway_exec(struct ast_channel *chan, const char *data)
++{
++	int res = 0;
++	char *parse;
++	struct ast_channel *peer;
++	int state, priority, timeout;
++	const char *account=NULL, *cid_name=NULL, *cid_num=NULL, *context=NULL, *exten=NULL;
++	struct ast_variable *vars=NULL;
++	struct outgoing_helper oh;
++	char *number, *tech;
++
++	parse = ast_strdupa(data);
++
++	AST_DECLARE_APP_ARGS(args,
++		AST_APP_ARG(dest);
++		AST_APP_ARG(timeout);
++	);
++	AST_STANDARD_APP_ARGS(args, parse);
++
++	/* Get a technology/[device:]number pair */
++	number = args.dest;
++	tech = strsep(&number, "/");
++	if (!number) {
++		ast_debug(1, "dialstring argument takes format (technology/[device:]number1)\n");
++		return -1;
++	}
++
++	if (args.timeout)
++		timeout = atoi(args.timeout) * 1000;
++	else
++		timeout = 35000;
++
++	char numsubst[256];
++	ast_copy_string(numsubst, number, sizeof(numsubst));
++
++	/* Setup the outgoing helper and dial waiting for timeout or answer*/
++	if (!ast_strlen_zero(chan->caller.id.number.str))
++		cid_num=ast_strdupa(chan->caller.id.number.str);
++	if (!ast_strlen_zero(chan->caller.id.name.str))
++		cid_name=ast_strdupa(chan->caller.id.name.str);
++	if (!ast_strlen_zero(chan->context))
++		context=ast_strdupa(chan->context);
++	if (!ast_strlen_zero(chan->exten))
++		exten=ast_strdupa(chan->exten);
++	priority=chan->priority;
++
++	oh.context = context;
++	oh.exten = exten;
++	oh.priority = priority;
++	oh.cid_num = cid_num;
++	oh.cid_name = cid_name;
++	oh.account = account;
++	oh.vars = vars;
++	oh.parent_channel = chan;
++	oh.parent_channel=chan;
++
++	if (!(peer = __ast_request_and_dial(tech, chan->nativeformats, NULL, numsubst, timeout, &state, chan->caller.id.number.str, chan->caller.id.name.str, &oh))) {
++		chan->hangupcause = state;
++		return -1;
++	}
++	ast_debug(1, "Outgoing channel '%s'\n", peer->name);
++
++	ast_channel_lock(chan);
++	ast_copy_string(chan->cdr->dstchannel, peer->name, sizeof(chan->cdr->dstchannel));
++	ast_channel_unlock(chan);
++
++	res=__ast_bridge_t38(chan, peer);
++
++	return res;
++}
++
++static int faxdetect_run(struct ast_channel *chan, int timeout, enum ast_t38_state *t38state)
++{
++	struct ast_dsp *dsp;
++	struct ast_frame *f;
++	int timeleft=timeout, res=0;
++	struct ast_control_t38_parameters t38_parameters = { .version = 0,
++							     .max_ifp = 400,
++							     .rate = AST_T38_RATE_14400,
++							     .rate_management = AST_T38_RATE_MANAGEMENT_TRANSFERRED_TCF,
++							     .fill_bit_removal = 1,
++							     .transcoding_mmr = 1,
++							     .transcoding_jbig = 1,
++	};
++
++	if (chan->_state != AST_STATE_UP)
++		ast_answer(chan);
++   
++	res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
++	if (res < 0) {
++		ast_log(LOG_WARNING, "Unable to set to linear read mode, giving up\n");
++		return 0;
++	}
++
++	/* Setup DSP CNG/CED processing */
++	if ((dsp=ast_dsp_new())) {
++		ast_dsp_set_features(dsp, DSP_FEATURE_FAX_DETECT);
++		ast_dsp_set_faxmode(dsp, DSP_FAXMODE_DETECT_CNG | DSP_FAXMODE_DETECT_CED);
++	} else {
++		ast_log(LOG_WARNING, "Unable to allocate All DSP Ignoring CNG/CED!\n");
++		return 0;
++	}
++
++	*t38state = ast_channel_get_t38_state(chan);
++
++	while((timeleft=ast_waitfor(chan, timeleft))) {
++		if (!(f=ast_read(chan))) {
++			break;
++		}
++		if ((f->frametype == AST_FRAME_VOICE) && (f->subclass.codec == AST_FORMAT_SLINEAR)) {
++			f=ast_dsp_process(chan, dsp, f);
++			if ((f->frametype == AST_FRAME_DTMF) && ((f->subclass.integer == 'e') || (f->subclass.integer == 'f'))) {
++				switch (f->subclass.integer) {
++					case 'f':res=1;
++					case 'e':res=2;
++				}
++				if (*t38state == T38_STATE_UNKNOWN) {
++					t38_parameters.request_response = AST_T38_REQUEST_NEGOTIATE;
++					ast_indicate_data(chan, AST_CONTROL_T38_PARAMETERS, &t38_parameters, sizeof(t38_parameters));
++				}
++			}
++		}
++		ast_frfree(f);
++		if ((*t38state != T38_STATE_UNAVAILABLE) && (*t38state != T38_STATE_REJECTED) && (*t38state != T38_STATE_NEGOTIATED)) {
++			*t38state = ast_channel_get_t38_state(chan);
++		}
++		if (((res > 0) && (*t38state != T38_STATE_UNKNOWN) && (*t38state != T38_STATE_NEGOTIATING)) || (timeleft <= 0)) {
++			break;
++		}
++	}
++	if (dsp) {
++		ast_dsp_free(dsp);
++	}
++	return res;
++}
++
++static int faxdetect_exec(struct ast_channel *chan, const char *data)
++{
++	char *parse;
++	int timeout, tone;
++	enum ast_t38_state t38state = T38_STATE_UNKNOWN;
++         
++	parse = ast_strdupa(data);
++
++	AST_DECLARE_APP_ARGS(args,
++		AST_APP_ARG(timeout);
++	);
++	AST_STANDARD_APP_ARGS(args, parse);
++                        
++	if (args.timeout) {
++		timeout = atoi(args.timeout) * 1000;
++	} else {
++		pbx_builtin_setvar_helper(chan, "FAXTONE", "NONE");
++		return 0;
++	}
++        
++	tone=faxdetect_run(chan, timeout, &t38state);
++	
++	if (t38state == T38_STATE_NEGOTIATED) {
++		pbx_builtin_setvar_helper(chan, "T38STATUS", "1");
++	} else {
++		pbx_builtin_setvar_helper(chan, "T38STATUS", "0");
++	}
++
++	switch (tone) {
++		case 0:
++			pbx_builtin_setvar_helper(chan, "FAXTONE", "NONE");
++			return 0;
++		case 1:
++			pbx_builtin_setvar_helper(chan, "FAXTONE", "CNG");
++			return 0;
++		case 2:
++			pbx_builtin_setvar_helper(chan, "FAXTONE", "CED");
++			return 0;
++		default:
++			return -1;
++	}
++}
++
++/*! \brief unload res_fax */
++static int unload_module(void)
++{
++	if (ast_unregister_application(app_faxgateway) < 0) {
++		ast_log(LOG_WARNING, "failed to unregister '%s'\n", app_faxgateway);
++	}
++
++	if (ast_unregister_application(app_faxdetect) < 0) {
++		ast_log(LOG_WARNING, "failed to unregister '%s'\n", app_faxdetect);
++	}
++
++	/* Unpublish __ast_bridge_t38 function */
++	ast_bridge_t38 = NULL;
++
++	return 0;
++}
++
++/*! \brief load res_fax */
++static int load_module(void)
++{
++	int res;
++
++	res = ast_register_application_xml(app_faxgateway, faxgateway_exec);
++	res |= ast_register_application_xml(app_faxdetect, faxdetect_exec);
++
++	/* Publish __ast_bridge_t38 function to be used by Dial application */
++	ast_bridge_t38 = __ast_bridge_t38;
++
++	return res;
++}
++
++
++AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "Generic FAX Applications",
++		.load = load_module,
++		.unload = unload_module,
++		.load_pri = AST_MODPRI_APP_DEPEND,
++	       );
+Index: apps/app_directed_pickup.c
+===================================================================
+--- apps/app_directed_pickup.c	(revision 226)
++++ apps/app_directed_pickup.c	(working copy)
+@@ -141,13 +141,26 @@
+ 	ast_manager_event_multichan(EVENT_FLAG_CALL, "Pickup", 2, chans,
+ 		"Channel: %s\r\nTargetChannel: %s\r\n", chan->name, target->name);
+ 
++	struct ast_channel *bridge;
++	const char *macro;
++	const char *macro_args;
++
++	macro=pbx_builtin_getvar_helper(chan, "PICKUP_BRIDGE_MACRO");
++	macro_args=pbx_builtin_getvar_helper(chan, "PICKUP_BRIDGE_MACRO_ARGS");
++	if (!ast_strlen_zero(macro)) {
++		ast_channel_unlock(target);
++		while (target && !(bridge = ast_bridged_channel(target)))
++			usleep(1000);
++		ast_channel_lock(target);
++		ast_app_run_macro(NULL, bridge, macro, macro_args);
++	}
+ 	return res;
+ }
+ 
+ /* Helper function that determines whether a channel is capable of being picked up */
+ static int can_pickup(struct ast_channel *chan)
+ {
+-	if (!chan->pbx && (chan->_state == AST_STATE_RINGING || chan->_state == AST_STATE_RING || chan->_state == AST_STATE_DOWN))
++	if (!chan->pbx && !chan->masq && (chan->_state == AST_STATE_RINGING || chan->_state == AST_STATE_RING))
+ 		return 1;
+ 	else
+ 		return 0;
+@@ -287,6 +300,30 @@
+ 	return res;
+ }
+ 
++static int find_channel_by_group(void *obj, void *arg, void *data, int flags)
++{
++	struct ast_channel *chan = obj;
++	struct ast_channel *c = data;
++
++	int i = (can_pickup(chan) && (c != chan) && (c->pickupgroup & chan->callgroup));
++
++	return i ? CMP_MATCH | CMP_STOP : 0;
++}
++
++static int pickup_by_group(struct ast_channel *chan)
++{
++	struct ast_channel *target=NULL;
++	int res=-1;
++
++	if ((target = ast_channel_callback(find_channel_by_group, NULL, chan, 0))) {
++		ast_channel_lock(target);
++		res=pickup_do(chan, target);
++		ast_channel_unlock(target);
++		target = ast_channel_unref(target);
++	}
++	return res;
++}
++
+ /* application entry point for Pickup() */
+ static int pickup_exec(struct ast_channel *chan, const char *data)
+ {
+@@ -295,7 +332,7 @@
+ 	char *exten = NULL, *context = NULL;
+ 
+ 	if (ast_strlen_zero(data)) {
+-		res = ast_pickup_call(chan);
++		pickup_by_group(chan);
+ 		return res;
+ 	}
+ 	
+Index: apps/app_dial.c
+===================================================================
+--- apps/app_dial.c	(revision 226)
++++ apps/app_dial.c	(working copy)
+@@ -106,6 +106,10 @@
+ 					channel before doing anything on the called channel. You will rarely need to use
+ 					this option, the default behavior is adequate in most cases.</para>
+ 				</option>
++				<option name="b">
++					<para>Bridge T.38 Fax. This disables other call features that are usually available after
++					the calling party answers. This includes transfer, call and DTMF recording,etc.</para>
++				</option>
+ 				<option name="C">
+ 					<para>Reset the call detail record (CDR) for this call.</para>
+ 				</option>
+@@ -559,6 +563,7 @@
+ #define OPT_CANCEL_TIMEOUT   ((uint64_t)1 << 37)
+ #define OPT_FORCE_CID_TAG    ((uint64_t)1 << 38)
+ #define OPT_FORCE_CID_PRES   ((uint64_t)1 << 39)
++#define OPT_BRIDGE_T38       ((uint64_t)1 << 40)
+ 
+ enum {
+ 	OPT_ARG_ANNOUNCE = 0,
+@@ -584,6 +589,7 @@
+ AST_APP_OPTIONS(dial_exec_options, BEGIN_OPTIONS
+ 	AST_APP_OPTION_ARG('A', OPT_ANNOUNCE, OPT_ARG_ANNOUNCE),
+ 	AST_APP_OPTION('a', OPT_CALLER_ANSWER),
++	AST_APP_OPTION('b', OPT_BRIDGE_T38),
+ 	AST_APP_OPTION('C', OPT_RESETCDR),
+ 	AST_APP_OPTION('c', OPT_CANCEL_ELSEWHERE),
+ 	AST_APP_OPTION('d', OPT_DTMF_EXIT),
+@@ -2638,8 +2644,14 @@
+ 
+ 				ast_channel_setoption(chan, AST_OPTION_OPRMODE, &oprmode, sizeof(oprmode), 0);
+ 			}
+-			res = ast_bridge_call(chan, peer, &config);
+-		}
++			/* Unless we want the T.38 fax bridge, use standard bridging function */
++			if (ast_test_flag64(&opts, OPT_BRIDGE_T38) && (ast_bridge_t38 == NULL))
++				ast_log(LOG_WARNING, "You need to load res_fax.so first to use the fax gateway option. Disabling T.38 gateway.\n");
++			if (!ast_test_flag64(&opts, OPT_BRIDGE_T38) || (ast_bridge_t38 == NULL))
++				res = ast_bridge_call(chan, peer, &config);
++			else
++				res = ast_bridge_t38(chan, peer);
++                }
+ 
+ 		strcpy(peer->context, chan->context);
+ 
+Index: apps/app_queue.c
+===================================================================
+--- apps/app_queue.c	(revision 226)
++++ apps/app_queue.c	(working copy)
+@@ -447,11 +447,25 @@
+ 					<enum name="count">
+ 						<para>Returns the total number of members for the specified queue.</para>
+ 					</enum>
++					<enum name="penalty">
++						<para>Gets or sets queue member penalty.</para>
++					</enum>
++					<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>
+ 				</enumlist>
+ 			</parameter>
++			<parameter name="interface" required="false" />
+ 		</syntax>
+ 		<description>
+-			<para>Returns the number of members currently associated with the specified <replaceable>queuename</replaceable>.</para>
++			<para>Allows access to queue counts [R] and member information [R/W].</para>
++			<para>
++				<replaceable>queuename</replaceable> is required for all operations 
++				<replaceable>interface</replaceable> is required for all member operations.
++			</para>
+ 		</description>
+ 	</function>
+ 	<function name="QUEUE_MEMBER_COUNT" language="en_US">
+@@ -774,6 +788,9 @@
+ /*! \brief queues.conf [general] option */
+ static int update_cdr = 0;
+ 
++/*! \brief queues.conf [genral] option */
++static int negitive_penalty_invalid = 0;
++
+ enum queue_result {
+ 	QUEUE_UNKNOWN = 0,
+ 	QUEUE_TIMEOUT = 1,
+@@ -883,6 +900,7 @@
+ 	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 */
+ };
+ 
+ enum empty_conditions {
+@@ -1000,6 +1018,7 @@
+ 	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 */
+@@ -1030,6 +1049,7 @@
+ static struct ao2_container *queues;
+ 
+ static void update_realtime_members(struct call_queue *q);
++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); 
+@@ -1537,6 +1557,7 @@
+ 	q->numperiodicannounce = 0;
+ 	q->autopause = QUEUE_AUTOPAUSE_OFF;
+ 	q->timeoutpriority = TIMEOUT_PRIORITY_APP;
++	q->autopausedelay = 0;
+ 	if (!q->members) {
+ 		if (q->strategy == QUEUE_STRATEGY_LINEAR)
+ 			/* linear strategy depends on order, so we have to place all members in a single bucket */
+@@ -1842,6 +1863,8 @@
+ 			q->montype = 1;
+ 	} else if (!strcasecmp(param, "autopause")) {
+ 		q->autopause = autopause2int(val);
++	} else if (!strcasecmp(param, "autopausedelay")) {
++		q->autopausedelay = atoi(val);
+ 	} else if (!strcasecmp(param, "maxlen")) {
+ 		q->maxlen = atoi(val);
+ 		if (q->maxlen < 0)
+@@ -1913,14 +1936,22 @@
+  * Search for member in queue, if found update penalty/paused state,
+  * if no member exists create one flag it as a RT member and add to queue member list. 
+ */
+-static void rt_handle_member_record(struct call_queue *q, char *interface, const char *rt_uniqueid, const char *membername, const char *penalty_str, const char *paused_str, const char* state_interface)
++static void rt_handle_member_record(struct call_queue *q, char *interface, struct ast_config *member_config)
+ {
+ 	struct member *m;
+ 	struct ao2_iterator mem_iter;
+ 	int penalty = 0;
+ 	int paused  = 0;
+ 	int found = 0;
++	int ignorebusy = 0;
+ 
++	const char *config_val;
++	const char *rt_uniqueid=ast_variable_retrieve(member_config, interface, "uniqueid");
++	const char *membername=S_OR(ast_variable_retrieve(member_config, interface, "membername"),interface);
++	const char *state_interface=S_OR(ast_variable_retrieve(member_config, interface, "state_interface"),interface);
++	const char *penalty_str=ast_variable_retrieve(member_config, interface, "penalty");
++	const char *paused_str=ast_variable_retrieve(member_config, interface, "paused");
++
+ 	if (ast_strlen_zero(rt_uniqueid)) {
+ 		ast_log(LOG_WARNING, "Realtime field uniqueid is empty for member %s\n", S_OR(membername, "NULL"));
+ 		return;
+@@ -1928,7 +1959,9 @@
+ 
+ 	if (penalty_str) {
+ 		penalty = atoi(penalty_str);
+-		if (penalty < 0)
++		if ((penalty < 0) && negitive_penalty_invalid)
++			return;
++		else if (penalty < 0)
+ 			penalty = 0;
+ 	}
+ 
+@@ -1938,6 +1971,11 @@
+ 			paused = 0;
+ 	}
+ 
++	if ((config_val = ast_variable_retrieve(member_config, interface, "ignorebusy")))
++		ignorebusy=ast_true(config_val);
++	else
++		ignorebusy=1;
++
+  	/* Find member by realtime uniqueid and update */
+  	mem_iter = ao2_iterator_init(q->members, 0);
+  	while ((m = ao2_iterator_next(&mem_iter))) {
+@@ -1950,6 +1988,7 @@
+  				ast_copy_string(m->state_interface, state_interface, sizeof(m->state_interface));
+  			}	   
+  			m->penalty = penalty;
++			m->ignorebusy = ignorebusy;
+  			found = 1;
+  			ao2_ref(m, -1);
+  			break;
+@@ -1963,6 +2002,7 @@
+ 		if ((m = create_queue_member(interface, membername, penalty, paused, state_interface))) {
+ 			m->dead = 0;
+ 			m->realtime = 1;
++			m->ignorebusy = ignorebusy;
+ 			ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid));
+ 			ast_queue_log(q->name, "REALTIME", m->interface, "ADDMEMBER", "%s", "");
+ 			ao2_link(q->members, m);
+@@ -2138,12 +2178,7 @@
+ 	ao2_iterator_destroy(&mem_iter);
+ 
+ 	while ((interface = ast_category_browse(member_config, interface))) {
+-		rt_handle_member_record(q, interface,
+-			ast_variable_retrieve(member_config, interface, "uniqueid"),
+-			S_OR(ast_variable_retrieve(member_config, interface, "membername"),interface),
+-			ast_variable_retrieve(member_config, interface, "penalty"),
+-			ast_variable_retrieve(member_config, interface, "paused"),
+-			S_OR(ast_variable_retrieve(member_config, interface, "state_interface"),interface));
++		rt_handle_member_record(q, interface, member_config);
+ 	}
+ 
+ 	/* Delete all realtime members that have been deleted in DB. */
+@@ -2265,12 +2300,7 @@
+ 	ao2_iterator_destroy(&mem_iter);
+ 
+ 	while ((interface = ast_category_browse(member_config, interface))) {
+-		rt_handle_member_record(q, interface,
+-			ast_variable_retrieve(member_config, interface, "uniqueid"),
+-			S_OR(ast_variable_retrieve(member_config, interface, "membername"), interface),
+-			ast_variable_retrieve(member_config, interface, "penalty"),
+-			ast_variable_retrieve(member_config, interface, "paused"),
+-			S_OR(ast_variable_retrieve(member_config, interface, "state_interface"), interface));
++		rt_handle_member_record(q, interface, member_config);
+ 	}
+ 
+ 	/* Delete all realtime members that have been deleted in DB. */
+@@ -2707,7 +2737,7 @@
+ 	while ((mem = ao2_iterator_next(&mem_iter))) {
+ 		switch (mem->status) {
+ 		case AST_DEVICE_INUSE:
+-			if (!q->ringinuse)
++			if ((!q->ringinuse) || (!mem->ignorebusy))
+ 				break;
+ 			/* else fall through */
+ 		case AST_DEVICE_NOT_INUSE:
+@@ -2856,7 +2886,7 @@
+ 		return 0;
+ 	}
+ 
+-	if (!qe->parent->ringinuse && (tmp->member->status != AST_DEVICE_NOT_INUSE) && (tmp->member->status != AST_DEVICE_UNKNOWN)) {
++	if ((!qe->parent->ringinuse || !tmp->member->ignorebusy) && (tmp->member->status != AST_DEVICE_NOT_INUSE) && (tmp->member->status != AST_DEVICE_UNKNOWN)) {
+ 		ast_debug(1, "%s in use, can't receive call\n", tmp->interface);
+ 		if (qe->chan->cdr)
+ 			ast_cdr_busy(qe->chan->cdr);
+@@ -3225,6 +3255,18 @@
+ 	}
+ 	ast_queue_log(qe->parent->name, qe->chan->uniqueid, membername, "RINGNOANSWER", "%d", rnatime);
+ 	if (qe->parent->autopause != QUEUE_AUTOPAUSE_OFF && pause) {
++		if (qe->parent->autopausedelay > 0) {
++			struct member *mem;
++			ao2_lock(qe->parent);
++			if ((mem = interface_exists(qe->parent, interface))) {
++				time_t idletime = time(&idletime)-mem->lastcall;
++ 				if ((mem->lastcall != 0) && (qe->parent->autopausedelay > idletime)) {
++					ao2_unlock(qe->parent);
++					return;
++				}
++			}
++			ao2_unlock(qe->parent);
++		}
+ 		if (qe->parent->autopause == QUEUE_AUTOPAUSE_ON) {
+ 			if (!set_member_paused(qe->parent->name, interface, "Auto-Pause", 1)) {
+ 				ast_verb(3, "Auto-Pausing Queue Member %s in queue %s since they failed to answer.\n",
+@@ -4996,7 +5038,10 @@
+ 		ao2_lock(q);
+ 		if ((mem = ao2_find(q->members, &tmpmem, OBJ_POINTER))) {
+ 			/* XXX future changes should beware of this assumption!! */
+-			if (!mem->dynamic) {
++			/*Change Penalty on realtime users*/
++			if (mem->realtime && !ast_strlen_zero(mem->rt_uniqueid) && negitive_penalty_invalid) {
++				update_realtime_member_field(mem, q->name, "penalty", "-1");
++			} else if (!mem->dynamic) {
+ 				ao2_ref(mem, -1);
+ 				ao2_unlock(q);
+ 				queue_t_unref(q, "Interface wasn't dynamic, expiring temporary reference");
+@@ -5172,6 +5217,7 @@
+ 	struct call_queue *q;
+ 	struct member *mem;
+ 	struct ao2_iterator queue_iter;
++	char rtpenalty[80];
+ 
+ 	if (penalty < 0) {
+ 		ast_log(LOG_ERROR, "Invalid penalty (%d)\n", penalty);
+@@ -5185,8 +5231,12 @@
+ 			foundqueue++;
+ 			if ((mem = interface_exists(q, interface))) {
+ 				foundinterface++;
+-				mem->penalty = penalty;
+-				
++				if (!mem->realtime)
++					mem->penalty = penalty;
++				else {
++					sprintf(rtpenalty,"%i",penalty);
++					update_realtime_member_field(mem, q->name, "penalty", rtpenalty);
++				}
+ 				ast_queue_log(q->name, "NONE", interface, "PENALTY", "%d", penalty);
+ 				manager_event(EVENT_FLAG_AGENT, "QueueMemberPenalty",
+ 					"Queue: %s\r\n"
+@@ -5975,29 +6025,35 @@
+ 
+ /*! 
+  * \brief Get number either busy / free / ready or total members of a specific queue
+- * \retval number of members (busy / free / ready / total)
++ * \brief Get or set member properties penalty / paused / ignorebusy
++ * \retval number of members (busy / free / ready / total) or member info (penalty / paused / ignorebusy)
+  * \retval -1 on error
+ */
+-static int queue_function_qac(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
++static int queue_function_mem_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
+ {
+ 	int count = 0;
+ 	struct member *m;
+ 	struct ao2_iterator mem_iter;
+ 	struct call_queue *q;
+-	char *option;
+ 
++	AST_DECLARE_APP_ARGS(args,
++		AST_APP_ARG(queuename);
++		AST_APP_ARG(option);
++		AST_APP_ARG(interface);
++	);
++	/* Make sure the returned value on error is NULL. */
++	buf[0] = '\0';
++
+ 	if (ast_strlen_zero(data)) {
+ 		ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
+ 		return -1;
+ 	}
+ 
+-	if ((option = strchr(data, ',')))
+-		*option++ = '\0';
+-	else
+-		option = "logged";
+-	if ((q = load_realtime_queue(data))) {
++	AST_STANDARD_APP_ARGS(args, data);
++
++	if ((q = load_realtime_queue(args.queuename))) {
+ 		ao2_lock(q);
+-		if (!strcasecmp(option, "logged")) {
++		if (!strcasecmp(args.option, "logged")) {
+ 			mem_iter = ao2_iterator_init(q->members, 0);
+ 			while ((m = ao2_iterator_next(&mem_iter))) {
+ 				/* Count the agents who are logged in and presently answering calls */
+@@ -6007,7 +6063,7 @@
+ 				ao2_ref(m, -1);
+ 			}
+ 			ao2_iterator_destroy(&mem_iter);
+-		} else if (!strcasecmp(option, "free")) {
++		} else if (!strcasecmp(args.option, "free")) {
+ 			mem_iter = ao2_iterator_init(q->members, 0);
+ 			while ((m = ao2_iterator_next(&mem_iter))) {
+ 				/* Count the agents who are logged in and presently answering calls */
+@@ -6017,7 +6073,7 @@
+ 				ao2_ref(m, -1);
+ 			}
+ 			ao2_iterator_destroy(&mem_iter);
+-		} else if (!strcasecmp(option, "ready")) {
++		} else if (!strcasecmp(args.option, "ready")) {
+ 			time_t now;
+ 			time(&now);
+ 			mem_iter = ao2_iterator_init(q->members, 0);
+@@ -6030,18 +6086,97 @@
+ 				ao2_ref(m, -1);
+ 			}
+ 			ao2_iterator_destroy(&mem_iter);
+-		} else /* must be "count" */
++		} else if (!strcasecmp(args.option, "count") || ast_strlen_zero(args.option)) {
+ 			count = q->membercount;
++		} else if (!strcasecmp(args.option, "penalty") && !ast_strlen_zero(args.interface)) {
++			if ((m = interface_exists(q, args.interface)))
++				count = m->penalty;

[... 9652 lines stripped ...]



More information about the asterisk-commits mailing list