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

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Sun Sep 4 05:59:06 CDT 2011


Author: irroot
Date: Sun Sep  4 05:58:55 2011
New Revision: 334437

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=334437
Log:
New patches for 1.8 and 1.8.6

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

Added: team/irroot/patches/distrotech-1.8.6.patch
URL: http://svnview.digium.com/svn/asterisk/team/irroot/patches/distrotech-1.8.6.patch?view=auto&rev=334437
==============================================================================
--- team/irroot/patches/distrotech-1.8.6.patch (added)
+++ team/irroot/patches/distrotech-1.8.6.patch Sun Sep  4 05:58:55 2011
@@ -1,0 +1,5540 @@
+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	(revision 334292)
++++ channels/chan_sip.c	(working copy)
+@@ -4314,6 +4314,9 @@
+ 			case T38_ENABLED:
+ 				state = T38_STATE_NEGOTIATED;
+ 				break;
++			case T38_REJECTED:
++				state = T38_STATE_REJECTED;
++				break;
+ 			default:
+ 				state = T38_STATE_UNKNOWN;
+ 			}
+@@ -4978,6 +4981,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;
+@@ -5447,17 +5451,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;
++			}
+ 		}
+ 	}
+ 
+@@ -6556,11 +6566,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"));
+@@ -6598,7 +6608,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);
+@@ -8834,27 +8844,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) {
+@@ -9034,7 +9060,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;
+         }
+@@ -10853,14 +10879,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);
+ 		}
+ 
+@@ -11020,7 +11057,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");
+ 
+@@ -11037,7 +11074,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 ? */
+@@ -11050,7 +11087,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");
+ 
+@@ -14278,24 +14315,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:
+@@ -14303,8 +14337,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;
+ 					}
+@@ -14329,19 +14361,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:
+@@ -14349,7 +14378,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;
+ 			}
+@@ -14365,6 +14393,7 @@
+ 		sched_yield();
+ 	}
+ 	if (!res) {
++		sip_send_mwi_to_peer(peer, NULL, 0);
+ 		ast_devstate_changed(AST_DEVICE_UNKNOWN, "SIP/%s", peer->name);
+ 	}
+ 	if (res < 0) {
+@@ -16863,7 +16892,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)
+@@ -16978,7 +17006,6 @@
+ 		astman_append(s, "VoiceMailbox: %s\r\n", mailbox_str->str);
+ 		astman_append(s, "TransferMode: %s\r\n", transfermode2str(peer->allowtransfer));
+ 		astman_append(s, "Maxforwards: %d\r\n", peer->maxforwards);
+-		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);
+@@ -18945,7 +18972,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);
+@@ -19711,7 +19738,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);
+ 
+@@ -21510,7 +21537,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");
+@@ -22385,9 +22412,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 {
+@@ -24887,19 +24915,23 @@
+ 	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, const struct ast_event *event, 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;
++	}
+ 
+ 	if (event) {
+ 		newmsgs = ast_event_get_ie_uint(event, AST_EVENT_IE_NEWMSGS);
+@@ -24908,9 +24940,13 @@
+ 		/* Fall back to manually checking the mailbox */
+ 		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);
+ 	}
+-	
++
+ 	if (peer->mwipvt) {
+ 		/* Base message on subscription */
+ 		p = dialog_ref(peer->mwipvt, "sip_send_mwi_to_peer: Setting dialog ptr p from peer->mwipvt-- should this be done?");
+@@ -24928,7 +24964,7 @@
+ 			dialog_unlink_all(p, TRUE, TRUE);
+ 			dialog_unref(p, "unref dialog p just created via sip_alloc");
+ 			/* sip_destroy(p); */
+-			return 0;
++			return -1;
+ 		}
+ 		/* Recalculate our side, and recalculate Call ID */
+ 		ast_sip_ouraddrfor(&p->sa, &p->ourip, p);
+@@ -26392,6 +26428,10 @@
+ 	while ((mbox = context = strsep(&next, ","))) {
+ 		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, "@");
+ 
+@@ -26483,7 +26523,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;
+@@ -26858,7 +26897,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);
+ 			}
+@@ -28763,7 +28810,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/chan_misdn.c
+===================================================================
+--- channels/chan_misdn.c	(revision 334292)
++++ channels/chan_misdn.c	(working copy)
+@@ -7871,64 +7871,63 @@
+ 		}
+ 
+ 		if (rr) {
+-			int robin_channel = rr->channel;
+ 			int port_start;
+-			int next_chan = 1;
++			int bchan_start;
++			int port_up;
++			int check;
++			int maxbchans;
+ 
+-			do {
+-				port_start = 0;
+-				for (port = misdn_cfg_get_next_port_spin(rr->port); port > 0 && port != port_start;
+-					 port = misdn_cfg_get_next_port_spin(port)) {
++			if (!rr->port) {
++				rr->port = misdn_cfg_get_next_port_spin(0);
++			}
+ 
+-					if (!port_start) {
+-						port_start = port;
+-					}
++			if (!rr->channel) {
++				rr->channel = 1;
++			}
+ 
+-					if (port >= port_start) {
+-						next_chan = 1;
+-					}
++			bchan_start = rr->channel;
++			port_start = rr->port;
++			do {
++				misdn_cfg_get(rr->port, MISDN_CFG_GROUPNAME, cfg_group, sizeof(cfg_group));
++				if (strcasecmp(cfg_group, group)) {
++					rr->port = misdn_cfg_get_next_port_spin(rr->port);
++					rr->channel = 1;
++					continue;
++				}
+ 
+-					if (port <= port_start && next_chan) {
+-						int maxbchans = misdn_lib_get_maxchans(port);
++				misdn_cfg_get(rr->port, MISDN_CFG_PMP_L1_CHECK, &check, sizeof(check));
++				port_up = misdn_lib_port_up(rr->port, check);
+ 
+-						if (++robin_channel >= maxbchans) {
+-							robin_channel = 1;
+-						}
+-						next_chan = 0;
+-					}
++				if (!port_up) {
++					chan_misdn_log(1, rr->port, "L1 is not Up on this Port\n");
++					rr->port = misdn_cfg_get_next_port_spin(rr->port);
++					rr->channel = 1;
++				} else if (port_up < 0) {
++					ast_log(LOG_WARNING, "This port (%d) is blocked\n", rr->port);
++					rr->port = misdn_cfg_get_next_port_spin(rr->port);
++					rr->channel = 1;
++				} else {
++					chan_misdn_log(4, rr->port, "portup\n");
++					maxbchans = misdn_lib_get_maxchans(rr->port);
+ 
+-					misdn_cfg_get(port, MISDN_CFG_GROUPNAME, cfg_group, sizeof(cfg_group));
++					for (;rr->channel <= maxbchans;rr->channel++) {
++						chan_misdn_log(4, rr->port, "Checking channel %d\n",  rr->channel);
+ 
+-					if (!strcasecmp(cfg_group, group)) {
+-						int port_up;
+-						int check;
+-
+-						misdn_cfg_get(port, MISDN_CFG_PMP_L1_CHECK, &check, sizeof(check));
+-						port_up = misdn_lib_port_up(port, check);
+-
+-						if (check && !port_up) {
+-							chan_misdn_log(1, port, "L1 is not Up on this Port\n");
++						if ((newbc = misdn_lib_get_free_bc(rr->port, rr->channel, 0, 0))) {
++							chan_misdn_log(4, rr->port, " Success! Found port:%d channel:%d\n", newbc->port, newbc->channel);
++							rr->channel++;
++							break;
+ 						}
+-
+-						if (check && port_up < 0) {
+-							ast_log(LOG_WARNING, "This port (%d) is blocked\n", port);
+-						}
+-
+-						if (port_up > 0)	{
+-							newbc = misdn_lib_get_free_bc(port, robin_channel, 0, 0);
+-							if (newbc) {
+-								chan_misdn_log(4, port, " Success! Found port:%d channel:%d\n", newbc->port, newbc->channel);
+-								if (port_up) {
+-									chan_misdn_log(4, port, "portup:%d\n",  port_up);
+-								}
+-								rr->port = newbc->port;
+-								rr->channel = newbc->channel;
+-								break;
+-							}
+-						}
+ 					}
++					if (!newbc || (rr->channel > maxbchans)) {
++						rr->port = misdn_cfg_get_next_port_spin(rr->port);
++						rr->channel = 1;
++					}
++
+ 				}
+-			} while (!newbc && robin_channel != rr->channel);
++			} while (!newbc && (rr->port > 0) &&
++				 ((rr->port != port_start) || ((rr->port == port_start) && (rr->channel < bchan_start))));
++
+ 		} else {
+ 			for (port = misdn_cfg_get_next_port(0); port > 0;
+ 				port = misdn_cfg_get_next_port(port)) {
+Index: channels/sip/include/sip.h
+===================================================================
+--- channels/sip/include/sip.h	(revision 334292)
++++ channels/sip/include/sip.h	(working copy)
+@@ -351,9 +351,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)
+ 
+ /*@}*/
+ 
+@@ -596,7 +598,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 */
+@@ -1217,7 +1220,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	(revision 334292)
++++ channels/sip/include/sdp_crypto.h	(working copy)
+@@ -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	(revision 334292)
++++ channels/sip/include/srtp.h	(working copy)
+@@ -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	(revision 334292)
++++ channels/sip/sdp_crypto.c	(working copy)
+@@ -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	(revision 334292)
++++ channels/chan_local.c	(working copy)
+@@ -588,6 +588,7 @@
+ static int local_write(struct ast_channel *ast, struct ast_frame *f)
+ {
+ 	struct local_pvt *p = ast->tech_pvt;
++	struct ast_channel *bridge;
+ 	int res = -1;
+ 	int isoutbound;
+ 
+@@ -602,6 +603,20 @@
+ 
+ 	if (isoutbound && f && (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO)) {
+ 		check_bridge(p);
++	} else if (!isoutbound) {
++		/* fixup formats nativeformat has changed we must adjust
++		 * ast is p->owner and is locked here*/
++		bridge = ast_bridged_channel(ast);
++		if (bridge && !(bridge->nativeformats & ast->nativeformats)) {
++			ast->nativeformats = bridge->nativeformats;
++			ast_set_read_format(ast, ast->readformat);
++			ast_set_write_format(ast, ast->writeformat);
++			ast_channel_lock(p->chan);
++			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);
++		}
+ 	}
+ 
+ 	if (!ast_test_flag(p, LOCAL_ALREADY_MASQED)) {
+Index: apps/app_queue.c
+===================================================================
+--- apps/app_queue.c	(revision 334292)
++++ apps/app_queue.c	(working copy)
+@@ -522,11 +522,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>
+@@ -659,6 +673,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>
+@@ -934,6 +949,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,
+@@ -1043,6 +1064,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 {
+@@ -1160,6 +1182,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 */
+@@ -1190,9 +1213,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)
+ {
+@@ -1436,13 +1462,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
+ 	);
+ 
+@@ -1552,7 +1579,7 @@
+ 	return state;
+ }
+ 
+-static int extension_state_cb(char *context, char *exten, enum ast_extension_states state, void *data)
++static int extension_state_cb(const char *context, const char *exten, enum ast_extension_states state, void *data)
+ {
+ 	struct ao2_iterator miter, qiter;
+ 	struct member *m;
+@@ -1698,6 +1725,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 */
+@@ -2003,6 +2031,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)
+@@ -2072,16 +2102,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;
+@@ -2089,8 +2127,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) {
+@@ -2099,33 +2140,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;
+@@ -2299,19 +2352,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--;
+ 		}
+@@ -2426,19 +2478,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--;
+ 		}
+@@ -2877,16 +2928,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);
+ 
+@@ -3014,38 +3073,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) {

[... 5817 lines stripped ...]



More information about the asterisk-commits mailing list