[asterisk-commits] irroot: branch irroot/patches r333539 - /team/irroot/patches/
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Sun Aug 28 05:26:06 CDT 2011
Author: irroot
Date: Sun Aug 28 05:26:02 2011
New Revision: 333539
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=333539
Log:
Add patches for branches
Added:
team/irroot/patches/distrotech-1.8.patch (with props)
team/irroot/patches/distrotech-10.patch (with props)
team/irroot/patches/distrotech-trunk.patch (with props)
team/irroot/patches/t38gateway-1.8.patch (with props)
Added: team/irroot/patches/distrotech-1.8.patch
URL: http://svnview.digium.com/svn/asterisk/team/irroot/patches/distrotech-1.8.patch?view=auto&rev=333539
==============================================================================
--- team/irroot/patches/distrotech-1.8.patch (added)
+++ team/irroot/patches/distrotech-1.8.patch Sun Aug 28 05:26:02 2011
@@ -1,0 +1,5117 @@
+Index: channels/chan_sip.c
+===================================================================
+--- channels/chan_sip.c (.../branches/1.8) (revision 333497)
++++ channels/chan_sip.c (.../team/irroot/distrotech-customers-1.8) (revision 333497)
+@@ -4316,6 +4316,9 @@
+ case T38_ENABLED:
+ state = T38_STATE_NEGOTIATED;
+ break;
++ case T38_REJECTED:
++ state = T38_STATE_REJECTED;
++ break;
+ default:
+ state = T38_STATE_UNKNOWN;
+ }
+@@ -4980,6 +4983,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;
+@@ -5449,17 +5453,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;
++ }
+ }
+ }
+
+@@ -6558,11 +6568,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"));
+@@ -6600,7 +6610,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);
+@@ -8836,27 +8846,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) {
+@@ -9036,7 +9062,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;
+ }
+@@ -10855,14 +10881,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);
+ }
+
+@@ -11022,7 +11059,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");
+
+@@ -11039,7 +11076,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 ? */
+@@ -11052,7 +11089,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");
+
+@@ -14280,24 +14317,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:
+@@ -14305,8 +14339,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;
+ }
+@@ -14331,19 +14363,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:
+@@ -14351,7 +14380,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;
+ }
+@@ -14367,6 +14395,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) {
+@@ -16865,7 +16894,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)
+@@ -16980,7 +17008,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);
+@@ -18948,7 +18975,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);
+@@ -19714,7 +19741,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);
+
+@@ -21513,7 +21540,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");
+@@ -22388,9 +22415,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 {
+@@ -24947,25 +24975,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);
+ }
+
+@@ -24986,7 +25022,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);
+@@ -26454,6 +26490,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)) {
+@@ -26544,7 +26585,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;
+@@ -26919,7 +26959,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);
+ }
+@@ -28827,7 +28875,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 (.../branches/1.8) (revision 333497)
++++ channels/sip/include/sip.h (.../team/irroot/distrotech-customers-1.8) (revision 333497)
+@@ -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 */
+@@ -1218,7 +1221,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 (.../branches/1.8) (revision 333497)
++++ channels/sip/include/sdp_crypto.h (.../team/irroot/distrotech-customers-1.8) (revision 333497)
+@@ -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 (.../branches/1.8) (revision 333497)
++++ channels/sip/include/srtp.h (.../team/irroot/distrotech-customers-1.8) (revision 333497)
+@@ -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 (.../branches/1.8) (revision 333497)
++++ channels/sip/sdp_crypto.c (.../team/irroot/distrotech-customers-1.8) (revision 333497)
+@@ -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 (.../branches/1.8) (revision 333497)
++++ channels/chan_local.c (.../team/irroot/distrotech-customers-1.8) (revision 333497)
+@@ -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: configure.ac
+===================================================================
+--- configure.ac (.../branches/1.8) (revision 333497)
++++ configure.ac (.../team/irroot/distrotech-customers-1.8) (revision 333497)
+@@ -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_queue.c
+===================================================================
+--- apps/app_queue.c (.../branches/1.8) (revision 333497)
++++ apps/app_queue.c (.../team/irroot/distrotech-customers-1.8) (revision 333497)
+@@ -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 */
+@@ -2008,6 +2036,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)
+@@ -2077,16 +2107,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;
+@@ -2094,8 +2132,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) {
+@@ -2104,33 +2145,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;
+@@ -2304,19 +2357,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--;
+ }
+@@ -2430,19 +2482,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--;
+ }
+@@ -2883,16 +2934,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);
+
+@@ -3020,38 +3079,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)) {
++ 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 (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 (use_weight && compare_weight(qe->parent,tmp->member)) {
+ ast_debug(1, "Priority queue delaying call to %s:%s\n", 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;
+@@ -3066,8 +3141,9 @@
+ /* Request the peer */
+ tmp->chan = ast_request(tech, qe->chan->nativeformats, qe->chan, location, &status);
+ if (!tmp->chan) { /* If we can't, just go on to the next call */
+- if (qe->chan->cdr)
++ if (qe->chan->cdr) {
+ ast_cdr_busy(qe->chan->cdr);
++ }
+ tmp->stillgoing = 0;
+
+ ao2_lock(qe->parent);
+@@ -3406,6 +3482,18 @@
+ }
+ ast_queue_log(qe->parent->name, qe->chan->uniqueid, membername, "RINGNOANSWER", "%d", rnatime);
+ if (qe->parent->autopause != QUEUE_AUTOPAUSE_OFF && pause) {
++ if (qe->parent->autopausedelay > 0) {
++ struct member *mem;
++ ao2_lock(qe->parent);
++ if ((mem = interface_exists(qe->parent, interface))) {
++ time_t idletime = time(&idletime)-mem->lastcall;
++ if ((mem->lastcall != 0) && (qe->parent->autopausedelay > idletime)) {
++ ao2_unlock(qe->parent);
++ return;
++ }
++ }
++ ao2_unlock(qe->parent);
++ }
+ if (qe->parent->autopause == QUEUE_AUTOPAUSE_ON) {
+ if (!set_member_paused(qe->parent->name, interface, "Auto-Pause", 1)) {
+ ast_verb(3, "Auto-Pausing Queue Member %s in queue %s since they failed to answer.\n",
+@@ -4717,8 +4805,9 @@
+ else
+ ast_moh_stop(qe->chan);
+ /* If appropriate, log that we have a destination channel */
+- if (qe->chan->cdr)
++ if (qe->chan->cdr) {
+ ast_cdr_setdestchan(qe->chan->cdr, peer->name);
++ }
+ /* Make sure channels are compatible */
[... 10029 lines stripped ...]
More information about the asterisk-commits
mailing list