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

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Fri Oct 7 05:30:48 CDT 2011


Author: irroot
Date: Fri Oct  7 05:30:45 2011
New Revision: 339775

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=339775
Log:
1.8 Patches up dated [1.8.8]

Added:
    team/irroot/patches/distrotech-1.8.8.patch   (with props)
Modified:
    team/irroot/patches/distrotech-1.8.patch
    team/irroot/patches/t38gateway-1.8.patch

Added: team/irroot/patches/distrotech-1.8.8.patch
URL: http://svnview.digium.com/svn/asterisk/team/irroot/patches/distrotech-1.8.8.patch?view=auto&rev=339775
==============================================================================
--- team/irroot/patches/distrotech-1.8.8.patch (added)
+++ team/irroot/patches/distrotech-1.8.8.patch Fri Oct  7 05:30:45 2011
@@ -1,0 +1,5757 @@
+Index: configure
+===================================================================
+Cannot display: file marked as a binary type.
+svn:mime-type = application/octet-stream
+Index: channels/chan_sip.c
+===================================================================
+--- channels/chan_sip.c	(.../digium/1.8)	(revision 556)
++++ channels/chan_sip.c	(.../distrotech/1.8/1.8.8.0)	(revision 545)
+@@ -4317,6 +4317,9 @@
+ 			case T38_ENABLED:
+ 				state = T38_STATE_NEGOTIATED;
+ 				break;
++			case T38_REJECTED:
++				state = T38_STATE_REJECTED;
++				break;
+ 			default:
+ 				state = T38_STATE_UNKNOWN;
+ 			}
+@@ -4981,6 +4984,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;
+@@ -5441,17 +5445,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;
++			}
+ 		}
+ 	}
+ 
+@@ -6550,11 +6560,11 @@
+ 	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);
+ 			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);
+ 			}
++			change_t38_state(p, T38_REJECTED);
+ 			break;
+ 		} else 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"));
+@@ -6592,7 +6602,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);
+@@ -8844,27 +8854,43 @@
+ 
+ 	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");
+-		return -4;
++		if (!ast_test_flag(&p->flags[2], SIP_PAGE3_SRTP_TRY)) {
++			return -4;
++		}
+ 	}
+ 
+ 	if (!secure_audio && p->srtp) {
+ 		ast_log(LOG_WARNING, "We are requesting SRTP, but they responded without it!\n");
+-		return -4;
++		if (ast_test_flag(&p->flags[2], SIP_PAGE3_SRTP_TRY)) {
++			sip_srtp_destroy(p->srtp);
++			p->srtp = NULL;
++		} else {
++			return -4;
++		}
+ 	}
+ 
+ 	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");
+-		return -4;
++		if (!ast_test_flag(&p->flags[2], SIP_PAGE3_SRTP_TRY)) {
++			return -4;
++		}
+ 	}
+ 
+ 	if (!p->novideo && !secure_video && p->vsrtp) {
+ 		ast_log(LOG_WARNING, "We are requesting SRTP, but they responded without it!\n");
+-		return -4;
++		if (ast_test_flag(&p->flags[2], SIP_PAGE3_SRTP_TRY)) {
++			sip_srtp_destroy(p->vsrtp);
++			p->srtp = NULL;
++		} else {
++			return -4;
++		}
+ 	}
+ 
+ 	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");
+-		return -4;
++		if (!ast_test_flag(&p->flags[2], SIP_PAGE3_SRTP_TRY)) {
++			return -4;
++		}
+ 	}
+ 
+ 	if (udptlportno == -1) {
+@@ -9045,7 +9071,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;
+         }
+@@ -10869,14 +10895,25 @@
+ 	}
+ }
+ 
+-static void get_crypto_attrib(struct sip_srtp *srtp, const char **a_crypto)
++static void get_crypto_attrib(struct sip_pvt *p, struct sip_srtp *srtp, const char **a_crypto)
+ {
++	int taglen = 80;
++
+ 	/* Set encryption properties */
+ 	if (srtp) {
+ 		if (!srtp->crypto) {
+ 			srtp->crypto = sdp_crypto_setup();
+ 		}
+-		if (srtp->crypto && (sdp_crypto_offer(srtp->crypto) >= 0)) {
++
++		/* set the key length based on INVITE or settings */
++		if (ast_test_flag(srtp, SRTP_CRYPTO_TAG_80)) {
++			taglen = 80;
++		} else if (ast_test_flag(&p->flags[2], SIP_PAGE3_SRTP_TAG_32) ||
++		    ast_test_flag(srtp, SRTP_CRYPTO_TAG_32)) {
++			taglen = 32;
++		}
++
++		if (srtp->crypto && (sdp_crypto_offer(srtp->crypto, taglen) >= 0)) {
+ 			*a_crypto = sdp_crypto_attrib(srtp->crypto);
+ 		}
+ 
+@@ -11036,7 +11073,7 @@
+ 		/* Ok, we need video. Let's add what we need for video and set codecs.
+ 		   Video is handled differently than audio since we can not transcode. */
+ 		if (needvideo) {
+-			get_crypto_attrib(p->vsrtp, &v_a_crypto);
++			get_crypto_attrib(p, p->vsrtp, &v_a_crypto);
+ 			ast_str_append(&m_video, 0, "m=video %d RTP/%s", ast_sockaddr_port(&vdest),
+ 				v_a_crypto ? "SAVP" : "AVP");
+ 
+@@ -11053,7 +11090,7 @@
+ 		if (needtext) {
+ 			if (sipdebug_text)
+ 				ast_verbose("Lets set up the text sdp\n");
+-			get_crypto_attrib(p->tsrtp, &t_a_crypto);
++			get_crypto_attrib(p, p->tsrtp, &t_a_crypto);
+ 			ast_str_append(&m_text, 0, "m=text %d RTP/%s", ast_sockaddr_port(&tdest),
+ 				t_a_crypto ? "SAVP" : "AVP");
+ 			if (debug) {  /* XXX should I use tdest below ? */
+@@ -11066,7 +11103,7 @@
+ 		/* We break with the "recommendation" and send our IP, in order that our
+ 		   peer doesn't have to ast_gethostbyname() us */
+ 
+-		get_crypto_attrib(p->srtp, &a_crypto);
++		get_crypto_attrib(p, p->srtp, &a_crypto);
+ 		ast_str_append(&m_audio, 0, "m=audio %d RTP/%s", ast_sockaddr_port(&dest),
+ 			a_crypto ? "SAVP" : "AVP");
+ 
+@@ -14311,24 +14348,21 @@
+ 				} else {
+ 
+ 					/* We have a successful registration attempt with proper authentication,
+-				   	now, update the peer */
++					now, update the peer */
+ 					switch (parse_register_contact(p, peer, req)) {
+ 					case PARSE_REGISTER_DENIED:
+ 						ast_log(LOG_WARNING, "Registration denied because of contact ACL\n");
+ 						transmit_response_with_date(p, "603 Denied", req);
+-						peer->lastmsgssent = -1;
+ 						res = 0;
+ 						break;
+ 					case PARSE_REGISTER_FAILED:
+ 						ast_log(LOG_WARNING, "Failed to parse contact info\n");
+ 						transmit_response_with_date(p, "400 Bad Request", req);
+-						peer->lastmsgssent = -1;
+ 						res = 0;
+ 						break;
+ 					case PARSE_REGISTER_QUERY:
+ 						ast_string_field_set(p, fullcontact, peer->fullcontact);
+ 						transmit_response_with_date(p, "200 OK", req);
+-						peer->lastmsgssent = -1;
+ 						res = 0;
+ 						break;
+ 					case PARSE_REGISTER_UPDATE:
+@@ -14336,8 +14370,6 @@
+ 						update_peer(peer, p->expiry);
+ 						/* Say OK and ask subsystem to retransmit msg counter */
+ 						transmit_response_with_date(p, "200 OK", req);
+-						if (!ast_test_flag((&peer->flags[1]), SIP_PAGE2_SUBSCRIBEMWIONLY))
+-							peer->lastmsgssent = -1;
+ 						res = 0;
+ 						break;
+ 					}
+@@ -14362,19 +14394,16 @@
+ 			case PARSE_REGISTER_DENIED:
+ 				ast_log(LOG_WARNING, "Registration denied because of contact ACL\n");
+ 				transmit_response_with_date(p, "403 Forbidden (ACL)", req);
+-				peer->lastmsgssent = -1;
+ 				res = 0;
+ 				break;
+ 			case PARSE_REGISTER_FAILED:
+ 				ast_log(LOG_WARNING, "Failed to parse contact info\n");
+ 				transmit_response_with_date(p, "400 Bad Request", req);
+-				peer->lastmsgssent = -1;
+ 				res = 0;
+ 				break;
+ 			case PARSE_REGISTER_QUERY:
+ 				ast_string_field_set(p, fullcontact, peer->fullcontact);
+ 				transmit_response_with_date(p, "200 OK", req);
+-				peer->lastmsgssent = -1;
+ 				res = 0;
+ 				break;
+ 			case PARSE_REGISTER_UPDATE:
+@@ -14382,7 +14411,6 @@
+ 				/* Say OK and ask subsystem to retransmit msg counter */
+ 				transmit_response_with_date(p, "200 OK", req);
+ 				manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: SIP\r\nPeer: SIP/%s\r\nPeerStatus: Registered\r\nAddress: %s\r\n", peer->name, ast_sockaddr_stringify(addr));
+-				peer->lastmsgssent = -1;
+ 				res = 0;
+ 				break;
+ 			}
+@@ -14398,6 +14426,7 @@
+ 		sched_yield();
+ 	}
+ 	if (!res) {
++		sip_send_mwi_to_peer(peer, 0);
+ 		ast_devstate_changed(AST_DEVICE_UNKNOWN, "SIP/%s", peer->name);
+ 	}
+ 	if (res < 0) {
+@@ -16902,7 +16931,6 @@
+ 		ast_cli(fd, "  MOH Suggest  : %s\n", peer->mohsuggest);
+ 		ast_cli(fd, "  Mailbox      : %s\n", mailbox_str->str);
+ 		ast_cli(fd, "  VM Extension : %s\n", peer->vmexten);
+-		ast_cli(fd, "  LastMsgsSent : %d/%d\n", (peer->lastmsgssent & 0x7fff0000) >> 16, peer->lastmsgssent & 0xffff);
+ 		ast_cli(fd, "  Call limit   : %d\n", peer->call_limit);
+ 		ast_cli(fd, "  Max forwards : %d\n", peer->maxforwards);
+ 		if (peer->busy_level)
+@@ -17016,7 +17044,6 @@
+ 		peer_mailboxes_to_str(&mailbox_str, peer);
+ 		astman_append(s, "VoiceMailbox: %s\r\n", mailbox_str->str);
+ 		astman_append(s, "TransferMode: %s\r\n", transfermode2str(peer->allowtransfer));
+-		astman_append(s, "LastMsgsSent: %d\r\n", peer->lastmsgssent);
+ 		astman_append(s, "Maxforwards: %d\r\n", peer->maxforwards);
+ 		astman_append(s, "Call-limit: %d\r\n", peer->call_limit);
+ 		astman_append(s, "Busy-level: %d\r\n", peer->busy_level);
+@@ -18984,7 +19011,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);
+@@ -19754,7 +19781,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);
+ 
+@@ -21562,7 +21589,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");
+@@ -22437,9 +22464,10 @@
+ 			} 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)) {
++				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 {
+@@ -24995,25 +25023,33 @@
+ 	return in_cache;
+ }
+ 
+-/*! \brief Send message waiting indication to alert peer that they've got voicemail */
++/*! \brief Send message waiting indication to alert peer that they've got voicemail
++ *  \returns -1 on failure, 0 on success
++ */
+ static int sip_send_mwi_to_peer(struct sip_peer *peer, int cache_only)
+ {
+ 	/* Called with peerl lock, but releases it */
+ 	struct sip_pvt *p;
+ 	int newmsgs = 0, oldmsgs = 0;
+ 
+-	if (ast_test_flag((&peer->flags[1]), SIP_PAGE2_SUBSCRIBEMWIONLY) && !peer->mwipvt)
+-		return 0;
++	if (ast_test_flag((&peer->flags[1]), SIP_PAGE2_SUBSCRIBEMWIONLY) && !peer->mwipvt) {
++		return -1;
++	}
+ 
+ 	/* Do we have an IP address? If not, skip this peer */
+-	if (ast_sockaddr_isnull(&peer->addr) && ast_sockaddr_isnull(&peer->defaddr))
+-		return 0;
++	if (ast_sockaddr_isnull(&peer->addr) && ast_sockaddr_isnull(&peer->defaddr)) {
++		return -1;
++	}
+ 
+ 	/* Attempt to use cached mwi to get message counts. */
+ 	if (!get_cached_mwi(peer, &newmsgs, &oldmsgs) && !cache_only) {
+ 		/* Fall back to manually checking the mailbox if not cache_only and get_cached_mwi failed */
+ 		struct ast_str *mailbox_str = ast_str_alloca(512);
+ 		peer_mailboxes_to_str(&mailbox_str, peer);
++		/* if there is no mailbox do nothing */
++		if (ast_strlen_zero(mailbox_str->str)) {
++			return -1;
++		}
+ 		ast_app_inboxcount(mailbox_str->str, &newmsgs, &oldmsgs);
+ 	}
+ 	ao2_lock(peer);
+@@ -25039,7 +25075,7 @@
+ 			dialog_unref(p, "unref dialog p just created via sip_alloc");
+ 			/* sip_destroy(p); */
+ 			ao2_unlock(peer);
+-			return 0;
++			return -1;
+ 		}
+ 		/* Recalculate our side, and recalculate Call ID */
+ 		ast_sip_ouraddrfor(&p->sa, &p->ourip, p);
+@@ -26513,6 +26549,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)) {
+@@ -26606,7 +26647,6 @@
+ 
+ 	/* Note that our peer HAS had its reference count increased */
+ 	if (firstpass) {
+-		peer->lastmsgssent = -1;
+ 		oldha = peer->ha;
+ 		peer->ha = NULL;
+ 		olddirectmediaha = peer->directmediaha;
+@@ -26981,7 +27021,15 @@
+ 			} 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")) {
+ 				ast_set2_flag(&peer->flags[2], ast_true(v->value), SIP_PAGE3_SNOM_AOC);
+ 			}
+@@ -28889,7 +28937,7 @@
+ 		return FALSE;
+ 	}
+ 
+-	if (sdp_crypto_process((*srtp)->crypto, a, rtp) < 0) {
++	if (sdp_crypto_process((*srtp)->crypto, a, rtp, *srtp) < 0) {
+ 		return FALSE;
+ 	}
+ 
+Index: channels/sip/include/sip.h
+===================================================================
+--- channels/sip/include/sip.h	(.../digium/1.8)	(revision 556)
++++ channels/sip/include/sip.h	(.../distrotech/1.8/1.8.8.0)	(revision 545)
+@@ -352,9 +352,11 @@
+ 
+ 
+ #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_SNOM_AOC | SIP_PAGE3_SRTP_TAG_32 | SIP_PAGE3_SRTP_TRY)
+ 
+ /*@}*/
+ 
+@@ -597,7 +599,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 */
+@@ -1220,7 +1223,6 @@
+ 	int maxforwards;                /*!< SIP Loop prevention */
+ 	enum transfermodes allowtransfer;   /*! SIP Refer restriction scheme */
+ 	struct ast_codec_pref prefs;    /*!<  codec prefs */
+-	int lastmsgssent;
+ 	unsigned int sipoptions;        /*!<  Supported SIP options */
+ 	struct ast_flags flags[3];      /*!<  SIP_ flags */
+ 
+Index: channels/sip/include/sdp_crypto.h
+===================================================================
+--- channels/sip/include/sdp_crypto.h	(.../digium/1.8)	(revision 556)
++++ channels/sip/include/sdp_crypto.h	(.../distrotech/1.8/1.8.8.0)	(revision 545)
+@@ -31,6 +31,7 @@
+ #include <asterisk/rtp_engine.h>
+ 
+ struct sdp_crypto;
++struct sip_srtp;
+ 
+ /*! \brief Initialize an return an sdp_crypto struct
+  *
+@@ -51,11 +52,12 @@
+  * \param p A valid sdp_crypto struct
+  * \param attr the a:crypto line from SDP
+  * \param rtp The rtp instance associated with the SDP being parsed
++ * \param srtp SRTP structure
+  *
+  * \retval 0 success
+  * \retval nonzero failure
+  */
+-int sdp_crypto_process(struct sdp_crypto *p, const char *attr, struct ast_rtp_instance *rtp);
++int sdp_crypto_process(struct sdp_crypto *p, const char *attr, struct ast_rtp_instance *rtp, struct sip_srtp *srtp);
+ 
+ 
+ /*! \brief Generate an SRTP a=crypto offer
+@@ -68,7 +70,7 @@
+  * \retval 0 success
+  * \retval nonzero failure
+  */
+-int sdp_crypto_offer(struct sdp_crypto *p);
++int sdp_crypto_offer(struct sdp_crypto *p, int taglen);
+ 
+ 
+ /*! \brief Return the a_crypto value of the sdp_crypto struct
+Index: channels/sip/include/srtp.h
+===================================================================
+--- channels/sip/include/srtp.h	(.../digium/1.8)	(revision 556)
++++ channels/sip/include/srtp.h	(.../distrotech/1.8/1.8.8.0)	(revision 545)
+@@ -34,6 +34,8 @@
+ #define SRTP_ENCR_OPTIONAL	(1 << 1)	/* SRTP encryption optional */
+ #define SRTP_CRYPTO_ENABLE	(1 << 2)
+ #define SRTP_CRYPTO_OFFER_OK	(1 << 3)
++#define SRTP_CRYPTO_TAG_32	(1 << 4)
++#define SRTP_CRYPTO_TAG_80	(1 << 5)
+ 
+ /*! \brief structure for secure RTP audio */
+ struct sip_srtp {
+Index: channels/sip/sdp_crypto.c
+===================================================================
+--- channels/sip/sdp_crypto.c	(.../digium/1.8)	(revision 556)
++++ channels/sip/sdp_crypto.c	(.../distrotech/1.8/1.8.8.0)	(revision 545)
+@@ -32,6 +32,7 @@
+ #include "asterisk/options.h"
+ #include "asterisk/utils.h"
+ #include "include/sdp_crypto.h"
++#include "include/srtp.h"
+ 
+ #define SRTP_MASTER_LEN 30
+ #define SRTP_MASTERKEY_LEN 16
+@@ -188,7 +189,7 @@
+ 	return res;
+ }
+ 
+-int sdp_crypto_process(struct sdp_crypto *p, const char *attr, struct ast_rtp_instance *rtp)
++int sdp_crypto_process(struct sdp_crypto *p, const char *attr, struct ast_rtp_instance *rtp, struct sip_srtp *srtp)
+ {
+ 	char *str = NULL;
+ 	char *tag = NULL;
+@@ -228,8 +229,10 @@
+ 
+ 	if (!strcmp(suite, "AES_CM_128_HMAC_SHA1_80")) {
+ 		suite_val = AST_AES_CM_128_HMAC_SHA1_80;
++		ast_set_flag(srtp, SRTP_CRYPTO_TAG_80);
+ 	} else if (!strcmp(suite, "AES_CM_128_HMAC_SHA1_32")) {
+ 		suite_val = AST_AES_CM_128_HMAC_SHA1_32;
++		ast_set_flag(srtp, SRTP_CRYPTO_TAG_32);
+ 	} else {
+ 		ast_log(LOG_WARNING, "Unsupported crypto suite: %s\n", suite);
+ 		return -1;
+@@ -283,16 +286,16 @@
+ 	return 0;
+ }
+ 
+-int sdp_crypto_offer(struct sdp_crypto *p)
++int sdp_crypto_offer(struct sdp_crypto *p, int taglen)
+ {
+ 	char crypto_buf[128];
+-	const char *crypto_suite = "AES_CM_128_HMAC_SHA1_80"; /* Crypto offer */
+ 
+ 	if (p->a_crypto) {
+ 		ast_free(p->a_crypto);
+ 	}
+ 
+-	if (snprintf(crypto_buf, sizeof(crypto_buf), "a=crypto:1 %s inline:%s\r\n",  crypto_suite, p->local_key64) < 1) {
++	if (snprintf(crypto_buf, sizeof(crypto_buf), "a=crypto:1 AES_CM_128_HMAC_SHA1_%i inline:%s\r\n",
++			taglen, p->local_key64) < 1) {
+ 		return -1;
+ 	}
+ 
+Index: channels/chan_local.c
+===================================================================
+--- channels/chan_local.c	(.../digium/1.8)	(revision 556)
++++ channels/chan_local.c	(.../distrotech/1.8/1.8.8.0)	(revision 545)
+@@ -650,9 +650,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;
+@@ -675,7 +676,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;
+@@ -698,10 +698,32 @@
+ 			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) && !(bridge->nativeformats & ast->nativeformats)) {
++			if (!ast_channel_trylock(p->chan)) {
++				ast->nativeformats = bridge->nativeformats;
++				ast_set_read_format(ast, ast->readformat);
++				ast_set_write_format(ast, ast->writeformat);
++				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: configure.ac
+===================================================================
+--- configure.ac	(.../digium/1.8)	(revision 556)
++++ configure.ac	(.../distrotech/1.8/1.8.8.0)	(revision 545)
+@@ -1699,7 +1699,7 @@
+    AST_EXT_LIB_CHECK([SUPPSERV], [suppserv], [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/1.8)	(revision 556)
++++ apps/app_directed_pickup.c	(.../distrotech/1.8/1.8.8.0)	(revision 545)
+@@ -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/1.8)	(revision 556)
++++ apps/app_queue.c	(.../distrotech/1.8/1.8.8.0)	(revision 545)
+@@ -524,11 +524,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>
+ 		<see-also>
+ 			<ref type="application">Queue</ref>
+@@ -661,6 +675,7 @@
+ 		</syntax>
+ 		<description>
+ 			<para>Gets or sets queue members penalty.</para>
++			<warning><para>This function has been deprecated in favor of the <literal>QUEUE_MEMBER()</literal> function</para></warning>
+ 		</description>
+ 		<see-also>
+ 			<ref type="application">Queue</ref>
+@@ -936,6 +951,12 @@
+ /*! \brief queues.conf [general] option */
+ static int update_cdr = 0;
+ 
++/*! \brief queues.conf [general] option */
++static int negative_penalty_invalid = 0;
++
++/*! \brief queues.conf [general] option */
++static int log_membername_as_agent = 0;
++
+ enum queue_result {
+ 	QUEUE_UNKNOWN = 0,
+ 	QUEUE_TIMEOUT = 1,
+@@ -1045,6 +1066,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 {
+@@ -1162,6 +1184,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 */
+@@ -1192,9 +1215,12 @@
+ 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); 
++static void queue_transfer_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan);
++
++static struct member *find_member_by_queuename_and_interface(const char *queuename, const char *interface);
+ /*! \brief sets the QUEUESTATUS channel variable */
+ static void set_queue_result(struct ast_channel *chan, enum queue_result res)
+ {
+@@ -1438,13 +1464,14 @@
+ 		"Queue: %s\r\n"
+ 		"Location: %s\r\n"
+ 		"MemberName: %s\r\n"
++		"StateInterface: %s\r\n"
+ 		"Membership: %s\r\n"
+ 		"Penalty: %d\r\n"
+ 		"CallsTaken: %d\r\n"
+ 		"LastCall: %d\r\n"
+ 		"Status: %d\r\n"
+ 		"Paused: %d\r\n",
+-		q->name, m->interface, m->membername, m->dynamic ? "dynamic" : m->realtime ? "realtime" : "static",
++		q->name, m->interface, m->membername, m->state_interface, m->dynamic ? "dynamic" : m->realtime ? "realtime" : "static",
+ 		m->penalty, m->calls, (int)m->lastcall, m->status, m->paused
+ 	);
+ 
+@@ -1700,6 +1727,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 || q->strategy == QUEUE_STRATEGY_RRORDERED)
+ 			/* linear strategy depends on order, so we have to place all members in a single bucket */
+@@ -2010,6 +2038,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)
+@@ -2079,16 +2109,24 @@
+  * \brief Find rt member record to update otherwise create one.
+  *
+  * 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. 
++ * 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;
+@@ -2096,8 +2134,11 @@
+ 
+ 	if (penalty_str) {
+ 		penalty = atoi(penalty_str);
+-		if (penalty < 0)
++		if ((penalty < 0) && negative_penalty_invalid) {
++			return;
++		} else if (penalty < 0) {
+ 			penalty = 0;
++		}
+ 	}
+ 
+ 	if (paused_str) {
+@@ -2106,33 +2147,45 @@
+ 			paused = 0;
+ 	}
+ 
+- 	/* Find member by realtime uniqueid and update */
+- 	mem_iter = ao2_iterator_init(q->members, 0);
+- 	while ((m = ao2_iterator_next(&mem_iter))) {
+- 		if (!strcasecmp(m->rt_uniqueid, rt_uniqueid)) {
+- 			m->dead = 0;	/* Do not delete this one. */
+- 			ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid));
+- 			if (paused_str)
+- 				m->paused = paused;
+- 			if (strcasecmp(state_interface, m->state_interface)) {
+- 				ast_copy_string(m->state_interface, state_interface, sizeof(m->state_interface));
+- 			}	   
+- 			m->penalty = penalty;
+- 			found = 1;
+- 			ao2_ref(m, -1);
+- 			break;
+- 		}
+- 		ao2_ref(m, -1);
+- 	}
++	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))) {
++		if (!strcasecmp(m->rt_uniqueid, rt_uniqueid)) {
++			m->dead = 0;	/* Do not delete this one. */
++			ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid));
++			if (paused_str)
++				m->paused = paused;
++			if (strcasecmp(state_interface, m->state_interface)) {
++				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;
++		}
++		ao2_ref(m, -1);
++	}
+ 	ao2_iterator_destroy(&mem_iter);
+ 
+- 	/* Create a new member */
+- 	if (!found) {
++	/* Create a new member */
++	if (!found) {
+ 		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", "");
++			if (!log_membername_as_agent) {
++				ast_queue_log(q->name, "REALTIME", m->interface, "ADDMEMBER", "%s", "");
++			} else {
++				ast_queue_log(q->name, "REALTIME", m->membername, "ADDMEMBER", "%s", "");
++			}
+ 			ao2_link(q->members, m);
+ 			ao2_ref(m, -1);
+ 			m = NULL;
+@@ -2306,19 +2359,18 @@
+ 	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. */
+ 	mem_iter = ao2_iterator_init(q->members, 0);
+ 	while ((m = ao2_iterator_next(&mem_iter))) {
+ 		if (m->dead) {
+-			ast_queue_log(q->name, "REALTIME", m->interface, "REMOVEMEMBER", "%s", "");
++			if (ast_strlen_zero(m->membername) || !log_membername_as_agent) {
++				ast_queue_log(q->name, "REALTIME", m->interface, "REMOVEMEMBER", "%s", "");
++			} else {
++				ast_queue_log(q->name, "REALTIME", m->membername, "REMOVEMEMBER", "%s", "");
++			}
+ 			ao2_unlink(q->members, m);
+ 			q->membercount--;
+ 		}
+@@ -2427,19 +2479,18 @@
+ 	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. */
+ 	mem_iter = ao2_iterator_init(q->members, 0);
+ 	while ((m = ao2_iterator_next(&mem_iter))) {
+ 		if (m->dead) {
+-			ast_queue_log(q->name, "REALTIME", m->interface, "REMOVEMEMBER", "%s", "");
++			if (ast_strlen_zero(m->membername) || !log_membername_as_agent) {
++				ast_queue_log(q->name, "REALTIME", m->interface, "REMOVEMEMBER", "%s", "");
++			} else {
++				ast_queue_log(q->name, "REALTIME", m->membername, "REMOVEMEMBER", "%s", "");
++			}
+ 			ao2_unlink(q->members, m);
+ 			q->membercount--;
+ 		}
+@@ -2876,16 +2927,24 @@
+ 	mem_iter = ao2_iterator_init(q->members, 0);
+ 	while ((mem = ao2_iterator_next(&mem_iter))) {
+ 		switch (mem->status) {
+-		case AST_DEVICE_INUSE:
+-			if (!q->ringinuse)
++			case AST_DEVICE_INVALID:
++			case AST_DEVICE_UNAVAILABLE:
+ 				break;
+-			/* else fall through */
+-		case AST_DEVICE_NOT_INUSE:
+-		case AST_DEVICE_UNKNOWN:
+-			if (!mem->paused) {
+-				avl++;
+-			}
+-			break;
++			case AST_DEVICE_INUSE:
++			case AST_DEVICE_BUSY:
++			case AST_DEVICE_RINGING:
++			case AST_DEVICE_RINGINUSE:
++			case AST_DEVICE_ONHOLD:
++				if ((!q->ringinuse) || (!mem->ignorebusy)) {
++					break;
++				}
++				/* else fall through */
++			case AST_DEVICE_NOT_INUSE:
++			case AST_DEVICE_UNKNOWN:
++				if (!mem->paused) {
++					avl++;
++				}
++				break;
+ 		}
+ 		ao2_ref(mem, -1);
+ 
+@@ -3011,38 +3070,54 @@
+ 	char tech[256];
+ 	char *location;
+ 	const char *macrocontext, *macroexten;
++	enum ast_device_state newstate;
+ 
+ 	/* on entry here, we know that tmp->chan == NULL */
++	if (tmp->member->paused) {
++		ast_debug(1, "%s paused, can't receive call\n", tmp->interface);
++		if (qe->chan->cdr) {
++			ast_cdr_busy(qe->chan->cdr);
++		}
++		tmp->stillgoing = 0;
++		return 0;
++	}
++
+ 	if ((tmp->lastqueue && tmp->lastqueue->wrapuptime && (time(NULL) - tmp->lastcall < tmp->lastqueue->wrapuptime)) ||
+ 		(!tmp->lastqueue && qe->parent->wrapuptime && (time(NULL) - tmp->lastcall < qe->parent->wrapuptime))) {
+-		ast_debug(1, "Wrapuptime not yet expired on queue %s for %s\n", 
++		ast_debug(1, "Wrapuptime not yet expired on queue %s for %s\n",
+ 				(tmp->lastqueue ? tmp->lastqueue->name : qe->parent->name), tmp->interface);
+-		if (qe->chan->cdr)
++		if (qe->chan->cdr) {
+ 			ast_cdr_busy(qe->chan->cdr);
++		}
+ 		tmp->stillgoing = 0;
+ 		(*busies)++;
+ 		return 0;
+ 	}
+ 
+-	if (!qe->parent->ringinuse && (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);
+-		tmp->stillgoing = 0;
+-		return 0;
++	if (!qe->parent->ringinuse || !tmp->member->ignorebusy) {
++		if ((tmp->member->status == AST_DEVICE_UNKNOWN) || (tmp->member->status == AST_DEVICE_NOT_INUSE)) {
++			newstate = ast_parse_device_state(tmp->member->interface);
++			if (newstate != tmp->member->status) {
++				ast_log(LOG_ERROR, "Found a channel matching iterface %s while status was %i changed to %i\n",
++					tmp->member->interface, tmp->member->status, newstate);
++				update_status(qe->parent, tmp->member, newstate);
++			}
++		}
++		if ((tmp->member->status != AST_DEVICE_NOT_INUSE) && (tmp->member->status != AST_DEVICE_UNKNOWN)) {

[... 7352 lines stripped ...]



More information about the asterisk-commits mailing list