[asterisk-commits] mjordan: tag 10.1.0-rc2 r352290 - in /tags/10.1.0-rc2: ./ apps/ channels/ con...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Tue Jan 24 10:38:49 CST 2012


Author: mjordan
Date: Tue Jan 24 10:38:46 2012
New Revision: 352290

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=352290
Log:
Merged 349732, 350553, 352228, 352015, 351505, 351289, 351308

Removed:
    tags/10.1.0-rc2/asterisk-10.1.0-rc1-summary.html
    tags/10.1.0-rc2/asterisk-10.1.0-rc1-summary.txt
Modified:
    tags/10.1.0-rc2/   (props changed)
    tags/10.1.0-rc2/.version
    tags/10.1.0-rc2/CHANGES
    tags/10.1.0-rc2/ChangeLog
    tags/10.1.0-rc2/apps/app_queue.c
    tags/10.1.0-rc2/channels/chan_sip.c
    tags/10.1.0-rc2/configs/rtp.conf.sample
    tags/10.1.0-rc2/main/features.c
    tags/10.1.0-rc2/main/file.c
    tags/10.1.0-rc2/res/res_rtp_asterisk.c

Propchange: tags/10.1.0-rc2/
------------------------------------------------------------------------------
    svn:mergeinfo = /branches/10:349732,350553,351289,351308,351505,352015,352228

Modified: tags/10.1.0-rc2/.version
URL: http://svnview.digium.com/svn/asterisk/tags/10.1.0-rc2/.version?view=diff&rev=352290&r1=352289&r2=352290
==============================================================================
--- tags/10.1.0-rc2/.version (original)
+++ tags/10.1.0-rc2/.version Tue Jan 24 10:38:46 2012
@@ -1,1 +1,1 @@
-10.1.0-rc1
+10.1.0-rc2

Modified: tags/10.1.0-rc2/CHANGES
URL: http://svnview.digium.com/svn/asterisk/tags/10.1.0-rc2/CHANGES?view=diff&rev=352290&r1=352289&r2=352290
==============================================================================
--- tags/10.1.0-rc2/CHANGES (original)
+++ tags/10.1.0-rc2/CHANGES Tue Jan 24 10:38:46 2012
@@ -7,6 +7,21 @@
 === and the other UPGRADE files for older releases.
 ===
 ==============================================================================
+
+------------------------------------------------------------------------------
+--- Functionality changes since Asterisk 10.0.0 ------------------------------
+------------------------------------------------------------------------------
+
+RTP changes
+-------------
+ * A new option, 'probation' has been added to rtp.conf
+   RTP in strictrtp mode can now require more than 1 packet to exit learning
+   mode with a new source (and by default requires 4). The probation option
+   allows the user to change the required number of packets in sequence to any
+   desired value. Use a value of 1 to essentially restore the old behavior.
+   Also, with strictrtp on, Asterisk will now drop all packets until learning
+   mode has successfully exited. These changes are based on how pjmedia handles
+   media sources and source changes.
 
 ------------------------------------------------------------------------------
 --- Functionality changes from Asterisk 1.8 to Asterisk 10 -------------------

Modified: tags/10.1.0-rc2/ChangeLog
URL: http://svnview.digium.com/svn/asterisk/tags/10.1.0-rc2/ChangeLog?view=diff&rev=352290&r1=352289&r2=352290
==============================================================================
--- tags/10.1.0-rc2/ChangeLog (original)
+++ tags/10.1.0-rc2/ChangeLog Tue Jan 24 10:38:46 2012
@@ -1,3 +1,51 @@
+2012-01-24  Asterisk Development Team <asteriskteam at digium.com>
+
+	* Asterisk 10.1.0-rc2 Released.
+
+	* Test results:
+	  http://bamboo.asterisk.org/browse/TESTING-ASTERISK1010RCS-
+
+	* main/file.c: Allow playback of formats that don't support
+	  seeking.  ast_streamfile previously did unconditional seeking
+	  on files that broke playback of formats that don't support that
+	  functionality.  This patch avoids the seek that was causing the
+	  problem.  (closes issue ASTERISK-18994) Patch-by: Timo Teras
+
+	* channels/chan_sip.c: AST-2012-001: prevent crash when an SDP offer
+	  is received with an encrypted video stream when support for video
+	  is disabled and res_srtp is loaded.  (closes issue ASTERISK-19202)
+	  Reported by: Catalin Sanda
+
+	* channels/chan_sip.c: Fix RTP reference leak.  If a blind transfer
+	  were initiated using a REFER without a prior reINVITE to place the
+	  call on hold, AND if Asterisk were sending RTCP reports, then there
+	  was a reference leak for the RTP instance of the transferer.
+	  (closes issue ASERISK-19192) Reported by: Tyuta Vitali
+
+	* res/res_rtp_asterisk: Add pjmedia probation concepts to
+	  res_rtp_asterisk's learning mode.  In order to better handle RTP
+	  sources with strictrtp enabled (which is the default setting in 10)
+	  using the learning mode to figure out new sources when they change is
+	  handled by checking for a number of consecutive (by sequence number)
+	  packets received to an rtp struct based on a new configurable value
+	  called 'probation'.  Also, during learning mode instead of liberally
+	  accepting all packets received, we now reject packets until a clear
+	  source has been determined.
+
+	* main/features.c: Fix blind transfers from failing if an 'h' extension
+	  is present.  This prevents the 'h' extension from being run on the
+	  transferee channel when it is transferred via a native transfer
+	  mechanism such as SIP REFER.  (closes issue ASTERISK-19173) Reported
+	  by: Ross Beer Tested by: Kristjan Vrban Patches: ASTERISK-19173 by
+	  Mark Michelson (license 5049)
+
+	* apps/app_queue.c: Realtime queues failed to load queue
+	  information without queue member table.  Revision 342223 
+	  broke this when it changed the return value for 
+	  realtime_multientry to return NULL when no results are
+	  returned.  (closes issue ASTERISK-19170) Reported by: Rene
+	  Mendoza Tested by: Rene Mendoza
+
 2011-12-30  Asterisk Development Team <asteriskteam at digium.com>
 
         * Asterisk 10.1.0-rc1 Released.

Modified: tags/10.1.0-rc2/apps/app_queue.c
URL: http://svnview.digium.com/svn/asterisk/tags/10.1.0-rc2/apps/app_queue.c?view=diff&rev=352290&r1=352289&r2=352290
==============================================================================
--- tags/10.1.0-rc2/apps/app_queue.c (original)
+++ tags/10.1.0-rc2/apps/app_queue.c Tue Jan 24 10:38:46 2012
@@ -2397,9 +2397,8 @@
 		if (queue_vars) {
 			member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", queuename, SENTINEL);
 			if (!member_config) {
-				ast_log(LOG_ERROR, "no queue_members defined in your config (extconfig.conf).\n");
-				ast_variables_destroy(queue_vars);
-				return NULL;
+				ast_debug(1, "No queue_members defined in config extconfig.conf\n");
+				member_config = ast_config_new();
 			}
 		}
 		if (q) {

Modified: tags/10.1.0-rc2/channels/chan_sip.c
URL: http://svnview.digium.com/svn/asterisk/tags/10.1.0-rc2/channels/chan_sip.c?view=diff&rev=352290&r1=352289&r2=352290
==============================================================================
--- tags/10.1.0-rc2/channels/chan_sip.c (original)
+++ tags/10.1.0-rc2/channels/chan_sip.c Tue Jan 24 10:38:46 2012
@@ -3882,6 +3882,7 @@
 		ast_channel_unref(owner);
 	} else if (p->refer && !p->alreadygone) {
 		ast_debug(3, "Finally hanging up channel after transfer: %s\n", p->callid);
+		stop_media_flows(p);
 		transmit_request_with_auth(p, SIP_BYE, 0, XMIT_RELIABLE, 1);
 		append_history(p, "ReferBYE", "Sending BYE on transferer call leg %s", p->callid);
 		sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
@@ -20714,15 +20715,22 @@
 	case 200:   /* Notify accepted */
 		/* They got the notify, this is the end */
 		if (p->owner) {
-			if (!p->refer) {
+			if (p->refer) {
+				ast_log(LOG_NOTICE, "Got OK on REFER Notify message\n");
+			} else {
 				ast_log(LOG_WARNING, "Notify answer on an owned channel? - %s\n", p->owner->name);
-				ast_queue_hangup_with_cause(p->owner, AST_CAUSE_NORMAL_UNSPECIFIED);
-			} else {
-				ast_debug(4, "Got OK on REFER Notify message\n");
+				/*
+				 * XXX There is discrepancy on whether a hangup should be queued
+				 * or not. This code used to be duplicated in two places, and the more
+				 * frequently hit area had this disabled, making it the de facto
+				 * "correct" way to go.
+				 *
+				 * ast_queue_hangup_with_cause(p->owner, AST_CAUSE_NORMAL_UNSPECIFIED);
+				 */
 			}
 		} else {
-			if (p->subscribed == NONE) {
-				ast_debug(4, "Got 200 accepted on NOTIFY\n");
+			if (p->subscribed == NONE && !p->refer) {
+				ast_debug(4, "Got 200 accepted on NOTIFY %s\n", p->callid);
 				pvt_set_needdestroy(p, "received 200 response");
 			}
 			if (ast_test_flag(&p->flags[1], SIP_PAGE2_STATECHANGEQUEUE)) {
@@ -20746,6 +20754,9 @@
 			ast_log(LOG_NOTICE, "Failed to authenticate on NOTIFY to '%s'\n", sip_get_header(&p->initreq, "From"));
 			pvt_set_needdestroy(p, "failed to authenticate NOTIFY");
 		}
+		break;
+	case 481: /* Call leg does not exist */
+		pvt_set_needdestroy(p, "Received 481 response for NOTIFY");
 		break;
 	}
 }
@@ -21389,6 +21400,9 @@
 	} else if (sipmethod == SIP_MESSAGE) {
 		/* More good gravy! */
 		handle_response_message(p, resp, rest, req, seqno);
+	} else if (sipmethod == SIP_NOTIFY) {
+		/* The gravy train continues to roll */
+		handle_response_notify(p, resp, rest, req, seqno);
 	} else if (ast_test_flag(&p->flags[0], SIP_OUTGOING)) {
 		switch(resp) {
 		case 100:	/* 100 Trying */
@@ -21404,8 +21418,6 @@
 			p->authtries = 0;	/* Reset authentication counter */
 			if (sipmethod == SIP_INVITE) {
 				handle_response_invite(p, resp, rest, req, seqno);
-			} else if (sipmethod == SIP_NOTIFY) {
-				handle_response_notify(p, resp, rest, req, seqno);
 			} else if (sipmethod == SIP_REGISTER) {
 				handle_response_register(p, resp, rest, req, seqno);
 			} else if (sipmethod == SIP_SUBSCRIBE) {
@@ -21420,8 +21432,6 @@
 		case 407: /* Proxy auth required */
 			if (sipmethod == SIP_INVITE)
 				handle_response_invite(p, resp, rest, req, seqno);
-			else if (sipmethod == SIP_NOTIFY)
-				handle_response_notify(p, resp, rest, req, seqno);
 			else if (sipmethod == SIP_SUBSCRIBE)
 				handle_response_subscribe(p, resp, rest, req, seqno);
 			else if (p->registry && sipmethod == SIP_REGISTER)
@@ -21496,8 +21506,6 @@
 				handle_response_invite(p, resp, rest, req, seqno);
 			} else if (sipmethod == SIP_SUBSCRIBE) {
 				handle_response_subscribe(p, resp, rest, req, seqno);
-			} else if (sipmethod == SIP_NOTIFY) {
-				pvt_set_needdestroy(p, "received 481 response");
 			} else if (sipmethod == SIP_BYE) {
 				/* The other side has no transaction to bye,
 				just assume it's all right then */
@@ -21658,24 +21666,6 @@
 				ast_debug(1, "Got 200 OK on CANCEL\n");
 
 				/* Wait for 487, then destroy */
-			} else if (sipmethod == SIP_NOTIFY) {
-				/* They got the notify, this is the end */
-				if (p->owner) {
-					if (p->refer) {
-						ast_debug(1, "Got 200 OK on NOTIFY for transfer\n");
-					} else
-						ast_log(LOG_WARNING, "Notify answer on an owned channel?\n");
-					/* ast_queue_hangup(p->owner); Disabled */
-				} else {
-					if (!p->subscribed && !p->refer) {
-						pvt_set_needdestroy(p, "transaction completed");
-					}
-					if (ast_test_flag(&p->flags[1], SIP_PAGE2_STATECHANGEQUEUE)) {
-						/* Ready to send the next state we have on queue */
-						ast_clear_flag(&p->flags[1], SIP_PAGE2_STATECHANGEQUEUE);
-						cb_extensionstate((char *)p->context, (char *)p->exten, p->laststate, (void *) p);
-					}
-				}
 			} else if (sipmethod == SIP_BYE) {
 				pvt_set_needdestroy(p, "transaction completed");
 			}
@@ -21696,8 +21686,6 @@
 				/* Re-invite failed */
 				handle_response_invite(p, resp, rest, req, seqno);
 			} else if (sipmethod == SIP_BYE) {
-				pvt_set_needdestroy(p, "received 481 response");
-			} else if (sipmethod == SIP_NOTIFY) {
 				pvt_set_needdestroy(p, "received 481 response");
 			} else if (sipdebug) {
 				ast_debug(1, "Remote host can't match request %s to call '%s'. Giving up\n", sip_methods[sipmethod].text, p->callid);
@@ -30103,6 +30091,12 @@
 
 static int process_crypto(struct sip_pvt *p, struct ast_rtp_instance *rtp, struct sip_srtp **srtp, const char *a)
 {
+	/* If no RTP instance exists for this media stream don't bother processing the crypto line */
+	if (!rtp) {
+		ast_debug(3, "Received offer with crypto line for media stream that is not enabled\n");
+		return FALSE;
+	}
+
 	if (strncasecmp(a, "crypto:", 7)) {
 		return FALSE;
 	}

Modified: tags/10.1.0-rc2/configs/rtp.conf.sample
URL: http://svnview.digium.com/svn/asterisk/tags/10.1.0-rc2/configs/rtp.conf.sample?view=diff&rev=352290&r1=352289&r2=352290
==============================================================================
--- tags/10.1.0-rc2/configs/rtp.conf.sample (original)
+++ tags/10.1.0-rc2/configs/rtp.conf.sample Tue Jan 24 10:38:46 2012
@@ -25,3 +25,10 @@
 ; do not come from the source of the RTP stream. This option is
 ; enabled by default.
 ; strictrtp=yes
+;
+; Number of packets containing consecutive sequence values needed
+; to change the RTP source socket address. This option only comes
+; into play while using strictrtp=yes. Consider changing this value
+; if rtp packets are dropped from one or both ends after a call is
+; connected. This option is set to 4 by default.
+; probation=8

Modified: tags/10.1.0-rc2/main/features.c
URL: http://svnview.digium.com/svn/asterisk/tags/10.1.0-rc2/main/features.c?view=diff&rev=352290&r1=352289&r2=352290
==============================================================================
--- tags/10.1.0-rc2/main/features.c (original)
+++ tags/10.1.0-rc2/main/features.c Tue Jan 24 10:38:46 2012
@@ -4110,6 +4110,17 @@
 		if (!f || (f->frametype == AST_FRAME_CONTROL &&
 				(f->subclass.integer == AST_CONTROL_HANGUP || f->subclass.integer == AST_CONTROL_BUSY ||
 					f->subclass.integer == AST_CONTROL_CONGESTION))) {
+			/*
+			 * If the bridge was broken for a hangup that isn't real, then
+			 * then don't run the h extension, because the channel isn't
+			 * really hung up. This should really only happen with AST_SOFTHANGUP_ASYNCGOTO,
+			 * but it doesn't hurt to check AST_SOFTHANGUP_UNBRIDGE either.
+			 */
+			ast_channel_lock(chan);
+			if (chan->_softhangup & (AST_SOFTHANGUP_ASYNCGOTO | AST_SOFTHANGUP_UNBRIDGE)) {
+				ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_DONT);
+			}
+			ast_channel_unlock(chan);
 			res = -1;
 			break;
 		}

Modified: tags/10.1.0-rc2/main/file.c
URL: http://svnview.digium.com/svn/asterisk/tags/10.1.0-rc2/main/file.c?view=diff&rev=352290&r1=352289&r2=352290
==============================================================================
--- tags/10.1.0-rc2/main/file.c (original)
+++ tags/10.1.0-rc2/main/file.c Tue Jan 24 10:38:46 2012
@@ -1012,6 +1012,7 @@
 	struct ast_filestream *fs;
 	struct ast_filestream *vfs=NULL;
 	char fmt[256];
+	off_t pos;
 	int seekattempt;
 	int res;
 
@@ -1024,12 +1025,17 @@
 	/* check to see if there is any data present (not a zero length file),
 	 * done this way because there is no where for ast_openstream_full to
 	 * return the file had no data. */
-	seekattempt = fseek(fs->f, -1, SEEK_END);
-	if (seekattempt && errno == EINVAL) {
-		/* Zero-length file, as opposed to a pipe */
-		return 0;
+	pos = ftello(fs->f);
+	seekattempt = fseeko(fs->f, -1, SEEK_END);
+	if (seekattempt) {
+		if (errno == EINVAL) {
+			/* Zero-length file, as opposed to a pipe */
+			return 0;
+		} else {
+			ast_seekstream(fs, 0, SEEK_SET);
+		}
 	} else {
-		ast_seekstream(fs, 0, SEEK_SET);
+		fseeko(fs->f, pos, SEEK_SET);
 	}
 
 	vfs = ast_openvstream(chan, filename, preflang);

Modified: tags/10.1.0-rc2/res/res_rtp_asterisk.c
URL: http://svnview.digium.com/svn/asterisk/tags/10.1.0-rc2/res/res_rtp_asterisk.c?view=diff&rev=352290&r1=352289&r2=352290
==============================================================================
--- tags/10.1.0-rc2/res/res_rtp_asterisk.c (original)
+++ tags/10.1.0-rc2/res/res_rtp_asterisk.c Tue Jan 24 10:38:46 2012
@@ -80,6 +80,8 @@
 
 #define ZFONE_PROFILE_ID 0x505a
 
+#define DEFAULT_LEARNING_MIN_SEQUENTIAL 4
+
 extern struct ast_srtp_res *res_srtp;
 static int dtmftimeout = DEFAULT_DTMF_TIMEOUT;
 
@@ -96,7 +98,8 @@
 #ifdef SO_NO_CHECK
 static int nochecksums;
 #endif
-static int strictrtp;
+static int strictrtp;			/*< Only accept RTP frames from a defined source. If we receive an indication of a changing source, enter learning mode. */
+static int learning_min_sequential;	/*< Number of sequential RTP frames needed from a single source during learning mode to accept new source. */
 
 enum strict_rtp_state {
 	STRICT_RTP_OPEN = 0, /*! No RTP packets should be dropped, all sources accepted */
@@ -175,6 +178,13 @@
 	enum strict_rtp_state strict_rtp_state; /*!< Current state that strict RTP protection is in */
 	struct ast_sockaddr strict_rtp_address;  /*!< Remote address information for strict RTP purposes */
 	struct ast_sockaddr alt_rtp_address; /*!<Alternate remote address information */
+
+	/*
+	 * Learning mode values based on pjmedia's probation mode.  Many of these values are redundant to the above,
+	 * but these are in place to keep learning mode sequence values sealed from their normal counterparts.
+	 */
+	uint16_t learning_max_seq;		/*!< Highest sequence number heard */
+	int learning_probation;		/*!< Sequential packets untill source is valid */
 
 	struct rtp_red *red;
 };
@@ -460,6 +470,50 @@
 	return sock;
 }
 
+/*!
+ * \internal
+ * \brief Initializes sequence values and probation for learning mode.
+ * \note This is an adaptation of pjmedia's pjmedia_rtp_seq_init function.
+ *
+ * \param rtp pointer to rtp struct used with the received rtp packet.
+ * \param seq sequence number read from the rtp header
+ */
+static void rtp_learning_seq_init(struct ast_rtp *rtp, uint16_t seq)
+{
+	rtp->learning_max_seq = seq - 1;
+	rtp->learning_probation = learning_min_sequential;
+}
+
+/*!
+ * \internal
+ * \brief Updates sequence information for learning mode and determines if probation/learning mode should remain in effect.
+ * \note This function was adapted from pjmedia's pjmedia_rtp_seq_update function.
+ *
+ * \param rtp pointer to rtp struct used with the received rtp packet.
+ * \param seq sequence number read from the rtp header
+ * \return boolean value indicating if probation mode is active at the end of the function
+ */
+static int rtp_learning_rtp_seq_update(struct ast_rtp *rtp, uint16_t seq)
+{
+	int probation = 1;
+
+	ast_debug(1, "%p -- probation = %d, seq = %d\n", rtp, rtp->learning_probation, seq);
+
+	if (seq == rtp->learning_max_seq + 1) {
+		/* packet is in sequence */
+		rtp->learning_probation--;
+		rtp->learning_max_seq = seq;
+		if (rtp->learning_probation == 0) {
+			probation = 0;
+		}
+	} else {
+		rtp->learning_probation = learning_min_sequential - 1;
+		rtp->learning_max_seq = seq;
+	}
+
+	return probation;
+}
+
 static int ast_rtp_new(struct ast_rtp_instance *instance,
 		       struct ast_sched_context *sched, struct ast_sockaddr *addr,
 		       void *data)
@@ -476,6 +530,9 @@
 	rtp->ssrc = ast_random();
 	rtp->seqno = ast_random() & 0xffff;
 	rtp->strict_rtp_state = (strictrtp ? STRICT_RTP_LEARN : STRICT_RTP_OPEN);
+	if (strictrtp) {
+		rtp_learning_seq_init(rtp, (uint16_t)rtp->seqno);
+	}
 
 	/* Create a new socket for us to listen on and use */
 	if ((rtp->s =
@@ -2082,7 +2139,17 @@
 
 	/* If strict RTP protection is enabled see if we need to learn the remote address or if we need to drop the packet */
 	if (rtp->strict_rtp_state == STRICT_RTP_LEARN) {
+		ast_debug(1, "%p -- start learning mode pass with addr = %s\n", rtp, ast_sockaddr_stringify(&addr));
+		/* For now, we always copy the address. */
 		ast_sockaddr_copy(&rtp->strict_rtp_address, &addr);
+
+		/* Send the rtp and the seqno from header to rtp_learning_rtp_seq_update to see whether we can exit or not*/
+		if (rtp_learning_rtp_seq_update(rtp, ntohl(rtpheader[0]))) {
+			ast_debug(1, "%p -- Condition for learning hasn't exited, so reject the frame.\n", rtp);
+			return &ast_null_frame;
+		}
+
+		ast_debug(1, "%p -- Probation Ended. Set strict_rtp_state to STRICT_RTP_CLOSED with address %s\n", rtp, ast_sockaddr_stringify(&addr));
 		rtp->strict_rtp_state = STRICT_RTP_CLOSED;
 	} else if (rtp->strict_rtp_state == STRICT_RTP_CLOSED) {
 		if (ast_sockaddr_cmp(&rtp->strict_rtp_address, &addr)) {
@@ -2497,6 +2564,7 @@
 
 	if (strictrtp) {
 		rtp->strict_rtp_state = STRICT_RTP_LEARN;
+		rtp_learning_seq_init(rtp, rtp->seqno);
 	}
 
 	return;
@@ -2884,6 +2952,7 @@
 	rtpend = DEFAULT_RTP_END;
 	dtmftimeout = DEFAULT_DTMF_TIMEOUT;
 	strictrtp = STRICT_RTP_CLOSED;
+	learning_min_sequential = DEFAULT_LEARNING_MIN_SEQUENTIAL;
 	if (cfg) {
 		if ((s = ast_variable_retrieve(cfg, "general", "rtpstart"))) {
 			rtpstart = atoi(s);
@@ -2927,6 +2996,12 @@
 		if ((s = ast_variable_retrieve(cfg, "general", "strictrtp"))) {
 			strictrtp = ast_true(s);
 		}
+		if ((s = ast_variable_retrieve(cfg, "general", "probation"))) {
+			if ((sscanf(s, "%d", &learning_min_sequential) <= 0) || learning_min_sequential <= 0) {
+				ast_log(LOG_WARNING, "Value for 'probation' could not be read, using default of '%d' instead\n",
+					DEFAULT_LEARNING_MIN_SEQUENTIAL);
+			}
+		}
 		ast_config_destroy(cfg);
 	}
 	if (rtpstart >= rtpend) {




More information about the asterisk-commits mailing list