Skip to content
Snippets Groups Projects
sig_pri.c 295 KiB
Newer Older
  • Learn to ignore specific revisions
  • /*
     * Asterisk -- An open source telephony toolkit.
     *
     * Copyright (C) 1999 - 2009, Digium, Inc.
     *
     * Mark Spencer <markster@digium.com>
     *
     * See http://www.asterisk.org for more information about
     * the Asterisk project. Please do not directly contact
     * any of the maintainers of this project for assistance;
     * the project provides a web site, mailing lists and IRC
     * channels for your use.
     *
     * This program is free software, distributed under the terms of
     * the GNU General Public License Version 2. See the LICENSE file
     * at the top of the source tree.
     */
    
    /*! \file
    
     * \brief PRI signaling module
     *
     * \author Matthew Fredrickson <creslin@digium.com>
     */
    
    
    /*** MODULEINFO
    	<support_level>core</support_level>
     ***/
    
    
    #include "asterisk.h"
    
    #ifdef HAVE_PRI
    
    #include <errno.h>
    #include <ctype.h>
    #include <signal.h>
    
    #include "asterisk/utils.h"
    #include "asterisk/options.h"
    #include "asterisk/pbx.h"
    
    #include "asterisk/file.h"
    #include "asterisk/callerid.h"
    #include "asterisk/say.h"
    #include "asterisk/manager.h"
    #include "asterisk/astdb.h"
    #include "asterisk/causes.h"
    #include "asterisk/musiconhold.h"
    #include "asterisk/cli.h"
    #include "asterisk/transcap.h"
    #include "asterisk/features.h"
    
    #include "asterisk/aoc.h"
    
    /* define this to send PRI user-user information elements */
    #undef SUPPORT_USERUSER
    
    
    /*!
     * Define to make always pick a channel if allowed.  Useful for
     * testing channel shifting.
     */
    //#define ALWAYS_PICK_CHANNEL	1
    
    /*!
     * Define to force a RESTART on a channel that returns a cause
     * code of PRI_CAUSE_REQUESTED_CHAN_UNAVAIL(44).  If the cause
     * is because of a stuck channel on the peer and the channel is
     * always the next channel we pick for an outgoing call then
     * this can help.
     */
    #define FORCE_RESTART_UNAVAIL_CHANS		1
    
    
    #if defined(HAVE_PRI_CCSS)
    struct sig_pri_cc_agent_prv {
    	/*! Asterisk span D channel control structure. */
    
    	/*! CC id value to use with libpri. -1 if invalid. */
    	long cc_id;
    	/*! TRUE if CC has been requested and we are waiting for the response. */
    	unsigned char cc_request_response_pending;
    };
    
    struct sig_pri_cc_monitor_instance {
    	/*! \brief Asterisk span D channel control structure. */
    
    	/*! CC id value to use with libpri. (-1 if already canceled). */
    	long cc_id;
    	/*! CC core id value. */
    	int core_id;
    	/*! Device name(Channel name less sequence number) */
    	char name[1];
    };
    
    /*! Upper level agent/monitor type name. */
    static const char *sig_pri_cc_type_name;
    /*! Container of sig_pri monitor instances. */
    static struct ao2_container *sig_pri_cc_monitors;
    #endif	/* defined(HAVE_PRI_CCSS) */
    
    static int pri_matchdigittimeout = 3000;
    
    static int pri_gendigittimeout = 8000;
    
    #define DCHAN_NOTINALARM  (1 << 0)
    #define DCHAN_UP          (1 << 1)
    
    
    /* Defines to help decode the encoded event channel id. */
    #define PRI_CHANNEL(p)	((p) & 0xff)
    #define PRI_SPAN(p)		(((p) >> 8) & 0xff)
    #define PRI_EXPLICIT	(1 << 16)
    #define PRI_CIS_CALL	(1 << 17)	/* Call is using the D channel only. */
    #define PRI_HELD_CALL	(1 << 18)
    
    
    
    #define DCHAN_AVAILABLE	(DCHAN_NOTINALARM | DCHAN_UP)
    
    
    static int pri_active_dchan_index(struct sig_pri_span *pri);
    
    static const char *sig_pri_call_level2str(enum sig_pri_call_level level)
    {
    	switch (level) {
    	case SIG_PRI_CALL_LEVEL_IDLE:
    		return "Idle";
    	case SIG_PRI_CALL_LEVEL_SETUP:
    		return "Setup";
    	case SIG_PRI_CALL_LEVEL_OVERLAP:
    		return "Overlap";
    	case SIG_PRI_CALL_LEVEL_PROCEEDING:
    		return "Proceeding";
    	case SIG_PRI_CALL_LEVEL_ALERTING:
    		return "Alerting";
    
    	case SIG_PRI_CALL_LEVEL_DEFER_DIAL:
    		return "DeferDial";
    
    	case SIG_PRI_CALL_LEVEL_CONNECT:
    		return "Connect";
    	}
    	return "Unknown";
    }
    
    
    static inline void pri_rel(struct sig_pri_span *pri)
    
    {
    	ast_mutex_unlock(&pri->lock);
    }
    
    static unsigned int PVT_TO_CHANNEL(struct sig_pri_chan *p)
    {
    
    	int res = (((p)->prioffset) | ((p)->logicalspan << 8) | (p->mastertrunkgroup ? PRI_EXPLICIT : 0));
    
    	ast_debug(5, "prioffset: %d mastertrunkgroup: %d logicalspan: %d result: %d\n",
    		p->prioffset, p->mastertrunkgroup, p->logicalspan, res);
    
    static void sig_pri_handle_dchan_exception(struct sig_pri_span *pri, int index)
    
    	if (sig_pri_callbacks.handle_dchan_exception) {
    		sig_pri_callbacks.handle_dchan_exception(pri, index);
    	}
    
    static void sig_pri_set_dialing(struct sig_pri_chan *p, int is_dialing)
    
    	if (sig_pri_callbacks.set_dialing) {
    		sig_pri_callbacks.set_dialing(p->chan_pvt, is_dialing);
    
    static void sig_pri_set_digital(struct sig_pri_chan *p, int is_digital)
    
    	if (sig_pri_callbacks.set_digital) {
    		sig_pri_callbacks.set_digital(p->chan_pvt, is_digital);
    
    static void sig_pri_set_outgoing(struct sig_pri_chan *p, int is_outgoing)
    {
    	p->outgoing = is_outgoing;
    
    	if (sig_pri_callbacks.set_outgoing) {
    		sig_pri_callbacks.set_outgoing(p->chan_pvt, is_outgoing);
    
    void sig_pri_set_alarm(struct sig_pri_chan *p, int in_alarm)
    
    	if (sig_pri_is_alarm_ignored(p->pri)) {
    		/* Always set not in alarm */
    		in_alarm = 0;
    	}
    
    
    	 * Clear the channel restart state when the channel alarm
    	 * changes to prevent the state from getting stuck when the link
    	 * goes down.
    
    	p->resetting = SIG_PRI_RESET_IDLE;
    
    	if (sig_pri_callbacks.set_alarm) {
    		sig_pri_callbacks.set_alarm(p->chan_pvt, in_alarm);
    
    static const char *sig_pri_get_orig_dialstring(struct sig_pri_chan *p)
    {
    
    	if (sig_pri_callbacks.get_orig_dialstring) {
    		return sig_pri_callbacks.get_orig_dialstring(p->chan_pvt);
    
    	}
    	ast_log(LOG_ERROR, "get_orig_dialstring callback not defined\n");
    	return "";
    }
    
    #if defined(HAVE_PRI_CCSS)
    static void sig_pri_make_cc_dialstring(struct sig_pri_chan *p, char *buf, size_t buf_size)
    {
    
    	if (sig_pri_callbacks.make_cc_dialstring) {
    		sig_pri_callbacks.make_cc_dialstring(p->chan_pvt, buf, buf_size);
    
    	} else {
    		ast_log(LOG_ERROR, "make_cc_dialstring callback not defined\n");
    		buf[0] = '\0';
    	}
    }
    #endif	/* defined(HAVE_PRI_CCSS) */
    
    
    static void sig_pri_dial_digits(struct sig_pri_chan *p, const char *dial_string)
    {
    
    	if (sig_pri_callbacks.dial_digits) {
    		sig_pri_callbacks.dial_digits(p->chan_pvt, dial_string);
    
    /*!
     * \internal
     * \brief Reevaluate the PRI span device state.
     * \since 1.8
     *
    
     * \param pri PRI span control structure.
    
     *
     * \return Nothing
     *
     * \note Assumes the pri->lock is already obtained.
     */
    
    static void sig_pri_span_devstate_changed(struct sig_pri_span *pri)
    
    	if (sig_pri_callbacks.update_span_devstate) {
    		sig_pri_callbacks.update_span_devstate(pri);
    
    /*!
     * \internal
     * \brief Set the caller id information in the parent module.
    
     *
     * \param p sig_pri channel structure.
     *
     * \return Nothing
     */
    static void sig_pri_set_caller_id(struct sig_pri_chan *p)
    {
    	struct ast_party_caller caller;
    
    
    	if (sig_pri_callbacks.set_callerid) {
    
    		ast_party_caller_init(&caller);
    
    
    		caller.id.name.str = p->cid_name;
    		caller.id.name.presentation = p->callingpres;
    		caller.id.name.valid = 1;
    
    		caller.id.number.str = p->cid_num;
    		caller.id.number.plan = p->cid_ton;
    		caller.id.number.presentation = p->callingpres;
    		caller.id.number.valid = 1;
    
    
    		if (!ast_strlen_zero(p->cid_subaddr)) {
    			caller.id.subaddress.valid = 1;
    			//caller.id.subaddress.type = 0;/* nsap */
    			//caller.id.subaddress.odd_even_indicator = 0;
    			caller.id.subaddress.str = p->cid_subaddr;
    		}
    
    
    		caller.ani.number.str = p->cid_ani;
    		//caller.ani.number.plan = p->xxx;
    		//caller.ani.number.presentation = p->xxx;
    		caller.ani.number.valid = 1;
    
    
    		caller.ani2 = p->cid_ani2;
    
    		sig_pri_callbacks.set_callerid(p->chan_pvt, &caller);
    
    	}
    }
    
    /*!
     * \internal
     * \brief Set the Dialed Number Identifier.
    
     *
     * \param p sig_pri channel structure.
     * \param dnid Dialed Number Identifier string.
     *
     * \return Nothing
     */
    static void sig_pri_set_dnid(struct sig_pri_chan *p, const char *dnid)
    {
    
    	if (sig_pri_callbacks.set_dnid) {
    		sig_pri_callbacks.set_dnid(p->chan_pvt, dnid);
    
    	}
    }
    
    /*!
     * \internal
     * \brief Set the Redirecting Directory Number Information Service (RDNIS).
    
     *
     * \param p sig_pri channel structure.
     * \param rdnis Redirecting Directory Number Information Service (RDNIS) string.
     *
     * \return Nothing
     */
    static void sig_pri_set_rdnis(struct sig_pri_chan *p, const char *rdnis)
    {
    
    	if (sig_pri_callbacks.set_rdnis) {
    		sig_pri_callbacks.set_rdnis(p->chan_pvt, rdnis);
    
    static void sig_pri_unlock_private(struct sig_pri_chan *p)
    {
    
    	if (sig_pri_callbacks.unlock_private) {
    		sig_pri_callbacks.unlock_private(p->chan_pvt);
    	}
    
    }
    
    static void sig_pri_lock_private(struct sig_pri_chan *p)
    {
    
    	if (sig_pri_callbacks.lock_private) {
    		sig_pri_callbacks.lock_private(p->chan_pvt);
    	}
    
    static void sig_pri_deadlock_avoidance_private(struct sig_pri_chan *p)
    {
    
    	if (sig_pri_callbacks.deadlock_avoidance_private) {
    		sig_pri_callbacks.deadlock_avoidance_private(p->chan_pvt);
    
    	} else {
    		/* Fallback to the old way if callback not present. */
    
    		sig_pri_unlock_private(p);
    		sched_yield();
    		sig_pri_lock_private(p);
    
    static void pri_grab(struct sig_pri_chan *p, struct sig_pri_span *pri)
    
    	while (ast_mutex_trylock(&pri->lock)) {
    		/* Avoid deadlock */
    		sig_pri_deadlock_avoidance_private(p);
    	}
    
    	if (pri->master != AST_PTHREADT_NULL) {
    		pthread_kill(pri->master, SIGURG);
    	}
    
    /*!
     * \internal
     * \brief Convert PRI redirecting reason to asterisk version.
    
     *
     * \param pri_reason PRI redirecting reason.
     *
     * \return Equivalent asterisk redirecting reason value.
     */
    static enum AST_REDIRECTING_REASON pri_to_ast_reason(int pri_reason)
    {
    	enum AST_REDIRECTING_REASON ast_reason;
    
    	switch (pri_reason) {
    	case PRI_REDIR_FORWARD_ON_BUSY:
    		ast_reason = AST_REDIRECTING_REASON_USER_BUSY;
    		break;
    	case PRI_REDIR_FORWARD_ON_NO_REPLY:
    		ast_reason = AST_REDIRECTING_REASON_NO_ANSWER;
    		break;
    	case PRI_REDIR_DEFLECTION:
    		ast_reason = AST_REDIRECTING_REASON_DEFLECTION;
    		break;
    	case PRI_REDIR_UNCONDITIONAL:
    		ast_reason = AST_REDIRECTING_REASON_UNCONDITIONAL;
    		break;
    	case PRI_REDIR_UNKNOWN:
    	default:
    		ast_reason = AST_REDIRECTING_REASON_UNKNOWN;
    		break;
    	}
    
    	return ast_reason;
    }
    
    /*!
     * \internal
     * \brief Convert asterisk redirecting reason to PRI version.
    
     *
     * \param ast_reason Asterisk redirecting reason.
     *
     * \return Equivalent PRI redirecting reason value.
     */
    static int ast_to_pri_reason(enum AST_REDIRECTING_REASON ast_reason)
    {
    	int pri_reason;
    
    	switch (ast_reason) {
    	case AST_REDIRECTING_REASON_USER_BUSY:
    		pri_reason = PRI_REDIR_FORWARD_ON_BUSY;
    		break;
    	case AST_REDIRECTING_REASON_NO_ANSWER:
    		pri_reason = PRI_REDIR_FORWARD_ON_NO_REPLY;
    		break;
    	case AST_REDIRECTING_REASON_UNCONDITIONAL:
    		pri_reason = PRI_REDIR_UNCONDITIONAL;
    		break;
    	case AST_REDIRECTING_REASON_DEFLECTION:
    		pri_reason = PRI_REDIR_DEFLECTION;
    		break;
    	case AST_REDIRECTING_REASON_UNKNOWN:
    	default:
    		pri_reason = PRI_REDIR_UNKNOWN;
    		break;
    	}
    
    	return pri_reason;
    }
    
    /*!
     * \internal
     * \brief Convert PRI number presentation to asterisk version.
    
     *
     * \param pri_presentation PRI number presentation.
     *
     * \return Equivalent asterisk number presentation value.
     */
    static int pri_to_ast_presentation(int pri_presentation)
    {
    	int ast_presentation;
    
    	switch (pri_presentation) {
    
    	case PRI_PRES_ALLOWED | PRI_PRES_USER_NUMBER_UNSCREENED:
    		ast_presentation = AST_PRES_ALLOWED | AST_PRES_USER_NUMBER_UNSCREENED;
    
    	case PRI_PRES_ALLOWED | PRI_PRES_USER_NUMBER_PASSED_SCREEN:
    		ast_presentation = AST_PRES_ALLOWED | AST_PRES_USER_NUMBER_PASSED_SCREEN;
    
    	case PRI_PRES_ALLOWED | PRI_PRES_USER_NUMBER_FAILED_SCREEN:
    		ast_presentation = AST_PRES_ALLOWED | AST_PRES_USER_NUMBER_FAILED_SCREEN;
    
    	case PRI_PRES_ALLOWED | PRI_PRES_NETWORK_NUMBER:
    		ast_presentation = AST_PRES_ALLOWED | AST_PRES_NETWORK_NUMBER;
    
    
    	case PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_UNSCREENED:
    		ast_presentation = AST_PRES_RESTRICTED | AST_PRES_USER_NUMBER_UNSCREENED;
    
    	case PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_PASSED_SCREEN:
    		ast_presentation = AST_PRES_RESTRICTED | AST_PRES_USER_NUMBER_PASSED_SCREEN;
    
    	case PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_FAILED_SCREEN:
    		ast_presentation = AST_PRES_RESTRICTED | AST_PRES_USER_NUMBER_FAILED_SCREEN;
    
    	case PRI_PRES_RESTRICTED | PRI_PRES_NETWORK_NUMBER:
    		ast_presentation = AST_PRES_RESTRICTED | AST_PRES_NETWORK_NUMBER;
    
    
    	case PRI_PRES_UNAVAILABLE | PRI_PRES_USER_NUMBER_UNSCREENED:
    	case PRI_PRES_UNAVAILABLE | PRI_PRES_USER_NUMBER_PASSED_SCREEN:
    	case PRI_PRES_UNAVAILABLE | PRI_PRES_USER_NUMBER_FAILED_SCREEN:
    	case PRI_PRES_UNAVAILABLE | PRI_PRES_NETWORK_NUMBER:
    
    		ast_presentation = AST_PRES_NUMBER_NOT_AVAILABLE;
    		break;
    
    		ast_presentation = AST_PRES_RESTRICTED | AST_PRES_USER_NUMBER_UNSCREENED;
    
    		break;
    	}
    
    	return ast_presentation;
    }
    
    /*!
     * \internal
     * \brief Convert asterisk number presentation to PRI version.
    
     *
     * \param ast_presentation Asterisk number presentation.
     *
     * \return Equivalent PRI number presentation value.
     */
    static int ast_to_pri_presentation(int ast_presentation)
    {
    	int pri_presentation;
    
    	switch (ast_presentation) {
    
    	case AST_PRES_ALLOWED | AST_PRES_USER_NUMBER_UNSCREENED:
    		pri_presentation = PRI_PRES_ALLOWED | PRI_PRES_USER_NUMBER_UNSCREENED;
    
    	case AST_PRES_ALLOWED | AST_PRES_USER_NUMBER_PASSED_SCREEN:
    		pri_presentation = PRI_PRES_ALLOWED | PRI_PRES_USER_NUMBER_PASSED_SCREEN;
    
    	case AST_PRES_ALLOWED | AST_PRES_USER_NUMBER_FAILED_SCREEN:
    		pri_presentation = PRI_PRES_ALLOWED | PRI_PRES_USER_NUMBER_FAILED_SCREEN;
    
    	case AST_PRES_ALLOWED | AST_PRES_NETWORK_NUMBER:
    		pri_presentation = PRI_PRES_ALLOWED | PRI_PRES_NETWORK_NUMBER;
    
    
    	case AST_PRES_RESTRICTED | AST_PRES_USER_NUMBER_UNSCREENED:
    		pri_presentation = PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_UNSCREENED;
    
    	case AST_PRES_RESTRICTED | AST_PRES_USER_NUMBER_PASSED_SCREEN:
    		pri_presentation = PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_PASSED_SCREEN;
    
    	case AST_PRES_RESTRICTED | AST_PRES_USER_NUMBER_FAILED_SCREEN:
    		pri_presentation = PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_FAILED_SCREEN;
    
    	case AST_PRES_RESTRICTED | AST_PRES_NETWORK_NUMBER:
    		pri_presentation = PRI_PRES_RESTRICTED | PRI_PRES_NETWORK_NUMBER;
    
    
    	case AST_PRES_UNAVAILABLE | AST_PRES_USER_NUMBER_UNSCREENED:
    	case AST_PRES_UNAVAILABLE | AST_PRES_USER_NUMBER_PASSED_SCREEN:
    	case AST_PRES_UNAVAILABLE | AST_PRES_USER_NUMBER_FAILED_SCREEN:
    	case AST_PRES_UNAVAILABLE | AST_PRES_NETWORK_NUMBER:
    
    		pri_presentation = PRES_NUMBER_NOT_AVAILABLE;
    		break;
    
    		pri_presentation = PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_UNSCREENED;
    
    		break;
    	}
    
    	return pri_presentation;
    }
    
    /*!
     * \internal
    
     * \brief Convert PRI name char_set to asterisk version.
    
     * \param pri_char_set PRI name char_set.
    
     * \return Equivalent asterisk name char_set value.
    
    static enum AST_PARTY_CHAR_SET pri_to_ast_char_set(int pri_char_set)
    
    	enum AST_PARTY_CHAR_SET ast_char_set;
    
    	switch (pri_char_set) {
    	default:
    	case PRI_CHAR_SET_UNKNOWN:
    		ast_char_set = AST_PARTY_CHAR_SET_UNKNOWN;
    		break;
    	case PRI_CHAR_SET_ISO8859_1:
    		ast_char_set = AST_PARTY_CHAR_SET_ISO8859_1;
    		break;
    	case PRI_CHAR_SET_WITHDRAWN:
    		ast_char_set = AST_PARTY_CHAR_SET_WITHDRAWN;
    		break;
    	case PRI_CHAR_SET_ISO8859_2:
    		ast_char_set = AST_PARTY_CHAR_SET_ISO8859_2;
    		break;
    	case PRI_CHAR_SET_ISO8859_3:
    		ast_char_set = AST_PARTY_CHAR_SET_ISO8859_3;
    		break;
    	case PRI_CHAR_SET_ISO8859_4:
    		ast_char_set = AST_PARTY_CHAR_SET_ISO8859_4;
    		break;
    	case PRI_CHAR_SET_ISO8859_5:
    		ast_char_set = AST_PARTY_CHAR_SET_ISO8859_5;
    		break;
    	case PRI_CHAR_SET_ISO8859_7:
    		ast_char_set = AST_PARTY_CHAR_SET_ISO8859_7;
    		break;
    	case PRI_CHAR_SET_ISO10646_BMPSTRING:
    		ast_char_set = AST_PARTY_CHAR_SET_ISO10646_BMPSTRING;
    		break;
    	case PRI_CHAR_SET_ISO10646_UTF_8STRING:
    		ast_char_set = AST_PARTY_CHAR_SET_ISO10646_UTF_8STRING;
    		break;
    
    	return ast_char_set;
    }
    
    /*!
     * \internal
     * \brief Convert asterisk name char_set to PRI version.
     * \since 1.8
     *
     * \param ast_char_set Asterisk name char_set.
     *
     * \return Equivalent PRI name char_set value.
     */
    static int ast_to_pri_char_set(enum AST_PARTY_CHAR_SET ast_char_set)
    {
    	int pri_char_set;
    
    	switch (ast_char_set) {
    	default:
    	case AST_PARTY_CHAR_SET_UNKNOWN:
    		pri_char_set = PRI_CHAR_SET_UNKNOWN;
    		break;
    	case AST_PARTY_CHAR_SET_ISO8859_1:
    		pri_char_set = PRI_CHAR_SET_ISO8859_1;
    		break;
    	case AST_PARTY_CHAR_SET_WITHDRAWN:
    		pri_char_set = PRI_CHAR_SET_WITHDRAWN;
    		break;
    	case AST_PARTY_CHAR_SET_ISO8859_2:
    		pri_char_set = PRI_CHAR_SET_ISO8859_2;
    		break;
    	case AST_PARTY_CHAR_SET_ISO8859_3:
    		pri_char_set = PRI_CHAR_SET_ISO8859_3;
    		break;
    	case AST_PARTY_CHAR_SET_ISO8859_4:
    		pri_char_set = PRI_CHAR_SET_ISO8859_4;
    		break;
    	case AST_PARTY_CHAR_SET_ISO8859_5:
    		pri_char_set = PRI_CHAR_SET_ISO8859_5;
    		break;
    	case AST_PARTY_CHAR_SET_ISO8859_7:
    		pri_char_set = PRI_CHAR_SET_ISO8859_7;
    		break;
    	case AST_PARTY_CHAR_SET_ISO10646_BMPSTRING:
    		pri_char_set = PRI_CHAR_SET_ISO10646_BMPSTRING;
    		break;
    	case AST_PARTY_CHAR_SET_ISO10646_UTF_8STRING:
    		pri_char_set = PRI_CHAR_SET_ISO10646_UTF_8STRING;
    		break;
    
    	return pri_char_set;
    
    #if defined(HAVE_PRI_SUBADDR)
    /*!
     * \internal
     * \brief Fill in the asterisk party subaddress from the given PRI party subaddress.
    
     *
     * \param ast_subaddress Asterisk party subaddress structure.
     * \param pri_subaddress PRI party subaddress structure.
     *
     * \return Nothing
     *
     */
    static void sig_pri_set_subaddress(struct ast_party_subaddress *ast_subaddress, const struct pri_party_subaddress *pri_subaddress)
    {
    	char *cnum, *ptr;
    	int x, len;
    
    	if (ast_subaddress->str) {
    		ast_free(ast_subaddress->str);
    	}
    	if (pri_subaddress->length <= 0) {
    		ast_party_subaddress_init(ast_subaddress);
    		return;
    	}
    
    	if (!pri_subaddress->type) {
    		/* NSAP */
    		ast_subaddress->str = ast_strdup((char *) pri_subaddress->data);
    	} else {
    		/* User Specified */
    		if (!(cnum = ast_malloc(2 * pri_subaddress->length + 1))) {
    			ast_party_subaddress_init(ast_subaddress);
    			return;
    		}
    
    		ptr = cnum;
    		len = pri_subaddress->length - 1; /* -1 account for zero based indexing */
    		for (x = 0; x < len; ++x) {
    			ptr += sprintf(ptr, "%02x", pri_subaddress->data[x]);
    		}
    
    		if (pri_subaddress->odd_even_indicator) {
    			/* ODD */
    			sprintf(ptr, "%01x", (pri_subaddress->data[len]) >> 4);
    		} else {
    			/* EVEN */
    			sprintf(ptr, "%02x", pri_subaddress->data[len]);
    		}
    		ast_subaddress->str = cnum;
    	}
    	ast_subaddress->type = pri_subaddress->type;
    	ast_subaddress->odd_even_indicator = pri_subaddress->odd_even_indicator;
    	ast_subaddress->valid = 1;
    }
    #endif	/* defined(HAVE_PRI_SUBADDR) */
    
    #if defined(HAVE_PRI_SUBADDR)
    static unsigned char ast_pri_pack_hex_char(char c)
    {
    	unsigned char res;
    
    	if (c < '0') {
    		res = 0;
    	} else if (c < ('9' + 1)) {
    		res = c - '0';
    	} else if (c < 'A') {
    		res = 0;
    	} else if (c < ('F' + 1)) {
    		res = c - 'A' + 10;
    	} else if (c < 'a') {
    		res = 0;
    	} else if (c < ('f' + 1)) {
    		res = c - 'a' + 10;
    	} else {
    		res = 0;
    	}
    	return res;
    }
    #endif	/* defined(HAVE_PRI_SUBADDR) */
    
    #if defined(HAVE_PRI_SUBADDR)
    /*!
     * \internal
     * \brief Convert a null terminated hexadecimal string to a packed hex byte array.
     * \details left justified, with 0 padding if odd length.
    
     *
     * \param dst pointer to packed byte array.
     * \param src pointer to null terminated hexadecimal string.
     * \param maxlen destination array size.
     *
     * \return Length of byte array
     *
     * \note The dst is not an ASCIIz string.
     * \note The src is an ASCIIz hex string.
     */
    static int ast_pri_pack_hex_string(unsigned char *dst, char *src, int maxlen)
    {
    	int res = 0;
    	int len = strlen(src);
    
    	if (len > (2 * maxlen)) {
    		len = 2 * maxlen;
    	}
    
    	res = len / 2 + len % 2;
    
    	while (len > 1) {
    		*dst = ast_pri_pack_hex_char(*src) << 4;
    		src++;
    		*dst |= ast_pri_pack_hex_char(*src);
    		dst++, src++;
    		len -= 2;
    	}
    	if (len) { /* 1 left */
    		*dst = ast_pri_pack_hex_char(*src) << 4;
    	}
    	return res;
    }
    #endif	/* defined(HAVE_PRI_SUBADDR) */
    
    #if defined(HAVE_PRI_SUBADDR)
    /*!
     * \internal
     * \brief Fill in the PRI party subaddress from the given asterisk party subaddress.
    
     *
     * \param pri_subaddress PRI party subaddress structure.
     * \param ast_subaddress Asterisk party subaddress structure.
     *
     * \return Nothing
     *
     * \note Assumes that pri_subaddress has been previously memset to zero.
     */
    static void sig_pri_party_subaddress_from_ast(struct pri_party_subaddress *pri_subaddress, const struct ast_party_subaddress *ast_subaddress)
    {
    	if (ast_subaddress->valid && !ast_strlen_zero(ast_subaddress->str)) {
    		pri_subaddress->type = ast_subaddress->type;
    		if (!ast_subaddress->type) {
    			/* 0 = NSAP */
    			ast_copy_string((char *) pri_subaddress->data, ast_subaddress->str,
    				sizeof(pri_subaddress->data));
    			pri_subaddress->length = strlen((char *) pri_subaddress->data);
    			pri_subaddress->odd_even_indicator = 0;
    			pri_subaddress->valid = 1;
    		} else {
    			/* 2 = User Specified */
    			/*
    			 * Copy HexString to packed HexData,
    			 * if odd length then right pad trailing byte with 0
    			 */
    			int length = ast_pri_pack_hex_string(pri_subaddress->data,
    				ast_subaddress->str, sizeof(pri_subaddress->data));
    
    
    			pri_subaddress->length = length; /* packed data length */
    
    			length = strlen(ast_subaddress->str);
    			if (length > 2 * sizeof(pri_subaddress->data)) {
    				pri_subaddress->odd_even_indicator = 0;
    			} else {
    				pri_subaddress->odd_even_indicator = (length & 1);
    			}
    
    			pri_subaddress->valid = 1;
    		}
    	}
    }
    #endif	/* defined(HAVE_PRI_SUBADDR) */
    
    
    /*!
     * \internal
     * \brief Fill in the PRI party name from the given asterisk party name.
     * \since 1.8
     *
     * \param pri_name PRI party name structure.
     * \param ast_name Asterisk party name structure.
     *
     * \return Nothing
     *
     * \note Assumes that pri_name has been previously memset to zero.
     */
    static void sig_pri_party_name_from_ast(struct pri_party_name *pri_name, const struct ast_party_name *ast_name)
    {
    	if (!ast_name->valid) {
    		return;
    	}
    	pri_name->valid = 1;
    	pri_name->presentation = ast_to_pri_presentation(ast_name->presentation);
    	pri_name->char_set = ast_to_pri_char_set(ast_name->char_set);
    	if (!ast_strlen_zero(ast_name->str)) {
    		ast_copy_string(pri_name->str, ast_name->str, sizeof(pri_name->str));
    	}
    }
    
    /*!
     * \internal
     * \brief Fill in the PRI party number from the given asterisk party number.
     * \since 1.8
     *
     * \param pri_number PRI party number structure.
     * \param ast_number Asterisk party number structure.
     *
     * \return Nothing
     *
     * \note Assumes that pri_number has been previously memset to zero.
     */
    static void sig_pri_party_number_from_ast(struct pri_party_number *pri_number, const struct ast_party_number *ast_number)
    {
    	if (!ast_number->valid) {
    		return;
    	}
    	pri_number->valid = 1;
    	pri_number->presentation = ast_to_pri_presentation(ast_number->presentation);
    	pri_number->plan = ast_number->plan;
    	if (!ast_strlen_zero(ast_number->str)) {
    		ast_copy_string(pri_number->str, ast_number->str, sizeof(pri_number->str));
    	}
    }
    
    
    /*!
     * \internal
     * \brief Fill in the PRI party id from the given asterisk party id.
    
     *
     * \param pri_id PRI party id structure.
     * \param ast_id Asterisk party id structure.
     *
     * \return Nothing
     *
     * \note Assumes that pri_id has been previously memset to zero.
     */
    static void sig_pri_party_id_from_ast(struct pri_party_id *pri_id, const struct ast_party_id *ast_id)
    {
    
    	sig_pri_party_name_from_ast(&pri_id->name, &ast_id->name);
    	sig_pri_party_number_from_ast(&pri_id->number, &ast_id->number);
    
    #if defined(HAVE_PRI_SUBADDR)
    	sig_pri_party_subaddress_from_ast(&pri_id->subaddress, &ast_id->subaddress);
    #endif	/* defined(HAVE_PRI_SUBADDR) */
    
    }
    
    /*!
     * \internal
     * \brief Update the PRI redirecting information for the current call.
    
     *
     * \param pvt sig_pri private channel structure.
     * \param ast Asterisk channel
     *
     * \return Nothing
     *
     * \note Assumes that the PRI lock is already obtained.
     */
    static void sig_pri_redirecting_update(struct sig_pri_chan *pvt, struct ast_channel *ast)
    {
    	struct pri_party_redirecting pri_redirecting;
    
    	const struct ast_party_redirecting *ast_redirecting;
    
    	struct ast_party_id redirecting_from = ast_channel_redirecting_effective_from(ast);
    	struct ast_party_id redirecting_to = ast_channel_redirecting_effective_to(ast);
    	struct ast_party_id redirecting_orig = ast_channel_redirecting_effective_orig(ast);
    
    
    	memset(&pri_redirecting, 0, sizeof(pri_redirecting));
    
    	ast_redirecting = ast_channel_redirecting(ast);
    
    	sig_pri_party_id_from_ast(&pri_redirecting.from, &redirecting_from);
    	sig_pri_party_id_from_ast(&pri_redirecting.to, &redirecting_to);
    	sig_pri_party_id_from_ast(&pri_redirecting.orig_called, &redirecting_orig);
    
    	pri_redirecting.count = ast_redirecting->count;
    	pri_redirecting.orig_reason = ast_to_pri_reason(ast_redirecting->orig_reason);
    	pri_redirecting.reason = ast_to_pri_reason(ast_redirecting->reason);
    
    
    	pri_redirecting_update(pvt->pri->pri, pvt->call, &pri_redirecting);
    }
    
    
    /*!
     * \internal
     * \brief Reset DTMF detector.
    
     *
     * \param p sig_pri channel structure.
     *
     * \return Nothing
     */
    static void sig_pri_dsp_reset_and_flush_digits(struct sig_pri_chan *p)
    {
    
    	if (sig_pri_callbacks.dsp_reset_and_flush_digits) {
    		sig_pri_callbacks.dsp_reset_and_flush_digits(p->chan_pvt);
    
    static int sig_pri_set_echocanceller(struct sig_pri_chan *p, int enable)
    {
    
    	if (sig_pri_callbacks.set_echocanceller) {
    		return sig_pri_callbacks.set_echocanceller(p->chan_pvt, enable);
    	} else {
    
    static void sig_pri_fixup_chans(struct sig_pri_chan *old_chan, struct sig_pri_chan *new_chan)
    
    	if (sig_pri_callbacks.fixup_chans) {
    		sig_pri_callbacks.fixup_chans(old_chan->chan_pvt, new_chan->chan_pvt);
    	}
    
    }
    
    static int sig_pri_play_tone(struct sig_pri_chan *p, enum sig_pri_tone tone)
    {
    
    	if (sig_pri_callbacks.play_tone) {
    		return sig_pri_callbacks.play_tone(p->chan_pvt, tone);
    	} else {
    
    static struct ast_channel *sig_pri_new_ast_channel(struct sig_pri_chan *p, int state, int ulaw, int transfercapability, char *exten, const struct ast_channel *requestor)
    
    	if (sig_pri_callbacks.new_ast_channel) {
    		c = sig_pri_callbacks.new_ast_channel(p->chan_pvt, state, ulaw, exten, requestor);
    
    
    	if (!p->owner)
    		p->owner = c;
    	p->isidlecall = 0;
    	p->alreadyhungup = 0;
    
    	ast_channel_transfercapability_set(c, transfercapability);
    
    	pbx_builtin_setvar_helper(c, "TRANSFERCAPABILITY",
    		ast_transfercapability2str(transfercapability));
    
    	if (transfercapability & AST_TRANS_CAP_DIGITAL) {
    		sig_pri_set_digital(p, 1);
    	}
    
    	if (p->pri) {
    		ast_mutex_lock(&p->pri->lock);
    
    		sig_pri_span_devstate_changed(p->pri);
    
    		ast_mutex_unlock(&p->pri->lock);
    
    /*!
     * \internal
     * \brief Open the PRI channel media path.