/*
 * libpri: An implementation of Primary Rate ISDN
 *
 * Copyright (C) 2009 Digium, Inc.
 *
 * Richard Mudgett <rmudgett@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 as published by the
 * Free Software Foundation. See the LICENSE file included with
 * this program for more details.
 *
 * In addition, when this program is distributed with Asterisk in
 * any form that would qualify as a 'combined work' or as a
 * 'derivative work' (but not mere aggregation), you can redistribute
 * and/or modify the combination under the terms of the license
 * provided with that copy of Asterisk, instead of the license
 * terms granted here.
 */

/*!
 * \file
 * \brief Call Completion controller
 *
 * \author Richard Mudgett <rmudgett@digium.com>
 */


#include "compat.h"
#include "libpri.h"
#include "pri_internal.h"
#include "pri_facility.h"

#include <stdlib.h>

/* Define CC_SANITY_CHECKS to add some consistency sanity checking. */
//#define CC_SANITY_CHECKS	1
#define CC_SANITY_CHECKS	1// BUGBUG

/*! Maximum times CCBSStatusRequest can have no response before canceling CC. */
#define RAW_STATUS_COUNT_MAX	3

/* ------------------------------------------------------------------- */

/*!
 * \brief Find a cc_record by the PTMP reference_id.
 *
 * \param ctrl D channel controller.
 * \param reference_id CCBS reference ID to look for in cc_record pool.
 *
 * \retval cc_record on success.
 * \retval NULL on error.
 */
struct pri_cc_record *pri_cc_find_by_reference(struct pri *ctrl, unsigned reference_id)
{
	struct pri_cc_record *cc_record;

	for (cc_record = ctrl->cc.pool; cc_record; cc_record = cc_record->next) {
		if (cc_record->ccbs_reference_id == reference_id) {
			/* Found the record */
			break;
		}
	}

	return cc_record;
}

/*!
 * \brief Find a cc_record by the PTMP linkage_id.
 *
 * \param ctrl D channel controller.
 * \param linkage_id Call linkage ID to look for in cc_record pool.
 *
 * \retval cc_record on success.
 * \retval NULL on error.
 */
struct pri_cc_record *pri_cc_find_by_linkage(struct pri *ctrl, unsigned linkage_id)
{
	struct pri_cc_record *cc_record;

	for (cc_record = ctrl->cc.pool; cc_record; cc_record = cc_record->next) {
		if (cc_record->call_linkage_id == linkage_id) {
			/* Found the record */
			break;
		}
	}

	return cc_record;
}

/*!
 * \internal
 * \brief Find a cc_record by the cc_id.
 *
 * \param ctrl D channel controller.
 * \param cc_id ID to look for in cc_record pool.
 *
 * \retval cc_record on success.
 * \retval NULL on error.
 */
static struct pri_cc_record *pri_cc_find_by_id(struct pri *ctrl, long cc_id)
{
	struct pri_cc_record *cc_record;

	for (cc_record = ctrl->cc.pool; cc_record; cc_record = cc_record->next) {
		if (cc_record->record_id == cc_id) {
			/* Found the record */
			break;
		}
	}

	return cc_record;
}

/*!
 * \internal
 * \brief Find the given ie_type in the string of q931 ies.
 *
 * \param ie_type Q.931 ie type to find in q931_ies.
 * \param length Length of the given q931_ies
 * \param q931_ies Given q931_ies
 *
 * \retval found-ie on success.
 * \retval NULL on error.
 */
static const struct q931_ie *pri_cc_find_ie(unsigned ie_type, unsigned length, const unsigned char *q931_ies)
{
	const unsigned char *pos;
	const unsigned char *end;
	const unsigned char *next;
	const struct q931_ie *cur;

	end = q931_ies + length;
	for (pos = q931_ies; pos < end; pos = next) {
		cur = (const struct q931_ie *) pos;
		if (cur->ie & 0x80) {
			/* Single octet ie. */
			next = pos + 1;
		} else {
			/* Variable length ie. */
			next = cur->data + cur->len;
		}
		if (cur->ie == ie_type && next <= end) {
			/* Found the ie and it is within the given q931_ies body. */
			return cur;
		}
	}
	return NULL;
}

/*!
 * \internal
 * \brief Compare the specified ie type in the CC record q931_ies to the given q931_ies.
 *
 * \details
 * The individual q931 ie is compared with memcmp().
 *
 * \param ie_type Q.931 ie type to compare.
 * \param record_ies CC record q931_ies
 * \param length Length of the given q931_ies
 * \param q931_ies Given q931_ies
 *
 * \retval == 0 when record_ies == q931_ies.
 * \retval != 0 when record_ies != q931_ies.
 */
static int pri_cc_cmp_ie(unsigned ie_type, const struct q931_saved_ie_contents *record_ies, unsigned length, const unsigned char *q931_ies)
{
	const struct q931_ie *left;
	const struct q931_ie *right;

	left = pri_cc_find_ie(ie_type, record_ies->length, record_ies->data);
	right = pri_cc_find_ie(ie_type, length, q931_ies);

	if (!left && !right) {
		/* Neither has the requested ie to compare so they match. */
		return 0;
	}
	if (!left || !right) {
		/* One or the other does not have the requested ie to compare. */
		return 1;
	}
	if (left->len != right->len) {
		/* They are not the same length. */
		return 1;
	}
	return memcmp(left->data, right->data, right->len);
}

/*!
 * \internal
 * \brief Compare the CC record q931_ies to the given q931_ies.
 *
 * \note
 * Only the first BC, HLC, and LLC ies in the given q931_ies are compared.
 *
 * \param record_ies CC record q931_ies
 * \param length Length of the given q931_ies
 * \param q931_ies Given q931_ies
 *
 * \retval == 0 when record_ies == q931_ies.
 * \retval != 0 when record_ies != q931_ies.
 */
static int pri_cc_cmp_q931_ies(const struct q931_saved_ie_contents *record_ies, unsigned length, const unsigned char *q931_ies)
{
	return pri_cc_cmp_ie(Q931_BEARER_CAPABILITY, record_ies, length, q931_ies)
		|| pri_cc_cmp_ie(Q931_HIGH_LAYER_COMPAT, record_ies, length, q931_ies)
		|| pri_cc_cmp_ie(Q931_LOW_LAYER_COMPAT, record_ies, length, q931_ies);
}

/*!
 * \brief Find a cc_record by an incoming call addressing data.
 *
 * \param ctrl D channel controller.
 * \param party_a Party A address.
 * \param party_b Party B address.
 * \param length Length of the given q931_ies.
 * \param q931_ies BC, HLC, LLC ies to compare with CC records.
 *
 * \retval cc_record on success.
 * \retval NULL on error.
 */
struct pri_cc_record *pri_cc_find_by_addressing(struct pri *ctrl, const struct q931_party_address *party_a, const struct q931_party_address *party_b, unsigned length, const unsigned char *q931_ies)
{
	struct pri_cc_record *cc_record;
	struct q931_party_address addr_a;
	struct q931_party_address addr_b;

	addr_a = *party_a;
	addr_b = *party_b;
	for (cc_record = ctrl->cc.pool; cc_record; cc_record = cc_record->next) {
		/* Do not compare the number presentation. */
		addr_a.number.presentation = cc_record->party_a.number.presentation;
		addr_b.number.presentation = cc_record->party_b.number.presentation;
		if (!q931_cmp_party_id_to_address(&cc_record->party_a, &addr_a)
			&& !q931_party_address_cmp(&cc_record->party_b, &addr_b)
			&& !pri_cc_cmp_q931_ies(&cc_record->saved_ie_contents, length, q931_ies)) {
			/* Found the record */
			break;
		}
	}

	return cc_record;
}

/*!
 * \internal
 * \brief Allocate a new cc_record reference id.
 *
 * \param ctrl D channel controller.
 *
 * \retval reference_id on success.
 * \retval CC_PTMP_INVALID_ID on error.
 */
static int pri_cc_new_reference_id(struct pri *ctrl)
{
	long reference_id;
	long first_id;

	ctrl->cc.last_reference_id = (ctrl->cc.last_reference_id + 1) & 0x7F;
	reference_id = ctrl->cc.last_reference_id;
	first_id = reference_id;
	while (pri_cc_find_by_reference(ctrl, reference_id)) {
		ctrl->cc.last_reference_id = (ctrl->cc.last_reference_id + 1) & 0x7F;
		reference_id = ctrl->cc.last_reference_id;
		if (reference_id == first_id) {
			/* We probably have a resource leak. */
			pri_error(ctrl, "PTMP call completion reference id exhaustion!\n");
			reference_id = CC_PTMP_INVALID_ID;
			break;
		}
	}

	return reference_id;
}

/*!
 * \internal
 * \brief Allocate a new cc_record linkage id.
 *
 * \param ctrl D channel controller.
 *
 * \retval linkage_id on success.
 * \retval CC_PTMP_INVALID_ID on error.
 */
static int pri_cc_new_linkage_id(struct pri *ctrl)
{
	long linkage_id;
	long first_id;

	ctrl->cc.last_linkage_id = (ctrl->cc.last_linkage_id + 1) & 0x7F;
	linkage_id = ctrl->cc.last_linkage_id;
	first_id = linkage_id;
	while (pri_cc_find_by_linkage(ctrl, linkage_id)) {
		ctrl->cc.last_linkage_id = (ctrl->cc.last_linkage_id + 1) & 0x7F;
		linkage_id = ctrl->cc.last_linkage_id;
		if (linkage_id == first_id) {
			/* We probably have a resource leak. */
			pri_error(ctrl, "PTMP call completion linkage id exhaustion!\n");
			linkage_id = CC_PTMP_INVALID_ID;
			break;
		}
	}

	return linkage_id;
}

/*!
 * \internal
 * \brief Allocate a new cc_record id.
 *
 * \param ctrl D channel controller.
 *
 * \retval cc_id on success.
 * \retval -1 on error.
 */
static long pri_cc_new_id(struct pri *ctrl)
{
	long record_id;
	long first_id;

	record_id = ++ctrl->cc.last_record_id;
	first_id = record_id;
	while (pri_cc_find_by_id(ctrl, record_id)) {
		record_id = ++ctrl->cc.last_record_id;
		if (record_id == first_id) {
			/*
			 * We have a resource leak.
			 * We should never need to allocate 64k records on a D channel.
			 */
			pri_error(ctrl, "Too many call completion records!\n");
			record_id = -1;
			break;
		}
	}

	return record_id;
}

/*!
 * \internal
 * \brief Disassociate the signaling link call from the cc_record.
 *
 * \param cc_record CC record to disassociate from the signaling link call.
 *
 * \return Nothing
 */
static void pri_cc_disassociate_signaling_link(struct pri_cc_record *cc_record)
{
	if (cc_record->signaling) {
		cc_record->signaling->cc.record = NULL;
		cc_record->signaling = NULL;
	}
}

/*!
 * \internal
 * \brief Delete the given call completion record
 *
 * \param ctrl D channel controller.
 * \param doomed Call completion record to destroy
 *
 * \return Nothing
 */
static void pri_cc_delete_record(struct pri *ctrl, struct pri_cc_record *doomed)
{
	struct pri_cc_record **prev;
	struct pri_cc_record *current;

	/* Unlink CC signaling link associations. */
	if (doomed->original_call) {
		doomed->original_call->cc.record = NULL;
		doomed->original_call = NULL;
	}
	pri_cc_disassociate_signaling_link(doomed);

	for (prev = &ctrl->cc.pool, current = ctrl->cc.pool; current;
		prev = &current->next, current = current->next) {
		if (current == doomed) {
			*prev = current->next;
			free(doomed);
			return;
		}
	}

	/* The doomed node is not in the call completion database */
}

/*!
 * \brief Allocate a new cc_record.
 *
 * \param ctrl D channel controller.
 * \param call Q.931 call leg.
 *
 * \retval pointer to new call completion record
 * \retval NULL if failed
 */
struct pri_cc_record *pri_cc_new_record(struct pri *ctrl, q931_call *call)
{
	struct pri_cc_record *cc_record;
	long record_id;

	record_id = pri_cc_new_id(ctrl);
	if (record_id < 0) {
		return NULL;
	}
	cc_record = calloc(1, sizeof(*cc_record));
	if (!cc_record) {
		return NULL;
	}

	/* Initialize the new record */
	cc_record->ctrl = ctrl;
	cc_record->record_id = record_id;
	cc_record->call_linkage_id = CC_PTMP_INVALID_ID;/* So it will never be found this way */
	cc_record->ccbs_reference_id = CC_PTMP_INVALID_ID;/* So it will never be found this way */
	cc_record->party_a = call->cc.party_a;
	cc_record->party_b = call->called;
	cc_record->saved_ie_contents = call->cc.saved_ie_contents;
	cc_record->bc = call->bc;
	cc_record->option.recall_mode = ctrl->cc.option.recall_mode;

	/*
	 * Append the new record to the end of the list so they are in
	 * cronological order for interrogations.
	 */
	if (ctrl->cc.pool) {
		struct pri_cc_record *cur;

		for (cur = ctrl->cc.pool; cur->next; cur = cur->next) {
		}
		cur->next = cc_record;
	} else {
		ctrl->cc.pool = cc_record;
	}

	return cc_record;
}

/*!
 * \internal
 * \brief Encode ETSI PTP call completion event operation message.
 *
 * \param ctrl D channel controller for diagnostic messages or global options.
 * \param pos Starting position to encode the facility ie contents.
 * \param end End of facility ie contents encoding data buffer.
 * \param operation PTP call completion event operation to encode.
 *
 * \retval Start of the next ASN.1 component to encode on success.
 * \retval NULL on error.
 */
static unsigned char *enc_etsi_ptp_cc_operation(struct pri *ctrl, unsigned char *pos,
	unsigned char *end, enum rose_operation operation)
{
	struct rose_msg_invoke msg;

	pos = facility_encode_header(ctrl, pos, end, NULL);
	if (!pos) {
		return NULL;
	}

	memset(&msg, 0, sizeof(msg));
	msg.invoke_id = get_invokeid(ctrl);
	msg.operation = operation;

	pos = rose_encode_invoke(ctrl, pos, end, &msg);

	return pos;
}

/*!
 * \internal
 * \brief Encode ETSI PTMP call completion available message.
 *
 * \param ctrl D channel controller for diagnostic messages or global options.
 * \param pos Starting position to encode the facility ie contents.
 * \param end End of facility ie contents encoding data buffer.
 * \param cc_record Call completion record to process event.
 *
 * \retval Start of the next ASN.1 component to encode on success.
 * \retval NULL on error.
 */
static unsigned char *enc_etsi_ptmp_cc_available(struct pri *ctrl, unsigned char *pos,
	unsigned char *end, struct pri_cc_record *cc_record)
{
	struct rose_msg_invoke msg;

	pos = facility_encode_header(ctrl, pos, end, NULL);
	if (!pos) {
		return NULL;
	}

	memset(&msg, 0, sizeof(msg));
	msg.invoke_id = get_invokeid(ctrl);
	msg.operation = ROSE_ETSI_CallInfoRetain;

	msg.args.etsi.CallInfoRetain.call_linkage_id = cc_record->call_linkage_id;

	pos = rose_encode_invoke(ctrl, pos, end, &msg);

	return pos;
}

/*!
 * \internal
 * \brief Encode and queue a cc-available message.
 *
 * \param ctrl D channel controller for diagnostic messages or global options.
 * \param call Call leg from which to encode call completion available.
 * \param cc_record Call completion record to process event.
 * \param msgtype Q.931 message type to put facility ie in.
 *
 * \retval 0 on success.
 * \retval -1 on error.
 */
static int rose_cc_available_encode(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record, int msgtype)
{
	unsigned char buffer[256];
	unsigned char *end;

	switch (ctrl->switchtype) {
	case PRI_SWITCH_EUROISDN_E1:
	case PRI_SWITCH_EUROISDN_T1:
		if (PTMP_MODE(ctrl)) {
			end =
				enc_etsi_ptmp_cc_available(ctrl, buffer, buffer + sizeof(buffer),
					cc_record);
		} else {
			end =
				enc_etsi_ptp_cc_operation(ctrl, buffer, buffer + sizeof(buffer),
					ROSE_ETSI_CCBS_T_Available);
		}
		break;
	case PRI_SWITCH_QSIG:
		/* Q.SIG does not have a cc-available type message. */
		return 0;
	default:
		return -1;
	}
	if (!end) {
		return -1;
	}

	return pri_call_apdu_queue(call, msgtype, buffer, end - buffer, NULL);
}

/*!
 * \internal
 * \brief Encode ETSI PTMP EraseCallLinkageID message.
 *
 * \param ctrl D channel controller for diagnostic messages or global options.
 * \param pos Starting position to encode the facility ie contents.
 * \param end End of facility ie contents encoding data buffer.
 * \param cc_record Call completion record to process event.
 *
 * \retval Start of the next ASN.1 component to encode on success.
 * \retval NULL on error.
 */
static unsigned char *enc_etsi_ptmp_erase_call_linkage(struct pri *ctrl,
	unsigned char *pos, unsigned char *end, struct pri_cc_record *cc_record)
{
	struct rose_msg_invoke msg;

	pos = facility_encode_header(ctrl, pos, end, NULL);
	if (!pos) {
		return NULL;
	}

	memset(&msg, 0, sizeof(msg));
	msg.invoke_id = get_invokeid(ctrl);
	msg.operation = ROSE_ETSI_EraseCallLinkageID;

	msg.args.etsi.EraseCallLinkageID.call_linkage_id = cc_record->call_linkage_id;

	pos = rose_encode_invoke(ctrl, pos, end, &msg);

	return pos;
}

/*!
 * \internal
 * \brief Encode and queue an EraseCallLinkageID message.
 *
 * \param ctrl D channel controller for diagnostic messages or global options.
 * \param call Call leg from which to encode EraseCallLinkageID.
 * \param cc_record Call completion record to process event.
 *
 * \retval 0 on success.
 * \retval -1 on error.
 */
static int rose_erase_call_linkage_encode(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record)
{
	unsigned char buffer[256];
	unsigned char *end;

	end =
		enc_etsi_ptmp_erase_call_linkage(ctrl, buffer, buffer + sizeof(buffer),
			cc_record);
	if (!end) {
		return -1;
	}

	return pri_call_apdu_queue(call, Q931_FACILITY, buffer, end - buffer, NULL);
}

/*!
 * \internal
 * \brief Encode and send an EraseCallLinkageID message.
 *
 * \param ctrl D channel controller for diagnostic messages or global options.
 * \param call Call leg from which to encode EraseCallLinkageID.
 * \param cc_record Call completion record to process event.
 *
 * \retval 0 on success.
 * \retval -1 on error.
 */
static int send_erase_call_linkage_id(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record)
{
	if (rose_erase_call_linkage_encode(ctrl, call, cc_record)
		|| q931_facility(ctrl, call)) {
		pri_message(ctrl,
			"Could not schedule facility message for EraseCallLinkageID.\n");
		return -1;
	}

	return 0;
}

/*!
 * \internal
 * \brief Encode ETSI PTMP CCBSErase message.
 *
 * \param ctrl D channel controller for diagnostic messages or global options.
 * \param pos Starting position to encode the facility ie contents.
 * \param end End of facility ie contents encoding data buffer.
 * \param cc_record Call completion record to process event.
 * \param reason CCBS Erase reason
 *  normal-unspecified(0), t-CCBS2-timeout(1), t-CCBS3-timeout(2), basic-call-failed(3)
 *
 * \retval Start of the next ASN.1 component to encode on success.
 * \retval NULL on error.
 */
static unsigned char *enc_etsi_ptmp_ccbs_erase(struct pri *ctrl,
	unsigned char *pos, unsigned char *end, struct pri_cc_record *cc_record, int reason)
{
	struct rose_msg_invoke msg;

	pos = facility_encode_header(ctrl, pos, end, NULL);
	if (!pos) {
		return NULL;
	}

	memset(&msg, 0, sizeof(msg));
	msg.invoke_id = get_invokeid(ctrl);
	msg.operation = ROSE_ETSI_CCBSErase;

	if (cc_record->saved_ie_contents.length
		<= sizeof(msg.args.etsi.CCBSErase.q931ie_contents)) {
		/* Saved BC, HLC, and LLC from initial SETUP */
		msg.args.etsi.CCBSErase.q931ie.length = cc_record->saved_ie_contents.length;
		memcpy(msg.args.etsi.CCBSErase.q931ie.contents, cc_record->saved_ie_contents.data,
			cc_record->saved_ie_contents.length);
	} else {
		pri_error(ctrl, "CCBSErase q931 ie contents did not fit.\n");
	}

	q931_copy_address_to_rose(ctrl, &msg.args.etsi.CCBSErase.address_of_b,
		&cc_record->party_b);
	msg.args.etsi.CCBSErase.recall_mode = cc_record->option.recall_mode;
	msg.args.etsi.CCBSErase.ccbs_reference = cc_record->ccbs_reference_id;
	msg.args.etsi.CCBSErase.reason = reason;

	pos = rose_encode_invoke(ctrl, pos, end, &msg);

	return pos;
}

/*!
 * \internal
 * \brief Encode and queue an CCBSErase message.
 *
 * \param ctrl D channel controller for diagnostic messages or global options.
 * \param call Call leg from which to encode CCBSErase.
 * \param cc_record Call completion record to process event.
 * \param reason CCBS Erase reason
 *  normal-unspecified(0), t-CCBS2-timeout(1), t-CCBS3-timeout(2), basic-call-failed(3)
 *
 * \retval 0 on success.
 * \retval -1 on error.
 */
static int rose_ccbs_erase_encode(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record, int reason)
{
	unsigned char buffer[256];
	unsigned char *end;

	end =
		enc_etsi_ptmp_ccbs_erase(ctrl, buffer, buffer + sizeof(buffer), cc_record,
			reason);
	if (!end) {
		return -1;
	}

	return pri_call_apdu_queue(call, Q931_FACILITY, buffer, end - buffer, NULL);
}

/*!
 * \internal
 * \brief Encode and send an CCBSErase message.
 *
 * \param ctrl D channel controller for diagnostic messages or global options.
 * \param call Call leg from which to encode EraseCallLinkageID.
 * \param cc_record Call completion record to process event.
 * \param reason CCBS Erase reason
 *  normal-unspecified(0), t-CCBS2-timeout(1), t-CCBS3-timeout(2), basic-call-failed(3)
 *
 * \retval 0 on success.
 * \retval -1 on error.
 */
static int send_ccbs_erase(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record, int reason)
{
/*
 * XXX May need to add called-party-ie with Party A number in FACILITY message. (CCBSErase)
 * ETSI EN 300-195-1 Section 5.41 MSN interaction.
 */
	if (rose_ccbs_erase_encode(ctrl, call, cc_record, reason)
		|| q931_facility(ctrl, call)) {
		pri_message(ctrl,
			"Could not schedule facility message for CCBSErase.\n");
		return -1;
	}

	return 0;
}

/*!
 * \internal
 * \brief Encode ETSI PTMP CCBSStatusRequest result message.
 *
 * \param ctrl D channel controller for diagnostic messages or global options.
 * \param pos Starting position to encode the facility ie contents.
 * \param end End of facility ie contents encoding data buffer.
 * \param cc_record Call completion record to process event.
 * \param is_free TRUE if the Party A status is available.
 *
 * \retval Start of the next ASN.1 component to encode on success.
 * \retval NULL on error.
 */
static unsigned char *enc_etsi_ptmp_ccbs_status_request_rsp(struct pri *ctrl,
	unsigned char *pos, unsigned char *end, struct pri_cc_record *cc_record, int is_free)
{
	struct rose_msg_result msg;

	pos = facility_encode_header(ctrl, pos, end, NULL);
	if (!pos) {
		return NULL;
	}

	memset(&msg, 0, sizeof(msg));
	msg.invoke_id = cc_record->response.invoke_id;
	msg.operation = ROSE_ETSI_CCBSStatusRequest;

	msg.args.etsi.CCBSStatusRequest.free = is_free;

	pos = rose_encode_result(ctrl, pos, end, &msg);

	return pos;
}

/*!
 * \internal
 * \brief Encode ETSI PTMP CCBSStatusRequest message.
 *
 * \param ctrl D channel controller for diagnostic messages or global options.
 * \param pos Starting position to encode the facility ie contents.
 * \param end End of facility ie contents encoding data buffer.
 * \param cc_record Call completion record to process event.
 *
 * \retval Start of the next ASN.1 component to encode on success.
 * \retval NULL on error.
 */
static unsigned char *enc_etsi_ptmp_ccbs_status_request(struct pri *ctrl,
	unsigned char *pos, unsigned char *end, struct pri_cc_record *cc_record)
{
	struct rose_msg_invoke msg;

	pos = facility_encode_header(ctrl, pos, end, NULL);
	if (!pos) {
		return NULL;
	}

	memset(&msg, 0, sizeof(msg));
	msg.invoke_id = get_invokeid(ctrl);
	msg.operation = ROSE_ETSI_CCBSStatusRequest;

	if (cc_record->saved_ie_contents.length
		<= sizeof(msg.args.etsi.CCBSStatusRequest.q931ie_contents)) {
		/* Saved BC, HLC, and LLC from initial SETUP */
		msg.args.etsi.CCBSStatusRequest.q931ie.length =
			cc_record->saved_ie_contents.length;
		memcpy(msg.args.etsi.CCBSStatusRequest.q931ie.contents,
			cc_record->saved_ie_contents.data, cc_record->saved_ie_contents.length);
	} else {
		pri_error(ctrl, "CCBSStatusRequest q931 ie contents did not fit.\n");
	}

	msg.args.etsi.CCBSStatusRequest.recall_mode = cc_record->option.recall_mode;
	msg.args.etsi.CCBSStatusRequest.ccbs_reference = cc_record->ccbs_reference_id;

	pos = rose_encode_invoke(ctrl, pos, end, &msg);

	return pos;
}

/*!
 * \internal
 * \brief Encode ETSI PTMP CCBSRequest/CCNRRequest message.
 *
 * \param ctrl D channel controller for diagnostic messages or global options.
 * \param pos Starting position to encode the facility ie contents.
 * \param end End of facility ie contents encoding data buffer.
 * \param cc_record Call completion record to process event.
 *
 * \retval Start of the next ASN.1 component to encode on success.
 * \retval NULL on error.
 */
static unsigned char *enc_etsi_ptmp_cc_request(struct pri *ctrl,
	unsigned char *pos, unsigned char *end, struct pri_cc_record *cc_record)
{
	struct rose_msg_invoke msg;

	pos = facility_encode_header(ctrl, pos, end, NULL);
	if (!pos) {
		return NULL;
	}

	memset(&msg, 0, sizeof(msg));
	msg.invoke_id = get_invokeid(ctrl);
	msg.operation = cc_record->is_ccnr ? ROSE_ETSI_CCNRRequest : ROSE_ETSI_CCBSRequest;

	msg.args.etsi.CCBSRequest.call_linkage_id = cc_record->call_linkage_id;

	pos = rose_encode_invoke(ctrl, pos, end, &msg);

	return pos;
}

/*!
 * \internal
 * \brief Encode ETSI PTP CCBS_T_Request/CCNR_T_Request message.
 *
 * \param ctrl D channel controller for diagnostic messages or global options.
 * \param pos Starting position to encode the facility ie contents.
 * \param end End of facility ie contents encoding data buffer.
 * \param cc_record Call completion record to process event.
 *
 * \retval Start of the next ASN.1 component to encode on success.
 * \retval NULL on error.
 */
static unsigned char *enc_etsi_ptp_cc_request(struct pri *ctrl,
	unsigned char *pos, unsigned char *end, struct pri_cc_record *cc_record)
{
	struct rose_msg_invoke msg;

	pos = facility_encode_header(ctrl, pos, end, NULL);
	if (!pos) {
		return NULL;
	}

	memset(&msg, 0, sizeof(msg));
	msg.invoke_id = get_invokeid(ctrl);
	msg.operation = cc_record->is_ccnr
		? ROSE_ETSI_CCNR_T_Request : ROSE_ETSI_CCBS_T_Request;

	if (cc_record->saved_ie_contents.length
		<= sizeof(msg.args.etsi.CCBS_T_Request.q931ie_contents)) {
		/* Saved BC, HLC, and LLC from initial SETUP */
		msg.args.etsi.CCBS_T_Request.q931ie.length = cc_record->saved_ie_contents.length;
		memcpy(msg.args.etsi.CCBS_T_Request.q931ie.contents,
			cc_record->saved_ie_contents.data, cc_record->saved_ie_contents.length);
	} else {
		pri_error(ctrl, "CCBS_T_Request q931 ie contents did not fit.\n");
	}

	q931_copy_address_to_rose(ctrl, &msg.args.etsi.CCBS_T_Request.destination,
		&cc_record->party_b);

	if (cc_record->party_a.number.valid && cc_record->party_a.number.str[0]) {
		q931_copy_id_address_to_rose(ctrl, &msg.args.etsi.CCBS_T_Request.originating,
			&cc_record->party_a);

		msg.args.etsi.CCBS_T_Request.presentation_allowed_indicator_present = 1;
		if ((cc_record->party_a.number.presentation & PRI_PRES_RESTRICTION)
			== PRI_PRES_ALLOWED) {
			msg.args.etsi.CCBS_T_Request.presentation_allowed_indicator = 1;
		}
	}

	//msg.args.etsi.CCBS_T_Request.retention_supported = 0;

	pos = rose_encode_invoke(ctrl, pos, end, &msg);

	return pos;
}

/*!
 * \internal
 * \brief Encode Q.SIG ccbsRequest/ccnrRequest message.
 *
 * \param ctrl D channel controller for diagnostic messages or global options.
 * \param pos Starting position to encode the facility ie contents.
 * \param end End of facility ie contents encoding data buffer.
 * \param cc_record Call completion record to process event.
 *
 * \retval Start of the next ASN.1 component to encode on success.
 * \retval NULL on error.
 */
static unsigned char *enc_qsig_cc_request(struct pri *ctrl,
	unsigned char *pos, unsigned char *end, struct pri_cc_record *cc_record)
{
	struct fac_extension_header header;
	struct rose_msg_invoke msg;

	memset(&header, 0, sizeof(header));
	header.nfe_present = 1;
	header.nfe.source_entity = 0;	/* endPINX */
	header.nfe.destination_entity = 0;	/* endPINX */
	header.interpretation_present = 1;
	header.interpretation = 1;	/* clearCallIfAnyInvokePduNotRecognised */
	pos = facility_encode_header(ctrl, pos, end, &header);
	if (!pos) {
		return NULL;
	}

	memset(&msg, 0, sizeof(msg));
	msg.invoke_id = get_invokeid(ctrl);
	msg.operation = cc_record->is_ccnr
		? ROSE_QSIG_CcnrRequest : ROSE_QSIG_CcbsRequest;

	/* Fill in Party B address. */
	q931_copy_number_to_rose(ctrl, &msg.args.qsig.CcbsRequest.number_b,
		&cc_record->party_b.number);
	q931_copy_subaddress_to_rose(ctrl, &msg.args.qsig.CcbsRequest.subaddr_b,
		&cc_record->party_b.subaddress);

	/* Fill in Party A address. */
	q931_copy_presented_number_unscreened_to_rose(ctrl,
		&msg.args.qsig.CcbsRequest.number_a, &cc_record->party_a.number);
	q931_copy_subaddress_to_rose(ctrl, &msg.args.qsig.CcbsRequest.subaddr_a,
		&cc_record->party_a.subaddress);

	/* Fill in service Q.931 ie information. */
	if (cc_record->saved_ie_contents.length
		<= sizeof(msg.args.qsig.CcbsRequest.q931ie_contents)) {
		/* Saved BC, HLC, and LLC from initial SETUP */
		msg.args.qsig.CcbsRequest.q931ie.length = cc_record->saved_ie_contents.length;
		memcpy(msg.args.qsig.CcbsRequest.q931ie.contents,
			cc_record->saved_ie_contents.data, cc_record->saved_ie_contents.length);
	} else {
		pri_error(ctrl, "CcbsRequest q931 ie contents did not fit.\n");
	}

	//msg.args.qsig.CcbsRequest.can_retain_service = 0;

	switch (ctrl->cc.option.signaling_retention_req) {
	case 0:/* Want release signaling link. */
		cc_record->option.retain_signaling_link = 0;

		msg.args.qsig.CcbsRequest.retain_sig_connection_present = 1;
		msg.args.qsig.CcbsRequest.retain_sig_connection = 0;
		break;
	case 1:/* Demand retain signaling link. */
		cc_record->option.retain_signaling_link = 1;

		msg.args.qsig.CcbsRequest.retain_sig_connection_present = 1;
		msg.args.qsig.CcbsRequest.retain_sig_connection = 1;
		break;
	case 2:/* Don't care about signaling link retention. */
	default:
		cc_record->option.retain_signaling_link = 0;
		break;
	}
	if (!cc_record->party_a.number.valid || cc_record->party_a.number.str[0] == '\0') {
		/*
		 * Party A number is not available for the other end to initiate
		 * a signaling link to us.  We must require that the signaling link
		 * be retained.
		 */
		cc_record->option.retain_signaling_link = 1;

		msg.args.qsig.CcbsRequest.retain_sig_connection_present = 1;
		msg.args.qsig.CcbsRequest.retain_sig_connection = 1;
	}

	pos = rose_encode_invoke(ctrl, pos, end, &msg);

	return pos;
}

/*!
 * \internal
 * \brief Encode Q.SIG ccSuspend/ccResume/ccPathReserve/ccRingout message.
 *
 * \param ctrl D channel controller for diagnostic messages or global options.
 * \param pos Starting position to encode the facility ie contents.
 * \param end End of facility ie contents encoding data buffer.
 * \param operation Q.SIG call completion event operation to encode.
 * \param interpretation Component interpretation:
 * discardAnyUnrecognisedInvokePdu(0),
 * clearCallIfAnyInvokePduNotRecognised(1),
 * rejectAnyUnrecognisedInvokePdu(2)
 *
 * \retval Start of the next ASN.1 component to encode on success.
 * \retval NULL on error.
 */
static unsigned char *enc_qsig_cc_extension_event(struct pri *ctrl,
	unsigned char *pos, unsigned char *end, enum rose_operation operation,
	int interpretation)
{
	struct fac_extension_header header;
	struct rose_msg_invoke msg;

	memset(&header, 0, sizeof(header));
	header.nfe_present = 1;
	header.nfe.source_entity = 0;	/* endPINX */
	header.nfe.destination_entity = 0;	/* endPINX */
	header.interpretation_present = 1;
	header.interpretation = interpretation;
	pos = facility_encode_header(ctrl, pos, end, &header);
	if (!pos) {
		return NULL;
	}

	memset(&msg, 0, sizeof(msg));
	msg.invoke_id = get_invokeid(ctrl);
	msg.operation = operation;

	pos = rose_encode_invoke(ctrl, pos, end, &msg);

	return pos;
}

/*!
 * \internal
 * \brief Encode ETSI PTMP CCBSDeactivate message.
 *
 * \param ctrl D channel controller for diagnostic messages or global options.
 * \param pos Starting position to encode the facility ie contents.
 * \param end End of facility ie contents encoding data buffer.
 * \param cc_record Call completion record to process event.
 *
 * \retval Start of the next ASN.1 component to encode on success.
 * \retval NULL on error.
 */
static unsigned char *enc_etsi_ptmp_cc_deactivate(struct pri *ctrl,
	unsigned char *pos, unsigned char *end, struct pri_cc_record *cc_record)
{
	struct rose_msg_invoke msg;

	pos = facility_encode_header(ctrl, pos, end, NULL);
	if (!pos) {
		return NULL;
	}

	memset(&msg, 0, sizeof(msg));
	msg.invoke_id = get_invokeid(ctrl);
	msg.operation = ROSE_ETSI_CCBSDeactivate;

	msg.args.etsi.CCBSDeactivate.ccbs_reference = cc_record->ccbs_reference_id;

	pos = rose_encode_invoke(ctrl, pos, end, &msg);

	return pos;
}

/*!
 * \internal
 * \brief Encode and queue an CCBSDeactivate message.
 *
 * \param ctrl D channel controller for diagnostic messages or global options.
 * \param call Call leg from which to encode CCBSDeactivate.
 * \param cc_record Call completion record to process event.
 *
 * \retval 0 on success.
 * \retval -1 on error.
 */
static int rose_cc_deactivate_encode(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record)
{
	unsigned char buffer[256];
	unsigned char *end;

	end =
		enc_etsi_ptmp_cc_deactivate(ctrl, buffer, buffer + sizeof(buffer), cc_record);
	if (!end) {
		return -1;
	}

	return pri_call_apdu_queue(call, Q931_FACILITY, buffer, end - buffer, NULL);
}

/*!
 * \internal
 * \brief Encode and send an CCBSDeactivate message.
 *
 * \param ctrl D channel controller for diagnostic messages or global options.
 * \param call Call leg from which to encode CCBSDeactivate.
 * \param cc_record Call completion record to process event.
 *
 * \retval 0 on success.
 * \retval -1 on error.
 */
static int send_cc_deactivate_req(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record)
{
	if (rose_cc_deactivate_encode(ctrl, call, cc_record)
		|| q931_facility(ctrl, call)) {
		pri_message(ctrl,
			"Could not schedule facility message for CCBSDeactivate.\n");
		return -1;
	}

	return 0;
}

/*!
 * \internal
 * \brief Encode ETSI PTMP CCBSBFree message.
 *
 * \param ctrl D channel controller for diagnostic messages or global options.
 * \param pos Starting position to encode the facility ie contents.
 * \param end End of facility ie contents encoding data buffer.
 * \param cc_record Call completion record to process event.
 *
 * \retval Start of the next ASN.1 component to encode on success.
 * \retval NULL on error.
 */
static unsigned char *enc_etsi_ptmp_ccbs_b_free(struct pri *ctrl,
	unsigned char *pos, unsigned char *end, struct pri_cc_record *cc_record)
{
	struct rose_msg_invoke msg;

	pos = facility_encode_header(ctrl, pos, end, NULL);
	if (!pos) {
		return NULL;
	}

	memset(&msg, 0, sizeof(msg));
	msg.invoke_id = get_invokeid(ctrl);
	msg.operation = ROSE_ETSI_CCBSBFree;

	if (cc_record->saved_ie_contents.length
		<= sizeof(msg.args.etsi.CCBSBFree.q931ie_contents)) {
		/* Saved BC, HLC, and LLC from initial SETUP */
		msg.args.etsi.CCBSBFree.q931ie.length = cc_record->saved_ie_contents.length;
		memcpy(msg.args.etsi.CCBSBFree.q931ie.contents, cc_record->saved_ie_contents.data,
			cc_record->saved_ie_contents.length);
	} else {
		pri_error(ctrl, "CCBSBFree q931 ie contents did not fit.\n");
	}

	q931_copy_address_to_rose(ctrl, &msg.args.etsi.CCBSBFree.address_of_b,
		&cc_record->party_b);
	msg.args.etsi.CCBSBFree.recall_mode = cc_record->option.recall_mode;
	msg.args.etsi.CCBSBFree.ccbs_reference = cc_record->ccbs_reference_id;

	pos = rose_encode_invoke(ctrl, pos, end, &msg);

	return pos;
}

/*!
 * \internal
 * \brief Encode and queue an CCBSBFree message.
 *
 * \param ctrl D channel controller for diagnostic messages or global options.
 * \param call Call leg from which to encode CCBSBFree.
 * \param cc_record Call completion record to process event.
 *
 * \retval 0 on success.
 * \retval -1 on error.
 */
static int rose_ccbs_b_free_encode(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record)
{
	unsigned char buffer[256];
	unsigned char *end;

	end =
		enc_etsi_ptmp_ccbs_b_free(ctrl, buffer, buffer + sizeof(buffer), cc_record);
	if (!end) {
		return -1;
	}

	return pri_call_apdu_queue(call, Q931_FACILITY, buffer, end - buffer, NULL);
}

/*!
 * \internal
 * \brief Encode and send an CCBSBFree message.
 *
 * \param ctrl D channel controller for diagnostic messages or global options.
 * \param call Call leg from which to encode CCBSBFree.
 * \param cc_record Call completion record to process event.
 *
 * \retval 0 on success.
 * \retval -1 on error.
 */
static int send_ccbs_b_free(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record)
{
/*
 * XXX May need to add called-party-ie with Party A number in FACILITY message. (CCBSBFree)
 * ETSI EN 300-195-1 Section 5.41 MSN interaction.
 */
	if (rose_ccbs_b_free_encode(ctrl, call, cc_record)
		|| q931_facility(ctrl, call)) {
		pri_message(ctrl,
			"Could not schedule facility message for CCBSBFree.\n");
		return -1;
	}

	return 0;
}

/*!
 * \internal
 * \brief Encode ETSI PTMP CCBSRemoteUserFree message.
 *
 * \param ctrl D channel controller for diagnostic messages or global options.
 * \param pos Starting position to encode the facility ie contents.
 * \param end End of facility ie contents encoding data buffer.
 * \param cc_record Call completion record to process event.
 *
 * \retval Start of the next ASN.1 component to encode on success.
 * \retval NULL on error.
 */
static unsigned char *enc_etsi_ptmp_remote_user_free(struct pri *ctrl,
	unsigned char *pos, unsigned char *end, struct pri_cc_record *cc_record)
{
	struct rose_msg_invoke msg;

	pos = facility_encode_header(ctrl, pos, end, NULL);
	if (!pos) {
		return NULL;
	}

	memset(&msg, 0, sizeof(msg));
	msg.invoke_id = get_invokeid(ctrl);
	msg.operation = ROSE_ETSI_CCBSRemoteUserFree;

	if (cc_record->saved_ie_contents.length
		<= sizeof(msg.args.etsi.CCBSRemoteUserFree.q931ie_contents)) {
		/* Saved BC, HLC, and LLC from initial SETUP */
		msg.args.etsi.CCBSRemoteUserFree.q931ie.length =
			cc_record->saved_ie_contents.length;
		memcpy(msg.args.etsi.CCBSRemoteUserFree.q931ie.contents,
			cc_record->saved_ie_contents.data, cc_record->saved_ie_contents.length);
	} else {
		pri_error(ctrl, "CCBSRemoteUserFree q931 ie contents did not fit.\n");
	}

	q931_copy_address_to_rose(ctrl, &msg.args.etsi.CCBSRemoteUserFree.address_of_b,
		&cc_record->party_b);
	msg.args.etsi.CCBSRemoteUserFree.recall_mode = cc_record->option.recall_mode;
	msg.args.etsi.CCBSRemoteUserFree.ccbs_reference = cc_record->ccbs_reference_id;

	pos = rose_encode_invoke(ctrl, pos, end, &msg);

	return pos;
}

/*!
 * \internal
 * \brief Encode Q.SIG CcOptionalArg for ccCancel/ccExecPossible message.
 *
 * \param ctrl D channel controller for diagnostic messages or global options.
 * \param pos Starting position to encode the facility ie contents.
 * \param end End of facility ie contents encoding data buffer.
 * \param cc_record Call completion record to process event.
 * \param msgtype Q.931 message type to put facility ie in.
 * \param operation library encoded operation-value
 *
 * \retval Start of the next ASN.1 component to encode on success.
 * \retval NULL on error.
 */
static unsigned char *enc_qsig_cc_optional_arg(struct pri *ctrl,
	unsigned char *pos, unsigned char *end, struct pri_cc_record *cc_record, int msgtype,
	enum rose_operation operation)
{
	struct fac_extension_header header;
	struct rose_msg_invoke msg;

	memset(&header, 0, sizeof(header));
	header.nfe_present = 1;
	header.nfe.source_entity = 0;	/* endPINX */
	header.nfe.destination_entity = 0;	/* endPINX */
	header.interpretation_present = 1;
	header.interpretation = 1;	/* clearCallIfAnyInvokePduNotRecognised */
	pos = facility_encode_header(ctrl, pos, end, &header);
	if (!pos) {
		return NULL;
	}

	memset(&msg, 0, sizeof(msg));
	msg.invoke_id = get_invokeid(ctrl);
	msg.operation = operation;

	if (cc_record && msgtype == Q931_SETUP) {
		msg.args.qsig.CcCancel.full_arg_present = 1;

		/* Fill in Party A address. */
		q931_copy_number_to_rose(ctrl, &msg.args.qsig.CcCancel.number_a,
			&cc_record->party_a.number);
		q931_copy_subaddress_to_rose(ctrl, &msg.args.qsig.CcCancel.subaddr_a,
			&cc_record->party_a.subaddress);

		/* Fill in Party B address. */
		q931_copy_number_to_rose(ctrl, &msg.args.qsig.CcCancel.number_b,
			&cc_record->party_b.number);
		q931_copy_subaddress_to_rose(ctrl, &msg.args.qsig.CcCancel.subaddr_b,
			&cc_record->party_b.subaddress);

		/* Fill in service Q.931 ie information. */
		if (cc_record->saved_ie_contents.length
			<= sizeof(msg.args.qsig.CcCancel.q931ie_contents)) {
			/* Saved BC, HLC, and LLC from initial SETUP */
			msg.args.qsig.CcCancel.q931ie.length = cc_record->saved_ie_contents.length;
			memcpy(msg.args.qsig.CcCancel.q931ie.contents,
				cc_record->saved_ie_contents.data, cc_record->saved_ie_contents.length);
		} else {
			pri_error(ctrl, "CcOptionalArg q931 ie contents did not fit.\n");
		}
	}

	pos = rose_encode_invoke(ctrl, pos, end, &msg);

	return pos;
}

/*!
 * \internal
 * \brief Encode and queue a remote user free message.
 *
 * \param ctrl D channel controller for diagnostic messages or global options.
 * \param call Call leg from which to encode remote user free message.
 * \param cc_record Call completion record to process event.
 * \param msgtype Q.931 message type to put facility ie in.
 *
 * \retval 0 on success.
 * \retval -1 on error.
 */
static int rose_remote_user_free_encode(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record, int msgtype)
{
	unsigned char buffer[256];
	unsigned char *end;

	switch (ctrl->switchtype) {
	case PRI_SWITCH_EUROISDN_E1:
	case PRI_SWITCH_EUROISDN_T1:
		if (PTMP_MODE(ctrl)) {
			end =
				enc_etsi_ptmp_remote_user_free(ctrl, buffer, buffer + sizeof(buffer),
					cc_record);
		} else {
			end =
				enc_etsi_ptp_cc_operation(ctrl, buffer, buffer + sizeof(buffer),
					ROSE_ETSI_CCBS_T_RemoteUserFree);
		}
		break;
	case PRI_SWITCH_QSIG:
		end = enc_qsig_cc_optional_arg(ctrl, buffer, buffer + sizeof(buffer), cc_record,
			msgtype, ROSE_QSIG_CcExecPossible);
		break;
	default:
		return -1;
	}
	if (!end) {
		return -1;
	}

	return pri_call_apdu_queue(call, msgtype, buffer, end - buffer, NULL);
}

/*!
 * \internal
 * \brief Encode and send a CC facility event in a SETUP message.
 *
 * \param ctrl D channel controller for diagnostic messages or global options.
 * \param cc_record Call completion record to process event.
 * \param encode Function to encode facility to send out in SETUP message.
 *
 * \retval 0 on success.
 * \retval -1 on error.
 */
static int pri_cc_send_setup_encode(struct pri *ctrl, struct pri_cc_record *cc_record,
	int (*encode)(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record,
		int msgtype))
{
	struct pri_sr req;
	q931_call *call;

	call = q931_new_call(ctrl);
	if (!call) {
		return -1;
	}

	/* Link the new call as the signaling link. */
	cc_record->signaling = call;
	call->cc.record = cc_record;

	if (encode(ctrl, call, cc_record, Q931_SETUP)) {
		/* Should not happen. */
		q931_destroycall(ctrl, call);
		return -1;
	}

	pri_sr_init(&req);
	if (cc_record->is_agent) {
		q931_party_address_to_id(&req.caller, &cc_record->party_b);
		q931_party_id_to_address(&req.called, &cc_record->party_a);
	} else {
		req.caller = cc_record->party_a;
		req.called = cc_record->party_b;
	}
	//req.cis_auto_disconnect = 0;
	req.cis_call = 1;
	if (q931_setup(ctrl, call, &req)) {
		/* Should not happen. */
		q931_destroycall(ctrl, call);
		return -1;
	}
	return 0;
}

/*!
 * \internal
 * \brief Encode and send an remote user free message.
 *
 * \param ctrl D channel controller for diagnostic messages or global options.
 * \param cc_record Call completion record to process event.
 *
 * \retval 0 on success.
 * \retval -1 on error.
 */
static int send_remote_user_free(struct pri *ctrl, struct pri_cc_record *cc_record)
{
	int retval;
	q931_call *call;

/*
 * XXX May need to add called-party-ie with Party A number in FACILITY message. (CCBSRemoteUserFree)
 * ETSI EN 300-195-1 Section 5.41 MSN interaction.
 */
	retval = -1;
	switch (ctrl->switchtype) {
	case PRI_SWITCH_EUROISDN_E1:
	case PRI_SWITCH_EUROISDN_T1:
		call = cc_record->signaling;
		retval = rose_remote_user_free_encode(ctrl, call, cc_record, Q931_FACILITY);
		if (!retval) {
			retval = q931_facility(ctrl, call);
		}
		break;
	case PRI_SWITCH_QSIG:
		/* ccExecPossible could be sent in FACILITY or SETUP. */
		call = cc_record->signaling;
		if (call) {
			retval = rose_remote_user_free_encode(ctrl, call, cc_record, Q931_FACILITY);
			if (!retval) {
				retval = q931_facility(ctrl, call);
			}
		} else {
			retval = pri_cc_send_setup_encode(ctrl, cc_record,
				rose_remote_user_free_encode);
		}
		break;
	default:
		break;
	}
	if (retval) {
		pri_message(ctrl, "Could not schedule message for remote user free.\n");
		return -1;
	}
	return 0;
}

/*!
 * \internal
 * \brief Encode and queue a Q.SIG ccCancel message.
 *
 * \param ctrl D channel controller for diagnostic messages or global options.
 * \param call Call leg from which to encode remote user free message.
 * \param cc_record Call completion record to process event.
 * \param msgtype Q.931 message type to put facility ie in.
 *
 * \retval 0 on success.
 * \retval -1 on error.
 */
static int rose_cc_cancel(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record, int msgtype)
{
	unsigned char buffer[256];
	unsigned char *end;

	end = enc_qsig_cc_optional_arg(ctrl, buffer, buffer + sizeof(buffer), cc_record,
		msgtype, ROSE_QSIG_CcCancel);
	if (!end) {
		return -1;
	}

	return pri_call_apdu_queue(call, msgtype, buffer, end - buffer, NULL);
}

/*!
 * \internal
 * \brief Encode and send a Q.SIG ccCancel message.
 *
 * \param ctrl D channel controller for diagnostic messages or global options.
 * \param cc_record Call completion record to process event.
 *
 * \retval 0 on success.
 * \retval -1 on error.
 */
static int send_cc_cancel(struct pri *ctrl, struct pri_cc_record *cc_record)
{
	int retval;
	q931_call *call;

	/*
	 * ccCancel could be sent in SETUP or RELEASE.
	 * If ccPathReserve is supported it could also be sent in DISCONNECT.
	 */
	retval = -1;
	call = cc_record->signaling;
	if (call) {
		retval = rose_cc_cancel(ctrl, call, cc_record, Q931_ANY_MESSAGE);
		if (!retval) {
			retval = pri_hangup(ctrl, call, -1);
		}
	} else {
		retval = pri_cc_send_setup_encode(ctrl, cc_record, rose_cc_cancel);
	}
	if (retval) {
		pri_message(ctrl, "Could not schedule message for ccCancel.\n");
		return -1;
	}
	return 0;
}

/*!
 * \internal
 * \brief Encode and queue a CC suspend message.
 *
 * \param ctrl D channel controller for diagnostic messages or global options.
 * \param call Call leg from which to encode CC suspend message.
 * \param msgtype Q.931 message type to put facility ie in.
 *
 * \retval 0 on success.
 * \retval -1 on error.
 */
static int rose_cc_suspend_encode(struct pri *ctrl, q931_call *call, int msgtype)
{
	unsigned char buffer[256];
	unsigned char *end;

	switch (ctrl->switchtype) {
	case PRI_SWITCH_EUROISDN_E1:
	case PRI_SWITCH_EUROISDN_T1:
		end =
			enc_etsi_ptp_cc_operation(ctrl, buffer, buffer + sizeof(buffer),
				ROSE_ETSI_CCBS_T_Suspend);
		break;
	case PRI_SWITCH_QSIG:
		end =
			enc_qsig_cc_extension_event(ctrl, buffer, buffer + sizeof(buffer),
				ROSE_QSIG_CcSuspend, 0/* discardAnyUnrecognisedInvokePdu */);
		break;
	default:
		return -1;
	}
	if (!end) {
		return -1;
	}

	return pri_call_apdu_queue(call, msgtype, buffer, end - buffer, NULL);
}

/*!
 * \internal
 * \brief Encode and send a CC suspend message.
 *
 * \param ctrl D channel controller for diagnostic messages or global options.
 * \param cc_record Call completion record to process event.
 *
 * \retval 0 on success.
 * \retval -1 on error.
 */
static int send_cc_suspend(struct pri *ctrl, struct pri_cc_record *cc_record)
{
	int retval;
	q931_call *call;

	retval = -1;
	switch (ctrl->switchtype) {
	case PRI_SWITCH_EUROISDN_E1:
	case PRI_SWITCH_EUROISDN_T1:
		call = cc_record->signaling;
		retval = rose_cc_suspend_encode(ctrl, call, Q931_FACILITY);
		if (!retval) {
			retval = q931_facility(ctrl, call);
		}
		break;
	case PRI_SWITCH_QSIG:
		/*
		 * Suspend is sent in a CONNECT or FACILITY message.
		 * If ccPathReserve is supported, it could also be sent in
		 * RELEASE or DISCONNECT.
		 */
		call = cc_record->signaling;
		if (!call) {
			break;
		}
		retval = rose_cc_suspend_encode(ctrl, call, Q931_ANY_MESSAGE);
		if (!retval) {
			if (call->ourcallstate == Q931_CALL_STATE_ACTIVE) {
				retval = q931_facility(ctrl, call);
			} else {
				retval = q931_connect(ctrl, call, 0, 0);
			}
		}
		break;
	default:
		break;
	}
	if (retval) {
		pri_message(ctrl, "Could not schedule message for CC suspend.\n");
		return -1;
	}
	return 0;
}

/*!
 * \internal
 * \brief Encode and queue a CC resume message.
 *
 * \param ctrl D channel controller for diagnostic messages or global options.
 * \param call Call leg from which to encode CC resume message.
 * \param msgtype Q.931 message type to put facility ie in.
 *
 * \retval 0 on success.
 * \retval -1 on error.
 */
static int rose_cc_resume_encode(struct pri *ctrl, q931_call *call, int msgtype)
{
	unsigned char buffer[256];
	unsigned char *end;

	switch (ctrl->switchtype) {
	case PRI_SWITCH_EUROISDN_E1:
	case PRI_SWITCH_EUROISDN_T1:
		end =
			enc_etsi_ptp_cc_operation(ctrl, buffer, buffer + sizeof(buffer),
				ROSE_ETSI_CCBS_T_Resume);
		break;
	case PRI_SWITCH_QSIG:
		end =
			enc_qsig_cc_extension_event(ctrl, buffer, buffer + sizeof(buffer),
				ROSE_QSIG_CcResume, 0/* discardAnyUnrecognisedInvokePdu */);
		break;
	default:
		return -1;
	}
	if (!end) {
		return -1;
	}

	return pri_call_apdu_queue(call, msgtype, buffer, end - buffer, NULL);
}

/*!
 * \internal
 * \brief Encode and send a CC resume message.
 *
 * \param ctrl D channel controller for diagnostic messages or global options.
 * \param cc_record Call completion record to process event.
 *
 * \retval 0 on success.
 * \retval -1 on error.
 */
static int send_cc_resume(struct pri *ctrl, struct pri_cc_record *cc_record)
{
	q931_call *call;

	call = cc_record->signaling;
	if (!call
		|| rose_cc_resume_encode(ctrl, call, Q931_FACILITY)
		|| q931_facility(ctrl, call)) {
		pri_message(ctrl, "Could not schedule message for CC resume.\n");
		return -1;
	}
	return 0;
}

/*!
 * \internal
 * \brief Encode ETSI PTMP CCBSStopAlerting message.
 *
 * \param ctrl D channel controller for diagnostic messages or global options.
 * \param pos Starting position to encode the facility ie contents.
 * \param end End of facility ie contents encoding data buffer.
 * \param cc_record Call completion record to process event.
 *
 * \retval Start of the next ASN.1 component to encode on success.
 * \retval NULL on error.
 */
static unsigned char *enc_etsi_ptmp_ccbs_stop_alerting(struct pri *ctrl,
	unsigned char *pos, unsigned char *end, struct pri_cc_record *cc_record)
{
	struct rose_msg_invoke msg;

	pos = facility_encode_header(ctrl, pos, end, NULL);
	if (!pos) {
		return NULL;
	}

	memset(&msg, 0, sizeof(msg));
	msg.invoke_id = get_invokeid(ctrl);
	msg.operation = ROSE_ETSI_CCBSStopAlerting;

	msg.args.etsi.CCBSStopAlerting.ccbs_reference = cc_record->ccbs_reference_id;

	pos = rose_encode_invoke(ctrl, pos, end, &msg);

	return pos;
}

/*!
 * \internal
 * \brief Encode and queue an CCBSStopAlerting message.
 *
 * \param ctrl D channel controller for diagnostic messages or global options.
 * \param call Call leg from which to encode CCBSStopAlerting.
 * \param cc_record Call completion record to process event.
 *
 * \retval 0 on success.
 * \retval -1 on error.
 */
static int rose_ccbs_stop_alerting_encode(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record)
{
	unsigned char buffer[256];
	unsigned char *end;

	end =
		enc_etsi_ptmp_ccbs_stop_alerting(ctrl, buffer, buffer + sizeof(buffer), cc_record);
	if (!end) {
		return -1;
	}

	return pri_call_apdu_queue(call, Q931_FACILITY, buffer, end - buffer, NULL);
}

/*!
 * \internal
 * \brief Encode and send CCBSStopAlerting message.
 *
 * \param ctrl D channel controller for diagnostic messages or global options.
 * \param call Call leg from which to encode remote user free.
 * \param cc_record Call completion record to process event.
 *
 * \retval 0 on success.
 * \retval -1 on error.
 */
static int send_ccbs_stop_alerting(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record)
{
	if (rose_ccbs_stop_alerting_encode(ctrl, call, cc_record)
		|| q931_facility(ctrl, call)) {
		pri_message(ctrl,
			"Could not schedule facility message for CCBSStopAlerting.\n");
		return -1;
	}

	return 0;
}

/*!
 * \internal
 * \brief Encode ETSI PTMP CCBSCall message.
 *
 * \param ctrl D channel controller for diagnostic messages or global options.
 * \param pos Starting position to encode the facility ie contents.
 * \param end End of facility ie contents encoding data buffer.
 * \param cc_record Call completion record to process event.
 *
 * \retval Start of the next ASN.1 component to encode on success.
 * \retval NULL on error.
 */
static unsigned char *enc_etsi_ptmp_cc_recall(struct pri *ctrl, unsigned char *pos,
	unsigned char *end, struct pri_cc_record *cc_record)
{
	struct rose_msg_invoke msg;

	pos = facility_encode_header(ctrl, pos, end, NULL);
	if (!pos) {
		return NULL;
	}

	memset(&msg, 0, sizeof(msg));
	msg.invoke_id = get_invokeid(ctrl);
	msg.operation = ROSE_ETSI_CCBSCall;

	msg.args.etsi.CCBSCall.ccbs_reference = cc_record->ccbs_reference_id;

	pos = rose_encode_invoke(ctrl, pos, end, &msg);

	return pos;
}

/*!
 * \internal
 * \brief Encode and queue a cc-recall message.
 *
 * \param ctrl D channel controller for diagnostic messages or global options.
 * \param call Call leg from which to encode cc-recall.
 * \param cc_record Call completion record to process event.
 *
 * \retval 0 on success.
 * \retval -1 on error.
 */
static int rose_cc_recall_encode(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record)
{
	unsigned char buffer[256];
	unsigned char *end;

	switch (ctrl->switchtype) {
	case PRI_SWITCH_EUROISDN_E1:
	case PRI_SWITCH_EUROISDN_T1:
		if (PTMP_MODE(ctrl)) {
			end =
				enc_etsi_ptmp_cc_recall(ctrl, buffer, buffer + sizeof(buffer), cc_record);
		} else {
			end =
				enc_etsi_ptp_cc_operation(ctrl, buffer, buffer + sizeof(buffer),
					ROSE_ETSI_CCBS_T_Call);
		}
		break;
	case PRI_SWITCH_QSIG:
		end =
			enc_qsig_cc_extension_event(ctrl, buffer, buffer + sizeof(buffer),
				ROSE_QSIG_CcRingout, 0/* discardAnyUnrecognisedInvokePdu */);
		break;
	default:
		return -1;
	}
	if (!end) {
		return -1;
	}

	return pri_call_apdu_queue(call, Q931_SETUP, buffer, end - buffer, NULL);
}

/*!
 * \internal
 * \brief Copy the cc information into the ETSI ROSE call-information record.
 *
 * \param ctrl D channel controller for diagnostic messages or global options.
 * \param call_information ROSE call-information record to fill in.
 * \param cc_record Call completion record to process event.
 *
 * \return Nothing
 */
static void q931_copy_call_information_to_etsi_rose(struct pri *ctrl, struct roseEtsiCallInformation *call_information, const struct pri_cc_record *cc_record)
{
	q931_copy_address_to_rose(ctrl, &call_information->address_of_b, &cc_record->party_b);

	if (cc_record->saved_ie_contents.length
		<= sizeof(call_information->q931ie_contents)) {
		/* Saved BC, HLC, and LLC from initial SETUP */
		call_information->q931ie.length = cc_record->saved_ie_contents.length;
		memcpy(call_information->q931ie.contents, cc_record->saved_ie_contents.data,
			cc_record->saved_ie_contents.length);
	} else {
		pri_error(ctrl, "call-information q931 ie contents did not fit.\n");
	}

	call_information->ccbs_reference = cc_record->ccbs_reference_id;

	q931_copy_subaddress_to_rose(ctrl, &call_information->subaddress_of_a,
		&cc_record->party_a.subaddress);
}

/*!
 * \internal
 * \brief Encode ETSI PTMP specific CCBSInterrogate/CCNRInterrogate result message.
 *
 * \param ctrl D channel controller for diagnostic messages or global options.
 * \param pos Starting position to encode the facility ie contents.
 * \param end End of facility ie contents encoding data buffer.
 * \param invoke Decoded ROSE invoke message contents.
 * \param cc_record Call completion record to process event.
 *
 * \retval Start of the next ASN.1 component to encode on success.
 * \retval NULL on error.
 */
static unsigned char *enc_etsi_ptmp_cc_interrogate_rsp_specific(struct pri *ctrl,
	unsigned char *pos, unsigned char *end, const struct rose_msg_invoke *invoke,
	const struct pri_cc_record *cc_record)
{
	struct rose_msg_result msg;

	pos = facility_encode_header(ctrl, pos, end, NULL);
	if (!pos) {
		return NULL;
	}

	memset(&msg, 0, sizeof(msg));
	msg.invoke_id = invoke->invoke_id;
	msg.operation = invoke->operation;

	msg.args.etsi.CCBSInterrogate.recall_mode = cc_record->option.recall_mode;
	msg.args.etsi.CCBSInterrogate.call_details.num_records = 1;
	q931_copy_call_information_to_etsi_rose(ctrl,
		&msg.args.etsi.CCBSInterrogate.call_details.list[0], cc_record);

	pos = rose_encode_result(ctrl, pos, end, &msg);

	return pos;
}

/*!
 * \internal
 * \brief Encode ETSI PTMP general CCBSInterrogate/CCNRInterrogate result message.
 *
 * \param ctrl D channel controller for diagnostic messages or global options.
 * \param pos Starting position to encode the facility ie contents.
 * \param end End of facility ie contents encoding data buffer.
 * \param invoke Decoded ROSE invoke message contents.
 *
 * \retval Start of the next ASN.1 component to encode on success.
 * \retval NULL on error.
 */
static unsigned char *enc_etsi_ptmp_cc_interrogate_rsp_general(struct pri *ctrl,
	unsigned char *pos, unsigned char *end, const struct rose_msg_invoke *invoke)
{
	struct rose_msg_result msg;
	struct q931_party_number party_a_number;
	const struct pri_cc_record *cc_record;
	unsigned char *new_pos;
	unsigned idx;

	pos = facility_encode_header(ctrl, pos, end, NULL);
	if (!pos) {
		return NULL;
	}

	memset(&msg, 0, sizeof(msg));
	msg.invoke_id = invoke->invoke_id;
	msg.operation = invoke->operation;

	msg.args.etsi.CCBSInterrogate.recall_mode = ctrl->cc.option.recall_mode;

	/* Convert the given party A number. */
	q931_party_number_init(&party_a_number);
	if (invoke->args.etsi.CCBSInterrogate.a_party_number.length) {
		/* The party A number was given. */
		rose_copy_number_to_q931(ctrl, &party_a_number,
			&invoke->args.etsi.CCBSInterrogate.a_party_number);
	}

	/* Build the CallDetails list. */
	idx = 0;
	for (cc_record = ctrl->cc.pool; cc_record; cc_record = cc_record->next) {
		if (cc_record->ccbs_reference_id == CC_PTMP_INVALID_ID
			|| (!cc_record->is_ccnr) != (invoke->operation == ROSE_ETSI_CCBSInterrogate)) {
			/*
			 * Record does not have a reference id yet
			 * or is not for the requested CCBS/CCNR mode.
			 */
			continue;
		}
		if (party_a_number.valid) {
			/* The party A number was given. */
			party_a_number.presentation = cc_record->party_a.number.presentation;
			if (q931_party_number_cmp(&party_a_number, &cc_record->party_a.number)) {
				/* Record party A does not match. */
				continue;
			}
		}

		/* Add call information to the CallDetails list. */
		q931_copy_call_information_to_etsi_rose(ctrl,
			&msg.args.etsi.CCBSInterrogate.call_details.list[idx], cc_record);

		++idx;
		if (ARRAY_LEN(msg.args.etsi.CCBSInterrogate.call_details.list) <= idx) {
			/* List is full. */
			break;
		}
	}
	msg.args.etsi.CCBSInterrogate.call_details.num_records = idx;

	new_pos = rose_encode_result(ctrl, pos, end, &msg);

	/* Reduce the CallDetails list until it fits into the given buffer. */
	while (!new_pos && msg.args.etsi.CCBSInterrogate.call_details.num_records) {
		--msg.args.etsi.CCBSInterrogate.call_details.num_records;
		new_pos = rose_encode_result(ctrl, pos, end, &msg);
	}

	return new_pos;
}

/*!
 * \internal
 * \brief Encode and queue a specific CCBSInterrogate/CCNRInterrogate result message.
 *
 * \param ctrl D channel controller for diagnostic messages or global options.
 * \param call Call leg from which to encode CCBSInterrogate/CCNRInterrogate response.
 * \param invoke Decoded ROSE invoke message contents.
 * \param cc_record Call completion record to process event.
 *
 * \retval 0 on success.
 * \retval -1 on error.
 */
static int rose_cc_interrogate_rsp_specific(struct pri *ctrl, q931_call *call, const struct rose_msg_invoke *invoke, const struct pri_cc_record *cc_record)
{
	unsigned char buffer[256];
	unsigned char *end;

	end =
		enc_etsi_ptmp_cc_interrogate_rsp_specific(ctrl, buffer, buffer + sizeof(buffer),
			invoke, cc_record);
	if (!end) {
		return -1;
	}

	return pri_call_apdu_queue(call, Q931_FACILITY, buffer, end - buffer, NULL);
}

/*!
 * \internal
 * \brief Encode and queue a general CCBSInterrogate/CCNRInterrogate result message.
 *
 * \param ctrl D channel controller for diagnostic messages or global options.
 * \param call Call leg from which to encode CCBSInterrogate/CCNRInterrogate response.
 * \param invoke Decoded ROSE invoke message contents.
 *
 * \retval 0 on success.
 * \retval -1 on error.
 */
static int rose_cc_interrogate_rsp_general(struct pri *ctrl, q931_call *call, const struct rose_msg_invoke *invoke)
{
	unsigned char buffer[256];
	unsigned char *end;

	end =
		enc_etsi_ptmp_cc_interrogate_rsp_general(ctrl, buffer, buffer + sizeof(buffer),
			invoke);
	if (!end) {
		return -1;
	}

	return pri_call_apdu_queue(call, Q931_FACILITY, buffer, end - buffer, NULL);
}

/*!
 * \brief Respond to the received CCBSInterrogate/CCNRInterrogate invoke message.
 *
 * \param ctrl D channel controller for diagnostic messages or global options.
 * \param call Call leg from which the message came.
 * \param invoke Decoded ROSE invoke message contents.
 *
 * \retval 0 on success.
 * \retval -1 on error.
 */
int pri_cc_interrogate_rsp(struct pri *ctrl, q931_call *call, const struct rose_msg_invoke *invoke)
{
	int encode_result;

	if (!ctrl->cc_support) {
		/* Call completion is disabled. */
		return send_facility_error(ctrl, call, invoke->invoke_id,
			ROSE_ERROR_Gen_NotSubscribed);
	}

	if (invoke->args.etsi.CCBSInterrogate.ccbs_reference_present) {
		struct pri_cc_record *cc_record;

		/* Specific CC request interrogation. */
		cc_record = pri_cc_find_by_reference(ctrl,
			invoke->args.etsi.CCBSInterrogate.ccbs_reference);
		if (!cc_record
			|| ((!cc_record->is_ccnr)
				== (invoke->operation == ROSE_ETSI_CCBSInterrogate))) {
			/* Record does not exist or is not for the requested CCBS/CCNR mode. */
			return send_facility_error(ctrl, call, invoke->invoke_id,
				ROSE_ERROR_CCBS_InvalidCCBSReference);
		}
		encode_result = rose_cc_interrogate_rsp_specific(ctrl, call, invoke, cc_record);
	} else {
		/* General CC request interrogation. */
		encode_result = rose_cc_interrogate_rsp_general(ctrl, call, invoke);
	}

	if (encode_result || q931_facility(ctrl, call)) {
		pri_message(ctrl,
			"Could not schedule facility message for cc-interrogate.\n");
		return -1;
	}

	return 0;
}

/*!
 * \brief Respond to the received PTMP CCBSRequest/CCNRRequest invoke message.
 *
 * \param ctrl D channel controller for diagnostic messages or global options.
 * \param call Call leg from which the message came.
 * \param invoke Decoded ROSE invoke message contents.
 *
 * \return Nothing
 */
void pri_cc_ptmp_request(struct pri *ctrl, q931_call *call, const struct rose_msg_invoke *invoke)
{
	struct pri_cc_record *cc_record;

	if (!ctrl->cc_support) {
		/* Call completion is disabled. */
		send_facility_error(ctrl, call, invoke->invoke_id,
			ROSE_ERROR_Gen_NotSubscribed);
		return;
	}
	cc_record = pri_cc_find_by_linkage(ctrl,
		invoke->args.etsi.CCBSRequest.call_linkage_id);
	if (!cc_record) {
		send_facility_error(ctrl, call, invoke->invoke_id,
			ROSE_ERROR_CCBS_InvalidCallLinkageID);
		return;
	}
	if (cc_record->state != CC_STATE_AVAILABLE) {
		send_facility_error(ctrl, call, invoke->invoke_id,
			ROSE_ERROR_CCBS_IsAlreadyActivated);
		return;
	}
	cc_record->ccbs_reference_id = pri_cc_new_reference_id(ctrl);
	if (cc_record->ccbs_reference_id == CC_PTMP_INVALID_ID) {
		/* Could not allocate a call reference id. */
		send_facility_error(ctrl, call, invoke->invoke_id,
			ROSE_ERROR_CCBS_OutgoingCCBSQueueFull);
		return;
	}

	/* Save off data to know how to send back any response. */
	cc_record->response.signaling = call;
	cc_record->response.invoke_operation = invoke->operation;
	cc_record->response.invoke_id = invoke->invoke_id;

	/* Set the requested CC mode. */
	cc_record->is_ccnr = (invoke->operation == ROSE_ETSI_CCNRRequest) ? 1 : 0;

	pri_cc_event(ctrl, call, cc_record, CC_EVENT_CC_REQUEST);
}

/*!
 * \brief Respond to the received PTP CCBS_T_Request/CCNR_T_Request invoke message.
 *
 * \param ctrl D channel controller for diagnostic messages or global options.
 * \param call Call leg from which the message came.
 * \param msgtype Q.931 message type ie is in.
 * \param invoke Decoded ROSE invoke message contents.
 *
 * \return Nothing
 */
void pri_cc_ptp_request(struct pri *ctrl, q931_call *call, int msgtype, const struct rose_msg_invoke *invoke)
{
	struct pri_cc_record *cc_record;
	struct q931_party_address party_a;
	struct q931_party_address party_b;

	if (msgtype != Q931_REGISTER) {
		/* Ignore CC request message since it did not come in on the correct message. */
		return;
	}
	if (!ctrl->cc_support) {
		/* Call completion is disabled. */
		rose_error_msg_encode(ctrl, call, Q931_ANY_MESSAGE, invoke->invoke_id,
			ROSE_ERROR_Gen_NotSubscribed);
		call->cc.hangup_call = 1;
		return;
	}

	q931_party_address_init(&party_a);
	if (invoke->args.etsi.CCBS_T_Request.originating.number.length) {
		/* The originating number is present. */
		rose_copy_address_to_q931(ctrl, &party_a,
			&invoke->args.etsi.CCBS_T_Request.originating);
	}
	q931_party_address_init(&party_b);
	rose_copy_address_to_q931(ctrl, &party_b,
		&invoke->args.etsi.CCBS_T_Request.destination);
	cc_record = pri_cc_find_by_addressing(ctrl, &party_a, &party_b,
		invoke->args.etsi.CCBS_T_Request.q931ie.length,
		invoke->args.etsi.CCBS_T_Request.q931ie.contents);
	if (!cc_record || cc_record->state != CC_STATE_AVAILABLE) {
		/* Could not find the record or already activated */
		rose_error_msg_encode(ctrl, call, Q931_ANY_MESSAGE, invoke->invoke_id,
			ROSE_ERROR_CCBS_T_ShortTermDenial);
		call->cc.hangup_call = 1;
		return;
	}

	/*
	 * We already have the presentationAllowedIndicator in the cc_record
	 * when we saved the original call information.
	 */
#if 0
	if (invoke->args.etsi.CCBS_T_Request.presentation_allowed_indicator_present) {
		if (invoke->args.etsi.CCBS_T_Request.presentation_allowed_indicator) {
			if (party_a.number.str[0]) {
				party_a.number.presentation =
					PRI_PRES_ALLOWED | PRI_PRES_USER_NUMBER_UNSCREENED;
			} else {
				party_a.number.presentation = PRES_NUMBER_NOT_AVAILABLE;
			}
		} else {
			party_a.number.presentation =
				PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_UNSCREENED;
		}
	}
#endif

	/* Link the signaling link to the cc_record. */
	call->cc.record = cc_record;
	cc_record->signaling = call;

	/* Save off data to know how to send back any response. */
	//cc_record->response.signaling = call;
	cc_record->response.invoke_operation = invoke->operation;
	cc_record->response.invoke_id = invoke->invoke_id;

	/* Set the requested CC mode. */
	cc_record->is_ccnr = (invoke->operation == ROSE_ETSI_CCNR_T_Request) ? 1 : 0;

	/* Lets keep this signaling link around for awhile. */
	call->cis_recognized = 1;

	pri_cc_event(ctrl, call, cc_record, CC_EVENT_CC_REQUEST);
}

/*!
 * \brief Respond to the received Q.SIG ccbsRequest/ccnrRequest invoke message.
 *
 * \param ctrl D channel controller for diagnostic messages or global options.
 * \param call Call leg from which the message came.
 * \param msgtype Q.931 message type ie is in.
 * \param invoke Decoded ROSE invoke message contents.
 *
 * \return Nothing
 */
void pri_cc_qsig_request(struct pri *ctrl, q931_call *call, int msgtype, const struct rose_msg_invoke *invoke)
{
	struct pri_cc_record *cc_record;
	struct q931_party_address party_a;
	struct q931_party_address party_b;

	if (msgtype != Q931_SETUP) {
		/* Ignore CC request message since it did not come in on the correct message. */
		return;
	}
	if (!ctrl->cc_support) {
		/* Call completion is disabled. */
		rose_error_msg_encode(ctrl, call, Q931_ANY_MESSAGE, invoke->invoke_id,
			ROSE_ERROR_QSIG_LongTermRejection);
		call->cc.hangup_call = 1;
		return;
	}

	/* Extract Party A address. */
	rose_copy_presented_number_unscreened_to_q931(ctrl, &party_a.number,
		&invoke->args.qsig.CcbsRequest.number_a);
	q931_party_subaddress_init(&party_a.subaddress);
	rose_copy_subaddress_to_q931(ctrl, &party_a.subaddress,
		&invoke->args.qsig.CcbsRequest.subaddr_a);

	/* Extract Party B address. */
	q931_party_address_init(&party_b);
	rose_copy_number_to_q931(ctrl, &party_b.number,
		&invoke->args.qsig.CcbsRequest.number_b);
	rose_copy_subaddress_to_q931(ctrl, &party_b.subaddress,
		&invoke->args.qsig.CcbsRequest.subaddr_b);

	cc_record = pri_cc_find_by_addressing(ctrl, &party_a, &party_b,
		invoke->args.qsig.CcbsRequest.q931ie.length,
		invoke->args.qsig.CcbsRequest.q931ie.contents);
	if (!cc_record || cc_record->state != CC_STATE_AVAILABLE) {
		/* Could not find the record or already activated */
		rose_error_msg_encode(ctrl, call, Q931_ANY_MESSAGE, invoke->invoke_id,
			ROSE_ERROR_QSIG_ShortTermRejection);
		call->cc.hangup_call = 1;
		return;
	}

	/* Determine negotiated signaling retention method. */
	if (invoke->args.qsig.CcbsRequest.retain_sig_connection_present) {
		/* We will do what the originator desires. */
		cc_record->option.retain_signaling_link =
			invoke->args.qsig.CcbsRequest.retain_sig_connection;
	} else {
		/* The originator does not care.  Do how we are configured. */
		cc_record->option.retain_signaling_link =
			ctrl->cc.option.signaling_retention_rsp;
	}
	if (!cc_record->party_a.number.valid || cc_record->party_a.number.str[0] == '\0') {
		/*
		 * Party A number is not available for us to initiate
		 * a signaling link.  We must retain the signaling link.
		 */
		cc_record->option.retain_signaling_link = 1;
	}

	/* Link the signaling link to the cc_record. */
	call->cc.record = cc_record;
	cc_record->signaling = call;

	/* Save off data to know how to send back any response. */
	//cc_record->response.signaling = call;
	cc_record->response.invoke_operation = invoke->operation;
	cc_record->response.invoke_id = invoke->invoke_id;

	/* Set the requested CC mode. */
	cc_record->is_ccnr = (invoke->operation == ROSE_QSIG_CcnrRequest) ? 1 : 0;

	/* Lets keep this signaling link around for awhile. */
	call->cis_recognized = 1;

	pri_cc_event(ctrl, call, cc_record, CC_EVENT_CC_REQUEST);
}

/*!
 * \brief Handle the received Q.SIG ccCancel invoke message.
 *
 * \param ctrl D channel controller for diagnostic messages or global options.
 * \param call Call leg from which the message came.
 * \param msgtype Q.931 message type ie is in.
 * \param invoke Decoded ROSE invoke message contents.
 *
 * \return Nothing
 */
void pri_cc_qsig_cancel(struct pri *ctrl, q931_call *call, int msgtype, const struct rose_msg_invoke *invoke)
{
	struct pri_cc_record *cc_record;
	struct q931_party_address party_a;
	struct q931_party_address party_b;

	cc_record = call->cc.record;
	if (!cc_record) {
		/* The current call is not associated with the cc_record. */
		if (invoke->args.qsig.CcCancel.full_arg_present) {
			/* Extract Party A address. */
			q931_party_address_init(&party_a);
			rose_copy_number_to_q931(ctrl, &party_a.number,
				&invoke->args.qsig.CcCancel.number_a);
			rose_copy_subaddress_to_q931(ctrl, &party_a.subaddress,
				&invoke->args.qsig.CcCancel.subaddr_a);

			/* Extract Party B address. */
			q931_party_address_init(&party_b);
			rose_copy_number_to_q931(ctrl, &party_b.number,
				&invoke->args.qsig.CcCancel.number_b);
			rose_copy_subaddress_to_q931(ctrl, &party_b.subaddress,
				&invoke->args.qsig.CcCancel.subaddr_b);

			cc_record = pri_cc_find_by_addressing(ctrl, &party_a, &party_b,
				invoke->args.qsig.CcCancel.q931ie.length,
				invoke->args.qsig.CcCancel.q931ie.contents);
		}
		if (!cc_record) {
			/*
			 * Could not find the cc_record
			 * or not enough information to look up a cc_record.
			 */
			if (msgtype == Q931_SETUP) {
				call->cc.hangup_call = 1;
			}
			return;
		}
	}

	if (msgtype == Q931_SETUP && call->cis_call) {
		if (cc_record->signaling) {
			/*
			 * We already have a signaling link.
			 * This could be a collision with our ccExecPossible.
			 * Could this be an alias match?
			 */
			switch (cc_record->state) {
			case CC_STATE_WAIT_CALLBACK:
				if (ctrl->debug & PRI_DEBUG_CC) {
					pri_message(ctrl,
						"-- Collision with our ccExecPossible event call.  Canceling CC.\n");
				}
				break;
			default:
				pri_message(ctrl,
					"-- Warning: Possible Q.SIG CC alias match.  Canceling CC.\n");
				break;
			}
			cc_record->fsm.qsig.msgtype = msgtype;
			pri_cc_event(ctrl, call, cc_record, CC_EVENT_LINK_CANCEL);

			call->cc.hangup_call = 1;
			return;
		}

		/* Link the signaling link to the cc_record. */
		call->cc.record = cc_record;
		cc_record->signaling = call;

		/* Lets keep this signaling link around for awhile. */
		call->cis_recognized = 1;
	}

	cc_record->fsm.qsig.msgtype = msgtype;
	pri_cc_event(ctrl, call, cc_record, CC_EVENT_LINK_CANCEL);
}

/*!
 * \brief Handle the received Q.SIG ccExecPossible invoke message.
 *
 * \param ctrl D channel controller for diagnostic messages or global options.
 * \param call Call leg from which the message came.
 * \param msgtype Q.931 message type ie is in.
 * \param invoke Decoded ROSE invoke message contents.
 *
 * \return Nothing
 */
void pri_cc_qsig_exec_possible(struct pri *ctrl, q931_call *call, int msgtype, const struct rose_msg_invoke *invoke)
{
	struct pri_cc_record *cc_record;
	struct q931_party_address party_a;
	struct q931_party_address party_b;

	cc_record = call->cc.record;
	if (!cc_record) {
		/* The current call is not associated with the cc_record. */
		if (invoke->args.qsig.CcExecPossible.full_arg_present) {
			/* Extract Party A address. */
			q931_party_address_init(&party_a);
			rose_copy_number_to_q931(ctrl, &party_a.number,
				&invoke->args.qsig.CcExecPossible.number_a);
			rose_copy_subaddress_to_q931(ctrl, &party_a.subaddress,
				&invoke->args.qsig.CcExecPossible.subaddr_a);

			/* Extract Party B address. */
			q931_party_address_init(&party_b);
			rose_copy_number_to_q931(ctrl, &party_b.number,
				&invoke->args.qsig.CcExecPossible.number_b);
			rose_copy_subaddress_to_q931(ctrl, &party_b.subaddress,
				&invoke->args.qsig.CcExecPossible.subaddr_b);

			cc_record = pri_cc_find_by_addressing(ctrl, &party_a, &party_b,
				invoke->args.qsig.CcExecPossible.q931ie.length,
				invoke->args.qsig.CcExecPossible.q931ie.contents);
		}
		if (!cc_record) {
			/*
			 * Could not find the cc_record
			 * or not enough information to look up a cc_record.
			 */
			rose_cc_cancel(ctrl, call, NULL, Q931_ANY_MESSAGE);
			if (msgtype == Q931_SETUP) {
				call->cc.hangup_call = 1;
			} else {
				/* msgtype should be Q931_FACILITY. */
				pri_hangup(ctrl, call, -1);
			}
			return;
		}
	}

	if (msgtype == Q931_SETUP && call->cis_call) {
		if (cc_record->signaling) {
			/*
			 * We already have a signaling link.  This should not happen.
			 * Could this be an alias match?
			 */
			pri_message(ctrl,
				"-- Warning: Possible Q.SIG CC alias match.  Sending ccCancel back.\n");
			rose_cc_cancel(ctrl, call, NULL, Q931_ANY_MESSAGE);
			call->cc.hangup_call = 1;
			return;
		}

		/* Link the signaling link to the cc_record. */
		call->cc.record = cc_record;
		cc_record->signaling = call;

		/* Lets keep this signaling link around for awhile. */
		call->cis_recognized = 1;
	}

	cc_record->fsm.qsig.msgtype = msgtype;
	pri_cc_event(ctrl, call, cc_record, CC_EVENT_REMOTE_USER_FREE);
}

/*!
 * \brief Convert the given call completion state to a string.
 *
 * \param state CC state to convert to string.
 *
 * \return String version of call completion state.
 */
const char *pri_cc_fsm_state_str(enum CC_STATES state)
{
	const char *str;

	str = "Unknown";
	switch (state) {
	case CC_STATE_IDLE:
		str = "CC_STATE_IDLE";
		break;
	case CC_STATE_PENDING_AVAILABLE:
		str = "CC_STATE_PENDING_AVAILABLE";
		break;
	case CC_STATE_AVAILABLE:
		str = "CC_STATE_AVAILABLE";
		break;
	case CC_STATE_REQUESTED:
		str = "CC_STATE_REQUESTED";
		break;
	case CC_STATE_ACTIVATED:
		str = "CC_STATE_ACTIVATED";
		break;
	case CC_STATE_B_AVAILABLE:
		str = "CC_STATE_B_AVAILABLE";
		break;
	case CC_STATE_SUSPENDED:
		str = "CC_STATE_SUSPENDED";
		break;
	case CC_STATE_WAIT_CALLBACK:
		str = "CC_STATE_WAIT_CALLBACK";
		break;
	case CC_STATE_CALLBACK:
		str = "CC_STATE_CALLBACK";
		break;
	case CC_STATE_WAIT_DESTRUCTION:
		str = "CC_STATE_WAIT_DESTRUCTION";
		break;
	case CC_STATE_NUM:
		/* Not a real state. */
		break;
	}
	return str;
}

/*!
 * \brief Convert the given call completion event to a string.
 *
 * \param event CC event to convert to string.
 *
 * \return String version of call completion event.
 */
const char *pri_cc_fsm_event_str(enum CC_EVENTS event)
{
	const char *str;

	str = "Unknown";
	switch (event) {
	case CC_EVENT_AVAILABLE:
		str = "CC_EVENT_AVAILABLE";
		break;
	case CC_EVENT_CC_REQUEST:
		str = "CC_EVENT_CC_REQUEST";
		break;
	case CC_EVENT_CC_REQUEST_ACCEPT:
		str = "CC_EVENT_CC_REQUEST_ACCEPT";
		break;
	case CC_EVENT_CC_REQUEST_FAIL:
		str = "CC_EVENT_CC_REQUEST_FAIL";
		break;
	case CC_EVENT_REMOTE_USER_FREE:
		str = "CC_EVENT_REMOTE_USER_FREE";
		break;
	case CC_EVENT_B_FREE:
		str = "CC_EVENT_B_FREE";
		break;
	case CC_EVENT_STOP_ALERTING:
		str = "CC_EVENT_STOP_ALERTING";
		break;
	case CC_EVENT_A_STATUS:
		str = "CC_EVENT_A_STATUS";
		break;
	case CC_EVENT_A_FREE:
		str = "CC_EVENT_A_FREE";
		break;
	case CC_EVENT_A_BUSY:
		str = "CC_EVENT_A_BUSY";
		break;
	case CC_EVENT_SUSPEND:
		str = "CC_EVENT_SUSPEND";
		break;
	case CC_EVENT_RESUME:
		str = "CC_EVENT_RESUME";
		break;
	case CC_EVENT_RECALL:
		str = "CC_EVENT_RECALL";
		break;
	case CC_EVENT_LINK_CANCEL:
		str = "CC_EVENT_LINK_CANCEL";
		break;
	case CC_EVENT_CANCEL:
		str = "CC_EVENT_CANCEL";
		break;
	case CC_EVENT_INTERNAL_CLEARING:
		str = "CC_EVENT_INTERNAL_CLEARING";
		break;
	case CC_EVENT_SIGNALING_GONE:
		str = "CC_EVENT_SIGNALING_GONE";
		break;
	case CC_EVENT_HANGUP_SIGNALING:
		str = "CC_EVENT_HANGUP_SIGNALING";
		break;
	case CC_EVENT_MSG_ALERTING:
		str = "CC_EVENT_MSG_ALERTING";
		break;
	case CC_EVENT_MSG_DISCONNECT:
		str = "CC_EVENT_MSG_DISCONNECT";
		break;
	case CC_EVENT_MSG_RELEASE:
		str = "CC_EVENT_MSG_RELEASE";
		break;
	case CC_EVENT_MSG_RELEASE_COMPLETE:
		str = "CC_EVENT_MSG_RELEASE_COMPLETE";
		break;
	case CC_EVENT_TIMEOUT_T_ACTIVATE:
		str = "CC_EVENT_TIMEOUT_T_ACTIVATE";
		break;
#if 0
	case CC_EVENT_TIMEOUT_T_DEACTIVATE:
		str = "CC_EVENT_TIMEOUT_T_DEACTIVATE";
		break;
	case CC_EVENT_TIMEOUT_T_INTERROGATE:
		str = "CC_EVENT_TIMEOUT_T_INTERROGATE";
		break;
#endif
	case CC_EVENT_TIMEOUT_T_RETENTION:
		str = "CC_EVENT_TIMEOUT_T_RETENTION";
		break;
	case CC_EVENT_TIMEOUT_T_CCBS1:
		str = "CC_EVENT_TIMEOUT_T_CCBS1";
		break;
	case CC_EVENT_TIMEOUT_EXTENDED_T_CCBS1:
		str = "CC_EVENT_TIMEOUT_EXTENDED_T_CCBS1";
		break;
	case CC_EVENT_TIMEOUT_T_SUPERVISION:
		str = "CC_EVENT_TIMEOUT_T_SUPERVISION";
		break;
	case CC_EVENT_TIMEOUT_T_RECALL:
		str = "CC_EVENT_TIMEOUT_T_RECALL";
		break;
	}
	return str;
}

static const char pri_cc_act_header[] = "%ld  CC-Act: %s\n";
#define PRI_CC_ACT_DEBUG_OUTPUT(ctrl, cc_id)							\
	if ((ctrl)->debug & PRI_DEBUG_CC) {									\
		pri_message((ctrl), pri_cc_act_header, (cc_id), __FUNCTION__);	\
	}

/*!
 * \internal
 * \brief FSM action to mark FSM for destruction.
 *
 * \param ctrl D channel controller.
 * \param cc_record Call completion record to process event.
 *
 * \return Nothing
 */
static void pri_cc_act_set_self_destruct(struct pri *ctrl, struct pri_cc_record *cc_record)
{
#if defined(CC_SANITY_CHECKS)
	struct apdu_event *msg;
#endif	/* defined(CC_SANITY_CHECKS) */

	PRI_CC_ACT_DEBUG_OUTPUT(ctrl, cc_record->record_id);

	/* Abort any pending indirect events. */
	pri_schedule_del(ctrl, cc_record->t_indirect);
	cc_record->t_indirect = 0;

#if defined(CC_SANITY_CHECKS)
	if (cc_record->t_retention) {
		pri_error(ctrl, "T_RETENTION still active");
		pri_schedule_del(ctrl, cc_record->t_retention);
		cc_record->t_retention = 0;
	}
	if (cc_record->t_supervision) {
		pri_error(ctrl, "T_SUPERVISION still active");
		pri_schedule_del(ctrl, cc_record->t_supervision);
		cc_record->t_supervision = 0;
	}
	if (cc_record->t_recall) {
		pri_error(ctrl, "T_RECALL still active");
		pri_schedule_del(ctrl, cc_record->t_recall);
		cc_record->t_recall = 0;
	}
	if (PTMP_MODE(ctrl)) {
		msg = pri_call_apdu_find(cc_record->signaling,
			cc_record->fsm.ptmp.t_ccbs1_invoke_id);
		if (msg) {
			pri_error(ctrl, "T_CCBS1 still active");
			cc_record->fsm.ptmp.t_ccbs1_invoke_id = APDU_INVALID_INVOKE_ID;
			pri_call_apdu_delete(cc_record->signaling, msg);
		}
		if (cc_record->fsm.ptmp.extended_t_ccbs1) {
			pri_error(ctrl, "Extended T_CCBS1 still active");
			pri_schedule_del(ctrl, cc_record->fsm.ptmp.extended_t_ccbs1);
			cc_record->fsm.ptmp.extended_t_ccbs1 = 0;
		}
	}
	if (cc_record->signaling) {
		msg = pri_call_apdu_find(cc_record->signaling, cc_record->t_activate_invoke_id);
		if (msg) {
			pri_error(ctrl, "T_ACTIVATE still active");
			cc_record->t_activate_invoke_id = APDU_INVALID_INVOKE_ID;
			pri_call_apdu_delete(cc_record->signaling, msg);
		}
	}
#endif	/* defined(CC_SANITY_CHECKS) */

	cc_record->fsm_complete = 1;
}

/*!
 * \internal
 * \brief FSM action to disassociate the signaling link from the cc_record.
 *
 * \param ctrl D channel controller.
 * \param cc_record Call completion record to process event.
 *
 * \return Nothing
 */
static void pri_cc_act_disassociate_signaling_link(struct pri *ctrl, struct pri_cc_record *cc_record)
{
	PRI_CC_ACT_DEBUG_OUTPUT(ctrl, cc_record->record_id);
	pri_cc_disassociate_signaling_link(cc_record);
}

/*!
 * \internal
 * \brief FSM action to send CC available message.
 *
 * \param ctrl D channel controller.
 * \param cc_record Call completion record to process event.
 * \param call Q.931 call leg.
 * \param msgtype Q.931 message type to put facility ie in.
 *
 * \return Nothing
 */
static void pri_cc_act_send_cc_available(struct pri *ctrl, struct pri_cc_record *cc_record, q931_call *call, int msgtype)
{
	PRI_CC_ACT_DEBUG_OUTPUT(ctrl, cc_record->record_id);
	rose_cc_available_encode(ctrl, call, cc_record, msgtype);
}

/*!
 * \internal
 * \brief FSM action to stop the PTMP T_RETENTION timer.
 *
 * \param ctrl D channel controller.
 * \param cc_record Call completion record to process event.
 *
 * \return Nothing
 */
static void pri_cc_act_stop_t_retention(struct pri *ctrl, struct pri_cc_record *cc_record)
{
	PRI_CC_ACT_DEBUG_OUTPUT(ctrl, cc_record->record_id);
	pri_schedule_del(ctrl, cc_record->t_retention);
	cc_record->t_retention = 0;
}

/*!
 * \internal
 * \brief T_RETENTION timeout callback.
 *
 * \param data CC record pointer.
 *
 * \return Nothing
 */
static void pri_cc_timeout_t_retention(void *data)
{
	struct pri_cc_record *cc_record = data;

	cc_record->t_retention = 0;
	q931_cc_timeout(cc_record->ctrl, cc_record, CC_EVENT_TIMEOUT_T_RETENTION);
}

/*!
 * \internal
 * \brief FSM action to start the PTMP T_RETENTION timer.
 *
 * \param ctrl D channel controller.
 * \param cc_record Call completion record to process event.
 *
 * \return Nothing
 */
static void pri_cc_act_start_t_retention(struct pri *ctrl, struct pri_cc_record *cc_record)
{
	PRI_CC_ACT_DEBUG_OUTPUT(ctrl, cc_record->record_id);
	if (cc_record->t_retention) {
		pri_error(ctrl, "!! T_RETENTION is already running!");
		pri_schedule_del(ctrl, cc_record->t_retention);
	}
	cc_record->t_retention = pri_schedule_event(ctrl,
		ctrl->timers[PRI_TIMER_T_RETENTION], pri_cc_timeout_t_retention, cc_record);
}

/*!
 * \internal
 * \brief FSM action to stop the PTMP EXTENDED_T_CCBS1 timer.
 *
 * \param ctrl D channel controller.
 * \param cc_record Call completion record to process event.
 *
 * \return Nothing
 */
static void pri_cc_act_stop_extended_t_ccbs1(struct pri *ctrl, struct pri_cc_record *cc_record)
{
	PRI_CC_ACT_DEBUG_OUTPUT(ctrl, cc_record->record_id);
	pri_schedule_del(ctrl, cc_record->fsm.ptmp.extended_t_ccbs1);
	cc_record->fsm.ptmp.extended_t_ccbs1 = 0;
}

/*!
 * \internal
 * \brief EXTENDED_T_CCBS1 timeout callback.
 *
 * \param data CC record pointer.
 *
 * \return Nothing
 */
static void pri_cc_timeout_extended_t_ccbs1(void *data)
{
	struct pri_cc_record *cc_record = data;

	cc_record->fsm.ptmp.extended_t_ccbs1 = 0;
	q931_cc_timeout(cc_record->ctrl, cc_record, CC_EVENT_TIMEOUT_EXTENDED_T_CCBS1);
}

/*!
 * \internal
 * \brief FSM action to start the PTMP extended T_CCBS1 timer.
 *
 * \param ctrl D channel controller.
 * \param cc_record Call completion record to process event.
 *
 * \return Nothing
 */
static void pri_cc_act_start_extended_t_ccbs1(struct pri *ctrl, struct pri_cc_record *cc_record)
{
	PRI_CC_ACT_DEBUG_OUTPUT(ctrl, cc_record->record_id);
	if (cc_record->fsm.ptmp.extended_t_ccbs1) {
		pri_error(ctrl, "!! Extended T_CCBS1 is already running!");
		pri_schedule_del(ctrl, cc_record->fsm.ptmp.extended_t_ccbs1);
	}
	/* Timeout is T_CCBS1 + 2 seconds. */
	cc_record->fsm.ptmp.extended_t_ccbs1 = pri_schedule_event(ctrl,
		ctrl->timers[PRI_TIMER_T_CCBS1] + 2000, pri_cc_timeout_extended_t_ccbs1,
		cc_record);
}

/*!
 * \internal
 * \brief FSM action to stop the T_SUPERVISION timer.
 *
 * \param ctrl D channel controller.
 * \param cc_record Call completion record to process event.
 *
 * \return Nothing
 */
static void pri_cc_act_stop_t_supervision(struct pri *ctrl, struct pri_cc_record *cc_record)
{
	PRI_CC_ACT_DEBUG_OUTPUT(ctrl, cc_record->record_id);
	pri_schedule_del(ctrl, cc_record->t_supervision);
	cc_record->t_supervision = 0;
}

/*!
 * \internal
 * \brief T_SUPERVISION timeout callback.
 *
 * \param data CC record pointer.
 *
 * \return Nothing
 */
static void pri_cc_timeout_t_supervision(void *data)
{
	struct pri_cc_record *cc_record = data;

	cc_record->t_supervision = 0;
	q931_cc_timeout(cc_record->ctrl, cc_record, CC_EVENT_TIMEOUT_T_SUPERVISION);
}

/*!
 * \internal
 * \brief FSM action to start the T_SUPERVISION timer.
 *
 * \param ctrl D channel controller.
 * \param cc_record Call completion record to process event.
 *
 * \return Nothing
 */
static void pri_cc_act_start_t_supervision(struct pri *ctrl, struct pri_cc_record *cc_record)
{
	int timer_id;
	int duration;

	PRI_CC_ACT_DEBUG_OUTPUT(ctrl, cc_record->record_id);
	if (cc_record->t_supervision) {
		pri_error(ctrl, "!! A CC supervision timer is already running!");
		pri_schedule_del(ctrl, cc_record->t_supervision);
	}
	switch (ctrl->switchtype) {
	case PRI_SWITCH_EUROISDN_E1:
	case PRI_SWITCH_EUROISDN_T1:
		if (PTMP_MODE(ctrl)) {
			/* ETSI PTMP mode. */
			timer_id = cc_record->is_ccnr ? PRI_TIMER_T_CCNR2 : PRI_TIMER_T_CCBS2;
		} else if (cc_record->is_agent) {
			/* ETSI PTP mode network B side. */
			timer_id = cc_record->is_ccnr ? PRI_TIMER_T_CCNR5 : PRI_TIMER_T_CCBS5;
		} else {
			/* ETSI PTP mode network A side. */
			timer_id = cc_record->is_ccnr ? PRI_TIMER_T_CCNR6 : PRI_TIMER_T_CCBS6;
		}
		duration = ctrl->timers[timer_id];
		break;
	case PRI_SWITCH_QSIG:
		timer_id = cc_record->is_ccnr ? PRI_TIMER_QSIG_CCNR_T2 : PRI_TIMER_QSIG_CCBS_T2;
		duration = ctrl->timers[timer_id];
		break;
	default:
		/* Timer not defined for this switch type.  Should never happen. */
		pri_error(ctrl, "!! A CC supervision timer is not defined!");
		duration = 0;
		break;
	}
	cc_record->t_supervision = pri_schedule_event(ctrl, duration,
		pri_cc_timeout_t_supervision, cc_record);
}

/*!
 * \internal
 * \brief FSM action to stop the T_RECALL timer.
 *
 * \param ctrl D channel controller.
 * \param cc_record Call completion record to process event.
 *
 * \return Nothing
 */
static void pri_cc_act_stop_t_recall(struct pri *ctrl, struct pri_cc_record *cc_record)
{
	PRI_CC_ACT_DEBUG_OUTPUT(ctrl, cc_record->record_id);
	pri_schedule_del(ctrl, cc_record->t_recall);
	cc_record->t_recall = 0;
}

/*!
 * \internal
 * \brief T_RECALL timeout callback.
 *
 * \param data CC record pointer.
 *
 * \return Nothing
 */
static void pri_cc_timeout_t_recall(void *data)
{
	struct pri_cc_record *cc_record = data;

	cc_record->t_recall = 0;
	q931_cc_timeout(cc_record->ctrl, cc_record, CC_EVENT_TIMEOUT_T_RECALL);
}

/*!
 * \internal
 * \brief FSM action to start the T_RECALL timer.
 *
 * \param ctrl D channel controller.
 * \param cc_record Call completion record to process event.
 *
 * \return Nothing
 */
static void pri_cc_act_start_t_recall(struct pri *ctrl, struct pri_cc_record *cc_record)
{
	int duration;

	PRI_CC_ACT_DEBUG_OUTPUT(ctrl, cc_record->record_id);
	if (cc_record->t_recall) {
		pri_error(ctrl, "!! T_RECALL is already running!");
		pri_schedule_del(ctrl, cc_record->t_recall);
	}
	switch (ctrl->switchtype) {
	case PRI_SWITCH_EUROISDN_E1:
	case PRI_SWITCH_EUROISDN_T1:
		duration = ctrl->timers[PRI_TIMER_T_CCBS3];
		break;
	case PRI_SWITCH_QSIG:
		duration = ctrl->timers[PRI_TIMER_QSIG_CC_T3];
		break;
	default:
		/* Timer not defined for this switch type.  Should never happen. */
		pri_error(ctrl, "!! A CC recall timer is not defined!");
		duration = 0;
		break;
	}
	cc_record->t_recall = pri_schedule_event(ctrl, duration, pri_cc_timeout_t_recall,
		cc_record);
}

/*!
 * \internal
 * \brief FSM action to send the EraseCallLinkageID message.
 *
 * \param ctrl D channel controller.
 * \param cc_record Call completion record to process event.
 *
 * \return Nothing
 */
static void pri_cc_act_send_erase_call_linkage_id(struct pri *ctrl, struct pri_cc_record *cc_record)
{
	PRI_CC_ACT_DEBUG_OUTPUT(ctrl, cc_record->record_id);
	send_erase_call_linkage_id(ctrl, cc_record->signaling, cc_record);
}

/*!
 * \internal
 * \brief FSM action to send the CCBSErase message.
 *
 * \param ctrl D channel controller.
 * \param cc_record Call completion record to process event.
 * \param reason CCBS Erase reason
 *  normal-unspecified(0), t-CCBS2-timeout(1), t-CCBS3-timeout(2), basic-call-failed(3)
 *
 * \return Nothing
 */
static void pri_cc_act_send_ccbs_erase(struct pri *ctrl, struct pri_cc_record *cc_record, int reason)
{
	PRI_CC_ACT_DEBUG_OUTPUT(ctrl, cc_record->record_id);
	send_ccbs_erase(ctrl, cc_record->signaling, cc_record, reason);
}

/*!
 * \internal
 * \brief Find the T_CCBS1 timer/CCBSStatusRequest message.
 *
 * \param cc_record Call completion record to process event.
 *
 * \return Facility message pointer or NULL if not active.
 */
static struct apdu_event *pri_cc_get_t_ccbs1_status(struct pri_cc_record *cc_record)
{
	return pri_call_apdu_find(cc_record->signaling,
		cc_record->fsm.ptmp.t_ccbs1_invoke_id);
}

/*!
 * \internal
 * \brief FSM action to stop the PTMP T_CCBS1 timer.
 *
 * \param ctrl D channel controller.
 * \param cc_record Call completion record to process event.
 *
 * \return Nothing
 */
static void pri_cc_act_stop_t_ccbs1(struct pri *ctrl, struct pri_cc_record *cc_record)
{
	struct apdu_event *msg;

	PRI_CC_ACT_DEBUG_OUTPUT(ctrl, cc_record->record_id);

	msg = pri_call_apdu_find(cc_record->signaling, cc_record->fsm.ptmp.t_ccbs1_invoke_id);
	if (msg) {
		cc_record->fsm.ptmp.t_ccbs1_invoke_id = APDU_INVALID_INVOKE_ID;
		pri_call_apdu_delete(cc_record->signaling, msg);
	}
}

/*!
 * \internal
 * \brief CCBSStatusRequest response callback function.
 *
 * \param reason Reason callback is called.
 * \param ctrl D channel controller.
 * \param call Q.931 call leg.
 * \param apdu APDU queued entry.  Do not change!
 * \param msg APDU response message data.  (NULL if was not the reason called.)
 *
 * \return TRUE if no more responses are expected.
 */
static int pri_cc_ccbs_status_response(enum APDU_CALLBACK_REASON reason, struct pri *ctrl, struct q931_call *call, struct apdu_event *apdu, const struct apdu_msg_data *msg)
{
	struct pri_cc_record *cc_record;

	cc_record = apdu->response.user.ptr;
	switch (reason) {
	case APDU_CALLBACK_REASON_ERROR:
		cc_record->fsm.ptmp.t_ccbs1_invoke_id = APDU_INVALID_INVOKE_ID;
		break;
	case APDU_CALLBACK_REASON_TIMEOUT:
		cc_record->fsm.ptmp.t_ccbs1_invoke_id = APDU_INVALID_INVOKE_ID;
		pri_cc_event(ctrl, call, cc_record, CC_EVENT_TIMEOUT_T_CCBS1);
		break;
	case APDU_CALLBACK_REASON_MSG_RESULT:
		pri_cc_event(ctrl, call, cc_record,
			msg->response.result->args.etsi.CCBSStatusRequest.free
			? CC_EVENT_A_FREE : CC_EVENT_A_BUSY);
		break;
	default:
		break;
	}
	return 0;
}

/*!
 * \internal
 * \brief Encode and queue an CCBSStatusRequest message.
 *
 * \param ctrl D channel controller for diagnostic messages or global options.
 * \param call Call leg from which to encode CCBSStatusRequest.
 * \param cc_record Call completion record to process event.
 *
 * \retval 0 on success.
 * \retval -1 on error.
 */
static int rose_ccbs_status_request(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record)
{
	unsigned char buffer[256];
	unsigned char *end;
	struct apdu_callback_data response;

	end =
		enc_etsi_ptmp_ccbs_status_request(ctrl, buffer, buffer + sizeof(buffer),
			cc_record);
	if (!end) {
		return -1;
	}

	memset(&response, 0, sizeof(response));
	cc_record->fsm.ptmp.t_ccbs1_invoke_id = ctrl->last_invoke;
	response.invoke_id = ctrl->last_invoke;
	response.timeout_time = ctrl->timers[PRI_TIMER_T_CCBS1];
	response.callback = pri_cc_ccbs_status_response;
	response.user.ptr = cc_record;
	return pri_call_apdu_queue(call, Q931_FACILITY, buffer, end - buffer, &response);
}

/*!
 * \internal
 * \brief Encode and send an CCBSStatusRequest message.
 *
 * \param ctrl D channel controller for diagnostic messages or global options.
 * \param call Call leg from which to encode CCBSStatusRequest.
 * \param cc_record Call completion record to process event.
 *
 * \retval 0 on success.
 * \retval -1 on error.
 */
static int send_ccbs_status_request(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record)
{
/*
 * XXX May need to add called-party-ie with Party A number in FACILITY message. (CCBSStatusRequest)
 * ETSI EN 300-195-1 Section 5.41 MSN interaction.
 */
	if (rose_ccbs_status_request(ctrl, call, cc_record)
		|| q931_facility(ctrl, call)) {
		pri_message(ctrl,
			"Could not schedule facility message for CCBSStatusRequest.\n");
		return -1;
	}

	return 0;
}

/*!
 * \internal
 * \brief FSM action to send the CCBSStatusRequest message.
 *
 * \param ctrl D channel controller.
 * \param cc_record Call completion record to process event.
 *
 * \return Nothing
 */
static void pri_cc_act_send_ccbs_status_request(struct pri *ctrl, struct pri_cc_record *cc_record)
{
	PRI_CC_ACT_DEBUG_OUTPUT(ctrl, cc_record->record_id);
	send_ccbs_status_request(ctrl, cc_record->signaling, cc_record);
}

/*!
 * \internal
 * \brief FSM action to stop the PTMP T_ACTIVATE timer.
 *
 * \param ctrl D channel controller.
 * \param cc_record Call completion record to process event.
 *
 * \return Nothing
 */
static void pri_cc_act_stop_t_activate(struct pri *ctrl, struct pri_cc_record *cc_record)
{
	struct apdu_event *msg;

	PRI_CC_ACT_DEBUG_OUTPUT(ctrl, cc_record->record_id);

	if (!cc_record->signaling) {
		return;
	}
	msg = pri_call_apdu_find(cc_record->signaling, cc_record->t_activate_invoke_id);
	if (msg) {
		cc_record->t_activate_invoke_id = APDU_INVALID_INVOKE_ID;
		pri_call_apdu_delete(cc_record->signaling, msg);
	}
}

/*!
 * \internal
 * \brief cc-request PTMP response callback function.
 *
 * \param reason Reason callback is called.
 * \param ctrl D channel controller.
 * \param call Q.931 call leg.
 * \param apdu APDU queued entry.  Do not change!
 * \param msg APDU response message data.  (NULL if was not the reason called.)
 *
 * \return TRUE if no more responses are expected.
 */
static int pri_cc_req_response_ptmp(enum APDU_CALLBACK_REASON reason, struct pri *ctrl, struct q931_call *call, struct apdu_event *apdu, const struct apdu_msg_data *msg)
{
	struct pri_cc_record *cc_record;

	cc_record = apdu->response.user.ptr;

	switch (reason) {
	case APDU_CALLBACK_REASON_ERROR:
		cc_record->t_activate_invoke_id = APDU_INVALID_INVOKE_ID;
		break;
	case APDU_CALLBACK_REASON_TIMEOUT:
		cc_record->t_activate_invoke_id = APDU_INVALID_INVOKE_ID;
		pri_cc_event(ctrl, call, cc_record, CC_EVENT_TIMEOUT_T_ACTIVATE);
		break;
	case APDU_CALLBACK_REASON_MSG_RESULT:
		/*
		 * Since we received this facility, we will not be allocating any
		 * reference and linkage id's.
		 */
		cc_record->ccbs_reference_id =
			msg->response.result->args.etsi.CCBSRequest.ccbs_reference & 0x7F;
		cc_record->option.recall_mode =
			msg->response.result->args.etsi.CCBSRequest.recall_mode;

		pri_cc_event(ctrl, call, cc_record, CC_EVENT_CC_REQUEST_ACCEPT);
		break;
	case APDU_CALLBACK_REASON_MSG_ERROR:
		cc_record->msg.cc_req_rsp.reason = reason;
		cc_record->msg.cc_req_rsp.code = msg->response.error->code;

		pri_cc_event(ctrl, call, cc_record, CC_EVENT_CC_REQUEST_FAIL);
		break;
	case APDU_CALLBACK_REASON_MSG_REJECT:
		cc_record->msg.cc_req_rsp.reason = reason;
		cc_record->msg.cc_req_rsp.code = msg->response.reject->code;

		pri_cc_event(ctrl, call, cc_record, CC_EVENT_CC_REQUEST_FAIL);
		break;
	default:
		break;
	}

	/*
	 * No more reponses are really expected.
	 * However, the FSM will be removing the apdu_event itself instead.
	 */
	return 0;
}

/*!
 * \internal
 * \brief cc-request PTP response callback function.
 *
 * \param reason Reason callback is called.
 * \param ctrl D channel controller.
 * \param call Q.931 call leg.
 * \param apdu APDU queued entry.  Do not change!
 * \param msg APDU response message data.  (NULL if was not the reason called.)
 *
 * \return TRUE if no more responses are expected.
 */
static int pri_cc_req_response_ptp(enum APDU_CALLBACK_REASON reason, struct pri *ctrl, struct q931_call *call, struct apdu_event *apdu, const struct apdu_msg_data *msg)
{
	struct pri_cc_record *cc_record;

	cc_record = apdu->response.user.ptr;

	switch (reason) {
	case APDU_CALLBACK_REASON_ERROR:
		cc_record->t_activate_invoke_id = APDU_INVALID_INVOKE_ID;
		break;
	case APDU_CALLBACK_REASON_TIMEOUT:
		cc_record->t_activate_invoke_id = APDU_INVALID_INVOKE_ID;
		pri_cc_event(ctrl, call, cc_record, CC_EVENT_TIMEOUT_T_ACTIVATE);
		break;
	case APDU_CALLBACK_REASON_MSG_RESULT:
		pri_cc_event(ctrl, call, cc_record, CC_EVENT_CC_REQUEST_ACCEPT);
		break;
	case APDU_CALLBACK_REASON_MSG_ERROR:
		cc_record->msg.cc_req_rsp.reason = reason;
		cc_record->msg.cc_req_rsp.code = msg->response.error->code;

		pri_cc_event(ctrl, call, cc_record, CC_EVENT_CC_REQUEST_FAIL);
		break;
	case APDU_CALLBACK_REASON_MSG_REJECT:
		cc_record->msg.cc_req_rsp.reason = reason;
		cc_record->msg.cc_req_rsp.code = msg->response.reject->code;

		pri_cc_event(ctrl, call, cc_record, CC_EVENT_CC_REQUEST_FAIL);
		break;
	default:
		break;
	}

	/*
	 * No more reponses are really expected.
	 * However, the FSM will be removing the apdu_event itself instead.
	 */
	return 0;
}

/*!
 * \internal
 * \brief cc-request Q.SIG response callback function.
 *
 * \param reason Reason callback is called.
 * \param ctrl D channel controller.
 * \param call Q.931 call leg.
 * \param apdu APDU queued entry.  Do not change!
 * \param msg APDU response message data.  (NULL if was not the reason called.)
 *
 * \return TRUE if no more responses are expected.
 */
static int pri_cc_req_response_qsig(enum APDU_CALLBACK_REASON reason, struct pri *ctrl, struct q931_call *call, struct apdu_event *apdu, const struct apdu_msg_data *msg)
{
	struct pri_cc_record *cc_record;

	cc_record = apdu->response.user.ptr;

	switch (reason) {
	case APDU_CALLBACK_REASON_ERROR:
		cc_record->t_activate_invoke_id = APDU_INVALID_INVOKE_ID;
		break;
	case APDU_CALLBACK_REASON_TIMEOUT:
		cc_record->t_activate_invoke_id = APDU_INVALID_INVOKE_ID;
		pri_cc_event(ctrl, call, cc_record, CC_EVENT_TIMEOUT_T_ACTIVATE);
		break;
	case APDU_CALLBACK_REASON_MSG_RESULT:
		if (!cc_record->option.retain_signaling_link) {
			/* We were ambivalent about the signaling link retention option. */
			if (msg->type == Q931_CONNECT) {
				/* The far end elected to retain the signaling link. */
				cc_record->option.retain_signaling_link = 1;
			}
		}

		cc_record->fsm.qsig.msgtype = msg->type;
		pri_cc_event(ctrl, call, cc_record, CC_EVENT_CC_REQUEST_ACCEPT);
		break;
	case APDU_CALLBACK_REASON_MSG_ERROR:
		cc_record->msg.cc_req_rsp.reason = reason;
		cc_record->msg.cc_req_rsp.code = msg->response.error->code;

		cc_record->fsm.qsig.msgtype = msg->type;
		pri_cc_event(ctrl, call, cc_record, CC_EVENT_CC_REQUEST_FAIL);
		break;
	case APDU_CALLBACK_REASON_MSG_REJECT:
		cc_record->msg.cc_req_rsp.reason = reason;
		cc_record->msg.cc_req_rsp.code = msg->response.reject->code;

		cc_record->fsm.qsig.msgtype = msg->type;
		pri_cc_event(ctrl, call, cc_record, CC_EVENT_CC_REQUEST_FAIL);
		break;
	default:
		break;
	}

	/*
	 * No more reponses are really expected.
	 * However, the FSM will be removing the apdu_event itself instead.
	 */
	return 0;
}

/*!
 * \internal
 * \brief Encode and queue a cc-request message.
 *
 * \param ctrl D channel controller for diagnostic messages or global options.
 * \param call Call leg from which to encode cc-request.
 * \param cc_record Call completion record to process event.
 *
 * \retval 0 on success.
 * \retval -1 on error.
 */
static int rose_cc_request(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record)
{
	unsigned char buffer[256];
	unsigned char *end;
	struct apdu_callback_data response;
	int msgtype;

	memset(&response, 0, sizeof(response));

	switch (ctrl->switchtype) {
	case PRI_SWITCH_EUROISDN_E1:
	case PRI_SWITCH_EUROISDN_T1:
		if (PTMP_MODE(ctrl)) {
			end =
				enc_etsi_ptmp_cc_request(ctrl, buffer, buffer + sizeof(buffer),
					cc_record);
			msgtype = Q931_FACILITY;
			response.callback = pri_cc_req_response_ptmp;
		} else {
			end =
				enc_etsi_ptp_cc_request(ctrl, buffer, buffer + sizeof(buffer), cc_record);
			msgtype = Q931_REGISTER;
			response.callback = pri_cc_req_response_ptp;
		}
		response.timeout_time = ctrl->timers[PRI_TIMER_T_ACTIVATE];
		break;
	case PRI_SWITCH_QSIG:
		end = enc_qsig_cc_request(ctrl, buffer, buffer + sizeof(buffer), cc_record);
		msgtype = Q931_SETUP;
		response.callback = pri_cc_req_response_qsig;
		response.timeout_time = ctrl->timers[PRI_TIMER_QSIG_CC_T1];
		break;
	default:
		return -1;
	}
	if (!end) {
		return -1;
	}

	response.user.ptr = cc_record;
	response.invoke_id = ctrl->last_invoke;
	cc_record->t_activate_invoke_id = ctrl->last_invoke;
	return pri_call_apdu_queue(call, msgtype, buffer, end - buffer, &response);
}

/*!
 * \internal
 * \brief FSM action to queue the cc-request message.
 *
 * \param ctrl D channel controller.
 * \param cc_record Call completion record to process event.
 * \param call Call leg from which to encode cc-request.
 *
 * \return Nothing
 */
static void pri_cc_act_queue_cc_request(struct pri *ctrl, struct pri_cc_record *cc_record, q931_call *call)
{
	PRI_CC_ACT_DEBUG_OUTPUT(ctrl, cc_record->record_id);
	if (rose_cc_request(ctrl, call, cc_record)) {
		pri_message(ctrl, "Could not queue message for cc-request.\n");
	}
}

/*!
 * \internal
 * \brief FSM action to send the CCBSDeactivate message.
 *
 * \param ctrl D channel controller.
 * \param cc_record Call completion record to process event.
 *
 * \return Nothing
 */
static void pri_cc_act_send_cc_deactivate_req(struct pri *ctrl, struct pri_cc_record *cc_record)
{
	PRI_CC_ACT_DEBUG_OUTPUT(ctrl, cc_record->record_id);
	send_cc_deactivate_req(ctrl, cc_record->signaling, cc_record);
}

/*!
 * \internal
 * \brief FSM action to send the CCBSBFree message.
 *
 * \param ctrl D channel controller.
 * \param cc_record Call completion record to process event.
 *
 * \return Nothing
 */
static void pri_cc_act_send_ccbs_b_free(struct pri *ctrl, struct pri_cc_record *cc_record)
{
	PRI_CC_ACT_DEBUG_OUTPUT(ctrl, cc_record->record_id);
	send_ccbs_b_free(ctrl, cc_record->signaling, cc_record);
}

/*!
 * \internal
 * \brief FSM action to send the remote user free message.
 *
 * \param ctrl D channel controller.
 * \param cc_record Call completion record to process event.
 *
 * \return Nothing
 */
static void pri_cc_act_send_remote_user_free(struct pri *ctrl, struct pri_cc_record *cc_record)
{
	PRI_CC_ACT_DEBUG_OUTPUT(ctrl, cc_record->record_id);
	send_remote_user_free(ctrl, cc_record);
}

/*!
 * \internal
 * \brief FSM action to send the CALL_PROCEEDING message on the signaling link.
 *
 * \param ctrl D channel controller.
 * \param cc_record Call completion record to process event.
 *
 * \return Nothing
 */
static void pri_cc_act_send_call_proceeding(struct pri *ctrl, struct pri_cc_record *cc_record)
{
	PRI_CC_ACT_DEBUG_OUTPUT(ctrl, cc_record->record_id);
	pri_proceeding(ctrl, cc_record->signaling, 0, 0);
}

/*!
 * \internal
 * \brief FSM action to send the CC suspend message.
 *
 * \param ctrl D channel controller.
 * \param cc_record Call completion record to process event.
 *
 * \return Nothing
 */
static void pri_cc_act_send_cc_suspend(struct pri *ctrl, struct pri_cc_record *cc_record)
{
	PRI_CC_ACT_DEBUG_OUTPUT(ctrl, cc_record->record_id);
	send_cc_suspend(ctrl, cc_record);
}

/*!
 * \internal
 * \brief FSM action to send the CC resume message.
 *
 * \param ctrl D channel controller.
 * \param cc_record Call completion record to process event.
 *
 * \return Nothing
 */
static void pri_cc_act_send_cc_resume(struct pri *ctrl, struct pri_cc_record *cc_record)
{
	PRI_CC_ACT_DEBUG_OUTPUT(ctrl, cc_record->record_id);
	send_cc_resume(ctrl, cc_record);
}

/*!
 * \internal
 * \brief FSM action to send the ccCancel message.
 *
 * \param ctrl D channel controller.
 * \param cc_record Call completion record to process event.
 *
 * \return Nothing
 */
static void pri_cc_act_send_cc_cancel(struct pri *ctrl, struct pri_cc_record *cc_record)
{
	PRI_CC_ACT_DEBUG_OUTPUT(ctrl, cc_record->record_id);
	send_cc_cancel(ctrl, cc_record);
}

/*!
 * \internal
 * \brief FSM action to send the CCBSStopAlerting message.
 *
 * \param ctrl D channel controller.
 * \param cc_record Call completion record to process event.
 *
 * \return Nothing
 */
static void pri_cc_act_send_ccbs_stop_alerting(struct pri *ctrl, struct pri_cc_record *cc_record)
{
	PRI_CC_ACT_DEBUG_OUTPUT(ctrl, cc_record->record_id);
	send_ccbs_stop_alerting(ctrl, cc_record->signaling, cc_record);
}

/*!
 * \internal
 * \brief FSM action to release the call linkage id.
 *
 * \param ctrl D channel controller.
 * \param cc_record Call completion record to process event.
 *
 * \return Nothing
 */
static void pri_cc_act_release_link_id(struct pri *ctrl, struct pri_cc_record *cc_record)
{
	PRI_CC_ACT_DEBUG_OUTPUT(ctrl, cc_record->record_id);
	cc_record->call_linkage_id = CC_PTMP_INVALID_ID;
}

/*!
 * \internal
 * \brief FSM action to set the Q.SIG retain-signaling-link option.
 *
 * \param ctrl D channel controller.
 * \param cc_record Call completion record to process event.
 *
 * \return Nothing
 */
static void pri_cc_act_set_retain_signaling_link(struct pri *ctrl, struct pri_cc_record *cc_record)
{
	PRI_CC_ACT_DEBUG_OUTPUT(ctrl, cc_record->record_id);
	cc_record->option.retain_signaling_link = 1;
}

/*!
 * \internal
 * \brief FSM action to reset the raw A status request no response count.
 *
 * \param ctrl D channel controller.
 * \param cc_record Call completion record to process event.
 *
 * \return Nothing
 */
static void pri_cc_act_raw_status_count_reset(struct pri *ctrl, struct pri_cc_record *cc_record)
{
	PRI_CC_ACT_DEBUG_OUTPUT(ctrl, cc_record->record_id);
	cc_record->fsm.ptmp.party_a_status_count = 0;
}

/*!
 * \internal
 * \brief FSM action to increment the raw A status request no response count.
 *
 * \param ctrl D channel controller.
 * \param cc_record Call completion record to process event.
 *
 * \return Nothing
 */
static void pri_cc_act_raw_status_count_increment(struct pri *ctrl, struct pri_cc_record *cc_record)
{
	PRI_CC_ACT_DEBUG_OUTPUT(ctrl, cc_record->record_id);
	++cc_record->fsm.ptmp.party_a_status_count;
}

/*!
 * \internal
 * \brief FSM action to reset raw A status.
 *
 * \param ctrl D channel controller.
 * \param cc_record Call completion record to process event.
 *
 * \return Nothing
 */
static void pri_cc_act_reset_raw_a_status(struct pri *ctrl, struct pri_cc_record *cc_record)
{
	PRI_CC_ACT_DEBUG_OUTPUT(ctrl, cc_record->record_id);
	cc_record->fsm.ptmp.party_a_status_acc = CC_PARTY_A_AVAILABILITY_INVALID;
}

/*!
 * \internal
 * \brief FSM action to add raw A status with busy.
 *
 * \param ctrl D channel controller.
 * \param cc_record Call completion record to process event.
 *
 * \return Nothing
 */
static void pri_cc_act_add_raw_a_status_busy(struct pri *ctrl, struct pri_cc_record *cc_record)
{
	PRI_CC_ACT_DEBUG_OUTPUT(ctrl, cc_record->record_id);
	if (cc_record->fsm.ptmp.party_a_status_acc != CC_PARTY_A_AVAILABILITY_FREE) {
		cc_record->fsm.ptmp.party_a_status_acc = CC_PARTY_A_AVAILABILITY_BUSY;
	}
}

/*!
 * \internal
 * \brief FSM action to set raw A status to free.
 *
 * \param ctrl D channel controller.
 * \param cc_record Call completion record to process event.
 *
 * \return Nothing
 */
static void pri_cc_act_set_raw_a_status_free(struct pri *ctrl, struct pri_cc_record *cc_record)
{
	PRI_CC_ACT_DEBUG_OUTPUT(ctrl, cc_record->record_id);
	cc_record->fsm.ptmp.party_a_status_acc = CC_PARTY_A_AVAILABILITY_FREE;
}

/*!
 * \internal
 * \brief Fill in the status response party A status update event.
 *
 * \param ctrl D channel controller.
 * \param call Q.931 call leg.
 * \param cc_record Call completion record to process event.
 *
 * \return Nothing
 */
static void pri_cc_fill_status_rsp_a(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record)
{
	struct pri_subcommand *subcmd;

	if (cc_record->fsm.ptmp.party_a_status_acc == CC_PARTY_A_AVAILABILITY_INVALID) {
		/* Accumulated party A status is invalid so don't pass it up. */
		return;
	}

	subcmd = q931_alloc_subcommand(ctrl);
	if (!subcmd) {
		return;
	}

	subcmd->cmd = PRI_SUBCMD_CC_STATUS_REQ_RSP;
	subcmd->u.cc_status_req_rsp.cc_id =  cc_record->record_id;
	subcmd->u.cc_status_req_rsp.status =
		(cc_record->fsm.ptmp.party_a_status_acc == CC_PARTY_A_AVAILABILITY_FREE)
		? 0 /* free */ : 1 /* busy */;
}

/*!
 * \internal
 * \brief Pass up party A status response to upper layer (indirectly).
 *
 * \param data CC record pointer.
 *
 * \return Nothing
 */
static void pri_cc_indirect_status_rsp_a(void *data)
{
	struct pri_cc_record *cc_record = data;

	cc_record->t_indirect = 0;
	q931_cc_indirect(cc_record->ctrl, cc_record, pri_cc_fill_status_rsp_a);
}

/*!
 * \internal
 * \brief FSM action to pass up party A status response to upper layer (indirectly).
 *
 * \param ctrl D channel controller.
 * \param cc_record Call completion record to process event.
 *
 * \return Nothing
 *
 * \note
 * Warning:  Must not use this action with pri_cc_act_set_self_destruct() in the
 * same event.
 */
static void pri_cc_act_pass_up_status_rsp_a_indirect(struct pri *ctrl, struct pri_cc_record *cc_record)
{
	PRI_CC_ACT_DEBUG_OUTPUT(ctrl, cc_record->record_id);
	if (cc_record->fsm.ptmp.party_a_status_acc != CC_PARTY_A_AVAILABILITY_INVALID) {
		/* Accumulated party A status is not invalid so pass it up. */
		if (cc_record->t_indirect) {
			pri_error(ctrl, "!! An indirect action is already active!");
			pri_schedule_del(ctrl, cc_record->t_indirect);
		}
		cc_record->t_indirect = pri_schedule_event(ctrl, 0, pri_cc_indirect_status_rsp_a,
			cc_record);
	}
}

/*!
 * \internal
 * \brief FSM action to pass up party A status response to upper layer.
 *
 * \param ctrl D channel controller.
 * \param cc_record Call completion record to process event.
 *
 * \return Nothing
 */
static void pri_cc_act_pass_up_status_rsp_a(struct pri *ctrl, struct pri_cc_record *cc_record)
{
	PRI_CC_ACT_DEBUG_OUTPUT(ctrl, cc_record->record_id);
	pri_cc_fill_status_rsp_a(ctrl, cc_record->signaling, cc_record);
}

/*!
 * \internal
 * \brief FSM action to promote raw A status.
 *
 * \param ctrl D channel controller.
 * \param cc_record Call completion record to process event.
 *
 * \return Nothing
 */
static void pri_cc_act_promote_raw_a_status(struct pri *ctrl, struct pri_cc_record *cc_record)
{
	PRI_CC_ACT_DEBUG_OUTPUT(ctrl, cc_record->record_id);
	cc_record->party_a_status = cc_record->fsm.ptmp.party_a_status_acc;
}

/*!
 * \internal
 * \brief FSM action to reset A status.
 *
 * \param ctrl D channel controller.
 * \param cc_record Call completion record to process event.
 *
 * \return Nothing
 */
static void pri_cc_act_reset_a_status(struct pri *ctrl, struct pri_cc_record *cc_record)
{
	PRI_CC_ACT_DEBUG_OUTPUT(ctrl, cc_record->record_id);
	cc_record->party_a_status = CC_PARTY_A_AVAILABILITY_INVALID;
}

/*!
 * \internal
 * \brief FSM action to set A status as busy.
 *
 * \param ctrl D channel controller.
 * \param cc_record Call completion record to process event.
 *
 * \return Nothing
 */
static void pri_cc_act_set_a_status_busy(struct pri *ctrl, struct pri_cc_record *cc_record)
{
	PRI_CC_ACT_DEBUG_OUTPUT(ctrl, cc_record->record_id);
	cc_record->party_a_status = CC_PARTY_A_AVAILABILITY_BUSY;
}

/*!
 * \internal
 * \brief FSM action to set A status as free.
 *
 * \param ctrl D channel controller.
 * \param cc_record Call completion record to process event.
 *
 * \return Nothing
 */
static void pri_cc_act_set_a_status_free(struct pri *ctrl, struct pri_cc_record *cc_record)
{
	PRI_CC_ACT_DEBUG_OUTPUT(ctrl, cc_record->record_id);
	cc_record->party_a_status = CC_PARTY_A_AVAILABILITY_FREE;
}

/*!
 * \internal
 * \brief Fill in the party A status update event.
 *
 * \param ctrl D channel controller.
 * \param call Q.931 call leg.
 * \param cc_record Call completion record to process event.
 *
 * \return Nothing
 */
static void pri_cc_fill_status_a(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record)
{
	struct pri_subcommand *subcmd;

	if (cc_record->party_a_status == CC_PARTY_A_AVAILABILITY_INVALID) {
		/* Party A status is invalid so don't pass it up. */
		return;
	}

	subcmd = q931_alloc_subcommand(ctrl);
	if (!subcmd) {
		return;
	}

	subcmd->cmd = PRI_SUBCMD_CC_STATUS;
	subcmd->u.cc_status.cc_id =  cc_record->record_id;
	subcmd->u.cc_status.status =
		(cc_record->party_a_status == CC_PARTY_A_AVAILABILITY_FREE)
		? 0 /* free */ : 1 /* busy */;
}

/*!
 * \internal
 * \brief Pass up party A status to upper layer (indirectly).
 *
 * \param data CC record pointer.
 *
 * \return Nothing
 */
static void pri_cc_indirect_status_a(void *data)
{
	struct pri_cc_record *cc_record = data;

	cc_record->t_indirect = 0;
	q931_cc_indirect(cc_record->ctrl, cc_record, pri_cc_fill_status_a);
}

/*!
 * \internal
 * \brief FSM action to pass up party A status to upper layer (indirectly).
 *
 * \param ctrl D channel controller.
 * \param cc_record Call completion record to process event.
 *
 * \return Nothing
 *
 * \note
 * Warning:  Must not use this action with pri_cc_act_set_self_destruct() in the
 * same event.
 */
static void pri_cc_act_pass_up_a_status_indirect(struct pri *ctrl, struct pri_cc_record *cc_record)
{
	PRI_CC_ACT_DEBUG_OUTPUT(ctrl, cc_record->record_id);
	if (cc_record->party_a_status != CC_PARTY_A_AVAILABILITY_INVALID) {
		/* Party A status is not invalid so pass it up. */
		if (cc_record->t_indirect) {
			pri_error(ctrl, "!! An indirect action is already active!");
			pri_schedule_del(ctrl, cc_record->t_indirect);
		}
		cc_record->t_indirect = pri_schedule_event(ctrl, 0, pri_cc_indirect_status_a,
			cc_record);
	}
}

/*!
 * \internal
 * \brief FSM action to pass up party A status to upper layer.
 *
 * \param ctrl D channel controller.
 * \param cc_record Call completion record to process event.
 *
 * \return Nothing
 */
static void pri_cc_act_pass_up_a_status(struct pri *ctrl, struct pri_cc_record *cc_record)
{
	PRI_CC_ACT_DEBUG_OUTPUT(ctrl, cc_record->record_id);
	pri_cc_fill_status_a(ctrl, cc_record->signaling, cc_record);
}

/*!
 * \internal
 * \brief FSM action to pass up CC request (CCBS/CCNR) to upper layer.
 *
 * \param ctrl D channel controller.
 * \param cc_record Call completion record to process event.
 *
 * \return Nothing
 */
static void pri_cc_act_pass_up_cc_request(struct pri *ctrl, struct pri_cc_record *cc_record)
{
	struct pri_subcommand *subcmd;

	PRI_CC_ACT_DEBUG_OUTPUT(ctrl, cc_record->record_id);

	subcmd = q931_alloc_subcommand(ctrl);
	if (!subcmd) {
		return;
	}

	subcmd->cmd = PRI_SUBCMD_CC_REQ;
	subcmd->u.cc_request.cc_id =  cc_record->record_id;
	subcmd->u.cc_request.mode = cc_record->is_ccnr ? 1 /* ccnr */ : 0 /* ccbs */;
}

/*!
 * \internal
 * \brief FSM action to pass up CC cancel to upper layer.
 *
 * \param ctrl D channel controller.
 * \param cc_record Call completion record to process event.
 *
 * \return Nothing
 */
static void pri_cc_act_pass_up_cc_cancel(struct pri *ctrl, struct pri_cc_record *cc_record)
{
	struct pri_subcommand *subcmd;

	PRI_CC_ACT_DEBUG_OUTPUT(ctrl, cc_record->record_id);

	subcmd = q931_alloc_subcommand(ctrl);
	if (!subcmd) {
		return;
	}

	subcmd->cmd = PRI_SUBCMD_CC_CANCEL;
	subcmd->u.cc_cancel.cc_id =  cc_record->record_id;
	subcmd->u.cc_cancel.is_agent = cc_record->is_agent;
}

/*!
 * \internal
 * \brief FSM action to pass up CC call to upper layer.
 *
 * \param ctrl D channel controller.
 * \param cc_record Call completion record to process event.
 *
 * \return Nothing
 */
static void pri_cc_act_pass_up_cc_call(struct pri *ctrl, struct pri_cc_record *cc_record)
{
	struct pri_subcommand *subcmd;

	PRI_CC_ACT_DEBUG_OUTPUT(ctrl, cc_record->record_id);

	subcmd = q931_alloc_subcommand(ctrl);
	if (!subcmd) {
		return;
	}

	subcmd->cmd = PRI_SUBCMD_CC_CALL;
	subcmd->u.cc_call.cc_id = cc_record->record_id;
}

/*!
 * \internal
 * \brief FSM action to pass up CC available to upper layer.
 *
 * \param ctrl D channel controller.
 * \param cc_record Call completion record to process event.
 *
 * \return Nothing
 */
static void pri_cc_act_pass_up_cc_available(struct pri *ctrl, struct pri_cc_record *cc_record)
{
	struct pri_subcommand *subcmd;

	PRI_CC_ACT_DEBUG_OUTPUT(ctrl, cc_record->record_id);

	subcmd = q931_alloc_subcommand(ctrl);
	if (!subcmd) {
		return;
	}

	subcmd->cmd = PRI_SUBCMD_CC_AVAILABLE;
	subcmd->u.cc_available.cc_id = cc_record->record_id;
}

/*!
 * \internal
 * \brief FSM action to pass up CC request response is success to upper layer.
 *
 * \param ctrl D channel controller.
 * \param cc_record Call completion record to process event.
 *
 * \return Nothing
 */
static void pri_cc_act_pass_up_cc_req_rsp_success(struct pri *ctrl, struct pri_cc_record *cc_record)
{
	struct pri_subcommand *subcmd;

	PRI_CC_ACT_DEBUG_OUTPUT(ctrl, cc_record->record_id);

	subcmd = q931_alloc_subcommand(ctrl);
	if (!subcmd) {
		return;
	}

	subcmd->cmd = PRI_SUBCMD_CC_REQ_RSP;
	subcmd->u.cc_request_rsp.cc_id = cc_record->record_id;
	subcmd->u.cc_request_rsp.status = 0;/* success */
	subcmd->u.cc_request_rsp.fail_code = 0;
}

/*!
 * \internal
 * \brief FSM action to pass up CC request response is failed to upper layer.
 *
 * \param ctrl D channel controller.
 * \param cc_record Call completion record to process event.
 *
 * \return Nothing
 */
static void pri_cc_act_pass_up_cc_req_rsp_fail(struct pri *ctrl, struct pri_cc_record *cc_record)
{
	struct pri_subcommand *subcmd;

	PRI_CC_ACT_DEBUG_OUTPUT(ctrl, cc_record->record_id);

	subcmd = q931_alloc_subcommand(ctrl);
	if (!subcmd) {
		return;
	}

	subcmd->cmd = PRI_SUBCMD_CC_REQ_RSP;
	subcmd->u.cc_request_rsp.cc_id = cc_record->record_id;
	subcmd->u.cc_request_rsp.status =
		(cc_record->msg.cc_req_rsp.reason == APDU_CALLBACK_REASON_MSG_ERROR)
		? 2 /* error */ : 3 /* reject */;
	subcmd->u.cc_request_rsp.fail_code = cc_record->msg.cc_req_rsp.code;
}

/*!
 * \internal
 * \brief FSM action to pass up CC request response is timeout to upper layer.
 *
 * \param ctrl D channel controller.
 * \param cc_record Call completion record to process event.
 *
 * \return Nothing
 */
static void pri_cc_act_pass_up_cc_req_rsp_timeout(struct pri *ctrl, struct pri_cc_record *cc_record)
{
	struct pri_subcommand *subcmd;

	PRI_CC_ACT_DEBUG_OUTPUT(ctrl, cc_record->record_id);

	subcmd = q931_alloc_subcommand(ctrl);
	if (!subcmd) {
		return;
	}

	subcmd->cmd = PRI_SUBCMD_CC_REQ_RSP;
	subcmd->u.cc_request_rsp.cc_id = cc_record->record_id;
	subcmd->u.cc_request_rsp.status = 1;/* timeout */
	subcmd->u.cc_request_rsp.fail_code = 0;
}

/*!
 * \internal
 * \brief FSM action to pass up CC B free to upper layer.
 *
 * \param ctrl D channel controller.
 * \param cc_record Call completion record to process event.
 *
 * \return Nothing
 */
static void pri_cc_act_pass_up_b_free(struct pri *ctrl, struct pri_cc_record *cc_record)
{
	struct pri_subcommand *subcmd;

	PRI_CC_ACT_DEBUG_OUTPUT(ctrl, cc_record->record_id);

	subcmd = q931_alloc_subcommand(ctrl);
	if (!subcmd) {
		return;
	}

	subcmd->cmd = PRI_SUBCMD_CC_B_FREE;
	subcmd->u.cc_b_free.cc_id =  cc_record->record_id;
}

/*!
 * \internal
 * \brief FSM action to pass up CC remote user free to upper layer.
 *
 * \param ctrl D channel controller.
 * \param cc_record Call completion record to process event.
 *
 * \return Nothing
 */
static void pri_cc_act_pass_up_remote_user_free(struct pri *ctrl, struct pri_cc_record *cc_record)
{
	struct pri_subcommand *subcmd;

	PRI_CC_ACT_DEBUG_OUTPUT(ctrl, cc_record->record_id);

	subcmd = q931_alloc_subcommand(ctrl);
	if (!subcmd) {
		return;
	}

	subcmd->cmd = PRI_SUBCMD_CC_REMOTE_USER_FREE;
	subcmd->u.cc_remote_user_free.cc_id =  cc_record->record_id;
}

/*!
 * \internal
 * \brief FSM action to pass up stop alerting to upper layer.
 *
 * \param ctrl D channel controller.
 * \param cc_record Call completion record to process event.
 *
 * \return Nothing
 */
static void pri_cc_act_pass_up_stop_alerting(struct pri *ctrl, struct pri_cc_record *cc_record)
{
	struct pri_subcommand *subcmd;

	PRI_CC_ACT_DEBUG_OUTPUT(ctrl, cc_record->record_id);

	subcmd = q931_alloc_subcommand(ctrl);
	if (!subcmd) {
		return;
	}

	subcmd->cmd = PRI_SUBCMD_CC_STOP_ALERTING;
	subcmd->u.cc_stop_alerting.cc_id =  cc_record->record_id;
}

/*!
 * \internal
 * \brief FSM action to send error response to recall attempt.
 *
 * \param ctrl D channel controller.
 * \param cc_record Call completion record to process event.
 * \param code Error code to put in error message response.
 *
 * \return Nothing
 */
static void pri_cc_act_send_error_recall(struct pri *ctrl, struct pri_cc_record *cc_record, enum rose_error_code code)
{
	PRI_CC_ACT_DEBUG_OUTPUT(ctrl, cc_record->record_id);
	rose_error_msg_encode(ctrl, cc_record->response.signaling, Q931_ANY_MESSAGE,
		cc_record->response.invoke_id, code);
}

/*!
 * \internal
 * \brief FSM action to queue CC recall marker.
 *
 * \param ctrl D channel controller.
 * \param cc_record Call completion record to process event.
 * \param call Q.931 call leg.
 *
 * \return Nothing
 */
static void pri_cc_act_queue_setup_recall(struct pri *ctrl, struct pri_cc_record *cc_record, q931_call *call)
{
	PRI_CC_ACT_DEBUG_OUTPUT(ctrl, cc_record->record_id);
	rose_cc_recall_encode(ctrl, call, cc_record);
}

/*!
 * \internal
 * \brief FSM action to request the call be hung up.
 *
 * \param ctrl D channel controller.
 * \param cc_record Call completion record to process event.
 * \param call Q.931 call leg.
 *
 * \return Nothing
 */
static void pri_cc_act_set_call_to_hangup(struct pri *ctrl, struct pri_cc_record *cc_record, q931_call *call)
{
	PRI_CC_ACT_DEBUG_OUTPUT(ctrl, cc_record->record_id);
	call->cc.hangup_call = 1;
}

/*!
 * \internal
 * \brief Post the CC_EVENT_HANGUP_SIGNALING event (timeout action).
 *
 * \param data CC record pointer.
 *
 * \return Nothing
 */
static void pri_cc_post_hangup_signaling(void *data)
{
	struct pri_cc_record *cc_record = data;

	cc_record->t_indirect = 0;
	q931_cc_timeout(cc_record->ctrl, cc_record, CC_EVENT_HANGUP_SIGNALING);
}

/*!
 * \internal
 * \brief FSM action to post the CC_EVENT_HANGUP_SIGNALING event indirectly.
 *
 * \param ctrl D channel controller.
 * \param cc_record Call completion record to process event.
 *
 * \return Nothing
 */
static void pri_cc_act_post_hangup_signaling(struct pri *ctrl, struct pri_cc_record *cc_record)
{
	PRI_CC_ACT_DEBUG_OUTPUT(ctrl, cc_record->record_id);
	if (cc_record->t_indirect) {
		pri_error(ctrl, "!! An indirect action is already active!");
		pri_schedule_del(ctrl, cc_record->t_indirect);
	}
	cc_record->t_indirect = pri_schedule_event(ctrl, 0, pri_cc_post_hangup_signaling,
		cc_record);
}

/*!
 * \internal
 * \brief FSM action to immediately hangup the signaling link.
 *
 * \param ctrl D channel controller.
 * \param cc_record Call completion record to process event.
 *
 * \return Nothing
 */
static void pri_cc_act_hangup_signaling_link(struct pri *ctrl, struct pri_cc_record *cc_record)
{
	PRI_CC_ACT_DEBUG_OUTPUT(ctrl, cc_record->record_id);
	pri_hangup(ctrl, cc_record->signaling, -1);
}

/*!
 * \internal
 * \brief FSM action to set original call data into recall call.
 *
 * \param ctrl D channel controller.
 * \param call Q.931 call leg.
 * \param cc_record Call completion record to process event.
 *
 * \return Nothing
 */
static void pri_cc_act_set_original_call_parameters(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record)
{
	call->called = cc_record->party_b;
	call->remote_id = cc_record->party_a;
	call->cc.saved_ie_contents = cc_record->saved_ie_contents;
	call->bc = cc_record->bc;
}

/*!
 * \internal
 * \brief CC FSM PTMP agent CC_STATE_IDLE.
 *
 * \param ctrl D channel controller.
 * \param call Q.931 call leg.
 * \param cc_record Call completion record to process event.
 * \param event Event to process.
 *
 * \return Nothing
 */
static void pri_cc_fsm_ptmp_agent_idle(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record, enum CC_EVENTS event)
{
	switch (event) {
	case CC_EVENT_AVAILABLE:
		cc_record->state = CC_STATE_PENDING_AVAILABLE;
		break;
	case CC_EVENT_CANCEL:
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		break;
	default:
		break;
	}
}

/*!
 * \internal
 * \brief CC FSM PTMP agent CC_STATE_PENDING_AVAILABLE.
 *
 * \param ctrl D channel controller.
 * \param call Q.931 call leg.
 * \param cc_record Call completion record to process event.
 * \param event Event to process.
 *
 * \return Nothing
 */
static void pri_cc_fsm_ptmp_agent_pend_avail(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record, enum CC_EVENTS event)
{
	switch (event) {
	case CC_EVENT_MSG_ALERTING:
		pri_cc_act_send_cc_available(ctrl, cc_record, call, Q931_ALERTING);
		cc_record->state = CC_STATE_AVAILABLE;
		break;
	case CC_EVENT_MSG_DISCONNECT:
		pri_cc_act_send_cc_available(ctrl, cc_record, call, Q931_DISCONNECT);
		cc_record->state = CC_STATE_AVAILABLE;
		break;
	case CC_EVENT_INTERNAL_CLEARING:
		pri_cc_act_release_link_id(ctrl, cc_record);
		pri_cc_act_pass_up_cc_cancel(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	case CC_EVENT_CANCEL:
		pri_cc_act_release_link_id(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	default:
		break;
	}
}

/*!
 * \internal
 * \brief CC FSM PTMP agent CC_STATE_AVAILABLE.
 *
 * \param ctrl D channel controller.
 * \param call Q.931 call leg.
 * \param cc_record Call completion record to process event.
 * \param event Event to process.
 *
 * \return Nothing
 */
static void pri_cc_fsm_ptmp_agent_avail(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record, enum CC_EVENTS event)
{
	switch (event) {
	case CC_EVENT_MSG_RELEASE:
	case CC_EVENT_MSG_RELEASE_COMPLETE:
		pri_cc_act_stop_t_retention(ctrl, cc_record);
		pri_cc_act_start_t_retention(ctrl, cc_record);
		break;
	case CC_EVENT_CC_REQUEST:
		pri_cc_act_pass_up_cc_request(ctrl, cc_record);
		pri_cc_act_stop_t_retention(ctrl, cc_record);
		cc_record->state = CC_STATE_REQUESTED;
		break;
	case CC_EVENT_INTERNAL_CLEARING:
		pri_cc_act_stop_t_retention(ctrl, cc_record);
		pri_cc_act_start_t_retention(ctrl, cc_record);
		break;
	case CC_EVENT_TIMEOUT_T_RETENTION:
		pri_cc_act_send_erase_call_linkage_id(ctrl, cc_record);
		pri_cc_act_release_link_id(ctrl, cc_record);
		pri_cc_act_pass_up_cc_cancel(ctrl, cc_record);
		pri_cc_act_stop_t_retention(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	case CC_EVENT_CANCEL:
		pri_cc_act_send_erase_call_linkage_id(ctrl, cc_record);
		pri_cc_act_release_link_id(ctrl, cc_record);
		pri_cc_act_stop_t_retention(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	default:
		break;
	}
}

/*!
 * \internal
 * \brief CC FSM PTMP agent CC_STATE_REQUESTED.
 *
 * \param ctrl D channel controller.
 * \param call Q.931 call leg.
 * \param cc_record Call completion record to process event.
 * \param event Event to process.
 *
 * \return Nothing
 */
static void pri_cc_fsm_ptmp_agent_req(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record, enum CC_EVENTS event)
{
	switch (event) {
	case CC_EVENT_CC_REQUEST_ACCEPT:
		pri_cc_act_send_erase_call_linkage_id(ctrl, cc_record);
		pri_cc_act_release_link_id(ctrl, cc_record);
		pri_cc_act_start_t_supervision(ctrl, cc_record);
		pri_cc_act_reset_a_status(ctrl, cc_record);
		pri_cc_act_raw_status_count_reset(ctrl, cc_record);
		cc_record->state = CC_STATE_ACTIVATED;
		break;
	case CC_EVENT_CANCEL:
		pri_cc_act_send_erase_call_linkage_id(ctrl, cc_record);
		pri_cc_act_release_link_id(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	default:
		break;
	}
}

/*!
 * \internal
 * \brief CC FSM PTMP agent CC_STATE_ACTIVATED.
 *
 * \param ctrl D channel controller.
 * \param call Q.931 call leg.
 * \param cc_record Call completion record to process event.
 * \param event Event to process.
 *
 * \return Nothing
 */
static void pri_cc_fsm_ptmp_agent_activated(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record, enum CC_EVENTS event)
{
	switch (event) {
	case CC_EVENT_RECALL:
		pri_cc_act_send_error_recall(ctrl, cc_record, ROSE_ERROR_CCBS_NotReadyForCall);
		pri_cc_act_set_call_to_hangup(ctrl, cc_record, call);
		break;
	case CC_EVENT_B_FREE:
		pri_cc_act_send_ccbs_b_free(ctrl, cc_record);
		break;
	case CC_EVENT_REMOTE_USER_FREE:
		switch (cc_record->party_a_status) {
		case CC_PARTY_A_AVAILABILITY_INVALID:
			if (!pri_cc_get_t_ccbs1_status(cc_record)) {
				pri_cc_act_reset_raw_a_status(ctrl, cc_record);
				pri_cc_act_send_ccbs_status_request(ctrl, cc_record);
				//pri_cc_act_start_t_ccbs1(ctrl, cc_record);
			}
			cc_record->state = CC_STATE_B_AVAILABLE;
			break;
		case CC_PARTY_A_AVAILABILITY_BUSY:
			pri_cc_act_pass_up_a_status_indirect(ctrl, cc_record);
			pri_cc_act_send_ccbs_b_free(ctrl, cc_record);
			if (!pri_cc_get_t_ccbs1_status(cc_record)) {
				pri_cc_act_reset_raw_a_status(ctrl, cc_record);
				pri_cc_act_send_ccbs_status_request(ctrl, cc_record);
				//pri_cc_act_start_t_ccbs1(ctrl, cc_record);
			}
			cc_record->state = CC_STATE_SUSPENDED;
			break;
		case CC_PARTY_A_AVAILABILITY_FREE:
			//pri_cc_act_pass_up_a_status_indirect(ctrl, cc_record);
			pri_cc_act_send_remote_user_free(ctrl, cc_record);
			pri_cc_act_stop_t_ccbs1(ctrl, cc_record);
			pri_cc_act_stop_extended_t_ccbs1(ctrl, cc_record);
			pri_cc_act_start_t_recall(ctrl, cc_record);
			cc_record->state = CC_STATE_WAIT_CALLBACK;
			break;
		default:
			break;
		}
		break;
	case CC_EVENT_A_STATUS:
		if (pri_cc_get_t_ccbs1_status(cc_record)) {
			pri_cc_act_pass_up_status_rsp_a_indirect(ctrl, cc_record);
		} else {
			pri_cc_act_reset_a_status(ctrl, cc_record);
			pri_cc_act_reset_raw_a_status(ctrl, cc_record);
			pri_cc_act_send_ccbs_status_request(ctrl, cc_record);
			//pri_cc_act_start_t_ccbs1(ctrl, cc_record);
			pri_cc_act_stop_extended_t_ccbs1(ctrl, cc_record);
			pri_cc_act_start_extended_t_ccbs1(ctrl, cc_record);
		}
		break;
	case CC_EVENT_A_FREE:
		pri_cc_act_raw_status_count_reset(ctrl, cc_record);
		pri_cc_act_set_raw_a_status_free(ctrl, cc_record);
		pri_cc_act_promote_raw_a_status(ctrl, cc_record);
		pri_cc_act_pass_up_a_status(ctrl, cc_record);
		pri_cc_act_stop_t_ccbs1(ctrl, cc_record);
		break;
	case CC_EVENT_A_BUSY:
		pri_cc_act_add_raw_a_status_busy(ctrl, cc_record);
		pri_cc_act_pass_up_status_rsp_a(ctrl, cc_record);
		break;
	case CC_EVENT_TIMEOUT_T_CCBS1:
		pri_cc_act_promote_raw_a_status(ctrl, cc_record);
		if (cc_record->party_a_status != CC_PARTY_A_AVAILABILITY_INVALID) {
			/* Only received User A busy. */
			pri_cc_act_raw_status_count_reset(ctrl, cc_record);
		} else {
			/* Did not get any responses. */
			pri_cc_act_raw_status_count_increment(ctrl, cc_record);
			if (cc_record->fsm.ptmp.party_a_status_count >= RAW_STATUS_COUNT_MAX) {
				/* User A no longer present. */
				pri_cc_act_send_ccbs_erase(ctrl, cc_record, 0 /* normal-unspecified */);
				pri_cc_act_pass_up_cc_cancel(ctrl, cc_record);
				pri_cc_act_stop_t_ccbs1(ctrl, cc_record);
				pri_cc_act_stop_extended_t_ccbs1(ctrl, cc_record);
				pri_cc_act_stop_t_supervision(ctrl, cc_record);
				pri_cc_act_set_self_destruct(ctrl, cc_record);
				cc_record->state = CC_STATE_IDLE;
			}
		}
		break;
	case CC_EVENT_TIMEOUT_EXTENDED_T_CCBS1:
		pri_cc_act_reset_a_status(ctrl, cc_record);
		pri_cc_act_raw_status_count_reset(ctrl, cc_record);
		break;
	case CC_EVENT_TIMEOUT_T_SUPERVISION:
		pri_cc_act_pass_up_cc_cancel(ctrl, cc_record);
		pri_cc_act_send_ccbs_erase(ctrl, cc_record, 1 /* t-CCBS2-timeout */);
		pri_cc_act_stop_t_ccbs1(ctrl, cc_record);
		pri_cc_act_stop_extended_t_ccbs1(ctrl, cc_record);
		pri_cc_act_stop_t_supervision(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	case CC_EVENT_LINK_CANCEL:
		pri_cc_act_pass_up_cc_cancel(ctrl, cc_record);
		pri_cc_act_send_ccbs_erase(ctrl, cc_record, 0 /* normal-unspecified */);
		pri_cc_act_stop_t_ccbs1(ctrl, cc_record);
		pri_cc_act_stop_extended_t_ccbs1(ctrl, cc_record);
		pri_cc_act_stop_t_supervision(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	case CC_EVENT_CANCEL:
		pri_cc_act_send_ccbs_erase(ctrl, cc_record, 0 /* normal-unspecified */);
		pri_cc_act_stop_t_ccbs1(ctrl, cc_record);
		pri_cc_act_stop_extended_t_ccbs1(ctrl, cc_record);
		pri_cc_act_stop_t_supervision(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	default:
		break;
	}
}

/*!
 * \internal
 * \brief CC FSM PTMP agent CC_STATE_B_AVAILABLE.
 *
 * \param ctrl D channel controller.
 * \param call Q.931 call leg.
 * \param cc_record Call completion record to process event.
 * \param event Event to process.
 *
 * \return Nothing
 */
static void pri_cc_fsm_ptmp_agent_b_avail(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record, enum CC_EVENTS event)
{
	switch (event) {
	case CC_EVENT_RECALL:
		pri_cc_act_send_error_recall(ctrl, cc_record, ROSE_ERROR_CCBS_NotReadyForCall);
		pri_cc_act_set_call_to_hangup(ctrl, cc_record, call);
		break;
	case CC_EVENT_A_STATUS:
		pri_cc_act_stop_extended_t_ccbs1(ctrl, cc_record);
		pri_cc_act_start_extended_t_ccbs1(ctrl, cc_record);
		pri_cc_act_pass_up_status_rsp_a_indirect(ctrl, cc_record);
		break;
	case CC_EVENT_A_FREE:
		pri_cc_act_send_remote_user_free(ctrl, cc_record);
		pri_cc_act_set_raw_a_status_free(ctrl, cc_record);
		//pri_cc_act_promote_raw_a_status(ctrl, cc_record);
		//pri_cc_act_pass_up_a_status(ctrl, cc_record);
		if (cc_record->fsm.ptmp.extended_t_ccbs1) {
			pri_cc_act_pass_up_status_rsp_a(ctrl, cc_record);
		}
		pri_cc_act_stop_t_ccbs1(ctrl, cc_record);
		pri_cc_act_stop_extended_t_ccbs1(ctrl, cc_record);
		pri_cc_act_start_t_recall(ctrl, cc_record);
		cc_record->state = CC_STATE_WAIT_CALLBACK;
		break;
	case CC_EVENT_A_BUSY:
		pri_cc_act_add_raw_a_status_busy(ctrl, cc_record);
		if (cc_record->fsm.ptmp.extended_t_ccbs1) {
			pri_cc_act_pass_up_status_rsp_a(ctrl, cc_record);
		}
		break;
	case CC_EVENT_TIMEOUT_T_CCBS1:
		if (cc_record->fsm.ptmp.party_a_status_acc != CC_PARTY_A_AVAILABILITY_INVALID) {
			/* Only received User A busy. */
			pri_cc_act_raw_status_count_reset(ctrl, cc_record);
			pri_cc_act_send_ccbs_b_free(ctrl, cc_record);
			pri_cc_act_promote_raw_a_status(ctrl, cc_record);
			pri_cc_act_pass_up_a_status(ctrl, cc_record);
			/* Optimization due to flattening. */
			//if (!pri_cc_get_t_ccbs1_status(cc_record))
			{
				pri_cc_act_reset_raw_a_status(ctrl, cc_record);
				pri_cc_act_send_ccbs_status_request(ctrl, cc_record);
				//pri_cc_act_start_t_ccbs1(ctrl, cc_record);
			}
			cc_record->state = CC_STATE_SUSPENDED;
		} else {
			/* Did not get any responses. */
			pri_cc_act_raw_status_count_increment(ctrl, cc_record);
			if (cc_record->fsm.ptmp.party_a_status_count >= RAW_STATUS_COUNT_MAX) {
				/* User A no longer present. */
				pri_cc_act_send_ccbs_erase(ctrl, cc_record, 0 /* normal-unspecified */);
				pri_cc_act_pass_up_cc_cancel(ctrl, cc_record);
				pri_cc_act_stop_t_ccbs1(ctrl, cc_record);
				pri_cc_act_stop_extended_t_ccbs1(ctrl, cc_record);
				pri_cc_act_stop_t_supervision(ctrl, cc_record);
				pri_cc_act_set_self_destruct(ctrl, cc_record);
				cc_record->state = CC_STATE_IDLE;
				break;
			}
			//pri_cc_act_reset_raw_a_status(ctrl, cc_record);
			pri_cc_act_send_ccbs_status_request(ctrl, cc_record);
			//pri_cc_act_start_t_ccbs1(ctrl, cc_record);
		}
		break;
	case CC_EVENT_TIMEOUT_T_SUPERVISION:
		pri_cc_act_pass_up_cc_cancel(ctrl, cc_record);
		pri_cc_act_send_ccbs_erase(ctrl, cc_record, 1 /* t-CCBS2-timeout */);
		pri_cc_act_stop_t_ccbs1(ctrl, cc_record);
		pri_cc_act_stop_extended_t_ccbs1(ctrl, cc_record);
		pri_cc_act_stop_t_supervision(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	case CC_EVENT_LINK_CANCEL:
		pri_cc_act_pass_up_cc_cancel(ctrl, cc_record);
		pri_cc_act_send_ccbs_erase(ctrl, cc_record, 0 /* normal-unspecified */);
		pri_cc_act_stop_t_ccbs1(ctrl, cc_record);
		pri_cc_act_stop_extended_t_ccbs1(ctrl, cc_record);
		pri_cc_act_stop_t_supervision(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	case CC_EVENT_CANCEL:
		pri_cc_act_send_ccbs_erase(ctrl, cc_record, 0 /* normal-unspecified */);
		pri_cc_act_stop_t_ccbs1(ctrl, cc_record);
		pri_cc_act_stop_extended_t_ccbs1(ctrl, cc_record);
		pri_cc_act_stop_t_supervision(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	default:
		break;
	}
}

/*!
 * \internal
 * \brief CC FSM PTMP agent CC_STATE_SUSPENDED.
 *
 * \param ctrl D channel controller.
 * \param call Q.931 call leg.
 * \param cc_record Call completion record to process event.
 * \param event Event to process.
 *
 * \return Nothing
 */
static void pri_cc_fsm_ptmp_agent_suspended(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record, enum CC_EVENTS event)
{
	switch (event) {
	case CC_EVENT_RECALL:
		pri_cc_act_send_error_recall(ctrl, cc_record, ROSE_ERROR_CCBS_NotReadyForCall);
		pri_cc_act_set_call_to_hangup(ctrl, cc_record, call);
		break;
	case CC_EVENT_A_STATUS:
		pri_cc_act_stop_extended_t_ccbs1(ctrl, cc_record);
		pri_cc_act_start_extended_t_ccbs1(ctrl, cc_record);
		pri_cc_act_pass_up_status_rsp_a_indirect(ctrl, cc_record);
		break;
	case CC_EVENT_A_FREE:
		pri_cc_act_set_raw_a_status_free(ctrl, cc_record);
		pri_cc_act_promote_raw_a_status(ctrl, cc_record);
		pri_cc_act_pass_up_a_status(ctrl, cc_record);
		if (cc_record->fsm.ptmp.extended_t_ccbs1) {
			pri_cc_act_pass_up_status_rsp_a(ctrl, cc_record);
		}
		pri_cc_act_stop_t_ccbs1(ctrl, cc_record);
		pri_cc_act_stop_extended_t_ccbs1(ctrl, cc_record);
		pri_cc_act_reset_a_status(ctrl, cc_record);
		pri_cc_act_raw_status_count_reset(ctrl, cc_record);
		cc_record->state = CC_STATE_ACTIVATED;
		break;
	case CC_EVENT_A_BUSY:
		pri_cc_act_add_raw_a_status_busy(ctrl, cc_record);
		if (cc_record->fsm.ptmp.extended_t_ccbs1) {
			pri_cc_act_pass_up_status_rsp_a(ctrl, cc_record);
		}
		break;
	case CC_EVENT_TIMEOUT_T_CCBS1:
		if (cc_record->fsm.ptmp.party_a_status_acc != CC_PARTY_A_AVAILABILITY_INVALID) {
			/* Only received User A busy. */
			pri_cc_act_raw_status_count_reset(ctrl, cc_record);
		} else {
			/* Did not get any responses. */
			pri_cc_act_raw_status_count_increment(ctrl, cc_record);
			if (cc_record->fsm.ptmp.party_a_status_count >= RAW_STATUS_COUNT_MAX) {
				/* User A no longer present. */
				pri_cc_act_send_ccbs_erase(ctrl, cc_record, 0 /* normal-unspecified */);
				pri_cc_act_pass_up_cc_cancel(ctrl, cc_record);
				pri_cc_act_stop_t_ccbs1(ctrl, cc_record);
				pri_cc_act_stop_extended_t_ccbs1(ctrl, cc_record);
				pri_cc_act_stop_t_supervision(ctrl, cc_record);
				pri_cc_act_set_self_destruct(ctrl, cc_record);
				cc_record->state = CC_STATE_IDLE;
				break;
			}
		}
		pri_cc_act_reset_raw_a_status(ctrl, cc_record);
		pri_cc_act_send_ccbs_status_request(ctrl, cc_record);
		//pri_cc_act_start_t_ccbs1(ctrl, cc_record);
		break;
	case CC_EVENT_TIMEOUT_T_SUPERVISION:
		pri_cc_act_pass_up_cc_cancel(ctrl, cc_record);
		pri_cc_act_send_ccbs_erase(ctrl, cc_record, 1 /* t-CCBS2-timeout */);
		pri_cc_act_stop_t_ccbs1(ctrl, cc_record);
		pri_cc_act_stop_extended_t_ccbs1(ctrl, cc_record);
		pri_cc_act_stop_t_supervision(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	case CC_EVENT_LINK_CANCEL:
		pri_cc_act_pass_up_cc_cancel(ctrl, cc_record);
		pri_cc_act_send_ccbs_erase(ctrl, cc_record, 0 /* normal-unspecified */);
		pri_cc_act_stop_t_ccbs1(ctrl, cc_record);
		pri_cc_act_stop_extended_t_ccbs1(ctrl, cc_record);
		pri_cc_act_stop_t_supervision(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	case CC_EVENT_CANCEL:
		pri_cc_act_send_ccbs_erase(ctrl, cc_record, 0 /* normal-unspecified */);
		pri_cc_act_stop_t_ccbs1(ctrl, cc_record);
		pri_cc_act_stop_extended_t_ccbs1(ctrl, cc_record);
		pri_cc_act_stop_t_supervision(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	default:
		break;
	}
}

/*!
 * \internal
 * \brief CC FSM PTMP agent CC_STATE_WAIT_CALLBACK.
 *
 * \param ctrl D channel controller.
 * \param call Q.931 call leg.
 * \param cc_record Call completion record to process event.
 * \param event Event to process.
 *
 * \return Nothing
 */
static void pri_cc_fsm_ptmp_agent_wait_callback(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record, enum CC_EVENTS event)
{
	switch (event) {
	case CC_EVENT_TIMEOUT_T_RECALL:
		pri_cc_act_pass_up_cc_cancel(ctrl, cc_record);
		pri_cc_act_send_ccbs_erase(ctrl, cc_record, 2 /* t-CCBS3-timeout */);
		pri_cc_act_stop_t_recall(ctrl, cc_record);
		pri_cc_act_stop_t_supervision(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	case CC_EVENT_STOP_ALERTING:
		/*
		 * If an earlier link can send us this event then we
		 * really should be configured for globalRecall like
		 * the earlier link.
		 */
		if (cc_record->option.recall_mode == 0 /* globalRecall */) {
			pri_cc_act_send_ccbs_stop_alerting(ctrl, cc_record);
		}
		pri_cc_act_stop_t_recall(ctrl, cc_record);
		pri_cc_act_reset_a_status(ctrl, cc_record);
		pri_cc_act_raw_status_count_reset(ctrl, cc_record);
		cc_record->state = CC_STATE_ACTIVATED;
		break;
	case CC_EVENT_RECALL:
		pri_cc_act_pass_up_cc_call(ctrl, cc_record);
		pri_cc_act_set_original_call_parameters(ctrl, call, cc_record);
		if (cc_record->option.recall_mode == 0 /* globalRecall */) {
			pri_cc_act_send_ccbs_stop_alerting(ctrl, cc_record);
		}
		pri_cc_act_stop_t_recall(ctrl, cc_record);
		cc_record->state = CC_STATE_CALLBACK;
		break;
	case CC_EVENT_A_STATUS:
		pri_cc_act_set_raw_a_status_free(ctrl, cc_record);
		pri_cc_act_pass_up_status_rsp_a_indirect(ctrl, cc_record);
		break;
	case CC_EVENT_TIMEOUT_T_SUPERVISION:
		pri_cc_act_pass_up_cc_cancel(ctrl, cc_record);
		pri_cc_act_send_ccbs_erase(ctrl, cc_record, 1 /* t-CCBS2-timeout */);
		pri_cc_act_stop_t_recall(ctrl, cc_record);
		pri_cc_act_stop_t_supervision(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	case CC_EVENT_LINK_CANCEL:
		pri_cc_act_pass_up_cc_cancel(ctrl, cc_record);
		pri_cc_act_send_ccbs_erase(ctrl, cc_record, 0 /* normal-unspecified */);
		pri_cc_act_stop_t_recall(ctrl, cc_record);
		pri_cc_act_stop_t_supervision(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	case CC_EVENT_CANCEL:
		pri_cc_act_send_ccbs_erase(ctrl, cc_record, 0 /* normal-unspecified */);
		pri_cc_act_stop_t_recall(ctrl, cc_record);
		pri_cc_act_stop_t_supervision(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	default:
		break;
	}
}

/*!
 * \internal
 * \brief CC FSM PTMP agent CC_STATE_CALLBACK.
 *
 * \param ctrl D channel controller.
 * \param call Q.931 call leg.
 * \param cc_record Call completion record to process event.
 * \param event Event to process.
 *
 * \return Nothing
 */
static void pri_cc_fsm_ptmp_agent_callback(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record, enum CC_EVENTS event)
{
	switch (event) {
	case CC_EVENT_RECALL:
		pri_cc_act_send_error_recall(ctrl, cc_record, ROSE_ERROR_CCBS_AlreadyAccepted);
		pri_cc_act_set_call_to_hangup(ctrl, cc_record, call);
		break;
	case CC_EVENT_A_STATUS:
		pri_cc_act_set_raw_a_status_free(ctrl, cc_record);
		pri_cc_act_pass_up_status_rsp_a_indirect(ctrl, cc_record);
		break;
	case CC_EVENT_TIMEOUT_T_SUPERVISION:
		pri_cc_act_pass_up_cc_cancel(ctrl, cc_record);
		pri_cc_act_send_ccbs_erase(ctrl, cc_record, 1 /* t-CCBS2-timeout */);
		pri_cc_act_stop_t_supervision(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	case CC_EVENT_LINK_CANCEL:
		pri_cc_act_pass_up_cc_cancel(ctrl, cc_record);
		pri_cc_act_send_ccbs_erase(ctrl, cc_record, 0 /* normal-unspecified */);
		pri_cc_act_stop_t_supervision(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	case CC_EVENT_CANCEL:
		pri_cc_act_send_ccbs_erase(ctrl, cc_record, 0 /* normal-unspecified */);
		pri_cc_act_stop_t_supervision(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	default:
		break;
	}
}

/*!
 * \internal
 * \brief CC FSM PTMP monitor CC_STATE_IDLE.
 *
 * \param ctrl D channel controller.
 * \param call Q.931 call leg.
 * \param cc_record Call completion record to process event.
 * \param event Event to process.
 *
 * \return Nothing
 */
static void pri_cc_fsm_ptmp_monitor_idle(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record, enum CC_EVENTS event)
{
	switch (event) {
	case CC_EVENT_AVAILABLE:
		/*
		 * Before event is posted:
		 *   Received CallInfoRetain
		 *   Created cc_record
		 *   Saved CallLinkageID
		 */
		pri_cc_act_pass_up_cc_available(ctrl, cc_record);
		cc_record->state = CC_STATE_AVAILABLE;
		break;
	case CC_EVENT_CANCEL:
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		break;
	default:
		break;
	}
}

/*!
 * \internal
 * \brief CC FSM PTMP monitor CC_STATE_AVAILABLE.
 *
 * \param ctrl D channel controller.
 * \param call Q.931 call leg.
 * \param cc_record Call completion record to process event.
 * \param event Event to process.
 *
 * \return Nothing
 */
static void pri_cc_fsm_ptmp_monitor_avail(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record, enum CC_EVENTS event)
{
	/*
	 * The upper layer is responsible for canceling the CC available
	 * offering as a safeguard in case the network cable is disconnected.
	 * The timer should be set much longer than the network T_RETENTION
	 * timer so normally the CC records will be cleaned up by network
	 * activity.
	 */
	switch (event) {
	case CC_EVENT_CC_REQUEST:
		/* cc_record->is_ccnr is set before event posted. */
		pri_cc_act_queue_cc_request(ctrl, cc_record, call);
		//pri_cc_act_start_t_activate(ctrl, cc_record);
		cc_record->state = CC_STATE_REQUESTED;
		break;
	case CC_EVENT_TIMEOUT_T_RETENTION:
		/*
		 * Received EraseCallLinkageID
		 * T_RETENTION expired on the network side so we will pretend
		 * that it expired on our side.
		 */
		pri_cc_act_pass_up_cc_cancel(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	case CC_EVENT_CANCEL:
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	default:
		break;
	}
}

/*!
 * \internal
 * \brief CC FSM PTMP monitor CC_STATE_REQUESTED.
 *
 * \param ctrl D channel controller.
 * \param call Q.931 call leg.
 * \param cc_record Call completion record to process event.
 * \param event Event to process.
 *
 * \return Nothing
 */
static void pri_cc_fsm_ptmp_monitor_req(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record, enum CC_EVENTS event)
{
	switch (event) {
	case CC_EVENT_CC_REQUEST_ACCEPT:
		/*
		 * Before event is posted:
		 *   Received CCBSRequest/CCNRRequest response
		 *   Saved CCBSReference
		 */
		pri_cc_act_release_link_id(ctrl, cc_record);
		pri_cc_act_pass_up_cc_req_rsp_success(ctrl, cc_record);
		pri_cc_act_stop_t_activate(ctrl, cc_record);
		/*
		 * Start T_CCBS2 or T_CCNR2 depending upon CC mode.
		 * For PTMP TE mode these timers are not defined.  However,
		 * we will use them anyway to protect our resources from leaks
		 * caused by the network cable being disconnected.  These
		 * timers should be set much longer than the network
		 * so normally the CC records will be cleaned up by network
		 * activity.
		 */
		pri_cc_act_start_t_supervision(ctrl, cc_record);
		cc_record->state = CC_STATE_ACTIVATED;
		break;
	case CC_EVENT_CC_REQUEST_FAIL:
		pri_cc_act_pass_up_cc_req_rsp_fail(ctrl, cc_record);
		pri_cc_act_pass_up_cc_cancel(ctrl, cc_record);
		pri_cc_act_stop_t_activate(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	case CC_EVENT_TIMEOUT_T_ACTIVATE:
		pri_cc_act_pass_up_cc_req_rsp_timeout(ctrl, cc_record);
		pri_cc_act_pass_up_cc_cancel(ctrl, cc_record);
		pri_cc_act_stop_t_activate(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	case CC_EVENT_LINK_CANCEL:
		/* Received CCBSErase */
		/* Claim it was a timeout */
		pri_cc_act_pass_up_cc_req_rsp_timeout(ctrl, cc_record);
		pri_cc_act_pass_up_cc_cancel(ctrl, cc_record);
		pri_cc_act_stop_t_activate(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	case CC_EVENT_CANCEL:
		cc_record->state = CC_STATE_WAIT_DESTRUCTION;
		break;
	default:
		break;
	}
}

/*!
 * \internal
 * \brief CC FSM PTMP monitor CC_STATE_WAIT_DESTRUCTION.
 *
 * \param ctrl D channel controller.
 * \param call Q.931 call leg.
 * \param cc_record Call completion record to process event.
 * \param event Event to process.
 *
 * \return Nothing
 */
static void pri_cc_fsm_ptmp_monitor_wait_destruction(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record, enum CC_EVENTS event)
{
	/* We were in the middle of a cc-request when we were asked to cancel. */
	switch (event) {
	case CC_EVENT_CC_REQUEST_ACCEPT:
		/*
		 * Before event is posted:
		 *   Received CCBSRequest/CCNRRequest response
		 *   Saved CCBSReference
		 */
		pri_cc_act_send_cc_deactivate_req(ctrl, cc_record);
		pri_cc_act_stop_t_activate(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	case CC_EVENT_CC_REQUEST_FAIL:
		pri_cc_act_stop_t_activate(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	case CC_EVENT_TIMEOUT_T_ACTIVATE:
		pri_cc_act_stop_t_activate(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	case CC_EVENT_LINK_CANCEL:
		/* Received CCBSErase */
		pri_cc_act_stop_t_activate(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	default:
		break;
	}
}

/*!
 * \internal
 * \brief CC FSM PTMP monitor CC_STATE_ACTIVATED.
 *
 * \param ctrl D channel controller.
 * \param call Q.931 call leg.
 * \param cc_record Call completion record to process event.
 * \param event Event to process.
 *
 * \return Nothing
 */
static void pri_cc_fsm_ptmp_monitor_activated(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record, enum CC_EVENTS event)
{
	switch (event) {
	case CC_EVENT_B_FREE:
		/* Received CCBSBFree */
		pri_cc_act_pass_up_b_free(ctrl, cc_record);
		break;
	case CC_EVENT_REMOTE_USER_FREE:
		/* Received CCBSRemoteUserFree */
		pri_cc_act_pass_up_remote_user_free(ctrl, cc_record);
		cc_record->state = CC_STATE_WAIT_CALLBACK;
		break;
	case CC_EVENT_TIMEOUT_T_SUPERVISION:
		pri_cc_act_send_cc_deactivate_req(ctrl, cc_record);
		pri_cc_act_pass_up_cc_cancel(ctrl, cc_record);
		pri_cc_act_stop_t_supervision(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	case CC_EVENT_LINK_CANCEL:
		/* Received CCBSErase */
		pri_cc_act_pass_up_cc_cancel(ctrl, cc_record);
		pri_cc_act_stop_t_supervision(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	case CC_EVENT_CANCEL:
		pri_cc_act_send_cc_deactivate_req(ctrl, cc_record);
		pri_cc_act_stop_t_supervision(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	default:
		break;
	}
}

/*!
 * \internal
 * \brief CC FSM PTMP monitor CC_STATE_WAIT_CALLBACK.
 *
 * \param ctrl D channel controller.
 * \param call Q.931 call leg.
 * \param cc_record Call completion record to process event.
 * \param event Event to process.
 *
 * \return Nothing
 */
static void pri_cc_fsm_ptmp_monitor_wait_callback(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record, enum CC_EVENTS event)
{
	switch (event) {
	case CC_EVENT_STOP_ALERTING:
		pri_cc_act_pass_up_stop_alerting(ctrl, cc_record);
		cc_record->state = CC_STATE_ACTIVATED;
		break;
	case CC_EVENT_RECALL:
		/* The original call parameters have already been set. */
		pri_cc_act_queue_setup_recall(ctrl, cc_record, call);
		cc_record->state = CC_STATE_CALLBACK;
		break;
	case CC_EVENT_TIMEOUT_T_SUPERVISION:
		pri_cc_act_send_cc_deactivate_req(ctrl, cc_record);
		pri_cc_act_pass_up_cc_cancel(ctrl, cc_record);
		pri_cc_act_stop_t_supervision(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	case CC_EVENT_LINK_CANCEL:
		/* Received CCBSErase */
		pri_cc_act_pass_up_cc_cancel(ctrl, cc_record);
		pri_cc_act_stop_t_supervision(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	case CC_EVENT_CANCEL:
		pri_cc_act_send_cc_deactivate_req(ctrl, cc_record);
		pri_cc_act_stop_t_supervision(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	default:
		break;
	}
}

/*!
 * \internal
 * \brief CC FSM PTMP monitor CC_STATE_CALLBACK.
 *
 * \param ctrl D channel controller.
 * \param call Q.931 call leg.
 * \param cc_record Call completion record to process event.
 * \param event Event to process.
 *
 * \return Nothing
 */
static void pri_cc_fsm_ptmp_monitor_callback(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record, enum CC_EVENTS event)
{
	/*
	 * We are waiting for the CC records to be torn down because
	 * CC is complete.
	 * This state is mainly to block CC_EVENT_STOP_ALERTING since
	 * we are the one doing the CC recall so we do not need to stop
	 * alerting.
	 */
	switch (event) {
	case CC_EVENT_TIMEOUT_T_SUPERVISION:
		pri_cc_act_send_cc_deactivate_req(ctrl, cc_record);
		pri_cc_act_pass_up_cc_cancel(ctrl, cc_record);
		pri_cc_act_stop_t_supervision(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	case CC_EVENT_LINK_CANCEL:
		/* Received CCBSErase */
		pri_cc_act_pass_up_cc_cancel(ctrl, cc_record);
		pri_cc_act_stop_t_supervision(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	case CC_EVENT_CANCEL:
		pri_cc_act_send_cc_deactivate_req(ctrl, cc_record);
		pri_cc_act_stop_t_supervision(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	default:
		break;
	}
}

/*!
 * \internal
 * \brief CC FSM PTP agent CC_STATE_IDLE.
 *
 * \param ctrl D channel controller.
 * \param call Q.931 call leg.
 * \param cc_record Call completion record to process event.
 * \param event Event to process.
 *
 * \return Nothing
 */
static void pri_cc_fsm_ptp_agent_idle(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record, enum CC_EVENTS event)
{
	switch (event) {
	case CC_EVENT_AVAILABLE:
		cc_record->state = CC_STATE_PENDING_AVAILABLE;
		break;
	case CC_EVENT_CANCEL:
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		break;
	default:
		break;
	}
}

/*!
 * \internal
 * \brief CC FSM PTP agent CC_STATE_PENDING_AVAILABLE.
 *
 * \param ctrl D channel controller.
 * \param call Q.931 call leg.
 * \param cc_record Call completion record to process event.
 * \param event Event to process.
 *
 * \return Nothing
 */
static void pri_cc_fsm_ptp_agent_pend_avail(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record, enum CC_EVENTS event)
{
	switch (event) {
	case CC_EVENT_MSG_ALERTING:
		pri_cc_act_send_cc_available(ctrl, cc_record, call, Q931_ALERTING);
		cc_record->state = CC_STATE_AVAILABLE;
		break;
	case CC_EVENT_MSG_DISCONNECT:
		pri_cc_act_send_cc_available(ctrl, cc_record, call, Q931_DISCONNECT);
		cc_record->state = CC_STATE_AVAILABLE;
		break;
	case CC_EVENT_INTERNAL_CLEARING:
		pri_cc_act_pass_up_cc_cancel(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	case CC_EVENT_CANCEL:
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	default:
		break;
	}
}

/*!
 * \internal
 * \brief CC FSM PTP agent CC_STATE_AVAILABLE.
 *
 * \param ctrl D channel controller.
 * \param call Q.931 call leg.
 * \param cc_record Call completion record to process event.
 * \param event Event to process.
 *
 * \return Nothing
 */
static void pri_cc_fsm_ptp_agent_avail(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record, enum CC_EVENTS event)
{
	/*
	 * For PTP mode the T_RETENTION timer is not defined.  However,
	 * we will use it anyway in this state to protect our resources
	 * from leaks caused by user A not requesting CC.  This timer
	 * should be set much longer than the PTMP network link to
	 * allow for variations in user A's CC offer timer.
	 */
	switch (event) {
	case CC_EVENT_MSG_RELEASE:
	case CC_EVENT_MSG_RELEASE_COMPLETE:
		pri_cc_act_stop_t_retention(ctrl, cc_record);
		pri_cc_act_start_t_retention(ctrl, cc_record);
		break;
	case CC_EVENT_CC_REQUEST:
		pri_cc_act_pass_up_cc_request(ctrl, cc_record);
		pri_cc_act_stop_t_retention(ctrl, cc_record);
		cc_record->state = CC_STATE_REQUESTED;
		break;
	case CC_EVENT_INTERNAL_CLEARING:
		pri_cc_act_stop_t_retention(ctrl, cc_record);
		pri_cc_act_start_t_retention(ctrl, cc_record);
		break;
	case CC_EVENT_TIMEOUT_T_RETENTION:
		pri_cc_act_pass_up_cc_cancel(ctrl, cc_record);
		pri_cc_act_stop_t_retention(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	case CC_EVENT_CANCEL:
		pri_cc_act_stop_t_retention(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	default:
		break;
	}
}

/*!
 * \internal
 * \brief CC FSM PTP agent CC_STATE_REQUESTED.
 *
 * \param ctrl D channel controller.
 * \param call Q.931 call leg.
 * \param cc_record Call completion record to process event.
 * \param event Event to process.
 *
 * \return Nothing
 */
static void pri_cc_fsm_ptp_agent_req(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record, enum CC_EVENTS event)
{
	switch (event) {
	case CC_EVENT_CC_REQUEST_ACCEPT:
		/* Start T_CCBS5/T_CCNR5 depending upon CC mode. */
		pri_cc_act_start_t_supervision(ctrl, cc_record);
		pri_cc_act_reset_a_status(ctrl, cc_record);
		cc_record->state = CC_STATE_ACTIVATED;
		break;
	case CC_EVENT_SIGNALING_GONE:
		/* Signaling link cleared. */
		pri_cc_act_pass_up_cc_cancel(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	case CC_EVENT_CANCEL:
		pri_cc_act_hangup_signaling_link(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	default:
		break;
	}
}

/*!
 * \internal
 * \brief CC FSM PTP agent CC_STATE_ACTIVATED.
 *
 * \param ctrl D channel controller.
 * \param call Q.931 call leg.
 * \param cc_record Call completion record to process event.
 * \param event Event to process.
 *
 * \return Nothing
 */
static void pri_cc_fsm_ptp_agent_activated(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record, enum CC_EVENTS event)
{
	switch (event) {
	case CC_EVENT_REMOTE_USER_FREE:
		pri_cc_act_pass_up_a_status_indirect(ctrl, cc_record);
		if (cc_record->party_a_status == CC_PARTY_A_AVAILABILITY_BUSY) {
			cc_record->state = CC_STATE_SUSPENDED;
		} else {
			pri_cc_act_send_remote_user_free(ctrl, cc_record);
			cc_record->state = CC_STATE_WAIT_CALLBACK;
		}
		break;
	case CC_EVENT_SUSPEND:
		/* Received CCBS_T_Suspend */
		pri_cc_act_set_a_status_busy(ctrl, cc_record);
		break;
	case CC_EVENT_RESUME:
		/* Received CCBS_T_Resume */
		pri_cc_act_reset_a_status(ctrl, cc_record);
		break;
	case CC_EVENT_RECALL:
		/* Received CCBS_T_Call */
		pri_cc_act_pass_up_cc_call(ctrl, cc_record);
		pri_cc_act_set_original_call_parameters(ctrl, call, cc_record);
		break;
	case CC_EVENT_TIMEOUT_T_SUPERVISION:
		pri_cc_act_pass_up_cc_cancel(ctrl, cc_record);
		pri_cc_act_hangup_signaling_link(ctrl, cc_record);
		pri_cc_act_stop_t_supervision(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	case CC_EVENT_SIGNALING_GONE:
		/* Signaling link cleared. */
		pri_cc_act_pass_up_cc_cancel(ctrl, cc_record);
		pri_cc_act_stop_t_supervision(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	case CC_EVENT_CANCEL:
		pri_cc_act_hangup_signaling_link(ctrl, cc_record);
		pri_cc_act_stop_t_supervision(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	default:
		break;
	}
}

/*!
 * \internal
 * \brief CC FSM PTP agent CC_STATE_WAIT_CALLBACK.
 *
 * \param ctrl D channel controller.
 * \param call Q.931 call leg.
 * \param cc_record Call completion record to process event.
 * \param event Event to process.
 *
 * \return Nothing
 */
static void pri_cc_fsm_ptp_agent_wait_callback(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record, enum CC_EVENTS event)
{
	switch (event) {
	case CC_EVENT_SUSPEND:
		/* Received CCBS_T_Suspend */
		pri_cc_act_set_a_status_busy(ctrl, cc_record);
		pri_cc_act_pass_up_a_status(ctrl, cc_record);
		cc_record->state = CC_STATE_SUSPENDED;
		break;
	case CC_EVENT_RECALL:
		/* Received CCBS_T_Call */
		pri_cc_act_pass_up_cc_call(ctrl, cc_record);
		pri_cc_act_set_original_call_parameters(ctrl, call, cc_record);
		break;
	case CC_EVENT_TIMEOUT_T_SUPERVISION:
		pri_cc_act_pass_up_cc_cancel(ctrl, cc_record);
		pri_cc_act_hangup_signaling_link(ctrl, cc_record);
		pri_cc_act_stop_t_supervision(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	case CC_EVENT_SIGNALING_GONE:
		/* Signaling link cleared. */
		pri_cc_act_pass_up_cc_cancel(ctrl, cc_record);
		pri_cc_act_stop_t_supervision(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	case CC_EVENT_CANCEL:
		pri_cc_act_hangup_signaling_link(ctrl, cc_record);
		pri_cc_act_stop_t_supervision(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	default:
		break;
	}
}

/*!
 * \internal
 * \brief CC FSM PTP agent CC_STATE_SUSPENDED.
 *
 * \param ctrl D channel controller.
 * \param call Q.931 call leg.
 * \param cc_record Call completion record to process event.
 * \param event Event to process.
 *
 * \return Nothing
 */
static void pri_cc_fsm_ptp_agent_suspended(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record, enum CC_EVENTS event)
{
	switch (event) {
	case CC_EVENT_RESUME:
		/* Received CCBS_T_Resume */
		pri_cc_act_set_a_status_free(ctrl, cc_record);
		pri_cc_act_pass_up_a_status(ctrl, cc_record);
		pri_cc_act_reset_a_status(ctrl, cc_record);
		cc_record->state = CC_STATE_ACTIVATED;
		break;
	case CC_EVENT_RECALL:
		/* Received CCBS_T_Call */
		pri_cc_act_pass_up_cc_call(ctrl, cc_record);
		pri_cc_act_set_original_call_parameters(ctrl, call, cc_record);
		break;
	case CC_EVENT_TIMEOUT_T_SUPERVISION:
		pri_cc_act_pass_up_cc_cancel(ctrl, cc_record);
		pri_cc_act_hangup_signaling_link(ctrl, cc_record);
		pri_cc_act_stop_t_supervision(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	case CC_EVENT_SIGNALING_GONE:
		/* Signaling link cleared. */
		pri_cc_act_pass_up_cc_cancel(ctrl, cc_record);
		pri_cc_act_stop_t_supervision(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	case CC_EVENT_CANCEL:
		pri_cc_act_hangup_signaling_link(ctrl, cc_record);
		pri_cc_act_stop_t_supervision(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	default:
		break;
	}
}

/*!
 * \internal
 * \brief CC FSM PTP monitor CC_STATE_IDLE.
 *
 * \param ctrl D channel controller.
 * \param call Q.931 call leg.
 * \param cc_record Call completion record to process event.
 * \param event Event to process.
 *
 * \return Nothing
 */
static void pri_cc_fsm_ptp_monitor_idle(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record, enum CC_EVENTS event)
{
	switch (event) {
	case CC_EVENT_AVAILABLE:
		/* Received CCBS-T-Aailable */
		pri_cc_act_pass_up_cc_available(ctrl, cc_record);
		cc_record->state = CC_STATE_AVAILABLE;
		break;
	case CC_EVENT_CANCEL:
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		break;
	default:
		break;
	}
}

/*!
 * \internal
 * \brief CC FSM PTP monitor CC_STATE_AVAILABLE.
 *
 * \param ctrl D channel controller.
 * \param call Q.931 call leg.
 * \param cc_record Call completion record to process event.
 * \param event Event to process.
 *
 * \return Nothing
 */
static void pri_cc_fsm_ptp_monitor_avail(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record, enum CC_EVENTS event)
{
	/* The upper layer is responsible for canceling the CC available offering. */
	switch (event) {
	case CC_EVENT_CC_REQUEST:
		/*
		 * Before event is posted:
		 *   cc_record->is_ccnr is set.
		 *   The signaling connection call record is created.
		 */
		pri_cc_act_queue_cc_request(ctrl, cc_record, call);
		/*
		 * For PTP mode the T_ACTIVATE timer is not defined.  However,
		 * we will use it to protect our resources from leaks caused
		 * by the network cable being disconnected.
		 * This timer should be set longer than normal so the
		 * CC records will normally be cleaned up by network activity.
		 */
		//pri_cc_act_start_t_activate(ctrl, cc_record);
		cc_record->state = CC_STATE_REQUESTED;
		break;
	case CC_EVENT_CANCEL:
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	default:
		break;
	}
}

/*!
 * \internal
 * \brief CC FSM PTP monitor CC_STATE_REQUESTED.
 *
 * \param ctrl D channel controller.
 * \param call Q.931 call leg.
 * \param cc_record Call completion record to process event.
 * \param event Event to process.
 *
 * \return Nothing
 */
static void pri_cc_fsm_ptp_monitor_req(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record, enum CC_EVENTS event)
{
	switch (event) {
	case CC_EVENT_CC_REQUEST_ACCEPT:
		/*
		 * Received CCBS-T-Request/CCNR-T-Request response
		 * Before event is posted:
		 *   Negotiated CC retention setting saved
		 */
		pri_cc_act_pass_up_cc_req_rsp_success(ctrl, cc_record);
		pri_cc_act_stop_t_activate(ctrl, cc_record);
		/* Start T_CCBS6/T_CCNR6 depending upon CC mode. */
		pri_cc_act_start_t_supervision(ctrl, cc_record);
		pri_cc_act_reset_a_status(ctrl, cc_record);
		cc_record->state = CC_STATE_ACTIVATED;
		break;
	case CC_EVENT_CC_REQUEST_FAIL:
		pri_cc_act_pass_up_cc_req_rsp_fail(ctrl, cc_record);
		pri_cc_act_pass_up_cc_cancel(ctrl, cc_record);
		/*
		 * If this request fail comes in with the RELEASE_COMPLETE
		 * message then the post action will never get a chance to
		 * run.  It will be aborted because the CC_EVENT_SIGNALING_GONE
		 * will be processed first.
		 */
		pri_cc_act_post_hangup_signaling(ctrl, cc_record);
		pri_cc_act_stop_t_activate(ctrl, cc_record);
		cc_record->state = CC_STATE_WAIT_DESTRUCTION;
		break;
	case CC_EVENT_TIMEOUT_T_ACTIVATE:
		pri_cc_act_pass_up_cc_req_rsp_timeout(ctrl, cc_record);
		pri_cc_act_pass_up_cc_cancel(ctrl, cc_record);
		pri_cc_act_hangup_signaling_link(ctrl, cc_record);
		pri_cc_act_stop_t_activate(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	case CC_EVENT_SIGNALING_GONE:
		/* Claim it was a timeout */
		pri_cc_act_pass_up_cc_req_rsp_timeout(ctrl, cc_record);
		pri_cc_act_pass_up_cc_cancel(ctrl, cc_record);
		pri_cc_act_stop_t_activate(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	case CC_EVENT_CANCEL:
		pri_cc_act_hangup_signaling_link(ctrl, cc_record);
		pri_cc_act_stop_t_activate(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	default:
		break;
	}
}

/*!
 * \internal
 * \brief CC FSM PTP monitor CC_STATE_WAIT_DESTRUCTION.
 *
 * \param ctrl D channel controller.
 * \param call Q.931 call leg.
 * \param cc_record Call completion record to process event.
 * \param event Event to process.
 *
 * \return Nothing
 */
static void pri_cc_fsm_ptp_monitor_wait_destruction(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record, enum CC_EVENTS event)
{
	/*
	 * Delayed disconnect of the signaling link to allow subcmd events
	 * from the signaling link to be passed up.
	 */
	switch (event) {
	case CC_EVENT_SIGNALING_GONE:
		/* Signaling link cleared. */
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	case CC_EVENT_HANGUP_SIGNALING:
		pri_cc_act_hangup_signaling_link(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	case CC_EVENT_CANCEL:
		pri_cc_act_hangup_signaling_link(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	default:
		break;
	}
}

/*!
 * \internal
 * \brief CC FSM PTP monitor CC_STATE_ACTIVATED.
 *
 * \param ctrl D channel controller.
 * \param call Q.931 call leg.
 * \param cc_record Call completion record to process event.
 * \param event Event to process.
 *
 * \return Nothing
 */
static void pri_cc_fsm_ptp_monitor_activated(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record, enum CC_EVENTS event)
{
	switch (event) {
	case CC_EVENT_REMOTE_USER_FREE:
		/* Received CCBS_T_RemoteUserFree */
		pri_cc_act_pass_up_remote_user_free(ctrl, cc_record);
		if (cc_record->party_a_status == CC_PARTY_A_AVAILABILITY_BUSY) {
			pri_cc_act_send_cc_suspend(ctrl, cc_record);
			cc_record->state = CC_STATE_SUSPENDED;
		} else {
			cc_record->state = CC_STATE_WAIT_CALLBACK;
		}
		break;
	case CC_EVENT_SUSPEND:
		pri_cc_act_set_a_status_busy(ctrl, cc_record);
		break;
	case CC_EVENT_RESUME:
		pri_cc_act_reset_a_status(ctrl, cc_record);
		break;
	case CC_EVENT_RECALL:
		/* The original call parameters have already been set. */
		pri_cc_act_queue_setup_recall(ctrl, cc_record, call);
		break;
	case CC_EVENT_TIMEOUT_T_SUPERVISION:
		pri_cc_act_pass_up_cc_cancel(ctrl, cc_record);
		pri_cc_act_hangup_signaling_link(ctrl, cc_record);
		pri_cc_act_stop_t_supervision(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	case CC_EVENT_SIGNALING_GONE:
		/* Signaling link cleared. */
		pri_cc_act_pass_up_cc_cancel(ctrl, cc_record);
		pri_cc_act_stop_t_supervision(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	case CC_EVENT_CANCEL:
		pri_cc_act_hangup_signaling_link(ctrl, cc_record);
		pri_cc_act_stop_t_supervision(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	default:
		break;
	}
}

/*!
 * \internal
 * \brief CC FSM PTP monitor CC_STATE_WAIT_CALLBACK.
 *
 * \param ctrl D channel controller.
 * \param call Q.931 call leg.
 * \param cc_record Call completion record to process event.
 * \param event Event to process.
 *
 * \return Nothing
 */
static void pri_cc_fsm_ptp_monitor_wait_callback(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record, enum CC_EVENTS event)
{
	switch (event) {
	case CC_EVENT_SUSPEND:
		pri_cc_act_send_cc_suspend(ctrl, cc_record);
		cc_record->state = CC_STATE_SUSPENDED;
		break;
	case CC_EVENT_RECALL:
		/* The original call parameters have already been set. */
		pri_cc_act_queue_setup_recall(ctrl, cc_record, call);
		break;
	case CC_EVENT_TIMEOUT_T_SUPERVISION:
		pri_cc_act_pass_up_cc_cancel(ctrl, cc_record);
		pri_cc_act_hangup_signaling_link(ctrl, cc_record);
		pri_cc_act_stop_t_supervision(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	case CC_EVENT_SIGNALING_GONE:
		/* Signaling link cleared. */
		pri_cc_act_pass_up_cc_cancel(ctrl, cc_record);
		pri_cc_act_stop_t_supervision(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	case CC_EVENT_CANCEL:
		pri_cc_act_hangup_signaling_link(ctrl, cc_record);
		pri_cc_act_stop_t_supervision(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	default:
		break;
	}
}

/*!
 * \internal
 * \brief CC FSM PTP monitor CC_STATE_SUSPENDED.
 *
 * \param ctrl D channel controller.
 * \param call Q.931 call leg.
 * \param cc_record Call completion record to process event.
 * \param event Event to process.
 *
 * \return Nothing
 */
static void pri_cc_fsm_ptp_monitor_suspended(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record, enum CC_EVENTS event)
{
	switch (event) {
	case CC_EVENT_RESUME:
		pri_cc_act_send_cc_resume(ctrl, cc_record);
		pri_cc_act_reset_a_status(ctrl, cc_record);
		cc_record->state = CC_STATE_ACTIVATED;
		break;
	case CC_EVENT_RECALL:
		/* The original call parameters have already been set. */
		pri_cc_act_queue_setup_recall(ctrl, cc_record, call);
		break;
	case CC_EVENT_TIMEOUT_T_SUPERVISION:
		pri_cc_act_pass_up_cc_cancel(ctrl, cc_record);
		pri_cc_act_hangup_signaling_link(ctrl, cc_record);
		pri_cc_act_stop_t_supervision(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	case CC_EVENT_SIGNALING_GONE:
		/* Signaling link cleared. */
		pri_cc_act_pass_up_cc_cancel(ctrl, cc_record);
		pri_cc_act_stop_t_supervision(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	case CC_EVENT_CANCEL:
		pri_cc_act_hangup_signaling_link(ctrl, cc_record);
		pri_cc_act_stop_t_supervision(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	default:
		break;
	}
}

/*!
 * \internal
 * \brief CC FSM Q.SIG agent CC_STATE_IDLE.
 *
 * \param ctrl D channel controller.
 * \param call Q.931 call leg.
 * \param cc_record Call completion record to process event.
 * \param event Event to process.
 *
 * \return Nothing
 */
static void pri_cc_fsm_qsig_agent_idle(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record, enum CC_EVENTS event)
{
	switch (event) {
	case CC_EVENT_AVAILABLE:
		cc_record->state = CC_STATE_AVAILABLE;
		break;
	case CC_EVENT_CANCEL:
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		break;
	default:
		break;
	}
}

/*!
 * \internal
 * \brief CC FSM Q.SIG agent CC_STATE_AVAILABLE.
 *
 * \param ctrl D channel controller.
 * \param call Q.931 call leg.
 * \param cc_record Call completion record to process event.
 * \param event Event to process.
 *
 * \return Nothing
 */
static void pri_cc_fsm_qsig_agent_avail(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record, enum CC_EVENTS event)
{
	/*
	 * For Q.SIG mode the T_RETENTION timer is not defined.  However,
	 * we will use it anyway in this state to protect our resources
	 * from leaks caused by user A not requesting CC.  This timer
	 * should be set much longer than the PTMP network link to
	 * allow for variations in user A's CC offer timer.
	 */
	switch (event) {
	case CC_EVENT_MSG_RELEASE:
	case CC_EVENT_MSG_RELEASE_COMPLETE:
		pri_cc_act_stop_t_retention(ctrl, cc_record);
		pri_cc_act_start_t_retention(ctrl, cc_record);
		break;
	case CC_EVENT_CC_REQUEST:
		pri_cc_act_pass_up_cc_request(ctrl, cc_record);
		/* Send Q931_CALL_PROCEEDING message on signaling link. */
		pri_cc_act_send_call_proceeding(ctrl, cc_record);
		pri_cc_act_stop_t_retention(ctrl, cc_record);
		cc_record->state = CC_STATE_REQUESTED;
		break;
	case CC_EVENT_INTERNAL_CLEARING:
		pri_cc_act_stop_t_retention(ctrl, cc_record);
		pri_cc_act_start_t_retention(ctrl, cc_record);
		break;
	case CC_EVENT_TIMEOUT_T_RETENTION:
		pri_cc_act_pass_up_cc_cancel(ctrl, cc_record);
		pri_cc_act_stop_t_retention(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	case CC_EVENT_CANCEL:
		pri_cc_act_stop_t_retention(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	default:
		break;
	}
}

/*!
 * \internal
 * \brief CC FSM Q.SIG agent CC_STATE_REQUESTED.
 *
 * \param ctrl D channel controller.
 * \param call Q.931 call leg.
 * \param cc_record Call completion record to process event.
 * \param event Event to process.
 *
 * \return Nothing
 */
static void pri_cc_fsm_qsig_agent_req(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record, enum CC_EVENTS event)
{
	switch (event) {
	case CC_EVENT_CC_REQUEST_ACCEPT:
		/* Start QSIG_CCBS_T2/QSIG_CCNR_T2 depending upon CC mode. */
		pri_cc_act_start_t_supervision(ctrl, cc_record);
		cc_record->state = CC_STATE_ACTIVATED;
		break;
	case CC_EVENT_SIGNALING_GONE:
		/* Signaling link cleared. */
		pri_cc_act_pass_up_cc_cancel(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	case CC_EVENT_CANCEL:
		pri_cc_act_hangup_signaling_link(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	default:
		break;
	}
}

/*!
 * \internal
 * \brief CC FSM Q.SIG agent CC_STATE_WAIT_DESTRUCTION.
 *
 * \param ctrl D channel controller.
 * \param call Q.931 call leg.
 * \param cc_record Call completion record to process event.
 * \param event Event to process.
 *
 * \return Nothing
 */
static void pri_cc_fsm_qsig_agent_wait_destruction(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record, enum CC_EVENTS event)
{
	/*
	 * Delayed disconnect of the signaling link to allow subcmd events
	 * from the signaling link to be passed up.
	 */
	switch (event) {
	case CC_EVENT_SIGNALING_GONE:
		/* Signaling link cleared. */
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	case CC_EVENT_HANGUP_SIGNALING:
		pri_cc_act_hangup_signaling_link(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	default:
		break;
	}
}

/*!
 * \internal
 * \brief CC FSM Q.SIG agent CC_STATE_ACTIVATED.
 *
 * \param ctrl D channel controller.
 * \param call Q.931 call leg.
 * \param cc_record Call completion record to process event.
 * \param event Event to process.
 *
 * \return Nothing
 */
static void pri_cc_fsm_qsig_agent_activated(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record, enum CC_EVENTS event)
{
	switch (event) {
	case CC_EVENT_REMOTE_USER_FREE:
		/* Send ccExecPossible in FACILITY or SETUP. */
		pri_cc_act_send_remote_user_free(ctrl, cc_record);
		cc_record->state = CC_STATE_WAIT_CALLBACK;
		break;
	case CC_EVENT_TIMEOUT_T_SUPERVISION:
		pri_cc_act_pass_up_cc_cancel(ctrl, cc_record);
		pri_cc_act_send_cc_cancel(ctrl, cc_record);
		pri_cc_act_stop_t_supervision(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	case CC_EVENT_SIGNALING_GONE:
		/* Signaling link cleared. */
		pri_cc_act_disassociate_signaling_link(ctrl, cc_record);
		break;
	case CC_EVENT_LINK_CANCEL:
		/* Received ccCancel */
		pri_cc_act_pass_up_cc_cancel(ctrl, cc_record);
		pri_cc_act_post_hangup_signaling(ctrl, cc_record);
		pri_cc_act_stop_t_supervision(ctrl, cc_record);
		cc_record->state = CC_STATE_WAIT_DESTRUCTION;
		break;
	case CC_EVENT_CANCEL:
		pri_cc_act_send_cc_cancel(ctrl, cc_record);
		pri_cc_act_stop_t_supervision(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	default:
		break;
	}
}

/*!
 * \internal
 * \brief CC FSM Q.SIG agent CC_STATE_WAIT_CALLBACK.
 *
 * \param ctrl D channel controller.
 * \param call Q.931 call leg.
 * \param cc_record Call completion record to process event.
 * \param event Event to process.
 *
 * \return Nothing
 */
static void pri_cc_fsm_qsig_agent_wait_callback(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record, enum CC_EVENTS event)
{
	switch (event) {
	case CC_EVENT_SUSPEND:
		/* Received ccSuspend */
		pri_cc_act_set_a_status_busy(ctrl, cc_record);
		pri_cc_act_pass_up_a_status(ctrl, cc_record);
		cc_record->state = CC_STATE_SUSPENDED;
		break;
	case CC_EVENT_RECALL:
		/* Received ccRingout */
		pri_cc_act_pass_up_cc_call(ctrl, cc_record);
		pri_cc_act_set_original_call_parameters(ctrl, call, cc_record);
		break;
	case CC_EVENT_TIMEOUT_T_SUPERVISION:
		pri_cc_act_pass_up_cc_cancel(ctrl, cc_record);
		pri_cc_act_send_cc_cancel(ctrl, cc_record);
		pri_cc_act_stop_t_supervision(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	case CC_EVENT_SIGNALING_GONE:
		/* Signaling link cleared. */
		pri_cc_act_disassociate_signaling_link(ctrl, cc_record);
		break;
	case CC_EVENT_LINK_CANCEL:
		/* Received ccCancel */
		pri_cc_act_pass_up_cc_cancel(ctrl, cc_record);
		pri_cc_act_post_hangup_signaling(ctrl, cc_record);
		pri_cc_act_stop_t_supervision(ctrl, cc_record);
		cc_record->state = CC_STATE_WAIT_DESTRUCTION;
		break;
	case CC_EVENT_CANCEL:
		pri_cc_act_send_cc_cancel(ctrl, cc_record);
		pri_cc_act_stop_t_supervision(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	default:
		break;
	}
}

/*!
 * \internal
 * \brief CC FSM Q.SIG agent CC_STATE_SUSPENDED.
 *
 * \param ctrl D channel controller.
 * \param call Q.931 call leg.
 * \param cc_record Call completion record to process event.
 * \param event Event to process.
 *
 * \return Nothing
 */
static void pri_cc_fsm_qsig_agent_suspended(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record, enum CC_EVENTS event)
{
	switch (event) {
	case CC_EVENT_RESUME:
		/* Received ccResume */
		pri_cc_act_set_a_status_free(ctrl, cc_record);
		pri_cc_act_pass_up_a_status(ctrl, cc_record);
		cc_record->state = CC_STATE_ACTIVATED;
		break;
	case CC_EVENT_TIMEOUT_T_SUPERVISION:
		pri_cc_act_pass_up_cc_cancel(ctrl, cc_record);
		pri_cc_act_send_cc_cancel(ctrl, cc_record);
		pri_cc_act_stop_t_supervision(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	case CC_EVENT_SIGNALING_GONE:
		/* Signaling link cleared. */
		pri_cc_act_disassociate_signaling_link(ctrl, cc_record);
		break;
	case CC_EVENT_LINK_CANCEL:
		/* Received ccCancel */
		pri_cc_act_pass_up_cc_cancel(ctrl, cc_record);
		pri_cc_act_post_hangup_signaling(ctrl, cc_record);
		pri_cc_act_stop_t_supervision(ctrl, cc_record);
		cc_record->state = CC_STATE_WAIT_DESTRUCTION;
		break;
	case CC_EVENT_CANCEL:
		pri_cc_act_send_cc_cancel(ctrl, cc_record);
		pri_cc_act_stop_t_supervision(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	default:
		break;
	}
}

/*!
 * \internal
 * \brief CC FSM Q.SIG monitor CC_STATE_IDLE.
 *
 * \param ctrl D channel controller.
 * \param call Q.931 call leg.
 * \param cc_record Call completion record to process event.
 * \param event Event to process.
 *
 * \return Nothing
 */
static void pri_cc_fsm_qsig_monitor_idle(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record, enum CC_EVENTS event)
{
	switch (event) {
	case CC_EVENT_AVAILABLE:
		/*
		 * LibPRI will determine if CC will be offered based upon
		 * if it is even possible.
		 * Essentially:
		 * 1) The call must not have been redirected in this link's
		 * setup.
		 * 2) Received an ALERTING or received a
		 * DISCONNECT(busy/congestion).
		 */
		pri_cc_act_pass_up_cc_available(ctrl, cc_record);
		cc_record->state = CC_STATE_AVAILABLE;
		break;
	case CC_EVENT_CANCEL:
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		break;
	default:
		break;
	}
}

/*!
 * \internal
 * \brief CC FSM Q.SIG monitor CC_STATE_AVAILABLE.
 *
 * \param ctrl D channel controller.
 * \param call Q.931 call leg.
 * \param cc_record Call completion record to process event.
 * \param event Event to process.
 *
 * \return Nothing
 */
static void pri_cc_fsm_qsig_monitor_avail(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record, enum CC_EVENTS event)
{
	/* The upper layer is responsible for canceling the CC available offering. */
	switch (event) {
	case CC_EVENT_CC_REQUEST:
		/*
		 * Before event is posted:
		 *   cc_record->is_ccnr is set.
		 *   The signaling connection call record is created.
		 */
		pri_cc_act_queue_cc_request(ctrl, cc_record, call);
		/* Start QSIG_CC_T1. */
		//pri_cc_act_start_t_activate(ctrl, cc_record);
		cc_record->state = CC_STATE_REQUESTED;
		break;
	case CC_EVENT_CANCEL:
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	default:
		break;
	}
}

/*!
 * \internal
 * \brief CC FSM Q.SIG monitor CC_STATE_REQUESTED.
 *
 * \param ctrl D channel controller.
 * \param call Q.931 call leg.
 * \param cc_record Call completion record to process event.
 * \param event Event to process.
 *
 * \return Nothing
 */
static void pri_cc_fsm_qsig_monitor_req(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record, enum CC_EVENTS event)
{
	switch (event) {
	case CC_EVENT_CC_REQUEST_ACCEPT:
		/*
		 * Received ccbsRequest/ccnrRequest response
		 * Before event is posted:
		 *   Negotiated CC retention setting saved
		 *   Negotiated signaling link retention setting saved
		 */
		pri_cc_act_stop_t_activate(ctrl, cc_record);
		if (cc_record->fsm.qsig.msgtype == Q931_RELEASE) {
			pri_cc_act_disassociate_signaling_link(ctrl, cc_record);
			if (cc_record->option.retain_signaling_link) {
				/*
				 * The far end did not honor the
				 * signaling link retention requirement.
				 * ECMA-186 Section 6.5.2.2.1
				 */
				pri_cc_act_pass_up_cc_req_rsp_timeout(ctrl, cc_record);
				pri_cc_act_pass_up_cc_cancel(ctrl, cc_record);
				pri_cc_act_send_cc_cancel(ctrl, cc_record);
				pri_cc_act_set_self_destruct(ctrl, cc_record);
				cc_record->state = CC_STATE_IDLE;
				break;
			}
		}
		pri_cc_act_pass_up_cc_req_rsp_success(ctrl, cc_record);
		/* Start QSIG_CCBS_T2/QSIG_CCNR_T2 depending upon CC mode. */
		pri_cc_act_start_t_supervision(ctrl, cc_record);
		pri_cc_act_reset_a_status(ctrl, cc_record);
		cc_record->state = CC_STATE_ACTIVATED;
		break;
	case CC_EVENT_CC_REQUEST_FAIL:
		pri_cc_act_stop_t_activate(ctrl, cc_record);
		pri_cc_act_pass_up_cc_req_rsp_fail(ctrl, cc_record);
		pri_cc_act_pass_up_cc_cancel(ctrl, cc_record);
		/*
		 * If this request fail comes in with the RELEASE message
		 * then the post action will never get a chance to run.
		 * It will be aborted because the CC_EVENT_SIGNALING_GONE
		 * will be processed first.
		 */
		pri_cc_act_post_hangup_signaling(ctrl, cc_record);
		cc_record->state = CC_STATE_WAIT_DESTRUCTION;
		break;
	case CC_EVENT_TIMEOUT_T_ACTIVATE:
		pri_cc_act_stop_t_activate(ctrl, cc_record);
		pri_cc_act_pass_up_cc_req_rsp_timeout(ctrl, cc_record);
		pri_cc_act_pass_up_cc_cancel(ctrl, cc_record);
		pri_cc_act_hangup_signaling_link(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	case CC_EVENT_SIGNALING_GONE:
		pri_cc_act_stop_t_activate(ctrl, cc_record);
		/* Claim it was a timeout */
		pri_cc_act_pass_up_cc_req_rsp_timeout(ctrl, cc_record);
		pri_cc_act_pass_up_cc_cancel(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	case CC_EVENT_CANCEL:
		cc_record->state = CC_STATE_WAIT_DESTRUCTION;
		break;
	default:
		break;
	}
}

/*!
 * \internal
 * \brief CC FSM Q.SIG monitor CC_STATE_WAIT_DESTRUCTION.
 *
 * \param ctrl D channel controller.
 * \param call Q.931 call leg.
 * \param cc_record Call completion record to process event.
 * \param event Event to process.
 *
 * \return Nothing
 */
static void pri_cc_fsm_qsig_monitor_wait_destruction(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record, enum CC_EVENTS event)
{
	/*
	 * Delayed disconnect of the signaling link to allow subcmd events
	 * from the signaling link to be passed up.
	 */
	switch (event) {
	case CC_EVENT_CC_REQUEST_ACCEPT:
		/*
		 * Received ccbsRequest/ccnrRequest response
		 * Before event is posted:
		 *   Negotiated CC retention setting saved
		 *   Negotiated signaling link retention setting saved
		 */
		pri_cc_act_stop_t_activate(ctrl, cc_record);
		if (cc_record->fsm.qsig.msgtype == Q931_RELEASE) {
			pri_cc_act_disassociate_signaling_link(ctrl, cc_record);
		}
		pri_cc_act_send_cc_cancel(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	case CC_EVENT_CC_REQUEST_FAIL:
		pri_cc_act_stop_t_activate(ctrl, cc_record);
		/*
		 * If this request fail comes in with the RELEASE message
		 * then the post action will never get a chance to run.
		 * It will be aborted because the CC_EVENT_SIGNALING_GONE
		 * will be processed first.
		 */
		pri_cc_act_post_hangup_signaling(ctrl, cc_record);
		break;
	case CC_EVENT_TIMEOUT_T_ACTIVATE:
		pri_cc_act_stop_t_activate(ctrl, cc_record);
		pri_cc_act_hangup_signaling_link(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	case CC_EVENT_SIGNALING_GONE:
		/* Signaling link cleared. */
		pri_cc_act_stop_t_activate(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	case CC_EVENT_HANGUP_SIGNALING:
		//pri_cc_act_stop_t_activate(ctrl, cc_record);
		pri_cc_act_hangup_signaling_link(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	default:
		break;
	}
}

/*!
 * \internal
 * \brief CC FSM Q.SIG monitor CC_STATE_ACTIVATED.
 *
 * \param ctrl D channel controller.
 * \param call Q.931 call leg.
 * \param cc_record Call completion record to process event.
 * \param event Event to process.
 *
 * \return Nothing
 */
static void pri_cc_fsm_qsig_monitor_activated(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record, enum CC_EVENTS event)
{
	switch (event) {
	case CC_EVENT_REMOTE_USER_FREE:
		/* Received ccExecPossible */
		pri_cc_act_pass_up_remote_user_free(ctrl, cc_record);
		/*
		 * ECMA-186 Section 6.5.2.1.7
		 * Implied switch to retain-signaling-link.
		 */
		pri_cc_act_set_retain_signaling_link(ctrl, cc_record);
		if (cc_record->fsm.qsig.msgtype == Q931_SETUP) {
			/* Send Q931_CALL_PROCEEDING message on signaling link. */
			pri_cc_act_send_call_proceeding(ctrl, cc_record);
		}
		if (cc_record->party_a_status == CC_PARTY_A_AVAILABILITY_BUSY) {
			/*
			 * The ccSuspend will be sent in a FACILITY or CONNECT
			 * message depending upon the CIS call state.
			 */
			pri_cc_act_send_cc_suspend(ctrl, cc_record);
			cc_record->state = CC_STATE_SUSPENDED;
		} else {
			/* Start QSIG_CC_T3 */
			pri_cc_act_start_t_recall(ctrl, cc_record);
			cc_record->state = CC_STATE_WAIT_CALLBACK;
		}
		break;
	case CC_EVENT_SUSPEND:
		pri_cc_act_set_a_status_busy(ctrl, cc_record);
		break;
	case CC_EVENT_RESUME:
		pri_cc_act_reset_a_status(ctrl, cc_record);
		break;
	case CC_EVENT_TIMEOUT_T_SUPERVISION:
		pri_cc_act_pass_up_cc_cancel(ctrl, cc_record);
		pri_cc_act_send_cc_cancel(ctrl, cc_record);
		pri_cc_act_stop_t_supervision(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	case CC_EVENT_SIGNALING_GONE:
		/* Signaling link cleared. */
		pri_cc_act_disassociate_signaling_link(ctrl, cc_record);
		break;
	case CC_EVENT_LINK_CANCEL:
		/* Received ccCancel */
		pri_cc_act_pass_up_cc_cancel(ctrl, cc_record);
		pri_cc_act_post_hangup_signaling(ctrl, cc_record);
		pri_cc_act_stop_t_supervision(ctrl, cc_record);
		cc_record->state = CC_STATE_WAIT_DESTRUCTION;
		break;
	case CC_EVENT_CANCEL:
		pri_cc_act_send_cc_cancel(ctrl, cc_record);
		pri_cc_act_stop_t_supervision(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	default:
		break;
	}
}

/*!
 * \internal
 * \brief CC FSM Q.SIG monitor CC_STATE_WAIT_CALLBACK.
 *
 * \param ctrl D channel controller.
 * \param call Q.931 call leg.
 * \param cc_record Call completion record to process event.
 * \param event Event to process.
 *
 * \return Nothing
 */
static void pri_cc_fsm_qsig_monitor_wait_callback(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record, enum CC_EVENTS event)
{
	switch (event) {
	case CC_EVENT_RECALL:
		/* The original call parameters have already been set. */
		pri_cc_act_queue_setup_recall(ctrl, cc_record, call);
		pri_cc_act_stop_t_recall(ctrl, cc_record);
		cc_record->state = CC_STATE_CALLBACK;
		break;
	case CC_EVENT_SUSPEND:
		pri_cc_act_stop_t_recall(ctrl, cc_record);
		/*
		 * The ccSuspend will be sent in a FACILITY or CONNECT
		 * message depending upon the CIS call state.
		 */
		pri_cc_act_send_cc_suspend(ctrl, cc_record);
		cc_record->state = CC_STATE_SUSPENDED;
		break;
	case CC_EVENT_TIMEOUT_T_RECALL:
		pri_cc_act_pass_up_cc_cancel(ctrl, cc_record);
		pri_cc_act_send_cc_cancel(ctrl, cc_record);
		pri_cc_act_stop_t_recall(ctrl, cc_record);
		pri_cc_act_stop_t_supervision(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	case CC_EVENT_TIMEOUT_T_SUPERVISION:
		pri_cc_act_pass_up_cc_cancel(ctrl, cc_record);
		pri_cc_act_send_cc_cancel(ctrl, cc_record);
		pri_cc_act_stop_t_recall(ctrl, cc_record);
		pri_cc_act_stop_t_supervision(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	case CC_EVENT_SIGNALING_GONE:
		/* Signaling link cleared. */
		pri_cc_act_disassociate_signaling_link(ctrl, cc_record);
		break;
	case CC_EVENT_LINK_CANCEL:
		/* Received ccCancel */
		pri_cc_act_pass_up_cc_cancel(ctrl, cc_record);
		pri_cc_act_post_hangup_signaling(ctrl, cc_record);
		pri_cc_act_stop_t_recall(ctrl, cc_record);
		pri_cc_act_stop_t_supervision(ctrl, cc_record);
		cc_record->state = CC_STATE_WAIT_DESTRUCTION;
		break;
	case CC_EVENT_CANCEL:
		pri_cc_act_send_cc_cancel(ctrl, cc_record);
		pri_cc_act_stop_t_recall(ctrl, cc_record);
		pri_cc_act_stop_t_supervision(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	default:
		break;
	}
}

/*!
 * \internal
 * \brief CC FSM Q.SIG monitor CC_STATE_CALLBACK.
 *
 * \param ctrl D channel controller.
 * \param call Q.931 call leg.
 * \param cc_record Call completion record to process event.
 * \param event Event to process.
 *
 * \return Nothing
 */
static void pri_cc_fsm_qsig_monitor_callback(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record, enum CC_EVENTS event)
{
	switch (event) {
	case CC_EVENT_TIMEOUT_T_SUPERVISION:
		pri_cc_act_pass_up_cc_cancel(ctrl, cc_record);
		pri_cc_act_send_cc_cancel(ctrl, cc_record);
		pri_cc_act_stop_t_supervision(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	case CC_EVENT_SIGNALING_GONE:
		/* Signaling link cleared. */
		pri_cc_act_disassociate_signaling_link(ctrl, cc_record);
		break;
	case CC_EVENT_LINK_CANCEL:
		/* Received ccCancel */
		pri_cc_act_pass_up_cc_cancel(ctrl, cc_record);
		pri_cc_act_post_hangup_signaling(ctrl, cc_record);
		pri_cc_act_stop_t_supervision(ctrl, cc_record);
		cc_record->state = CC_STATE_WAIT_DESTRUCTION;
		break;
	case CC_EVENT_CANCEL:
		pri_cc_act_send_cc_cancel(ctrl, cc_record);
		pri_cc_act_stop_t_supervision(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	default:
		break;
	}
}

/*!
 * \internal
 * \brief CC FSM Q.SIG monitor CC_STATE_SUSPENDED.
 *
 * \param ctrl D channel controller.
 * \param call Q.931 call leg.
 * \param cc_record Call completion record to process event.
 * \param event Event to process.
 *
 * \return Nothing
 */
static void pri_cc_fsm_qsig_monitor_suspended(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record, enum CC_EVENTS event)
{
	switch (event) {
	case CC_EVENT_RESUME:
		pri_cc_act_send_cc_resume(ctrl, cc_record);
		pri_cc_act_reset_a_status(ctrl, cc_record);
		cc_record->state = CC_STATE_ACTIVATED;
		break;
	case CC_EVENT_TIMEOUT_T_SUPERVISION:
		pri_cc_act_pass_up_cc_cancel(ctrl, cc_record);
		pri_cc_act_send_cc_cancel(ctrl, cc_record);
		pri_cc_act_stop_t_supervision(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	case CC_EVENT_SIGNALING_GONE:
		/* Signaling link cleared. */
		pri_cc_act_disassociate_signaling_link(ctrl, cc_record);
		break;
	case CC_EVENT_LINK_CANCEL:
		/* Received ccCancel */
		pri_cc_act_pass_up_cc_cancel(ctrl, cc_record);
		pri_cc_act_post_hangup_signaling(ctrl, cc_record);
		pri_cc_act_stop_t_supervision(ctrl, cc_record);
		cc_record->state = CC_STATE_WAIT_DESTRUCTION;
		break;
	case CC_EVENT_CANCEL:
		pri_cc_act_send_cc_cancel(ctrl, cc_record);
		pri_cc_act_stop_t_supervision(ctrl, cc_record);
		pri_cc_act_set_self_destruct(ctrl, cc_record);
		cc_record->state = CC_STATE_IDLE;
		break;
	default:
		break;
	}
}

/*!
 * \internal
 * \brief CC FSM state function type.
 *
 * \param ctrl D channel controller.
 * \param call Q.931 call leg.
 * \param cc_record Call completion record to process event.
 * \param event Event to process.
 *
 * \return Nothing
 */
typedef void (*pri_cc_fsm_state)(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record, enum CC_EVENTS event);

/*! CC FSM PTMP agent state table. */
static const pri_cc_fsm_state pri_cc_fsm_ptmp_agent[CC_STATE_NUM] = {
/* *INDENT-OFF* */
	[CC_STATE_IDLE] = pri_cc_fsm_ptmp_agent_idle,
	[CC_STATE_PENDING_AVAILABLE] = pri_cc_fsm_ptmp_agent_pend_avail,
	[CC_STATE_AVAILABLE] = pri_cc_fsm_ptmp_agent_avail,
	[CC_STATE_REQUESTED] = pri_cc_fsm_ptmp_agent_req,
	[CC_STATE_ACTIVATED] = pri_cc_fsm_ptmp_agent_activated,
	[CC_STATE_B_AVAILABLE] = pri_cc_fsm_ptmp_agent_b_avail,
	[CC_STATE_SUSPENDED] = pri_cc_fsm_ptmp_agent_suspended,
	[CC_STATE_WAIT_CALLBACK] = pri_cc_fsm_ptmp_agent_wait_callback,
	[CC_STATE_CALLBACK] = pri_cc_fsm_ptmp_agent_callback,
/* *INDENT-ON* */
};

/*! CC FSM PTMP monitor state table. */
static const pri_cc_fsm_state pri_cc_fsm_ptmp_monitor[CC_STATE_NUM] = {
/* *INDENT-OFF* */
	[CC_STATE_IDLE] = pri_cc_fsm_ptmp_monitor_idle,
	[CC_STATE_AVAILABLE] = pri_cc_fsm_ptmp_monitor_avail,
	[CC_STATE_REQUESTED] = pri_cc_fsm_ptmp_monitor_req,
	[CC_STATE_WAIT_DESTRUCTION] = pri_cc_fsm_ptmp_monitor_wait_destruction,
	[CC_STATE_ACTIVATED] = pri_cc_fsm_ptmp_monitor_activated,
	[CC_STATE_WAIT_CALLBACK] = pri_cc_fsm_ptmp_monitor_wait_callback,
	[CC_STATE_CALLBACK] = pri_cc_fsm_ptmp_monitor_callback,
/* *INDENT-ON* */
};

/*! CC FSM PTP agent state table. */
static const pri_cc_fsm_state pri_cc_fsm_ptp_agent[CC_STATE_NUM] = {
/* *INDENT-OFF* */
	[CC_STATE_IDLE] = pri_cc_fsm_ptp_agent_idle,
	[CC_STATE_PENDING_AVAILABLE] = pri_cc_fsm_ptp_agent_pend_avail,
	[CC_STATE_AVAILABLE] = pri_cc_fsm_ptp_agent_avail,
	[CC_STATE_REQUESTED] = pri_cc_fsm_ptp_agent_req,
	[CC_STATE_ACTIVATED] = pri_cc_fsm_ptp_agent_activated,
	[CC_STATE_WAIT_CALLBACK] = pri_cc_fsm_ptp_agent_wait_callback,
	[CC_STATE_SUSPENDED] = pri_cc_fsm_ptp_agent_suspended,
/* *INDENT-ON* */
};

/*! CC FSM PTP monitor state table. */
static const pri_cc_fsm_state pri_cc_fsm_ptp_monitor[CC_STATE_NUM] = {
/* *INDENT-OFF* */
	[CC_STATE_IDLE] = pri_cc_fsm_ptp_monitor_idle,
	[CC_STATE_AVAILABLE] = pri_cc_fsm_ptp_monitor_avail,
	[CC_STATE_REQUESTED] = pri_cc_fsm_ptp_monitor_req,
	[CC_STATE_WAIT_DESTRUCTION] = pri_cc_fsm_ptp_monitor_wait_destruction,
	[CC_STATE_ACTIVATED] = pri_cc_fsm_ptp_monitor_activated,
	[CC_STATE_WAIT_CALLBACK] = pri_cc_fsm_ptp_monitor_wait_callback,
	[CC_STATE_SUSPENDED] = pri_cc_fsm_ptp_monitor_suspended,
/* *INDENT-ON* */
};

/*! CC FSM Q.SIG agent state table. */
static const pri_cc_fsm_state pri_cc_fsm_qsig_agent[CC_STATE_NUM] = {
/* *INDENT-OFF* */
	[CC_STATE_IDLE] = pri_cc_fsm_qsig_agent_idle,
	[CC_STATE_AVAILABLE] = pri_cc_fsm_qsig_agent_avail,
	[CC_STATE_REQUESTED] = pri_cc_fsm_qsig_agent_req,
	[CC_STATE_WAIT_DESTRUCTION] = pri_cc_fsm_qsig_agent_wait_destruction,
	[CC_STATE_ACTIVATED] = pri_cc_fsm_qsig_agent_activated,
	[CC_STATE_WAIT_CALLBACK] = pri_cc_fsm_qsig_agent_wait_callback,
	[CC_STATE_SUSPENDED] = pri_cc_fsm_qsig_agent_suspended,
/* *INDENT-ON* */
};

/*! CC FSM Q.SIG monitor state table. */
static const pri_cc_fsm_state pri_cc_fsm_qsig_monitor[CC_STATE_NUM] = {
/* *INDENT-OFF* */
	[CC_STATE_IDLE] = pri_cc_fsm_qsig_monitor_idle,
	[CC_STATE_AVAILABLE] = pri_cc_fsm_qsig_monitor_avail,
	[CC_STATE_REQUESTED] = pri_cc_fsm_qsig_monitor_req,
	[CC_STATE_WAIT_DESTRUCTION] = pri_cc_fsm_qsig_monitor_wait_destruction,
	[CC_STATE_ACTIVATED] = pri_cc_fsm_qsig_monitor_activated,
	[CC_STATE_WAIT_CALLBACK] = pri_cc_fsm_qsig_monitor_wait_callback,
	[CC_STATE_CALLBACK] = pri_cc_fsm_qsig_monitor_callback,
	[CC_STATE_SUSPENDED] = pri_cc_fsm_qsig_monitor_suspended,
/* *INDENT-ON* */
};

/*!
 * \brief Send an event to the cc state machine.
 *
 * \param ctrl D channel controller.
 * \param call Q.931 call leg.
 * (May be NULL if it is supposed to be the signaling connection
 * for Q.SIG or PTP and it is not established yet.)
 * \param cc_record Call completion record to process event.
 * \param event Event to process.
 *
 * \retval nonzero if cc record destroyed because FSM completed.
 */
int pri_cc_event(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record, enum CC_EVENTS event)
{
	const pri_cc_fsm_state *cc_fsm;
	enum CC_STATES orig_state;

	switch (ctrl->switchtype) {
	case PRI_SWITCH_QSIG:
		if (cc_record->is_agent) {
			cc_fsm = pri_cc_fsm_qsig_agent;
		} else {
			cc_fsm = pri_cc_fsm_qsig_monitor;
		}
		break;
	case PRI_SWITCH_EUROISDN_E1:
	case PRI_SWITCH_EUROISDN_T1:
		if (PTMP_MODE(ctrl)) {
			if (cc_record->is_agent) {
				cc_fsm = pri_cc_fsm_ptmp_agent;
			} else {
				cc_fsm = pri_cc_fsm_ptmp_monitor;
			}
		} else {
			if (cc_record->is_agent) {
				cc_fsm = pri_cc_fsm_ptp_agent;
			} else {
				cc_fsm = pri_cc_fsm_ptp_monitor;
			}
		}
		break;
	default:
		/* CC not supported on this switch type. */
		cc_fsm = NULL;
		break;
	}

	if (!cc_fsm) {
		/* No FSM available. */
		pri_cc_delete_record(ctrl, cc_record);
		return 1;
	}
	orig_state = cc_record->state;
	if (ctrl->debug & PRI_DEBUG_CC) {
		pri_message(ctrl, "%ld CC-Event: %s in state %s\n", cc_record->record_id,
			pri_cc_fsm_event_str(event), pri_cc_fsm_state_str(orig_state));
	}
	if (orig_state < CC_STATE_IDLE || CC_STATE_NUM <= orig_state || !cc_fsm[orig_state]) {
		/* Programming error: State not implemented. */
		pri_error(ctrl, "!! CC state not implemented: %s(%d)\n",
			pri_cc_fsm_state_str(orig_state), orig_state);
		return 0;
	}
	/* Execute the state. */
	cc_fsm[orig_state](ctrl, call, cc_record, event);
	if (ctrl->debug & PRI_DEBUG_CC) {
		pri_message(ctrl, "%ld  CC-Next-State: %s\n", cc_record->record_id,
			(orig_state == cc_record->state)
			? "$" : pri_cc_fsm_state_str(cc_record->state));
	}
	if (cc_record->fsm_complete) {
		pri_cc_delete_record(ctrl, cc_record);
		return 1;
	} else {
		return 0;
	}
}

/*!
 * \brief Indicate to the far end that CCBS/CCNR is available.
 *
 * \param ctrl D channel controller.
 * \param call Q.931 call leg.
 *
 * \details
 * The CC available indication will go out with the next
 * DISCONNECT(busy/congested)/ALERTING message.
 *
 * \retval cc_id on success for subsequent reference.
 * \retval -1 on error.
 */
long pri_cc_available(struct pri *ctrl, q931_call *call)
{
	struct pri_cc_record *cc_record;
	long cc_id;

	if (!ctrl || !pri_is_call_valid(ctrl, call)) {
		return -1;
	}
	if (call->cc.record) {
		/* This call is already associated with call completion. */
		return -1;
	}

	cc_record = NULL;

	switch (ctrl->switchtype) {
	case PRI_SWITCH_QSIG:
		cc_record = pri_cc_new_record(ctrl, call);
		if (!cc_record) {
			break;
		}

		/*
		 * Q.SIG has no message to send when CC is available.
		 * Q.SIG assumes CC is always available and is denied when
		 * requested if CC is not possible or allowed.
		 */
		cc_record->original_call = call;
		cc_record->is_agent = 1;
		break;
	case PRI_SWITCH_EUROISDN_E1:
	case PRI_SWITCH_EUROISDN_T1:
		if (PTMP_MODE(ctrl)) {
			int linkage_id;

			if (!BRI_NT_PTMP(ctrl)) {
				/*
				 * No CC agent protocol defined for this mode.
				 * i.e.,  A device acting like a phone cannot be a CC agent.
				 */
				break;
			}

			linkage_id = pri_cc_new_linkage_id(ctrl);
			if (linkage_id == CC_PTMP_INVALID_ID) {
				break;
			}
			cc_record = pri_cc_new_record(ctrl, call);
			if (!cc_record) {
				break;
			}
			cc_record->call_linkage_id = linkage_id;
			cc_record->signaling = ctrl->link.dummy_call;
		} else {
			cc_record = pri_cc_new_record(ctrl, call);
			if (!cc_record) {
				break;
			}
		}
		cc_record->original_call = call;
		cc_record->is_agent = 1;
		break;
	default:
		break;
	}

	call->cc.record = cc_record;
	if (cc_record && !pri_cc_event(ctrl, call, cc_record, CC_EVENT_AVAILABLE)) {
		cc_id = cc_record->record_id;
	} else {
		cc_id = -1;
	}
	return cc_id;
}

/*!
 * \brief Determine if CC is available for Q.SIG outgoing call.
 *
 * \param ctrl D channel controller.
 * \param call Q.931 call leg.
 *
 * \return Nothing
 */
void pri_cc_qsig_determine_available(struct pri *ctrl, q931_call *call)
{
	struct pri_cc_record *cc_record;

	if (!call->cc.originated || call->cc.initially_redirected) {
		/*
		 * The call is not suitable for us to consider CC:
		 * The call was not originated by us.
		 * The call was originally redirected.
		 */
		return;
	}

	if (!ctrl->cc_support) {
		/*
		 * Blocking the cc-available event effectively
		 * disables call completion for outgoing calls.
		 */
		return;
	}
	if (call->cc.record) {
		/* Already made available. */
		return;
	}
	cc_record = pri_cc_new_record(ctrl, call);
	if (!cc_record) {
		return;
	}
	cc_record->original_call = call;
	call->cc.record = cc_record;
	pri_cc_event(ctrl, call, cc_record, CC_EVENT_AVAILABLE);
}

/*!
 * \brief Request to activate CC.
 *
 * \param ctrl D channel controller.
 * \param cc_id CC record ID to activate.
 * \param mode Which CC mode to use CCBS(0)/CCNR(1)
 *
 * \note
 * Will always get a reply from libpri.  libpri will start a timer to guarantee
 * that a reply will be passed back to the upper layer.
 * \note
 * If you cancel with pri_cc_cancel() you are indicating that you do not need
 * the request reply and the cc_id will no longer be valid anyway.
 * \note
 * Allow for the possibility that the reply may come in before this
 * function returns.
 *
 * \retval 0 on success.
 * \retval -1 on error.
 */
int pri_cc_req(struct pri *ctrl, long cc_id, int mode)
{
	struct pri_sr req;
	q931_call *call;
	struct pri_cc_record *cc_record;

	if (!ctrl) {
		return -1;
	}
	cc_record = pri_cc_find_by_id(ctrl, cc_id);
	if (!cc_record) {
		return -1;
	}
	if (cc_record->is_agent || cc_record->state != CC_STATE_AVAILABLE) {
		/* CC is an agent or already requested. */
		return -1;
	}

	/* Set the requested CC mode. */
	cc_record->is_ccnr = mode ? 1 : 0;

	switch (ctrl->switchtype) {
	case PRI_SWITCH_QSIG:
		if (cc_record->signaling) {
			/* We should not have a signaling link at this point. */
			return -1;
		}
		call = q931_new_call(ctrl);
		if (!call) {
			return -1;
		}

		/* Link the new call as the signaling link. */
		cc_record->signaling = call;
		call->cc.record = cc_record;

		if (pri_cc_event(ctrl, call, cc_record, CC_EVENT_CC_REQUEST)) {
			/* Should not happen. */
			q931_destroycall(ctrl, call);
			break;
		}

		pri_sr_init(&req);
		req.caller = cc_record->party_a;
		req.called = cc_record->party_b;
		//req.cis_auto_disconnect = 0;
		req.cis_call = 1;
		if (q931_setup(ctrl, call, &req)) {
			/* Should not happen. */
			q931_destroycall(ctrl, call);
			return -1;
		}
		break;
	case PRI_SWITCH_EUROISDN_E1:
	case PRI_SWITCH_EUROISDN_T1:
		if (PTMP_MODE(ctrl)) {
			/* ETSI PTMP */
			if (pri_cc_event(ctrl, cc_record->signaling, cc_record, CC_EVENT_CC_REQUEST)) {
				/* Should not happen. */
				break;
			}
			q931_facility(ctrl, cc_record->signaling);
			break;
		}

		/* ETSI PTP */
		if (cc_record->signaling) {
			/* We should not have a signaling link at this point. */
			return -1;
		}
		call = q931_new_call(ctrl);
		if (!call) {
			return -1;
		}

		cc_record->signaling = call;
		call->cc.record = cc_record;
		if (pri_cc_event(ctrl, call, cc_record, CC_EVENT_CC_REQUEST)) {
			/* Should not happen. */
			q931_destroycall(ctrl, call);
			break;
		}

		if (q931_register(ctrl, call)) {
			/* Should not happen. */
			q931_destroycall(ctrl, call);
			return -1;
		}
		break;
	default:
		return -1;
	}

	return 0;
}

/*!
 * \internal
 * \brief Encode a PTMP cc-request reply message.
 *
 * \param ctrl D channel controller for diagnostic messages or global options.
 * \param pos Starting position to encode the facility ie contents.
 * \param end End of facility ie contents encoding data buffer.
 * \param operation CCBS/CCNR operation code.
 * \param invoke_id Invoke id to put in error message response.
 * \param recall_mode Configured PTMP recall mode.
 * \param reference_id Active CC reference id.
 *
 * \retval Start of the next ASN.1 component to encode on success.
 * \retval NULL on error.
 */
static unsigned char *enc_cc_etsi_ptmp_req_rsp(struct pri *ctrl, unsigned char *pos,
	unsigned char *end, enum rose_operation operation, int invoke_id, int recall_mode,
	int reference_id)
{
	struct rose_msg_result msg;

	pos = facility_encode_header(ctrl, pos, end, NULL);
	if (!pos) {
		return NULL;
	}

	memset(&msg, 0, sizeof(msg));
	msg.invoke_id = invoke_id;
	msg.operation = operation;

	/* CCBS/CCNR reply */
	msg.args.etsi.CCBSRequest.recall_mode = recall_mode;
	msg.args.etsi.CCBSRequest.ccbs_reference = reference_id;

	pos = rose_encode_result(ctrl, pos, end, &msg);

	return pos;
}

/*!
 * \internal
 * \brief Encode and queue PTMP a cc-request reply message.
 *
 * \param ctrl D channel controller.
 * \param call Q.931 call leg.
 * \param msgtype Q.931 message type to put facility ie in.
 * \param operation CCBS/CCNR operation code.
 * \param invoke_id Invoke id to put in error message response.
 * \param recall_mode Configured PTMP recall mode.
 * \param reference_id Active CC reference id.
 *
 * \retval 0 on success.
 * \retval -1 on error.
 */
static int rose_cc_etsi_ptmp_req_rsp_encode(struct pri *ctrl, q931_call *call, int msgtype, enum rose_operation operation, int invoke_id, int recall_mode, int reference_id)
{
	unsigned char buffer[256];
	unsigned char *end;

	end = enc_cc_etsi_ptmp_req_rsp(ctrl, buffer, buffer + sizeof(buffer), operation,
		invoke_id, recall_mode, reference_id);
	if (!end) {
		return -1;
	}

	return pri_call_apdu_queue(call, msgtype, buffer, end - buffer, NULL);
}

/*!
 * \internal
 * \brief Send the CC activation request result PTMP.
 *
 * \param ctrl D channel controller.
 * \param call Q.931 call leg.
 * \param operation CCBS/CCNR operation code.
 * \param invoke_id Invoke id to put in error message response.
 * \param recall_mode Configured PTMP recall mode.
 * \param reference_id Active CC reference id.
 *
 * \retval 0 on success.
 * \retval -1 on error.
 */
static int send_cc_etsi_ptmp_req_rsp(struct pri *ctrl, q931_call *call, enum rose_operation operation, int invoke_id, int recall_mode, int reference_id)
{
	if (rose_cc_etsi_ptmp_req_rsp_encode(ctrl, call, Q931_FACILITY, operation, invoke_id,
		recall_mode, reference_id)
		|| q931_facility(ctrl, call)) {
		pri_message(ctrl, "Could not schedule CC request result message.\n");
		return -1;
	}

	return 0;
}

/*!
 * \internal
 * \brief Response to an incoming CC activation request PTMP.
 *
 * \param ctrl D channel controller.
 * \param cc_record Call completion record to process event.
 * \param status success(0)/timeout(1)/
 *		short_term_denial(2)/long_term_denial(3)/not_subscribed(4)/queue_full(5)
 *
 * \retval 0 on success.
 * \retval -1 on error.
 */
static int pri_cc_req_rsp_ptmp(struct pri *ctrl, struct pri_cc_record *cc_record, int status)
{
	int fail;

	switch (cc_record->response.invoke_operation) {
	case ROSE_ETSI_CCBSRequest:
	case ROSE_ETSI_CCNRRequest:
		break;
	default:
		/* We no longer know how to send the response.  Should not happen. */
		return -1;
	}

	fail = 0;
	if (status) {
		enum rose_error_code code;

		switch (status) {
		default:
		case 1:/* timeout */
		case 2:/* short_term_denial */
			code = ROSE_ERROR_CCBS_ShortTermDenial;
			break;
		case 3:/* long_term_denial */
			code = ROSE_ERROR_CCBS_LongTermDenial;
			break;
		case 4:/* not_subscribed */
			code = ROSE_ERROR_Gen_NotSubscribed;
			break;
		case 5:/* queue_full */
			code = ROSE_ERROR_CCBS_OutgoingCCBSQueueFull;
			break;
		}
		send_facility_error(ctrl, cc_record->response.signaling,
			cc_record->response.invoke_id, code);
		pri_cc_event(ctrl, cc_record->response.signaling, cc_record,
			CC_EVENT_CANCEL);
	} else {
		/* Successful CC activation. */
		if (send_cc_etsi_ptmp_req_rsp(ctrl, cc_record->response.signaling,
			cc_record->response.invoke_operation, cc_record->response.invoke_id,
			cc_record->option.recall_mode, cc_record->ccbs_reference_id)) {
			fail = -1;
		}
		pri_cc_event(ctrl, cc_record->response.signaling, cc_record,
			CC_EVENT_CC_REQUEST_ACCEPT);
	}
	return fail;
}

/*!
 * \internal
 * \brief Encode a PTP cc-request reply message.
 *
 * \param ctrl D channel controller for diagnostic messages or global options.
 * \param pos Starting position to encode the facility ie contents.
 * \param end End of facility ie contents encoding data buffer.
 * \param cc_record Call completion record to process event.
 *
 * \retval Start of the next ASN.1 component to encode on success.
 * \retval NULL on error.
 */
static unsigned char *enc_cc_etsi_ptp_req_rsp(struct pri *ctrl, unsigned char *pos,
	unsigned char *end, struct pri_cc_record *cc_record)
{
	struct rose_msg_result msg;

	pos = facility_encode_header(ctrl, pos, end, NULL);
	if (!pos) {
		return NULL;
	}

	memset(&msg, 0, sizeof(msg));
	msg.invoke_id = cc_record->response.invoke_id;
	msg.operation = cc_record->response.invoke_operation;

	/* CCBS/CCNR reply */
	//msg.args.etsi.CCBS_T_Request.retention_supported = 0;

	pos = rose_encode_result(ctrl, pos, end, &msg);

	return pos;
}

/*!
 * \internal
 * \brief Encode and queue PTP a cc-request reply message.
 *
 * \param ctrl D channel controller.
 * \param call Q.931 call leg.
 * \param cc_record Call completion record to process event.
 *
 * \retval 0 on success.
 * \retval -1 on error.
 */
static int rose_cc_etsi_ptp_req_rsp_encode(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record)
{
	unsigned char buffer[256];
	unsigned char *end;

	end = enc_cc_etsi_ptp_req_rsp(ctrl, buffer, buffer + sizeof(buffer), cc_record);
	if (!end) {
		return -1;
	}

	return pri_call_apdu_queue(call, Q931_FACILITY, buffer, end - buffer, NULL);
}

/*!
 * \internal
 * \brief Send the CC activation request result PTP.
 *
 * \param ctrl D channel controller.
 * \param cc_record Call completion record to process event.
 *
 * \retval 0 on success.
 * \retval -1 on error.
 */
static int send_cc_etsi_ptp_req_rsp(struct pri *ctrl, struct pri_cc_record *cc_record)
{
	if (rose_cc_etsi_ptp_req_rsp_encode(ctrl, cc_record->signaling, cc_record)
		|| q931_facility(ctrl, cc_record->signaling)) {
		pri_message(ctrl, "Could not schedule CC request result message.\n");
		return -1;
	}

	return 0;
}

/*!
 * \internal
 * \brief Response to an incoming CC activation request PTP.
 *
 * \param ctrl D channel controller.
 * \param cc_record Call completion record to process event.
 * \param status success(0)/timeout(1)/
 *		short_term_denial(2)/long_term_denial(3)/not_subscribed(4)/queue_full(5)
 *
 * \retval 0 on success.
 * \retval -1 on error.
 */
static int pri_cc_req_rsp_ptp(struct pri *ctrl, struct pri_cc_record *cc_record, int status)
{
	int fail;

	switch (cc_record->response.invoke_operation) {
	case ROSE_ETSI_CCBS_T_Request:
	case ROSE_ETSI_CCNR_T_Request:
		break;
	default:
		/* We no longer know how to send the response.  Should not happen. */
		return -1;
	}
	if (!cc_record->signaling) {
		return -1;
	}

	fail = 0;
	if (status) {
		enum rose_error_code code;

		switch (status) {
		default:
		case 1:/* timeout */
		case 5:/* queue_full */
		case 2:/* short_term_denial */
			code = ROSE_ERROR_CCBS_T_ShortTermDenial;
			break;
		case 3:/* long_term_denial */
			code = ROSE_ERROR_CCBS_T_LongTermDenial;
			break;
		case 4:/* not_subscribed */
			code = ROSE_ERROR_Gen_NotSubscribed;
			break;
		}
		rose_error_msg_encode(ctrl, cc_record->signaling, Q931_ANY_MESSAGE,
			cc_record->response.invoke_id, code);
		pri_cc_event(ctrl, cc_record->signaling, cc_record, CC_EVENT_CANCEL);
	} else {
		/* Successful CC activation. */
		if (send_cc_etsi_ptp_req_rsp(ctrl, cc_record)) {
			fail = -1;
		}
		pri_cc_event(ctrl, cc_record->signaling, cc_record, CC_EVENT_CC_REQUEST_ACCEPT);
	}
	return fail;
}

/*!
 * \internal
 * \brief Encode a Q.SIG cc-request reply message.
 *
 * \param ctrl D channel controller for diagnostic messages or global options.
 * \param pos Starting position to encode the facility ie contents.
 * \param end End of facility ie contents encoding data buffer.
 * \param cc_record Call completion record to process event.
 *
 * \retval Start of the next ASN.1 component to encode on success.
 * \retval NULL on error.
 */
static unsigned char *enc_cc_qsig_req_rsp(struct pri *ctrl, unsigned char *pos,
	unsigned char *end, struct pri_cc_record *cc_record)
{
	struct fac_extension_header header;
	struct rose_msg_result msg;

	memset(&header, 0, sizeof(header));
	header.nfe_present = 1;
	header.nfe.source_entity = 0;	/* endPINX */
	header.nfe.destination_entity = 0;	/* endPINX */
	header.interpretation_present = 1;
	header.interpretation = 0;	/* discardAnyUnrecognisedInvokePdu */
	pos = facility_encode_header(ctrl, pos, end, &header);
	if (!pos) {
		return NULL;
	}

	memset(&msg, 0, sizeof(msg));
	msg.invoke_id = cc_record->response.invoke_id;
	msg.operation = cc_record->response.invoke_operation;

	/* CCBS/CCNR reply */

	/* We do not support ccPathReserve */
	msg.args.qsig.CcbsRequest.no_path_reservation = 1;
	//msg.args.qsig.CcbsRequest.retain_service = 0;

	pos = rose_encode_result(ctrl, pos, end, &msg);

	return pos;
}

/*!
 * \internal
 * \brief Encode and queue Q.SIG a cc-request reply message.
 *
 * \param ctrl D channel controller.
 * \param call Q.931 call leg.
 * \param cc_record Call completion record to process event.
 *
 * \retval 0 on success.
 * \retval -1 on error.
 */
static int rose_cc_qsig_req_rsp_encode(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record)
{
	unsigned char buffer[256];
	unsigned char *end;

	end = enc_cc_qsig_req_rsp(ctrl, buffer, buffer + sizeof(buffer), cc_record);
	if (!end) {
		return -1;
	}

	return pri_call_apdu_queue(call, Q931_ANY_MESSAGE, buffer, end - buffer, NULL);
}

/*!
 * \internal
 * \brief Send the CC activation request result Q.SIG.
 *
 * \param ctrl D channel controller.
 * \param cc_record Call completion record to process event.
 *
 * \retval 0 on success.
 * \retval -1 on error.
 */
static int send_cc_qsig_req_rsp(struct pri *ctrl, struct pri_cc_record *cc_record)
{
	struct q931_call *call;
	int retval;

	/* The cc-request response goes out on either a CONNECT or RELEASE message. */
	call = cc_record->signaling;
	retval = rose_cc_qsig_req_rsp_encode(ctrl, call, cc_record);
	if (!retval) {
		if (cc_record->option.retain_signaling_link) {
			retval = q931_connect(ctrl, call, 0, 0);
		} else {
			pri_cc_disassociate_signaling_link(cc_record);
			retval = pri_hangup(ctrl, call, -1);
		}
	}
	if (retval) {
		pri_message(ctrl, "Could not schedule CC request result message.\n");
		return -1;
	}

	return 0;
}

/*!
 * \internal
 * \brief Response to an incoming CC activation request Q.SIG.
 *
 * \param ctrl D channel controller.
 * \param cc_record Call completion record to process event.
 * \param status success(0)/timeout(1)/
 *		short_term_denial(2)/long_term_denial(3)/not_subscribed(4)/queue_full(5)
 *
 * \retval 0 on success.
 * \retval -1 on error.
 */
static int pri_cc_req_rsp_qsig(struct pri *ctrl, struct pri_cc_record *cc_record, int status)
{
	int fail;

	switch (cc_record->response.invoke_operation) {
	case ROSE_QSIG_CcbsRequest:
	case ROSE_QSIG_CcnrRequest:
		break;
	default:
		/* We no longer know how to send the response.  Should not happen. */
		return -1;
	}
	if (!cc_record->signaling) {
		return -1;
	}

	fail = 0;
	if (status) {
		enum rose_error_code code;

		switch (status) {
		default:
		case 1:/* timeout */
		case 5:/* queue_full */
		case 2:/* short_term_denial */
			code = ROSE_ERROR_QSIG_ShortTermRejection;
			break;
		case 4:/* not_subscribed */
		case 3:/* long_term_denial */
			code = ROSE_ERROR_QSIG_LongTermRejection;
			break;
		}
		rose_error_msg_encode(ctrl, cc_record->signaling, Q931_ANY_MESSAGE,
			cc_record->response.invoke_id, code);
		pri_cc_event(ctrl, cc_record->signaling, cc_record, CC_EVENT_CANCEL);
	} else {
		/* Successful CC activation. */
		if (send_cc_qsig_req_rsp(ctrl, cc_record)) {
			fail = -1;
		}
		pri_cc_event(ctrl, cc_record->signaling, cc_record, CC_EVENT_CC_REQUEST_ACCEPT);
	}
	return fail;
}

/*!
 * \brief Response to an incoming CC activation request.
 *
 * \param ctrl D channel controller.
 * \param cc_id CC record ID to activate.
 * \param status success(0)/timeout(1)/
 *      short_term_denial(2)/long_term_denial(3)/not_subscribed(4)/queue_full(5)
 *
 * \note
 * If the given status was failure, then the cc_id is no longer valid.
 * \note
 * The caller should cancel CC if error is returned.
 *
 * \retval 0 on success.
 * \retval -1 on error.
 */
int pri_cc_req_rsp(struct pri *ctrl, long cc_id, int status)
{
	struct pri_cc_record *cc_record;
	int fail;

	if (!ctrl) {
		return -1;
	}
	cc_record = pri_cc_find_by_id(ctrl, cc_id);
	if (!cc_record) {
		return -1;
	}
	if (!cc_record->is_agent) {
		/* CC is a monitor and does not send this response event. */
		return -1;
	}

	fail = -1;
	switch (ctrl->switchtype) {
	case PRI_SWITCH_QSIG:
		if (!pri_cc_req_rsp_qsig(ctrl, cc_record, status)) {
			fail = 0;
		}
		break;
	case PRI_SWITCH_EUROISDN_E1:
	case PRI_SWITCH_EUROISDN_T1:
		if (PTMP_MODE(ctrl)) {
			if (!pri_cc_req_rsp_ptmp(ctrl, cc_record, status)) {
				fail = 0;
			}
		} else {
			if (!pri_cc_req_rsp_ptp(ctrl, cc_record, status)) {
				fail = 0;
			}
		}
		break;
	default:
		break;
	}
	return fail;
}

/*!
 * \brief Indicate that the remote user (Party B) is free to call.
 * The upper layer considers Party A is free.
 *
 * \param ctrl D channel controller.
 * \param cc_id CC record ID to activate.
 *
 * \return Nothing
 */
void pri_cc_remote_user_free(struct pri *ctrl, long cc_id)
{
	struct pri_cc_record *cc_record;

	if (!ctrl) {
		return;
	}
	cc_record = pri_cc_find_by_id(ctrl, cc_id);
	if (!cc_record) {
		return;
	}
	if (!cc_record->is_agent) {
		/* CC is a monitor and does not send this event. */
		return;
	}

	pri_cc_event(ctrl, cc_record->signaling, cc_record, CC_EVENT_REMOTE_USER_FREE);
}

/*!
 * \brief Indicate that the remote user (Party B) is free to call.
 * However, the upper layer considers Party A is busy.
 *
 * \details
 * Party B is free, but Party A is considered busy for some reason.
 * This is mainly due to the upper layer experiencing congestion.
 * The upper layer will be monitoring Party A until it considers
 * Party A free again.
 *
 * \param ctrl D channel controller.
 * \param cc_id CC record ID to activate.
 *
 * \return Nothing
 */
void pri_cc_b_free(struct pri *ctrl, long cc_id)
{
	struct pri_cc_record *cc_record;

	if (!ctrl) {
		return;
	}
	cc_record = pri_cc_find_by_id(ctrl, cc_id);
	if (!cc_record) {
		return;
	}
	if (!cc_record->is_agent) {
		/* CC is a monitor and does not send this event. */
		return;
	}

	pri_cc_event(ctrl, cc_record->signaling, cc_record, CC_EVENT_B_FREE);
}

/*!
 * \brief Indicate that some other Party A has responed to the CC recall.
 *
 * \param ctrl D channel controller.
 * \param cc_id CC record ID to activate.
 *
 * \return Nothing
 */
void pri_cc_stop_alerting(struct pri *ctrl, long cc_id)
{
	struct pri_cc_record *cc_record;

	if (!ctrl) {
		return;
	}
	cc_record = pri_cc_find_by_id(ctrl, cc_id);
	if (!cc_record) {
		return;
	}
	if (!cc_record->is_agent) {
		/* CC is a monitor and does not send this event. */
		return;
	}

	pri_cc_event(ctrl, cc_record->signaling, cc_record, CC_EVENT_STOP_ALERTING);
}

/*!
 * \brief Poll/Ping for the status of CC party A.
 *
 * \param ctrl D channel controller.
 * \param cc_id CC record ID to activate.
 *
 * \note
 * There could be zero, one, or more PRI_SUBCMD_CC_STATUS_REQ_RSP responses to
 * the status request depending upon how many endpoints respond to the request.
 * \note
 * This is expected to be called only if there are two PTMP links between
 * party A and the network.  (e.g., A --> * --> PSTN)
 *
 * \return Nothing
 */
void pri_cc_status_req(struct pri *ctrl, long cc_id)
{
	struct pri_cc_record *cc_record;

	if (!ctrl) {
		return;
	}
	cc_record = pri_cc_find_by_id(ctrl, cc_id);
	if (!cc_record) {
		return;
	}
	if (!cc_record->is_agent) {
		/* CC is a monitor and does not send this event. */
		return;
	}

	pri_cc_event(ctrl, cc_record->signaling, cc_record, CC_EVENT_A_STATUS);
}

/*!
 * \internal
 * \brief Encode and queue an CCBSStatusRequest result message.
 *
 * \param ctrl D channel controller for diagnostic messages or global options.
 * \param call Call leg from which to encode CCBSStatusRequest.
 * \param cc_record Call completion record to process event.
 * \param is_free TRUE if the Party A status is available.
 *
 * \retval 0 on success.
 * \retval -1 on error.
 */
static int rose_ccbs_status_request_rsp(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record, int is_free)
{
	unsigned char buffer[256];
	unsigned char *end;

	end =
		enc_etsi_ptmp_ccbs_status_request_rsp(ctrl, buffer, buffer + sizeof(buffer),
			cc_record, is_free);
	if (!end) {
		return -1;
	}

	return pri_call_apdu_queue(call, Q931_FACILITY, buffer, end - buffer, NULL);
}

/*!
 * \internal
 * \brief Encode and send an CCBSStatusRequest result message.
 *
 * \param ctrl D channel controller for diagnostic messages or global options.
 * \param call Call leg from which to encode CCBSStatusRequest.
 * \param cc_record Call completion record to process event.
 * \param is_free TRUE if the Party A status is available.
 *
 * \retval 0 on success.
 * \retval -1 on error.
 */
static int send_ccbs_status_request_rsp(struct pri *ctrl, q931_call *call, struct pri_cc_record *cc_record, int is_free)
{
	if (rose_ccbs_status_request_rsp(ctrl, call, cc_record, is_free)
		|| q931_facility(ctrl, call)) {
		pri_message(ctrl,
			"Could not schedule facility message for CCBSStatusRequest result.\n");
		return -1;
	}

	return 0;
}

/*!
 * \brief Update the busy status of CC party A.
 *
 * \param ctrl D channel controller.
 * \param cc_id CC record ID to activate.
 * \param status Updated party A status free(0)/busy(1)
 *
 * \note
 * This is expected to be called only if there are two PTMP links between
 * party A and the network.  (e.g., A --> * --> PSTN)
 *
 * \return Nothing
 */
void pri_cc_status_req_rsp(struct pri *ctrl, long cc_id, int status)
{
	struct pri_cc_record *cc_record;

	if (!ctrl) {
		return;
	}
	cc_record = pri_cc_find_by_id(ctrl, cc_id);
	if (!cc_record) {
		return;
	}
	if (cc_record->is_agent) {
		/* CC is an agent and does not send this response event. */
		return;
	}

	switch (ctrl->switchtype) {
	case PRI_SWITCH_QSIG:
		/* Does not apply. */
		break;
	case PRI_SWITCH_EUROISDN_E1:
	case PRI_SWITCH_EUROISDN_T1:
		if (PTMP_MODE(ctrl)) {
			if (cc_record->response.invoke_operation != ROSE_ETSI_CCBSStatusRequest) {
				/* We no longer know how to send the response. */
				break;
			}
			send_ccbs_status_request_rsp(ctrl, cc_record->signaling, cc_record,
				status ? 0 /* busy */ : 1 /* free */);
		}
		break;
	default:
		break;
	}
}

/*!
 * \brief Update the busy status of CC party A.
 *
 * \param ctrl D channel controller.
 * \param cc_id CC record ID to activate.
 * \param status Updated party A status free(0)/busy(1)
 *
 * \note
 * Party A status is used to suspend/resume monitoring party B.
 *
 * \return Nothing
 */
void pri_cc_status(struct pri *ctrl, long cc_id, int status)
{
	struct pri_cc_record *cc_record;

	if (!ctrl) {
		return;
	}
	cc_record = pri_cc_find_by_id(ctrl, cc_id);
	if (!cc_record) {
		return;
	}
	if (cc_record->is_agent) {
		/* CC is an agent and does not send this event. */
		return;
	}

	pri_cc_event(ctrl, cc_record->signaling, cc_record,
		status ? CC_EVENT_SUSPEND : CC_EVENT_RESUME);
}

/*!
 * \brief Initiate the CC callback call.
 *
 * \param ctrl D channel controller.
 * \param cc_id CC record ID to activate.
 * \param call Q.931 call leg.
 * \param req SETUP request parameters.  Parameters saved by CC will override.
 *
 * \retval 0 on success.
 * \retval -1 on error.
 */
int pri_cc_call(struct pri *ctrl, long cc_id, q931_call *call, struct pri_sr *req)
{
	struct pri_cc_record *cc_record;

	if (!ctrl || !pri_is_call_valid(ctrl, call) || !req) {
		return -1;
	}
	cc_record = pri_cc_find_by_id(ctrl, cc_id);
	if (!cc_record) {
		return -1;
	}
	if (cc_record->is_agent) {
		/* CC is an agent and does not initiate callbacks. */
		return -1;
	}

	/* Override parameters for sending recall. */
	req->caller = cc_record->party_a;
	req->called = cc_record->party_b;
	req->transmode = cc_record->bc.transcapability;
	req->userl1 = cc_record->bc.userl1;

	/*
	 * The caller is allowed to send different user-user information.
	 *
	 * It makes no sense for the caller to supply redirecting information
	 * but we'll allow it to pass anyway.
	 */
	//q931_party_redirecting_init(&req->redirecting);

	/* Add switch specific recall APDU to call. */
	pri_cc_event(ctrl, call, cc_record, CC_EVENT_RECALL);

	if (q931_setup(ctrl, call, req)) {
		return -1;
	}
	return 0;
}

/*!
 * \brief Unsolicited indication that CC is cancelled.
 *
 * \param ctrl D channel controller.
 * \param cc_id CC record ID to deactivate.
 *
 * \return Nothing.  The cc_id is no longer valid.
 */
void pri_cc_cancel(struct pri *ctrl, long cc_id)
{
	struct pri_cc_record *cc_record;

	if (!ctrl) {
		return;
	}
	cc_record = pri_cc_find_by_id(ctrl, cc_id);
	if (!cc_record) {
		return;
	}
	pri_cc_event(ctrl, cc_record->signaling, cc_record, CC_EVENT_CANCEL);
}

/* ------------------------------------------------------------------- */
/* end pri_cc.c */
