Skip to content
Snippets Groups Projects
sig_pri.c 295 KiB
Newer Older
  • Learn to ignore specific revisions
  • 		ast_free(ast_channel_dialed(chan)->number.str);
    		ast_channel_dialed(chan)->number.str = ast_strdup(exten);
    
    
    		if (p->pri->append_msn_to_user_tag && p->pri->nodetype != PRI_NETWORK) {
    			/*
    			 * Update the user tag for party id's from this device for this call
    			 * now that we have a complete MSN from the network.
    			 */
    			snprintf(p->user_tag, sizeof(p->user_tag), "%s_%s", p->pri->initial_user_tag,
    				exten);
    
    			ast_free(ast_channel_caller(chan)->id.tag);
    			ast_channel_caller(chan)->id.tag = ast_strdup(p->user_tag);
    
    	if (ast_exists_extension(chan, ast_channel_context(chan), exten, 1, p->cid_num)) {
    
    		ast_channel_exten_set(chan, exten);
    
    		sig_pri_dsp_reset_and_flush_digits(p);
    
    #if defined(ISSUE_16789)
    		/*
    		 * Conditionaled out this code to effectively revert the Mantis
    		 * issue 16789 change.  It breaks overlap dialing through
    		 * Asterisk.  There is not enough information available at this
    		 * point to know if dialing is complete.  The
    		 * ast_exists_extension(), ast_matchmore_extension(), and
    		 * ast_canmatch_extension() calls are not adequate to detect a
    		 * dial through extension pattern of "_9!".
    		 *
    		 * Workaround is to use the dialplan Proceeding() application
    		 * early on non-dial through extensions.
    		 */
    		if ((p->pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING)
    
    			&& !ast_matchmore_extension(chan, ast_channel_context(chan), exten, 1, p->cid_num)) {
    
    			sig_pri_lock_private(p);
    
    			if (p->pri->pri) {
    
    				pri_grab(p, p->pri);
    				if (p->call_level < SIG_PRI_CALL_LEVEL_PROCEEDING) {
    					p->call_level = SIG_PRI_CALL_LEVEL_PROCEEDING;
    
    				pri_proceeding(p->pri->pri, p->call, PVT_TO_CHANNEL(p), 0);
    				pri_rel(p->pri);
    
    			sig_pri_unlock_private(p);
    
    #endif	/* defined(ISSUE_16789) */
    
    		sig_pri_set_echocanceller(p, 1);
    		ast_setstate(chan, AST_STATE_RING);
    		res = ast_pbx_run(chan);
    		if (res) {
    			ast_log(LOG_WARNING, "PBX exited non-zero!\n");
    		}
    	} else {
    
    		ast_debug(1, "No such possible extension '%s' in context '%s'\n", exten, ast_channel_context(chan));
    
    		ast_channel_hangupcause_set(chan, AST_CAUSE_UNALLOCATED);
    
    		ast_hangup(chan);
    		p->exten[0] = '\0';
    		/* Since we send release complete here, we won't get one */
    		p->call = NULL;
    
    		ast_mutex_lock(&p->pri->lock);
    		sig_pri_span_devstate_changed(p->pri);
    		ast_mutex_unlock(&p->pri->lock);
    
    void pri_event_alarm(struct sig_pri_span *pri, int index, int before_start_pri)
    
    {
    	pri->dchanavail[index] &= ~(DCHAN_NOTINALARM | DCHAN_UP);
    
    void pri_event_noalarm(struct sig_pri_span *pri, int index, int before_start_pri)
    
    {
    	pri->dchanavail[index] |= DCHAN_NOTINALARM;
    	if (!before_start_pri)
    		pri_restart(pri->dchans[index]);
    }
    
    
    /*!
     * \internal
     * \brief Convert libpri party name into asterisk party name.
     * \since 1.8
     *
     * \param ast_name Asterisk party name structure to fill.  Must already be set initialized.
     * \param pri_name libpri party name structure containing source information.
     *
     * \note The filled in ast_name structure needs to be destroyed by
     * ast_party_name_free() when it is no longer needed.
     *
     * \return Nothing
     */
    static void sig_pri_party_name_convert(struct ast_party_name *ast_name, const struct pri_party_name *pri_name)
    {
    	ast_name->str = ast_strdup(pri_name->str);
    	ast_name->char_set = pri_to_ast_char_set(pri_name->char_set);
    	ast_name->presentation = pri_to_ast_presentation(pri_name->presentation);
    	ast_name->valid = 1;
    }
    
    /*!
     * \internal
     * \brief Convert libpri party number into asterisk party number.
     * \since 1.8
     *
     * \param ast_number Asterisk party number structure to fill.  Must already be set initialized.
     * \param pri_number libpri party number structure containing source information.
    
     * \param pri PRI span control structure.
    
     *
     * \note The filled in ast_number structure needs to be destroyed by
     * ast_party_number_free() when it is no longer needed.
     *
     * \return Nothing
     */
    
    static void sig_pri_party_number_convert(struct ast_party_number *ast_number, const struct pri_party_number *pri_number, struct sig_pri_span *pri)
    
    {
    	char number[AST_MAX_EXTENSION];
    
    
    	apply_plan_to_existing_number(number, sizeof(number), pri, pri_number->str,
    		pri_number->plan);
    
    	ast_number->str = ast_strdup(number);
    	ast_number->plan = pri_number->plan;
    	ast_number->presentation = pri_to_ast_presentation(pri_number->presentation);
    	ast_number->valid = 1;
    }
    
    
    /*!
     * \internal
     * \brief Convert libpri party id into asterisk party id.
    
     *
     * \param ast_id Asterisk party id structure to fill.  Must already be set initialized.
     * \param pri_id libpri party id structure containing source information.
    
     * \param pri PRI span control structure.
    
     *
     * \note The filled in ast_id structure needs to be destroyed by
     * ast_party_id_free() when it is no longer needed.
     *
     * \return Nothing
     */
    
    static void sig_pri_party_id_convert(struct ast_party_id *ast_id, const struct pri_party_id *pri_id, struct sig_pri_span *pri)
    
    {
    	if (pri_id->name.valid) {
    
    		sig_pri_party_name_convert(&ast_id->name, &pri_id->name);
    
    	}
    	if (pri_id->number.valid) {
    
    		sig_pri_party_number_convert(&ast_id->number, &pri_id->number, pri);
    
    #if defined(HAVE_PRI_SUBADDR)
    	if (pri_id->subaddress.valid) {
    		sig_pri_set_subaddress(&ast_id->subaddress, &pri_id->subaddress);
    	}
    #endif	/* defined(HAVE_PRI_SUBADDR) */
    
    }
    
    /*!
     * \internal
     * \brief Convert libpri redirecting information into asterisk redirecting information.
    
     *
     * \param ast_redirecting Asterisk redirecting structure to fill.
     * \param pri_redirecting libpri redirecting structure containing source information.
     * \param ast_guide Asterisk redirecting structure to use as an initialization guide.
    
     * \param pri PRI span control structure.
    
     *
     * \note The filled in ast_redirecting structure needs to be destroyed by
     * ast_party_redirecting_free() when it is no longer needed.
     *
     * \return Nothing
     */
    static void sig_pri_redirecting_convert(struct ast_party_redirecting *ast_redirecting,
    	const struct pri_party_redirecting *pri_redirecting,
    	const struct ast_party_redirecting *ast_guide,
    
    {
    	ast_party_redirecting_set_init(ast_redirecting, ast_guide);
    
    
    	sig_pri_party_id_convert(&ast_redirecting->orig, &pri_redirecting->orig_called, pri);
    
    	sig_pri_party_id_convert(&ast_redirecting->from, &pri_redirecting->from, pri);
    	sig_pri_party_id_convert(&ast_redirecting->to, &pri_redirecting->to, pri);
    	ast_redirecting->count = pri_redirecting->count;
    	ast_redirecting->reason = pri_to_ast_reason(pri_redirecting->reason);
    
    	ast_redirecting->orig_reason = pri_to_ast_reason(pri_redirecting->orig_reason);
    
    /*!
     * \internal
     * \brief Determine if the given extension matches one of the MSNs in the pattern list.
    
     *
     * \param msn_patterns Comma separated list of MSN patterns to match.
     * \param exten Extension to match in the MSN list.
     *
     * \retval 1 if matches.
     * \retval 0 if no match.
     */
    static int sig_pri_msn_match(const char *msn_patterns, const char *exten)
    {
    	char *pattern;
    	char *msn_list;
    	char *list_tail;
    
    
    	msn_list = ast_strdupa(msn_patterns);
    
    
    	list_tail = NULL;
    	pattern = strtok_r(msn_list, ",", &list_tail);
    	while (pattern) {
    		pattern = ast_strip(pattern);
    		if (!ast_strlen_zero(pattern) && ast_extension_match(pattern, exten)) {
    			/* Extension matched the pattern. */
    			return 1;
    		}
    		pattern = strtok_r(NULL, ",", &list_tail);
    	}
    	/* Did not match any pattern in the list. */
    	return 0;
    }
    
    
    #if defined(HAVE_PRI_MCID)
    /*!
     * \internal
     * \brief Append the given party id to the event string.
     * \since 1.8
     *
     * \param msg Event message string being built.
     * \param prefix Prefix to add to the party id lines.
     * \param party Party information to encode.
     *
     * \return Nothing
     */
    static void sig_pri_event_party_id(struct ast_str **msg, const char *prefix, struct ast_party_id *party)
    {
    
    	int pres;
    
    	/* Combined party presentation */
    	pres = ast_party_id_presentation(party);
    	ast_str_append(msg, 0, "%sPres: %d (%s)\r\n", prefix, pres,
    		ast_describe_caller_presentation(pres));
    
    	/* Party number */
    	ast_str_append(msg, 0, "%sNumValid: %d\r\n", prefix,
    		(unsigned) party->number.valid);
    	ast_str_append(msg, 0, "%sNum: %s\r\n", prefix,
    		S_COR(party->number.valid, party->number.str, ""));
    	ast_str_append(msg, 0, "%ston: %d\r\n", prefix, party->number.plan);
    	if (party->number.valid) {
    		ast_str_append(msg, 0, "%sNumPlan: %d\r\n", prefix, party->number.plan);
    		ast_str_append(msg, 0, "%sNumPres: %d (%s)\r\n", prefix,
    			party->number.presentation,
    			ast_describe_caller_presentation(party->number.presentation));
    	}
    
    	/* Party name */
    	ast_str_append(msg, 0, "%sNameValid: %d\r\n", prefix,
    		(unsigned) party->name.valid);
    	ast_str_append(msg, 0, "%sName: %s\r\n", prefix,
    		S_COR(party->name.valid, party->name.str, ""));
    	if (party->name.valid) {
    		ast_str_append(msg, 0, "%sNameCharSet: %s\r\n", prefix,
    			ast_party_name_charset_describe(party->name.char_set));
    		ast_str_append(msg, 0, "%sNamePres: %d (%s)\r\n", prefix,
    			party->name.presentation,
    			ast_describe_caller_presentation(party->name.presentation));
    	}
    
    
    #if defined(HAVE_PRI_SUBADDR)
    
    	/* Party subaddress */
    
    	if (party->subaddress.valid) {
    		static const char subaddress[] = "Subaddr";
    
    		ast_str_append(msg, 0, "%s%s: %s\r\n", prefix, subaddress,
    			S_OR(party->subaddress.str, ""));
    		ast_str_append(msg, 0, "%s%sType: %d\r\n", prefix, subaddress,
    			party->subaddress.type);
    		ast_str_append(msg, 0, "%s%sOdd: %d\r\n", prefix, subaddress,
    			party->subaddress.odd_even_indicator);
    	}
    #endif	/* defined(HAVE_PRI_SUBADDR) */
    }
    #endif	/* defined(HAVE_PRI_MCID) */
    
    #if defined(HAVE_PRI_MCID)
    /*!
     * \internal
     * \brief Handle the MCID event.
     * \since 1.8
     *
    
     * \param pri PRI span control structure.
    
     * \param mcid MCID event parameters.
     * \param owner Asterisk channel associated with the call.
     * NULL if Asterisk no longer has the ast_channel struct.
     *
     * \note Assumes the pri->lock is already obtained.
     * \note Assumes the owner channel lock is already obtained if still present.
     *
     * \return Nothing
     */
    
    static void sig_pri_mcid_event(struct sig_pri_span *pri, const struct pri_subcmd_mcid_req *mcid, struct ast_channel *owner)
    
    {
    	struct ast_channel *chans[1];
    	struct ast_str *msg;
    	struct ast_party_id party;
    
    	msg = ast_str_create(4096);
    	if (!msg) {
    		return;
    	}
    
    	if (owner) {
    
    		/*
    		 * The owner channel is present.
    		 * Pass the event to the peer as well.
    		 */
    		ast_queue_control(owner, AST_CONTROL_MCID);
    
    
    		ast_str_append(&msg, 0, "Channel: %s\r\n", ast_channel_name(owner));
    
    		ast_str_append(&msg, 0, "UniqueID: %s\r\n", ast_channel_uniqueid(owner));
    
    		sig_pri_event_party_id(&msg, "CallerID", &ast_channel_connected(owner)->id);
    
    	} else {
    		/*
    		 * Since we no longer have an owner channel,
    		 * we have to use the caller information supplied by libpri.
    		 */
    		ast_party_id_init(&party);
    		sig_pri_party_id_convert(&party, &mcid->originator, pri);
    		sig_pri_event_party_id(&msg, "CallerID", &party);
    		ast_party_id_free(&party);
    	}
    
    	/* Always use libpri's called party information. */
    	ast_party_id_init(&party);
    	sig_pri_party_id_convert(&party, &mcid->answerer, pri);
    	sig_pri_event_party_id(&msg, "ConnectedID", &party);
    	ast_party_id_free(&party);
    
    	chans[0] = owner;
    	ast_manager_event_multichan(EVENT_FLAG_CALL, "MCID", owner ? 1 : 0, chans, "%s",
    		ast_str_buffer(msg));
    	ast_free(msg);
    }
    #endif	/* defined(HAVE_PRI_MCID) */
    
    
    #if defined(HAVE_PRI_TRANSFER)
    
    struct xfer_rsp_data {
    	struct sig_pri_span *pri;
    	/*! Call to send transfer success/fail response over. */
    	q931_call *call;
    	/*! Invocation ID to use when sending a reply to the transfer request. */
    	int invoke_id;
    };
    
    #endif	/* defined(HAVE_PRI_TRANSFER) */
    
    #if defined(HAVE_PRI_TRANSFER)
    
    /*!
     * \internal
     * \brief Send the transfer success/fail response message.
     * \since 1.8
     *
     * \param data Callback user data pointer
     * \param is_successful TRUE if the transfer was successful.
     *
     * \return Nothing
     */
    static void sig_pri_transfer_rsp(void *data, int is_successful)
    {
    	struct xfer_rsp_data *rsp = data;
    
    	pri_transfer_rsp(rsp->pri->pri, rsp->call, rsp->invoke_id, is_successful);
    }
    
    #endif	/* defined(HAVE_PRI_TRANSFER) */
    
    #if defined(HAVE_PRI_CALL_HOLD) || defined(HAVE_PRI_TRANSFER)
    
    /*!
     * \brief Protocol callback to indicate if transfer will happen.
     * \since 1.8
     *
     * \param data Callback user data pointer
     * \param is_successful TRUE if the transfer will happen.
     *
     * \return Nothing
     */
    typedef void (*xfer_rsp_callback)(void *data, int is_successful);
    
    #endif	/* defined(HAVE_PRI_CALL_HOLD) || defined(HAVE_PRI_TRANSFER) */
    
    #if defined(HAVE_PRI_CALL_HOLD) || defined(HAVE_PRI_TRANSFER)
    
    /*!
     * \internal
     * \brief Attempt to transfer the two calls to each other.
     * \since 1.8
     *
    
     * \param pri PRI span control structure.
    
     * \param call_1_pri First call involved in the transfer. (transferee; usually on hold)
     * \param call_1_held TRUE if call_1_pri is on hold.
     * \param call_2_pri Second call involved in the transfer. (target; usually active/ringing)
     * \param call_2_held TRUE if call_2_pri is on hold.
     * \param rsp_callback Protocol callback to indicate if transfer will happen. NULL if not used.
     * \param data Callback user data pointer
    
     *
     * \note Assumes the pri->lock is already obtained.
     *
     * \retval 0 on success.
     * \retval -1 on error.
     */
    
    static int sig_pri_attempt_transfer(struct sig_pri_span *pri, q931_call *call_1_pri, int call_1_held, q931_call *call_2_pri, int call_2_held, xfer_rsp_callback rsp_callback, void *data)
    
    	struct attempt_xfer_call {
    		q931_call *pri;
    		struct ast_channel *ast;
    		int held;
    		int chanpos;
    	};
    
    	struct ast_channel *transferee;
    	struct attempt_xfer_call *call_1;
    	struct attempt_xfer_call *call_2;
    	struct attempt_xfer_call *swap_call;
    	struct attempt_xfer_call c1;
    	struct attempt_xfer_call c2;
    
    	c1.pri = call_1_pri;
    	c1.held = call_1_held;
    	call_1 = &c1;
    
    	c2.pri = call_2_pri;
    	c2.held = call_2_held;
    	call_2 = &c2;
    
    
    	call_1->chanpos = pri_find_principle_by_call(pri, call_1->pri);
    	call_2->chanpos = pri_find_principle_by_call(pri, call_2->pri);
    
    	if (call_1->chanpos < 0 || call_2->chanpos < 0) {
    		/* Calls not found in span control. */
    		if (rsp_callback) {
    			/* Transfer failed. */
    			rsp_callback(data, 0);
    		}
    
    	/* Attempt to make transferee and target consistent. */
    	if (!call_1->held && call_2->held) {
    		/*
    		 * Swap call_1 and call_2 to make call_1 the transferee(held call)
    		 * and call_2 the target(active call).
    		 */
    		swap_call = call_1;
    		call_1 = call_2;
    		call_2 = swap_call;
    	}
    
    
    	/* Deadlock avoidance is attempted. */
    
    	sig_pri_lock_private(pri->pvts[call_1->chanpos]);
    	sig_pri_lock_owner(pri, call_1->chanpos);
    	sig_pri_lock_private(pri->pvts[call_2->chanpos]);
    	sig_pri_lock_owner(pri, call_2->chanpos);
    
    	call_1->ast = pri->pvts[call_1->chanpos]->owner;
    	call_2->ast = pri->pvts[call_2->chanpos]->owner;
    	if (!call_1->ast || !call_2->ast) {
    		/* At least one owner is not present. */
    		if (call_1->ast) {
    			ast_channel_unlock(call_1->ast);
    		}
    		if (call_2->ast) {
    			ast_channel_unlock(call_2->ast);
    
    		sig_pri_unlock_private(pri->pvts[call_1->chanpos]);
    		sig_pri_unlock_private(pri->pvts[call_2->chanpos]);
    		if (rsp_callback) {
    			/* Transfer failed. */
    			rsp_callback(data, 0);
    
    	for (;;) {
    		transferee = ast_bridged_channel(call_1->ast);
    		if (transferee) {
    			break;
    
    		}
    
    		/* Try masquerading the other way. */
    
    		swap_call = call_1;
    		call_1 = call_2;
    		call_2 = swap_call;
    
    		transferee = ast_bridged_channel(call_1->ast);
    		if (transferee) {
    			break;
    		}
    
    		/* Could not transfer.  Neither call is bridged. */
    		ast_channel_unlock(call_1->ast);
    		ast_channel_unlock(call_2->ast);
    		sig_pri_unlock_private(pri->pvts[call_1->chanpos]);
    		sig_pri_unlock_private(pri->pvts[call_2->chanpos]);
    
    		if (rsp_callback) {
    			/* Transfer failed. */
    			rsp_callback(data, 0);
    
    	ast_verb(3, "TRANSFERRING %s to %s\n", ast_channel_name(call_1->ast), ast_channel_name(call_2->ast));
    
    
    	/*
    	 * Setup transfer masquerade.
    	 *
    	 * Note:  There is an extremely nasty deadlock avoidance issue
    
    	 * with ast_channel_transfer_masquerade().  Deadlock may be possible if
    
    	 * the channels involved are proxies (chan_agent channels) and
    	 * it is called with locks.  Unfortunately, there is no simple
    	 * or even merely difficult way to guarantee deadlock avoidance
    	 * and still be able to send an ECT success response without the
    	 * possibility of the bridged channel hanging up on us.
    	 */
    	ast_mutex_unlock(&pri->lock);
    
    	retval = ast_channel_transfer_masquerade(
    		call_2->ast,
    
    		ast_channel_connected(call_2->ast),
    
    		call_2->held,
    		transferee,
    
    		ast_channel_connected(call_1->ast),
    
    		call_1->held);
    
    	/* Reacquire the pri->lock to hold off completion of the transfer masquerade. */
    
    	ast_mutex_lock(&pri->lock);
    
    	ast_channel_unlock(call_1->ast);
    	ast_channel_unlock(call_2->ast);
    	sig_pri_unlock_private(pri->pvts[call_1->chanpos]);
    	sig_pri_unlock_private(pri->pvts[call_2->chanpos]);
    
    	if (rsp_callback) {
    		/*
    
    		 * Report transfer status.
    
    		 * Must do the callback before the masquerade completes to ensure
    
    		 * that the protocol message goes out before the call leg is
    		 * disconnected.
    		 */
    
    		rsp_callback(data, retval ? 0 : 1);
    
    #endif	/* defined(HAVE_PRI_CALL_HOLD) || defined(HAVE_PRI_TRANSFER) */
    
    #if defined(HAVE_PRI_CCSS)
    
     * \brief Compare the CC agent private data by libpri cc_id.
    
     * \param obj pointer to the (user-defined part) of an object.
     * \param arg callback argument from ao2_callback()
     * \param flags flags from ao2_callback()
    
     * \return values are a combination of enum _cb_results.
    
    static int sig_pri_cc_agent_cmp_cc_id(void *obj, void *arg, int flags)
    
    	struct ast_cc_agent *agent_1 = obj;
    	struct sig_pri_cc_agent_prv *agent_prv_1 = agent_1->private_data;
    	struct sig_pri_cc_agent_prv *agent_prv_2 = arg;
    
    	return (agent_prv_1 && agent_prv_1->pri == agent_prv_2->pri
    		&& agent_prv_1->cc_id == agent_prv_2->cc_id) ? CMP_MATCH | CMP_STOP : 0;
    }
    #endif	/* defined(HAVE_PRI_CCSS) */
    
    #if defined(HAVE_PRI_CCSS)
    /*!
     * \internal
     * \brief Find the CC agent by libpri cc_id.
     * \since 1.8
     *
    
     * \param pri PRI span control structure.
    
     * \param cc_id CC record ID to find.
     *
     * \note
     * Since agents are refcounted, and this function returns
     * a reference to the agent, it is imperative that you decrement
     * the refcount of the agent once you have finished using it.
     *
     * \retval agent on success.
     * \retval NULL not found.
     */
    
    static struct ast_cc_agent *sig_pri_find_cc_agent_by_cc_id(struct sig_pri_span *pri, long cc_id)
    
    {
    	struct sig_pri_cc_agent_prv finder = {
    		.pri = pri,
    		.cc_id = cc_id,
    	};
    
    	return ast_cc_agent_callback(0, sig_pri_cc_agent_cmp_cc_id, &finder,
    		sig_pri_cc_type_name);
    }
    #endif	/* defined(HAVE_PRI_CCSS) */
    
    #if defined(HAVE_PRI_CCSS)
    /*!
     * \internal
     * \brief Compare the CC monitor instance by libpri cc_id.
     * \since 1.8
     *
     * \param obj pointer to the (user-defined part) of an object.
     * \param arg callback argument from ao2_callback()
     * \param flags flags from ao2_callback()
     *
     * \return values are a combination of enum _cb_results.
     */
    static int sig_pri_cc_monitor_cmp_cc_id(void *obj, void *arg, int flags)
    {
    	struct sig_pri_cc_monitor_instance *monitor_1 = obj;
    	struct sig_pri_cc_monitor_instance *monitor_2 = arg;
    
    	return (monitor_1->pri == monitor_2->pri
    		&& monitor_1->cc_id == monitor_2->cc_id) ? CMP_MATCH | CMP_STOP : 0;
    }
    #endif	/* defined(HAVE_PRI_CCSS) */
    
    #if defined(HAVE_PRI_CCSS)
    /*!
     * \internal
     * \brief Find the CC monitor instance by libpri cc_id.
     * \since 1.8
     *
    
     * \param pri PRI span control structure.
    
     * \param cc_id CC record ID to find.
     *
     * \note
     * Since monitor_instances are refcounted, and this function returns
     * a reference to the instance, it is imperative that you decrement
     * the refcount of the instance once you have finished using it.
     *
     * \retval monitor_instance on success.
     * \retval NULL not found.
     */
    
    static struct sig_pri_cc_monitor_instance *sig_pri_find_cc_monitor_by_cc_id(struct sig_pri_span *pri, long cc_id)
    
    {
    	struct sig_pri_cc_monitor_instance finder = {
    		.pri = pri,
    		.cc_id = cc_id,
    	};
    
    	return ao2_callback(sig_pri_cc_monitors, 0, sig_pri_cc_monitor_cmp_cc_id, &finder);
    }
    #endif	/* defined(HAVE_PRI_CCSS) */
    
    #if defined(HAVE_PRI_CCSS)
    /*!
     * \internal
     * \brief Destroy the given monitor instance.
     * \since 1.8
     *
     * \param data Monitor instance to destroy.
     *
     * \return Nothing
     */
    static void sig_pri_cc_monitor_instance_destroy(void *data)
    {
    	struct sig_pri_cc_monitor_instance *monitor_instance = data;
    
    	if (monitor_instance->cc_id != -1) {
    		ast_mutex_lock(&monitor_instance->pri->lock);
    		pri_cc_cancel(monitor_instance->pri->pri, monitor_instance->cc_id);
    		ast_mutex_unlock(&monitor_instance->pri->lock);
    	}
    
    	sig_pri_callbacks.module_unref();
    
    }
    #endif	/* defined(HAVE_PRI_CCSS) */
    
    #if defined(HAVE_PRI_CCSS)
    /*!
     * \internal
     * \brief Construct a new monitor instance.
     * \since 1.8
     *
     * \param core_id CC core ID.
    
     * \param pri PRI span control structure.
    
     * \param cc_id CC record ID.
     * \param device_name Name of device (Asterisk channel name less sequence number).
     *
     * \note
     * Since monitor_instances are refcounted, and this function returns
     * a reference to the instance, it is imperative that you decrement
     * the refcount of the instance once you have finished using it.
     *
     * \retval monitor_instance on success.
     * \retval NULL on error.
     */
    
    static struct sig_pri_cc_monitor_instance *sig_pri_cc_monitor_instance_init(int core_id, struct sig_pri_span *pri, long cc_id, const char *device_name)
    
    {
    	struct sig_pri_cc_monitor_instance *monitor_instance;
    
    	if (!sig_pri_callbacks.module_ref || !sig_pri_callbacks.module_unref) {
    
    	monitor_instance = ao2_alloc(sizeof(*monitor_instance) + strlen(device_name),
    		sig_pri_cc_monitor_instance_destroy);
    	if (!monitor_instance) {
    		return NULL;
    	}
    
    	monitor_instance->cc_id = cc_id;
    	monitor_instance->pri = pri;
    	monitor_instance->core_id = core_id;
    	strcpy(monitor_instance->name, device_name);
    
    	sig_pri_callbacks.module_ref();
    
    	ao2_link(sig_pri_cc_monitors, monitor_instance);
    	return monitor_instance;
    
    #endif	/* defined(HAVE_PRI_CCSS) */
    
    #if defined(HAVE_PRI_CCSS)
    
     * \brief Announce to the CC core that protocol CC monitor is available for this call.
    
     * \param pri PRI span control structure.
    
     * \param chanpos Channel position in the span.
     * \param cc_id CC record ID.
     * \param service CCBS/CCNR indication.
    
     *
     * \note Assumes the pri->lock is already obtained.
    
     * \note Assumes the sig_pri_lock_private(pri->pvts[chanpos]) is already obtained.
     * \note Assumes the sig_pri_lock_owner(pri, chanpos) is already obtained.
    
    static int sig_pri_cc_available(struct sig_pri_span *pri, int chanpos, long cc_id, enum ast_cc_service_type service)
    
    	struct sig_pri_chan *pvt;
    	struct ast_cc_config_params *cc_params;
    	struct sig_pri_cc_monitor_instance *monitor;
    	enum ast_cc_monitor_policies monitor_policy;
    	int core_id;
    	int res;
    	char device_name[AST_CHANNEL_NAME];
    	char dialstring[AST_CHANNEL_NAME];
    
    	pvt = pri->pvts[chanpos];
    
    	core_id = ast_cc_get_current_core_id(pvt->owner);
    	if (core_id == -1) {
    		return -1;
    	}
    
    	cc_params = ast_channel_get_cc_config_params(pvt->owner);
    	if (!cc_params) {
    		return -1;
    	}
    
    	res = -1;
    	monitor_policy = ast_get_cc_monitor_policy(cc_params);
    	switch (monitor_policy) {
    	case AST_CC_MONITOR_NEVER:
    		/* CCSS is not enabled. */
    		break;
    	case AST_CC_MONITOR_NATIVE:
    	case AST_CC_MONITOR_ALWAYS:
    		/*
    		 * If it is AST_CC_MONITOR_ALWAYS and native fails we will attempt the fallback
    		 * later in the call to sig_pri_cc_generic_check().
    		 */
    		ast_channel_get_device_name(pvt->owner, device_name, sizeof(device_name));
    		sig_pri_make_cc_dialstring(pvt, dialstring, sizeof(dialstring));
    		monitor = sig_pri_cc_monitor_instance_init(core_id, pri, cc_id, device_name);
    		if (!monitor) {
    			break;
    		}
    		res = ast_queue_cc_frame(pvt->owner, sig_pri_cc_type_name, dialstring, service,
    			monitor);
    		if (res) {
    			monitor->cc_id = -1;
    			ao2_unlink(sig_pri_cc_monitors, monitor);
    			ao2_ref(monitor, -1);
    		}
    		break;
    	case AST_CC_MONITOR_GENERIC:
    		ast_queue_cc_frame(pvt->owner, AST_CC_GENERIC_MONITOR_TYPE,
    			sig_pri_get_orig_dialstring(pvt), service, NULL);
    		/* Say it failed to force caller to cancel native CC. */
    		break;
    	}
    	return res;
    }
    #endif	/* defined(HAVE_PRI_CCSS) */
    
    /*!
     * \internal
     * \brief Check if generic CC monitor is needed and request it.
     * \since 1.8
     *
    
     * \param pri PRI span control structure.
    
     * \param chanpos Channel position in the span.
     * \param service CCBS/CCNR indication.
     *
     * \note Assumes the pri->lock is already obtained.
     * \note Assumes the sig_pri_lock_private(pri->pvts[chanpos]) is already obtained.
     *
     * \return Nothing
     */
    
    static void sig_pri_cc_generic_check(struct sig_pri_span *pri, int chanpos, enum ast_cc_service_type service)
    
    {
    	struct ast_channel *owner;
    	struct ast_cc_config_params *cc_params;
    #if defined(HAVE_PRI_CCSS)
    	struct ast_cc_monitor *monitor;
    	char device_name[AST_CHANNEL_NAME];
    #endif	/* defined(HAVE_PRI_CCSS) */
    	enum ast_cc_monitor_policies monitor_policy;
    	int core_id;
    
    	if (!pri->pvts[chanpos]->outgoing) {
    		/* This is not an outgoing call so it cannot be CC monitor. */
    		return;
    	}
    
    	sig_pri_lock_owner(pri, chanpos);
    	owner = pri->pvts[chanpos]->owner;
    	if (!owner) {
    		return;
    	}
    	core_id = ast_cc_get_current_core_id(owner);
    	if (core_id == -1) {
    		/* No CC core setup */
    		goto done;
    	}
    
    	cc_params = ast_channel_get_cc_config_params(owner);
    	if (!cc_params) {
    		/* Could not get CC config parameters. */
    		goto done;
    	}
    
    #if defined(HAVE_PRI_CCSS)
    	ast_channel_get_device_name(owner, device_name, sizeof(device_name));
    	monitor = ast_cc_get_monitor_by_recall_core_id(core_id, device_name);
    	if (monitor) {
    		/* CC monitor is already present so no need for generic CC. */
    		ao2_ref(monitor, -1);
    		goto done;
    	}
    #endif	/* defined(HAVE_PRI_CCSS) */
    
    	monitor_policy = ast_get_cc_monitor_policy(cc_params);
    	switch (monitor_policy) {
    	case AST_CC_MONITOR_NEVER:
    		/* CCSS is not enabled. */
    		break;
    	case AST_CC_MONITOR_NATIVE:
    		if (pri->sig == SIG_BRI_PTMP && pri->nodetype == PRI_NETWORK) {
    			/* Request generic CC monitor. */
    			ast_queue_cc_frame(owner, AST_CC_GENERIC_MONITOR_TYPE,
    				sig_pri_get_orig_dialstring(pri->pvts[chanpos]), service, NULL);
    		}
    		break;
    	case AST_CC_MONITOR_ALWAYS:
    		if (pri->sig == SIG_BRI_PTMP && pri->nodetype != PRI_NETWORK) {
    			/*
    			 * Cannot monitor PTMP TE side since this is not defined.
    			 * We are playing the roll of a phone in this case and
    			 * a phone cannot monitor a party over the network without
    			 * protocol help.
    			 */
    			break;
    		}
    		/*
    		 * We are either falling back or this is a PTMP NT span.
    		 * Request generic CC monitor.
    		 */
    		ast_queue_cc_frame(owner, AST_CC_GENERIC_MONITOR_TYPE,
    			sig_pri_get_orig_dialstring(pri->pvts[chanpos]), service, NULL);
    		break;
    	case AST_CC_MONITOR_GENERIC:
    		if (pri->sig == SIG_BRI_PTMP && pri->nodetype == PRI_NETWORK) {
    			/* Request generic CC monitor. */
    			ast_queue_cc_frame(owner, AST_CC_GENERIC_MONITOR_TYPE,
    				sig_pri_get_orig_dialstring(pri->pvts[chanpos]), service, NULL);
    		}
    		break;
    	}
    
    done:
    	ast_channel_unlock(owner);
    }
    
    #if defined(HAVE_PRI_CCSS)
    /*!
     * \internal
     * \brief The CC link canceled the CC instance.
     * \since 1.8
     *
    
     * \param pri PRI span control structure.
    
     * \param cc_id CC record ID.
     * \param is_agent TRUE if the cc_id is for an agent.
     *
     * \return Nothing
     */
    
    static void sig_pri_cc_link_canceled(struct sig_pri_span *pri, long cc_id, int is_agent)
    
    {
    	if (is_agent) {
    		struct ast_cc_agent *agent;
    
    		agent = sig_pri_find_cc_agent_by_cc_id(pri, cc_id);
    		if (!agent) {
    			return;
    		}
    		ast_cc_failed(agent->core_id, "%s agent got canceled by link",
    			sig_pri_cc_type_name);
    		ao2_ref(agent, -1);
    	} else {
    		struct sig_pri_cc_monitor_instance *monitor;
    
    		monitor = sig_pri_find_cc_monitor_by_cc_id(pri, cc_id);
    		if (!monitor) {
    			return;
    		}
    		monitor->cc_id = -1;
    		ast_cc_monitor_failed(monitor->core_id, monitor->name,
    			"%s monitor got canceled by link", sig_pri_cc_type_name);
    		ao2_ref(monitor, -1);
    	}
    }
    #endif	/* defined(HAVE_PRI_CCSS) */
    
    
    #if defined(HAVE_PRI_AOC_EVENTS)
    /*!
     * \internal
    
     * \brief Convert ast_aoc_charged_item to PRI_AOC_CHARGED_ITEM .
    
     * \since 1.8
     *
     * \param value Value to convert to string.
     *
    
     * \return PRI_AOC_CHARGED_ITEM
    
    static enum PRI_AOC_CHARGED_ITEM sig_pri_aoc_charged_item_to_pri(enum PRI_AOC_CHARGED_ITEM value)
    
    	switch (value) {
    	case AST_AOC_CHARGED_ITEM_NA:
    		return PRI_AOC_CHARGED_ITEM_NOT_AVAILABLE;
    	case AST_AOC_CHARGED_ITEM_SPECIAL_ARRANGEMENT:
    		return PRI_AOC_CHARGED_ITEM_SPECIAL_ARRANGEMENT;
    	case AST_AOC_CHARGED_ITEM_BASIC_COMMUNICATION:
    		return PRI_AOC_CHARGED_ITEM_BASIC_COMMUNICATION;
    	case AST_AOC_CHARGED_ITEM_CALL_ATTEMPT:
    		return PRI_AOC_CHARGED_ITEM_CALL_ATTEMPT;
    	case AST_AOC_CHARGED_ITEM_CALL_SETUP:
    		return PRI_AOC_CHARGED_ITEM_CALL_SETUP;
    	case AST_AOC_CHARGED_ITEM_USER_USER_INFO:
    		return PRI_AOC_CHARGED_ITEM_USER_USER_INFO;
    	case AST_AOC_CHARGED_ITEM_SUPPLEMENTARY_SERVICE:
    		return PRI_AOC_CHARGED_ITEM_SUPPLEMENTARY_SERVICE;
    	}
    	return PRI_AOC_CHARGED_ITEM_NOT_AVAILABLE;
    }
    #endif	/* defined(HAVE_PRI_AOC_EVENTS) */
    
    #if defined(HAVE_PRI_AOC_EVENTS)
    /*!
     * \internal
     * \brief Convert PRI_AOC_CHARGED_ITEM to ast_aoc_charged_item.
     * \since 1.8
     *
     * \param value Value to convert to string.
     *
     * \return ast_aoc_charged_item
     */
    static enum ast_aoc_s_charged_item sig_pri_aoc_charged_item_to_ast(enum PRI_AOC_CHARGED_ITEM value)
    {
    
    	switch (value) {
    	case PRI_AOC_CHARGED_ITEM_NOT_AVAILABLE:
    
    		return AST_AOC_CHARGED_ITEM_NA;
    
    	case PRI_AOC_CHARGED_ITEM_SPECIAL_ARRANGEMENT:
    
    		return AST_AOC_CHARGED_ITEM_SPECIAL_ARRANGEMENT;
    
    	case PRI_AOC_CHARGED_ITEM_BASIC_COMMUNICATION:
    
    		return AST_AOC_CHARGED_ITEM_BASIC_COMMUNICATION;
    
    	case PRI_AOC_CHARGED_ITEM_CALL_ATTEMPT:
    
    		return AST_AOC_CHARGED_ITEM_CALL_ATTEMPT;
    
    	case PRI_AOC_CHARGED_ITEM_CALL_SETUP:
    
    		return AST_AOC_CHARGED_ITEM_CALL_SETUP;
    
    	case PRI_AOC_CHARGED_ITEM_USER_USER_INFO:
    
    		return AST_AOC_CHARGED_ITEM_USER_USER_INFO;
    
    	case PRI_AOC_CHARGED_ITEM_SUPPLEMENTARY_SERVICE:
    
    		return AST_AOC_CHARGED_ITEM_SUPPLEMENTARY_SERVICE;
    
    	return AST_AOC_CHARGED_ITEM_NA;
    
    }
    #endif	/* defined(HAVE_PRI_AOC_EVENTS) */