aboutsummaryrefslogtreecommitdiffstats
path: root/main/libpri
diff options
context:
space:
mode:
authorTimo Teras <timo.teras@iki.fi>2009-11-28 02:49:14 +0200
committerTimo Teras <timo.teras@iki.fi>2009-11-28 02:50:34 +0200
commitbf4a081b091fc26e782bb24c786ae5ceb0577fb3 (patch)
tree872c7b04573804463a6fe5dfa00dc58d6a68a899 /main/libpri
parent25668b00edf92d80fc2f15691948b659a4ac3b59 (diff)
downloadaports-bf4a081b091fc26e782bb24c786ae5ceb0577fb3.tar.bz2
aports-bf4a081b091fc26e782bb24c786ae5ceb0577fb3.tar.xz
main/libpri: upgrade to latest svn snapshot
Diffstat (limited to 'main/libpri')
-rw-r--r--main/libpri/APKBUILD17
-rw-r--r--main/libpri/libpri-1.4-r1357.patch39961
-rw-r--r--main/libpri/libpri-1.4.9-i14292.patch5668
3 files changed, 39969 insertions, 5677 deletions
diff --git a/main/libpri/APKBUILD b/main/libpri/APKBUILD
index d4d90a8103..05467c5352 100644
--- a/main/libpri/APKBUILD
+++ b/main/libpri/APKBUILD
@@ -1,8 +1,9 @@
# Contributor: Timo Teras <timo.teras@iki.fi>
# Maintainer: Timo Teras <timo.teras@iki.fi>
pkgname=libpri
-pkgver=1.4.9
-pkgrel=1
+pkgver=1.4.11_alpha1
+_pkgver=1.4.10.2
+pkgrel=0
pkgdesc="Primary Rate ISDN (PRI) library"
url="http://www.asterisk.orig"
license="GPL"
@@ -10,12 +11,11 @@ depends=""
makedepends=""
install=
subpackages="$pkgname-dev"
-source="http://downloads.digium.com/pub/telephony/libpri/releases/$pkgname-$pkgver.tar.gz
- libpri-cflags.patch
- libpri-1.4.9-i14292.patch"
+source="http://downloads.digium.com/pub/telephony/libpri/releases/$pkgname-$_pkgver.tar.gz
+ libpri-1.4-r1357.patch"
build() {
- cd "$srcdir/$pkgname-$pkgver"
+ cd "$srcdir/$pkgname-$_pkgver"
for i in ../*.patch; do
msg "Applying $i"
patch -p1 < $i || return 1;
@@ -28,6 +28,5 @@ build() {
# install -m644 -D "$srcdir"/$pkgname.confd "$pkgdir"/etc/conf.d/$pkgname
}
-md5sums="97332edeaa2de0320d85fda88afb96f9 libpri-1.4.9.tar.gz
-8df2ca48ce7db4f1a8604b0904bc9394 libpri-cflags.patch
-240e4057980c88f2c2576c5c25744c70 libpri-1.4.9-i14292.patch"
+md5sums="dc1523d8ee027cd62f20fc6cc9727489 libpri-1.4.10.2.tar.gz
+61a245689a40e456643ed654441a280d libpri-1.4-r1357.patch"
diff --git a/main/libpri/libpri-1.4-r1357.patch b/main/libpri/libpri-1.4-r1357.patch
new file mode 100644
index 0000000000..be827eebb7
--- /dev/null
+++ b/main/libpri/libpri-1.4-r1357.patch
@@ -0,0 +1,39961 @@
+===================================================================
+--- a/pri_timers.h (.../tags/1.4.10.2) (revision 1357)
++++ b/pri_timers.h (.../branches/1.4) (revision 1357)
+@@ -1,97 +0,0 @@
+-/*
+- * libpri: An implementation of Primary Rate ISDN
+- *
+- * Written by Mark Spencer <markster@digium.com>
+- *
+- * Copyright (C) 2001, Digium, Inc.
+- * All Rights Reserved.
+- */
+-
+-/*
+- * 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.
+- */
+-
+-#ifndef _PRI_TIMERS_H
+-#define _PRI_TIMERS_H
+-
+-/* -1 means we dont currently support the timer/counter */
+-#define PRI_TIMERS_DEFAULT { \
+- 3, /* N200 */ \
+- -1, /* N201 */ \
+- 3, /* N202 */ \
+- 7, /* K */ \
+- 1000, /* T200 */ \
+- -1, /* T201 */ \
+- 10000, /* T202 */ \
+- 10000, /* T203 */ \
+- -1, /* T300 */ \
+- -1, /* T301 */ \
+- -1, /* T302 */ \
+- -1, /* T303 */ \
+- -1, /* T304 */ \
+- 30000, /* T305 */ \
+- -1, /* T306 */ \
+- -1, /* T307 */ \
+- 4000, /* T308 */ \
+- -1, /* T309 */ \
+- -1, /* T310 */ \
+- 4000, /* T313 */ \
+- -1, /* T314 */ \
+- -1, /* T316 */ \
+- -1, /* T317 */ \
+- -1, /* T318 */ \
+- -1, /* T319 */ \
+- -1, /* T320 */ \
+- -1, /* T321 */ \
+- -1, /* T322 */ \
+- 2500, /* TM20 - Q.921 Appendix IV */ \
+- 3, /* NM20 - Q.921 Appendix IV */ \
+- }
+-
+-/* XXX Only our default timers are setup now XXX */
+-#define PRI_TIMERS_UNKNOWN PRI_TIMERS_DEFAULT
+-#define PRI_TIMERS_NI2 PRI_TIMERS_DEFAULT
+-#define PRI_TIMERS_DMS100 PRI_TIMERS_DEFAULT
+-#define PRI_TIMERS_LUCENT5E PRI_TIMERS_DEFAULT
+-#define PRI_TIMERS_ATT4ESS PRI_TIMERS_DEFAULT
+-#define PRI_TIMERS_EUROISDN_E1 PRI_TIMERS_DEFAULT
+-#define PRI_TIMERS_EUROISDN_T1 PRI_TIMERS_DEFAULT
+-#define PRI_TIMERS_NI1 PRI_TIMERS_DEFAULT
+-#define PRI_TIMERS_GR303_EOC PRI_TIMERS_DEFAULT
+-#define PRI_TIMERS_GR303_TMC PRI_TIMERS_DEFAULT
+-#define PRI_TIMERS_QSIG PRI_TIMERS_DEFAULT
+-#define __PRI_TIMERS_GR303_EOC_INT PRI_TIMERS_DEFAULT
+-#define __PRI_TIMERS_GR303_TMC_INT PRI_TIMERS_DEFAULT
+-
+-#define PRI_TIMERS_ALL { PRI_TIMERS_UNKNOWN, \
+- PRI_TIMERS_NI2, \
+- PRI_TIMERS_DMS100, \
+- PRI_TIMERS_LUCENT5E, \
+- PRI_TIMERS_ATT4ESS, \
+- PRI_TIMERS_EUROISDN_E1, \
+- PRI_TIMERS_EUROISDN_T1, \
+- PRI_TIMERS_NI1, \
+- PRI_TIMERS_QSIG, \
+- PRI_TIMERS_GR303_EOC, \
+- PRI_TIMERS_GR303_TMC, \
+- __PRI_TIMERS_GR303_EOC_INT, \
+- __PRI_TIMERS_GR303_TMC_INT, \
+- }
+-
+-#endif
+Index: .version
+===================================================================
+--- a/.version (.../tags/1.4.10.2) (revision 1357)
++++ b/.version (.../branches/1.4) (revision 1357)
+@@ -1 +1 @@
+-1.4.10.2
++1.4.10.2-r1357
+Index: prisched.c
+===================================================================
+--- a/prisched.c (.../tags/1.4.10.2) (revision 1357)
++++ b/prisched.c (.../branches/1.4) (revision 1357)
+@@ -33,25 +33,43 @@
+ #include "pri_internal.h"
+
+
++/*! \brief The maximum number of timers that were active at once. */
+ static int maxsched = 0;
+
+ /* Scheduler routines */
+-int pri_schedule_event(struct pri *pri, int ms, void (*function)(void *data), void *data)
++
++/*!
++ * \brief Start a timer to schedule an event.
++ *
++ * \param ctrl D channel controller.
++ * \param ms Number of milliseconds to scheduled event.
++ * \param function Callback function to call when timeout.
++ * \param data Value to give callback function when timeout.
++ *
++ * \retval 0 if scheduler table is full and could not schedule the event.
++ * \retval id Scheduled event id.
++ */
++int pri_schedule_event(struct pri *ctrl, int ms, void (*function)(void *data), void *data)
+ {
+ int x;
+ struct timeval tv;
++
+ /* Scheduling runs on master channels only */
+- while (pri->master)
+- pri = pri->master;
+- for (x=1;x<MAX_SCHED;x++)
+- if (!pri->pri_sched[x].callback)
++ while (ctrl->master) {
++ ctrl = ctrl->master;
++ }
++ for (x = 0; x < MAX_SCHED; ++x) {
++ if (!ctrl->pri_sched[x].callback) {
+ break;
++ }
++ }
+ if (x == MAX_SCHED) {
+- pri_error(pri, "No more room in scheduler\n");
+- return -1;
++ pri_error(ctrl, "No more room in scheduler\n");
++ return 0;
+ }
+- if (x > maxsched)
+- maxsched = x;
++ if (x >= maxsched) {
++ maxsched = x + 1;
++ }
+ gettimeofday(&tv, NULL);
+ tv.tv_sec += ms / 1000;
+ tv.tv_usec += (ms % 1000) * 1000;
+@@ -59,71 +77,110 @@
+ tv.tv_usec -= 1000000;
+ tv.tv_sec += 1;
+ }
+- pri->pri_sched[x].when = tv;
+- pri->pri_sched[x].callback = function;
+- pri->pri_sched[x].data = data;
+- return x;
++ ctrl->pri_sched[x].when = tv;
++ ctrl->pri_sched[x].callback = function;
++ ctrl->pri_sched[x].data = data;
++ return x + 1;
+ }
+
+-struct timeval *pri_schedule_next(struct pri *pri)
++/*!
++ * \brief Determine the time of the next scheduled event to expire.
++ *
++ * \param ctrl D channel controller.
++ *
++ * \return Time of the next scheduled event to expire or NULL if no timers active.
++ */
++struct timeval *pri_schedule_next(struct pri *ctrl)
+ {
+ struct timeval *closest = NULL;
+ int x;
+- /* Check subchannels */
+- if (pri->subchannel)
+- closest = pri_schedule_next(pri->subchannel);
+- for (x=1;x<MAX_SCHED;x++) {
+- if (pri->pri_sched[x].callback &&
+- (!closest || (closest->tv_sec > pri->pri_sched[x].when.tv_sec) ||
+- ((closest->tv_sec == pri->pri_sched[x].when.tv_sec) &&
+- (closest->tv_usec > pri->pri_sched[x].when.tv_usec))))
+- closest = &pri->pri_sched[x].when;
++
++ /* Scheduling runs on master channels only */
++ while (ctrl->master) {
++ ctrl = ctrl->master;
+ }
++ for (x = 0; x < MAX_SCHED; ++x) {
++ if (ctrl->pri_sched[x].callback && (!closest
++ || (closest->tv_sec > ctrl->pri_sched[x].when.tv_sec)
++ || ((closest->tv_sec == ctrl->pri_sched[x].when.tv_sec)
++ && (closest->tv_usec > ctrl->pri_sched[x].when.tv_usec)))) {
++ closest = &ctrl->pri_sched[x].when;
++ }
++ }
+ return closest;
+ }
+
+-static pri_event *__pri_schedule_run(struct pri *pri, struct timeval *tv)
++/*!
++ * \internal
++ * \brief Run all expired timers or return an event generated by an expired timer.
++ *
++ * \param ctrl D channel controller.
++ * \param tv Current time.
++ *
++ * \return Event for upper layer to process or NULL if all expired timers run.
++ */
++static pri_event *__pri_schedule_run(struct pri *ctrl, struct timeval *tv)
+ {
+ int x;
+ void (*callback)(void *);
+ void *data;
+- pri_event *e;
+- if (pri->subchannel) {
+- if ((e = __pri_schedule_run(pri->subchannel, tv))) {
+- return e;
++
++ /* Scheduling runs on master channels only */
++ while (ctrl->master) {
++ ctrl = ctrl->master;
++ }
++ for (x = 0; x < MAX_SCHED; ++x) {
++ if (ctrl->pri_sched[x].callback && ((ctrl->pri_sched[x].when.tv_sec < tv->tv_sec)
++ || ((ctrl->pri_sched[x].when.tv_sec == tv->tv_sec)
++ && (ctrl->pri_sched[x].when.tv_usec <= tv->tv_usec)))) {
++ /* This timer has expired. */
++ ctrl->schedev = 0;
++ callback = ctrl->pri_sched[x].callback;
++ data = ctrl->pri_sched[x].data;
++ ctrl->pri_sched[x].callback = NULL;
++ callback(data);
++ if (ctrl->schedev) {
++ return &ctrl->ev;
++ }
+ }
+ }
+- for (x=1;x<MAX_SCHED;x++) {
+- if (pri->pri_sched[x].callback &&
+- ((pri->pri_sched[x].when.tv_sec < tv->tv_sec) ||
+- ((pri->pri_sched[x].when.tv_sec == tv->tv_sec) &&
+- (pri->pri_sched[x].when.tv_usec <= tv->tv_usec)))) {
+- pri->schedev = 0;
+- callback = pri->pri_sched[x].callback;
+- data = pri->pri_sched[x].data;
+- pri->pri_sched[x].callback = NULL;
+- pri->pri_sched[x].data = NULL;
+- callback(data);
+- if (pri->schedev)
+- return &pri->ev;
+- }
+- }
+ return NULL;
+ }
+
+-pri_event *pri_schedule_run(struct pri *pri)
++/*!
++ * \brief Run all expired timers or return an event generated by an expired timer.
++ *
++ * \param ctrl D channel controller.
++ *
++ * \return Event for upper layer to process or NULL if all expired timers run.
++ */
++pri_event *pri_schedule_run(struct pri *ctrl)
+ {
+ struct timeval tv;
++
+ gettimeofday(&tv, NULL);
+- return __pri_schedule_run(pri, &tv);
++ return __pri_schedule_run(ctrl, &tv);
+ }
+
+-
+-void pri_schedule_del(struct pri *pri,int id)
++/*!
++ * \brief Delete a scheduled event.
++ *
++ * \param ctrl D channel controller.
++ * \param id Scheduled event id to delete.
++ * 0 is a disabled/unscheduled event id that is ignored.
++ * 1 - MAX_SCHED is a valid event id.
++ *
++ * \return Nothing
++ */
++void pri_schedule_del(struct pri *ctrl, int id)
+ {
+- while (pri->master)
+- pri = pri->master;
+- if ((id >= MAX_SCHED) || (id < 0))
+- pri_error(pri, "Asked to delete sched id %d???\n", id);
+- pri->pri_sched[id].callback = NULL;
++ /* Scheduling runs on master channels only */
++ while (ctrl->master) {
++ ctrl = ctrl->master;
++ }
++ if (0 < id && id <= MAX_SCHED) {
++ ctrl->pri_sched[id - 1].callback = NULL;
++ } else if (id) {
++ pri_error(ctrl, "Asked to delete sched id %d???\n", id);
++ }
+ }
+Index: rose_qsig_mwi.c
+===================================================================
+--- a/rose_qsig_mwi.c (.../tags/1.4.10.2) (revision 0)
++++ b/rose_qsig_mwi.c (.../branches/1.4) (revision 1357)
+@@ -0,0 +1,790 @@
++/*
++ * 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 Q.SIG ROSE SS-MWI-Operations
++ *
++ * SS-MWI-Operations ECMA-242 Annex E Table E.1
++ *
++ * \author Richard Mudgett <rmudgett@digium.com>
++ */
++
++
++#include "compat.h"
++#include "libpri.h"
++#include "pri_internal.h"
++#include "rose.h"
++#include "rose_internal.h"
++#include "asn1.h"
++
++
++/* ------------------------------------------------------------------- */
++
++/*!
++ * \internal
++ * \brief Encode the MsgCentreId type.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param msg_centre_id
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *rose_enc_qsig_MsgCentreId(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const struct roseQsigMsgCentreId *msg_centre_id)
++{
++ unsigned char *seq_len;
++
++ switch (msg_centre_id->type) {
++ case 0: /* integer */
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 0,
++ msg_centre_id->u.integer));
++ break;
++ case 1: /* partyNumber */
++ /* EXPLICIT tag */
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 1);
++ ASN1_CALL(pos, rose_enc_PartyNumber(ctrl, pos, end, &msg_centre_id->u.number));
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++ break;
++ case 2: /* numericString */
++ ASN1_CALL(pos, asn1_enc_string_max(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 2,
++ msg_centre_id->u.str, sizeof(msg_centre_id->u.str) - 1));
++ break;
++ default:
++ ASN1_ENC_ERROR(ctrl, "Unknown MsgCentreId type");
++ return NULL;
++ }
++
++ return pos;
++}
++
++/*!
++ * \brief Encode the MWIActivate invoke facility ie arguments.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param args Arguments to encode in the buffer.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_qsig_MWIActivate_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args)
++{
++ const struct roseQsigMWIActivateArg *mwi_activate;
++ unsigned char *seq_len;
++ unsigned char *explicit_len;
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_TAG_SEQUENCE);
++
++ mwi_activate = &args->qsig.MWIActivate;
++ ASN1_CALL(pos, rose_enc_PartyNumber(ctrl, pos, end,
++ &mwi_activate->served_user_number));
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED,
++ mwi_activate->basic_service));
++ if (mwi_activate->msg_centre_id_present) {
++ ASN1_CALL(pos, rose_enc_qsig_MsgCentreId(ctrl, pos, end,
++ &mwi_activate->msg_centre_id));
++ }
++ if (mwi_activate->number_of_messages_present) {
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 3,
++ mwi_activate->number_of_messages));
++ }
++ if (mwi_activate->originating_number.length) {
++ /* EXPLICIT tag */
++ ASN1_CONSTRUCTED_BEGIN(explicit_len, pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 4);
++ ASN1_CALL(pos, rose_enc_PartyNumber(ctrl, pos, end,
++ &mwi_activate->originating_number));
++ ASN1_CONSTRUCTED_END(explicit_len, pos, end);
++ }
++ if (mwi_activate->timestamp_present) {
++ ASN1_CALL(pos, asn1_enc_string_max(pos, end, ASN1_TYPE_GENERALIZED_TIME,
++ mwi_activate->timestamp, sizeof(mwi_activate->timestamp) - 1));
++ }
++ if (mwi_activate->priority_present) {
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 5,
++ mwi_activate->priority));
++ }
++
++ /* No extension to encode */
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Encode the MWIDeactivate invoke facility ie arguments.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param args Arguments to encode in the buffer.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_qsig_MWIDeactivate_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args)
++{
++ const struct roseQsigMWIDeactivateArg *mwi_deactivate;
++ unsigned char *seq_len;
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_TAG_SEQUENCE);
++
++ mwi_deactivate = &args->qsig.MWIDeactivate;
++ ASN1_CALL(pos, rose_enc_PartyNumber(ctrl, pos, end,
++ &mwi_deactivate->served_user_number));
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED,
++ mwi_deactivate->basic_service));
++ if (mwi_deactivate->msg_centre_id_present) {
++ ASN1_CALL(pos, rose_enc_qsig_MsgCentreId(ctrl, pos, end,
++ &mwi_deactivate->msg_centre_id));
++ }
++
++ /* No extension to encode */
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Encode the MWIInterrogate invoke facility ie arguments.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param args Arguments to encode in the buffer.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_qsig_MWIInterrogate_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args)
++{
++ const struct roseQsigMWIInterrogateArg *mwi_interrogate;
++ unsigned char *seq_len;
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_TAG_SEQUENCE);
++
++ mwi_interrogate = &args->qsig.MWIInterrogate;
++ ASN1_CALL(pos, rose_enc_PartyNumber(ctrl, pos, end,
++ &mwi_interrogate->served_user_number));
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED,
++ mwi_interrogate->basic_service));
++ if (mwi_interrogate->msg_centre_id_present) {
++ ASN1_CALL(pos, rose_enc_qsig_MsgCentreId(ctrl, pos, end,
++ &mwi_interrogate->msg_centre_id));
++ }
++
++ /* No extension to encode */
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Encode the MWIInterrogateResElt type.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param tag Component tag to identify the encoded component.
++ * The tag should be ASN1_TAG_SEQUENCE unless the caller implicitly
++ * tags it otherwise.
++ * \param record
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *rose_enc_qsig_MWIInterrogateResElt(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, unsigned tag,
++ const struct roseQsigMWIInterrogateResElt *record)
++{
++ unsigned char *seq_len;
++ unsigned char *explicit_len;
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, tag);
++
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED, record->basic_service));
++ if (record->msg_centre_id_present) {
++ ASN1_CALL(pos, rose_enc_qsig_MsgCentreId(ctrl, pos, end,
++ &record->msg_centre_id));
++ }
++ if (record->number_of_messages_present) {
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 3,
++ record->number_of_messages));
++ }
++ if (record->originating_number.length) {
++ /* EXPLICIT tag */
++ ASN1_CONSTRUCTED_BEGIN(explicit_len, pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 4);
++ ASN1_CALL(pos, rose_enc_PartyNumber(ctrl, pos, end,
++ &record->originating_number));
++ ASN1_CONSTRUCTED_END(explicit_len, pos, end);
++ }
++ if (record->timestamp_present) {
++ ASN1_CALL(pos, asn1_enc_string_max(pos, end, ASN1_TYPE_GENERALIZED_TIME,
++ record->timestamp, sizeof(record->timestamp) - 1));
++ }
++ if (record->priority_present) {
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 5,
++ record->priority));
++ }
++
++ /* No extension to encode */
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Encode the MWIInterrogate result facility ie arguments.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param args Arguments to encode in the buffer.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_qsig_MWIInterrogate_RES(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_result_args *args)
++{
++ unsigned index;
++ unsigned char *seq_len;
++ const struct roseQsigMWIInterrogateRes *mwi_interrogate;
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_TAG_SEQUENCE);
++
++ mwi_interrogate = &args->qsig.MWIInterrogate;
++ for (index = 0; index < mwi_interrogate->num_records; ++index) {
++ ASN1_CALL(pos, rose_enc_qsig_MWIInterrogateResElt(ctrl, pos, end,
++ ASN1_TAG_SEQUENCE, &mwi_interrogate->list[index]));
++ }
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Decode the MsgCentreId argument parameters.
++ *
++ * \param ctrl D channel controller for any diagnostic messages.
++ * \param name Field name
++ * \param tag Component tag that identified this production.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param msg_centre_id Parameter storage to fill.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++static const unsigned char *rose_dec_qsig_MsgCentreId(struct pri *ctrl, const char *name,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ struct roseQsigMsgCentreId *msg_centre_id)
++{
++ int32_t value;
++ size_t str_len;
++ int length;
++ int explicit_offset;
++ const unsigned char *explicit_end;
++
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " %s MsgCentreId\n", name);
++ }
++ switch (tag) {
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 0:
++ msg_centre_id->type = 0; /* integer */
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "integer", tag, pos, end, &value));
++ msg_centre_id->u.integer = value;
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 1:
++ msg_centre_id->type = 1; /* partyNumber */
++
++ /* Remove EXPLICIT tag */
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " Explicit %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(explicit_end, explicit_offset, length, pos, end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, explicit_end, &tag));
++ ASN1_CALL(pos, rose_dec_PartyNumber(ctrl, "partyNumber", tag, pos, explicit_end,
++ &msg_centre_id->u.number));
++
++ ASN1_END_FIXUP(ctrl, pos, explicit_offset, explicit_end, end);
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 2:
++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 2:
++ msg_centre_id->type = 2; /* numericString */
++ ASN1_CALL(pos, asn1_dec_string_max(ctrl, "numericString", tag, pos, end,
++ sizeof(msg_centre_id->u.str), msg_centre_id->u.str, &str_len));
++ break;
++ default:
++ ASN1_DID_NOT_EXPECT_TAG(ctrl, tag);
++ return NULL;
++ }
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the Q.SIG MWIActivate invoke argument parameters.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param args Arguments to fill in from the decoded buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_qsig_MWIActivate_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end, union rose_msg_invoke_args *args)
++{
++ int32_t value;
++ size_t str_len;
++ int length;
++ int seq_offset;
++ int explicit_offset;
++ const unsigned char *explicit_end;
++ const unsigned char *seq_end;
++ const unsigned char *save_pos;
++ struct roseQsigMWIActivateArg *mwi_activate;
++
++ mwi_activate = &args->qsig.MWIActivate;
++
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE);
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " MWIActivateArg %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CALL(pos, rose_dec_PartyNumber(ctrl, "servedUserNr", tag, pos, seq_end,
++ &mwi_activate->served_user_number));
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "basicService", tag, pos, seq_end, &value));
++ mwi_activate->basic_service = value;
++
++ /*
++ * A sequence specifies an ordered list of component types.
++ * However, for simplicity we are not checking the order of
++ * the remaining optional components.
++ */
++ mwi_activate->msg_centre_id_present = 0;
++ mwi_activate->number_of_messages_present = 0;
++ mwi_activate->originating_number.length = 0;
++ mwi_activate->timestamp_present = 0;
++ mwi_activate->priority_present = 0;
++ while (pos < seq_end && *pos != ASN1_INDEF_TERM) {
++ save_pos = pos;
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ switch (tag & ~ASN1_PC_MASK) {
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 0:
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 1:
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 2:
++ ASN1_CALL(pos, rose_dec_qsig_MsgCentreId(ctrl, "msgCentreId", tag, pos,
++ seq_end, &mwi_activate->msg_centre_id));
++ mwi_activate->msg_centre_id_present = 1;
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 3:
++ /* Must not be constructed but we will not check for it for simplicity. */
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "nbOfMessages", tag, pos, seq_end,
++ &value));
++ mwi_activate->number_of_messages = value;
++ mwi_activate->number_of_messages_present = 1;
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 4:
++ /* Must be constructed but we will not check for it for simplicity. */
++ /* Remove EXPLICIT tag */
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " Explicit %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, seq_end, &length));
++ ASN1_END_SETUP(explicit_end, explicit_offset, length, pos, seq_end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, explicit_end, &tag));
++ ASN1_CALL(pos, rose_dec_PartyNumber(ctrl, "originatingNr", tag, pos,
++ explicit_end, &mwi_activate->originating_number));
++
++ ASN1_END_FIXUP(ctrl, pos, explicit_offset, explicit_end, seq_end);
++ break;
++ case ASN1_TYPE_GENERALIZED_TIME:
++ ASN1_CALL(pos, asn1_dec_string_max(ctrl, "timestamp", tag, pos, end,
++ sizeof(mwi_activate->timestamp), mwi_activate->timestamp, &str_len));
++ mwi_activate->timestamp_present = 1;
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 5:
++ /* Must not be constructed but we will not check for it for simplicity. */
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "priority", tag, pos, seq_end, &value));
++ mwi_activate->priority = value;
++ mwi_activate->priority_present = 1;
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 6:
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 7:
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " argumentExt %s\n", asn1_tag2str(tag));
++ }
++ /* Fixup will skip over the manufacturer extension information */
++ default:
++ pos = save_pos;
++ goto cancel_options;
++ }
++ }
++cancel_options:;
++
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the Q.SIG MWIDeactivate invoke argument parameters.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param args Arguments to fill in from the decoded buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_qsig_MWIDeactivate_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end, union rose_msg_invoke_args *args)
++{
++ int32_t value;
++ int length;
++ int seq_offset;
++ const unsigned char *seq_end;
++ const unsigned char *save_pos;
++ struct roseQsigMWIDeactivateArg *mwi_deactivate;
++
++ mwi_deactivate = &args->qsig.MWIDeactivate;
++
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE);
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " MWIDeactivateArg %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CALL(pos, rose_dec_PartyNumber(ctrl, "servedUserNr", tag, pos, seq_end,
++ &mwi_deactivate->served_user_number));
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "basicService", tag, pos, seq_end, &value));
++ mwi_deactivate->basic_service = value;
++
++ /*
++ * A sequence specifies an ordered list of component types.
++ * However, for simplicity we are not checking the order of
++ * the remaining optional components.
++ */
++ mwi_deactivate->msg_centre_id_present = 0;
++ while (pos < seq_end && *pos != ASN1_INDEF_TERM) {
++ save_pos = pos;
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ switch (tag & ~ASN1_PC_MASK) {
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 0:
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 1:
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 2:
++ ASN1_CALL(pos, rose_dec_qsig_MsgCentreId(ctrl, "msgCentreId", tag, pos,
++ seq_end, &mwi_deactivate->msg_centre_id));
++ mwi_deactivate->msg_centre_id_present = 1;
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 3:
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 4:
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " argumentExt %s\n", asn1_tag2str(tag));
++ }
++ /* Fixup will skip over the manufacturer extension information */
++ default:
++ pos = save_pos;
++ goto cancel_options;
++ }
++ }
++cancel_options:;
++
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the Q.SIG MWIInterrogate invoke argument parameters.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param args Arguments to fill in from the decoded buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_qsig_MWIInterrogate_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end, union rose_msg_invoke_args *args)
++{
++ int32_t value;
++ int length;
++ int seq_offset;
++ const unsigned char *seq_end;
++ const unsigned char *save_pos;
++ struct roseQsigMWIInterrogateArg *mwi_interrogate;
++
++ mwi_interrogate = &args->qsig.MWIInterrogate;
++
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE);
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " MWIInterrogateArg %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CALL(pos, rose_dec_PartyNumber(ctrl, "servedUserNr", tag, pos, seq_end,
++ &mwi_interrogate->served_user_number));
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "basicService", tag, pos, seq_end, &value));
++ mwi_interrogate->basic_service = value;
++
++ /*
++ * A sequence specifies an ordered list of component types.
++ * However, for simplicity we are not checking the order of
++ * the remaining optional components.
++ */
++ mwi_interrogate->msg_centre_id_present = 0;
++ while (pos < seq_end && *pos != ASN1_INDEF_TERM) {
++ save_pos = pos;
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ switch (tag & ~ASN1_PC_MASK) {
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 0:
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 1:
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 2:
++ ASN1_CALL(pos, rose_dec_qsig_MsgCentreId(ctrl, "msgCentreId", tag, pos,
++ seq_end, &mwi_interrogate->msg_centre_id));
++ mwi_interrogate->msg_centre_id_present = 1;
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 3:
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 4:
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " argumentExt %s\n", asn1_tag2str(tag));
++ }
++ /* Fixup will skip over the manufacturer extension information */
++ default:
++ pos = save_pos;
++ goto cancel_options;
++ }
++ }
++cancel_options:;
++
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Decode the MWIInterrogateResElt argument parameters.
++ *
++ * \param ctrl D channel controller for any diagnostic messages.
++ * \param name Field name
++ * \param tag Component tag that identified this production.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param record Parameter storage to fill.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++static const unsigned char *rose_dec_qsig_MWIInterrogateResElt(struct pri *ctrl,
++ const char *name, unsigned tag, const unsigned char *pos, const unsigned char *end,
++ struct roseQsigMWIInterrogateResElt *record)
++{
++ int32_t value;
++ size_t str_len;
++ int length;
++ int seq_offset;
++ int explicit_offset;
++ const unsigned char *explicit_end;
++ const unsigned char *seq_end;
++ const unsigned char *save_pos;
++
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " MWIInterrogateResElt %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "basicService", tag, pos, seq_end, &value));
++ record->basic_service = value;
++
++ /*
++ * A sequence specifies an ordered list of component types.
++ * However, for simplicity we are not checking the order of
++ * the remaining optional components.
++ */
++ record->msg_centre_id_present = 0;
++ record->number_of_messages_present = 0;
++ record->originating_number.length = 0;
++ record->timestamp_present = 0;
++ record->priority_present = 0;
++ while (pos < seq_end && *pos != ASN1_INDEF_TERM) {
++ save_pos = pos;
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ switch (tag & ~ASN1_PC_MASK) {
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 0:
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 1:
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 2:
++ ASN1_CALL(pos, rose_dec_qsig_MsgCentreId(ctrl, "msgCentreId", tag, pos,
++ seq_end, &record->msg_centre_id));
++ record->msg_centre_id_present = 1;
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 3:
++ /* Must not be constructed but we will not check for it for simplicity. */
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "nbOfMessages", tag, pos, seq_end,
++ &value));
++ record->number_of_messages = value;
++ record->number_of_messages_present = 1;
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 4:
++ /* Must be constructed but we will not check for it for simplicity. */
++ /* Remove EXPLICIT tag */
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " Explicit %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, seq_end, &length));
++ ASN1_END_SETUP(explicit_end, explicit_offset, length, pos, seq_end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, explicit_end, &tag));
++ ASN1_CALL(pos, rose_dec_PartyNumber(ctrl, "originatingNr", tag, pos,
++ explicit_end, &record->originating_number));
++
++ ASN1_END_FIXUP(ctrl, pos, explicit_offset, explicit_end, seq_end);
++ break;
++ case ASN1_TYPE_GENERALIZED_TIME:
++ ASN1_CALL(pos, asn1_dec_string_max(ctrl, "timestamp", tag, pos, end,
++ sizeof(record->timestamp), record->timestamp, &str_len));
++ record->timestamp_present = 1;
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 5:
++ /* Must not be constructed but we will not check for it for simplicity. */
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "priority", tag, pos, seq_end, &value));
++ record->priority = value;
++ record->priority_present = 1;
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 6:
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 7:
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " argumentExt %s\n", asn1_tag2str(tag));
++ }
++ /* Fixup will skip over the manufacturer extension information */
++ default:
++ pos = save_pos;
++ goto cancel_options;
++ }
++ }
++cancel_options:;
++
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the Q.SIG MWIInterrogate result argument parameters.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param args Arguments to fill in from the decoded buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_qsig_MWIInterrogate_RES(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end, union rose_msg_result_args *args)
++{
++ int length;
++ int seq_offset;
++ const unsigned char *seq_end;
++ struct roseQsigMWIInterrogateRes *mwi_interrogate;
++
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE);
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " MWIInterrogateRes %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ mwi_interrogate = &args->qsig.MWIInterrogate;
++
++ mwi_interrogate->num_records = 0;
++ while (pos < seq_end && *pos != ASN1_INDEF_TERM) {
++ if (mwi_interrogate->num_records < ARRAY_LEN(mwi_interrogate->list)) {
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE);
++ ASN1_CALL(pos, rose_dec_qsig_MWIInterrogateResElt(ctrl, "listEntry", tag,
++ pos, seq_end, &mwi_interrogate->list[mwi_interrogate->num_records]));
++ ++mwi_interrogate->num_records;
++ } else {
++ /* Too many records */
++ return NULL;
++ }
++ }
++
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++
++/* ------------------------------------------------------------------- */
++/* end rose_qsig_mwi.c */
+
+Property changes on: rose_qsig_mwi.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+Added: svn:mime-type
+ + text/plain
+Added: svn:keywords
+ + 'Author Date Id Revision'
+
+Index: rosetest.c
+===================================================================
+--- a/rosetest.c (.../tags/1.4.10.2) (revision 0)
++++ b/rosetest.c (.../branches/1.4) (revision 1357)
+@@ -0,0 +1,2473 @@
++/*
++ * 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 ROSE encode/decode test program
++ *
++ * \author Richard Mudgett <rmudgett@digium.com>
++ */
++
++
++#include "compat.h"
++#include "libpri.h"
++#include "pri_internal.h"
++#include "rose.h"
++
++#include <stdio.h>
++#include <stdlib.h>
++
++
++/* ------------------------------------------------------------------- */
++
++
++static const struct fac_extension_header fac_headers[] = {
++/* *INDENT-OFF* */
++ {
++ .nfe_present = 0,
++ },
++ {
++ .nfe_present = 1,
++ .nfe.source_entity = 1,
++ .nfe.destination_entity = 1,
++ },
++ {
++ .nfe_present = 1,
++ .nfe.source_entity = 1,
++ .nfe.source_number.plan = 4,
++ .nfe.source_number.length = 4,
++ .nfe.source_number.str = "9834",
++ .nfe.destination_entity = 1,
++ .nfe.destination_number.plan = 4,
++ .nfe.destination_number.length = 4,
++ .nfe.destination_number.str = "9834",
++ },
++ {
++ .nfe_present = 1,
++ .nfe.source_entity = 1,
++ .nfe.destination_entity = 1,
++ .npp_present = 1,
++ .npp = 19,
++ .interpretation_present = 1,
++ .interpretation = 2,
++ },
++/* *INDENT-ON* */
++};
++
++
++static const struct rose_message rose_etsi_msgs[] = {
++/* *INDENT-OFF* */
++ /* Error messages */
++ {
++ .type = ROSE_COMP_TYPE_ERROR,
++ .component.error.invoke_id = 82,
++ .component.error.code = ROSE_ERROR_Div_SpecialServiceNr,
++ },
++ {
++ .type = ROSE_COMP_TYPE_ERROR,
++ .component.error.invoke_id = 8,
++ .component.error.code = ROSE_ERROR_ECT_LinkIdNotAssignedByNetwork,
++ },
++
++ /* Reject messages */
++ {
++ .type = ROSE_COMP_TYPE_REJECT,
++ .component.reject.code = ROSE_REJECT_Gen_BadlyStructuredComponent,
++ },
++ {
++ .type = ROSE_COMP_TYPE_REJECT,
++ .component.reject.invoke_id_present = 1,
++ .component.reject.invoke_id = 10,
++ .component.reject.code = ROSE_REJECT_Inv_InitiatorReleasing,
++ },
++ {
++ .type = ROSE_COMP_TYPE_REJECT,
++ .component.reject.invoke_id_present = 1,
++ .component.reject.invoke_id = 11,
++ .component.reject.code = ROSE_REJECT_Res_MistypedResult,
++ },
++ {
++ .type = ROSE_COMP_TYPE_REJECT,
++ .component.reject.invoke_id_present = 1,
++ .component.reject.invoke_id = 12,
++ .component.reject.code = ROSE_REJECT_Err_ErrorResponseUnexpected,
++ },
++
++ /* Anonymous result or result without any arguments. */
++ {
++ .type = ROSE_COMP_TYPE_RESULT,
++ .component.result.operation = ROSE_None,
++ .component.result.invoke_id = 9,
++ },
++
++ /* Advice Of Charge (AOC) */
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_ChargingRequest,
++ .component.invoke.invoke_id = 98,
++ .component.invoke.args.etsi.ChargingRequest.charging_case = 2,
++ },
++ {
++ .type = ROSE_COMP_TYPE_RESULT,
++ .component.result.operation = ROSE_ETSI_ChargingRequest,
++ .component.result.invoke_id = 99,
++ .component.result.args.etsi.ChargingRequest.type = 0,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.num_records = 1,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].charged_item = 4,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].currency_type = 0,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.special_charging_code = 3,
++ },
++ {
++ .type = ROSE_COMP_TYPE_RESULT,
++ .component.result.operation = ROSE_ETSI_ChargingRequest,
++ .component.result.invoke_id = 100,
++ .component.result.args.etsi.ChargingRequest.type = 0,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.num_records = 1,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].charged_item = 4,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].currency_type = 1,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.duration.currency = "Dollars",
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.duration.amount.currency = 7,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.duration.amount.multiplier = 1,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.duration.charging_type = 1,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.duration.time.length = 8,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.duration.time.scale = 4,
++ },
++ {
++ .type = ROSE_COMP_TYPE_RESULT,
++ .component.result.operation = ROSE_ETSI_ChargingRequest,
++ .component.result.invoke_id = 101,
++ .component.result.args.etsi.ChargingRequest.type = 0,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.num_records = 1,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].charged_item = 4,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].currency_type = 1,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.duration.currency = "Dollars",
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.duration.amount.currency = 7,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.duration.amount.multiplier = 1,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.duration.charging_type = 1,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.duration.time.length = 8,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.duration.time.scale = 4,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.duration.granularity_present = 1,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.duration.granularity.length = 20,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.duration.granularity.scale = 3,
++ },
++ {
++ .type = ROSE_COMP_TYPE_RESULT,
++ .component.result.operation = ROSE_ETSI_ChargingRequest,
++ .component.result.invoke_id = 102,
++ .component.result.args.etsi.ChargingRequest.type = 0,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.num_records = 1,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].charged_item = 4,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].currency_type = 2,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.flat_rate.currency = "Euros",
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.flat_rate.amount.currency = 4,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.flat_rate.amount.multiplier = 1,
++ },
++ {
++ .type = ROSE_COMP_TYPE_RESULT,
++ .component.result.operation = ROSE_ETSI_ChargingRequest,
++ .component.result.invoke_id = 103,
++ .component.result.args.etsi.ChargingRequest.type = 0,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.num_records = 1,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].charged_item = 4,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].currency_type = 3,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.volume_rate.currency = "Yen",
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.volume_rate.amount.currency = 300,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.volume_rate.amount.multiplier = 5,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.volume_rate.unit = 2,
++ },
++ {
++ .type = ROSE_COMP_TYPE_RESULT,
++ .component.result.operation = ROSE_ETSI_ChargingRequest,
++ .component.result.invoke_id = 104,
++ .component.result.args.etsi.ChargingRequest.type = 0,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.num_records = 2,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].charged_item = 4,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].currency_type = 2,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.flat_rate.currency = "Euros",
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.flat_rate.amount.currency = 4,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.flat_rate.amount.multiplier = 1,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[1].charged_item = 4,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[1].currency_type = 3,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[1].u.volume_rate.currency = "Yen",
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[1].u.volume_rate.amount.currency = 300,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[1].u.volume_rate.amount.multiplier = 5,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[1].u.volume_rate.unit = 2,
++ },
++ {
++ .type = ROSE_COMP_TYPE_RESULT,
++ .component.result.operation = ROSE_ETSI_ChargingRequest,
++ .component.result.invoke_id = 105,
++ .component.result.args.etsi.ChargingRequest.type = 0,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.num_records = 1,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].charged_item = 4,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].currency_type = 4,
++ },
++ {
++ .type = ROSE_COMP_TYPE_RESULT,
++ .component.result.operation = ROSE_ETSI_ChargingRequest,
++ .component.result.invoke_id = 106,
++ .component.result.args.etsi.ChargingRequest.type = 0,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.num_records = 1,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].charged_item = 4,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].currency_type = 5,
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_AOCSCurrency,
++ .component.invoke.invoke_id = 107,
++ .component.invoke.args.etsi.AOCSCurrency.type = 0,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_AOCSCurrency,
++ .component.invoke.invoke_id = 108,
++ .component.invoke.args.etsi.AOCSCurrency.type = 1,
++ .component.invoke.args.etsi.AOCSCurrency.currency_info.num_records = 1,
++ .component.invoke.args.etsi.AOCSCurrency.currency_info.list[0].charged_item = 3,
++ .component.invoke.args.etsi.AOCSCurrency.currency_info.list[0].currency_type = 4,
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_AOCSSpecialArr,
++ .component.invoke.invoke_id = 109,
++ .component.invoke.args.etsi.AOCSSpecialArr.type = 0,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_AOCSSpecialArr,
++ .component.invoke.invoke_id = 110,
++ .component.invoke.args.etsi.AOCSSpecialArr.type = 1,
++ .component.invoke.args.etsi.AOCSSpecialArr.special_arrangement = 9,
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_AOCDCurrency,
++ .component.invoke.invoke_id = 111,
++ .component.invoke.args.etsi.AOCDCurrency.type = 0,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_AOCDCurrency,
++ .component.invoke.invoke_id = 112,
++ .component.invoke.args.etsi.AOCDCurrency.type = 1,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_AOCDCurrency,
++ .component.invoke.invoke_id = 113,
++ .component.invoke.args.etsi.AOCDCurrency.type = 2,
++ .component.invoke.args.etsi.AOCDCurrency.specific.recorded.currency = "Francs",
++ .component.invoke.args.etsi.AOCDCurrency.specific.recorded.amount.currency = 674,
++ .component.invoke.args.etsi.AOCDCurrency.specific.recorded.amount.multiplier = 3,
++ .component.invoke.args.etsi.AOCDCurrency.specific.type_of_charging_info = 1,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_AOCDCurrency,
++ .component.invoke.invoke_id = 114,
++ .component.invoke.args.etsi.AOCDCurrency.type = 2,
++ .component.invoke.args.etsi.AOCDCurrency.specific.recorded.currency = "Francs",
++ .component.invoke.args.etsi.AOCDCurrency.specific.recorded.amount.currency = 674,
++ .component.invoke.args.etsi.AOCDCurrency.specific.recorded.amount.multiplier = 3,
++ .component.invoke.args.etsi.AOCDCurrency.specific.type_of_charging_info = 1,
++ .component.invoke.args.etsi.AOCDCurrency.specific.billing_id_present = 1,
++ .component.invoke.args.etsi.AOCDCurrency.specific.billing_id = 2,
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_AOCDChargingUnit,
++ .component.invoke.invoke_id = 115,
++ .component.invoke.args.etsi.AOCDChargingUnit.type = 0,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_AOCDChargingUnit,
++ .component.invoke.invoke_id = 116,
++ .component.invoke.args.etsi.AOCDChargingUnit.type = 1,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_AOCDChargingUnit,
++ .component.invoke.invoke_id = 117,
++ .component.invoke.args.etsi.AOCDChargingUnit.type = 2,
++ .component.invoke.args.etsi.AOCDChargingUnit.specific.recorded.num_records = 1,
++ .component.invoke.args.etsi.AOCDChargingUnit.specific.recorded.list[0].not_available = 1,
++ .component.invoke.args.etsi.AOCDChargingUnit.specific.type_of_charging_info = 1,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_AOCDChargingUnit,
++ .component.invoke.invoke_id = 118,
++ .component.invoke.args.etsi.AOCDChargingUnit.type = 2,
++ .component.invoke.args.etsi.AOCDChargingUnit.specific.recorded.num_records = 1,
++ .component.invoke.args.etsi.AOCDChargingUnit.specific.recorded.list[0].not_available = 0,
++ .component.invoke.args.etsi.AOCDChargingUnit.specific.recorded.list[0].number_of_units = 8523,
++ .component.invoke.args.etsi.AOCDChargingUnit.specific.type_of_charging_info = 1,
++ .component.invoke.args.etsi.AOCDChargingUnit.specific.billing_id_present = 1,
++ .component.invoke.args.etsi.AOCDChargingUnit.specific.billing_id = 2,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_AOCDChargingUnit,
++ .component.invoke.invoke_id = 119,
++ .component.invoke.args.etsi.AOCDChargingUnit.type = 2,
++ .component.invoke.args.etsi.AOCDChargingUnit.specific.recorded.num_records = 1,
++ .component.invoke.args.etsi.AOCDChargingUnit.specific.recorded.list[0].not_available = 1,
++ .component.invoke.args.etsi.AOCDChargingUnit.specific.recorded.list[0].type_of_unit_present = 1,
++ .component.invoke.args.etsi.AOCDChargingUnit.specific.recorded.list[0].type_of_unit = 13,
++ .component.invoke.args.etsi.AOCDChargingUnit.specific.type_of_charging_info = 1,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_AOCDChargingUnit,
++ .component.invoke.invoke_id = 120,
++ .component.invoke.args.etsi.AOCDChargingUnit.type = 2,
++ .component.invoke.args.etsi.AOCDChargingUnit.specific.recorded.num_records = 1,
++ .component.invoke.args.etsi.AOCDChargingUnit.specific.recorded.list[0].not_available = 0,
++ .component.invoke.args.etsi.AOCDChargingUnit.specific.recorded.list[0].number_of_units = 8523,
++ .component.invoke.args.etsi.AOCDChargingUnit.specific.recorded.list[0].type_of_unit_present = 1,
++ .component.invoke.args.etsi.AOCDChargingUnit.specific.recorded.list[0].type_of_unit = 13,
++ .component.invoke.args.etsi.AOCDChargingUnit.specific.type_of_charging_info = 1,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_AOCDChargingUnit,
++ .component.invoke.invoke_id = 121,
++ .component.invoke.args.etsi.AOCDChargingUnit.type = 2,
++ .component.invoke.args.etsi.AOCDChargingUnit.specific.recorded.num_records = 2,
++ .component.invoke.args.etsi.AOCDChargingUnit.specific.recorded.list[0].not_available = 1,
++ .component.invoke.args.etsi.AOCDChargingUnit.specific.recorded.list[1].not_available = 0,
++ .component.invoke.args.etsi.AOCDChargingUnit.specific.recorded.list[1].number_of_units = 8523,
++ .component.invoke.args.etsi.AOCDChargingUnit.specific.recorded.list[1].type_of_unit_present = 1,
++ .component.invoke.args.etsi.AOCDChargingUnit.specific.recorded.list[1].type_of_unit = 13,
++ .component.invoke.args.etsi.AOCDChargingUnit.specific.type_of_charging_info = 1,
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_AOCECurrency,
++ .component.invoke.invoke_id = 122,
++ .component.invoke.args.etsi.AOCECurrency.type = 0,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_AOCECurrency,
++ .component.invoke.invoke_id = 123,
++ .component.invoke.args.etsi.AOCECurrency.type = 1,
++ .component.invoke.args.etsi.AOCECurrency.currency_info.free_of_charge = 1,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_AOCECurrency,
++ .component.invoke.invoke_id = 124,
++ .component.invoke.args.etsi.AOCECurrency.type = 1,
++ .component.invoke.args.etsi.AOCECurrency.currency_info.free_of_charge = 1,
++ .component.invoke.args.etsi.AOCECurrency.currency_info.charging_association_present = 1,
++ .component.invoke.args.etsi.AOCECurrency.currency_info.charging_association.type = 0,
++ .component.invoke.args.etsi.AOCECurrency.currency_info.charging_association.id = -37,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_AOCECurrency,
++ .component.invoke.invoke_id = 125,
++ .component.invoke.args.etsi.AOCECurrency.type = 1,
++ .component.invoke.args.etsi.AOCECurrency.currency_info.free_of_charge = 1,
++ .component.invoke.args.etsi.AOCECurrency.currency_info.charging_association_present = 1,
++ .component.invoke.args.etsi.AOCECurrency.currency_info.charging_association.type = 1,
++ .component.invoke.args.etsi.AOCECurrency.currency_info.charging_association.number.plan = 0,
++ .component.invoke.args.etsi.AOCECurrency.currency_info.charging_association.number.length = 7,
++ .component.invoke.args.etsi.AOCECurrency.currency_info.charging_association.number.str = "5551212",
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_AOCECurrency,
++ .component.invoke.invoke_id = 126,
++ .component.invoke.args.etsi.AOCECurrency.type = 1,
++ .component.invoke.args.etsi.AOCECurrency.currency_info.free_of_charge = 0,
++ .component.invoke.args.etsi.AOCECurrency.currency_info.specific.recorded.currency = "Francs",
++ .component.invoke.args.etsi.AOCECurrency.currency_info.specific.recorded.amount.currency = 674,
++ .component.invoke.args.etsi.AOCECurrency.currency_info.specific.recorded.amount.multiplier = 3,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_AOCECurrency,
++ .component.invoke.invoke_id = 127,
++ .component.invoke.args.etsi.AOCECurrency.type = 1,
++ .component.invoke.args.etsi.AOCECurrency.currency_info.free_of_charge = 0,
++ .component.invoke.args.etsi.AOCECurrency.currency_info.specific.recorded.currency = "Francs",
++ .component.invoke.args.etsi.AOCECurrency.currency_info.specific.recorded.amount.currency = 674,
++ .component.invoke.args.etsi.AOCECurrency.currency_info.specific.recorded.amount.multiplier = 3,
++ .component.invoke.args.etsi.AOCECurrency.currency_info.charging_association_present = 1,
++ .component.invoke.args.etsi.AOCECurrency.currency_info.charging_association.type = 0,
++ .component.invoke.args.etsi.AOCECurrency.currency_info.charging_association.id = -37,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_AOCECurrency,
++ .component.invoke.invoke_id = 128,
++ .component.invoke.args.etsi.AOCECurrency.type = 1,
++ .component.invoke.args.etsi.AOCECurrency.currency_info.free_of_charge = 0,
++ .component.invoke.args.etsi.AOCECurrency.currency_info.specific.recorded.currency = "Francs",
++ .component.invoke.args.etsi.AOCECurrency.currency_info.specific.recorded.amount.currency = 674,
++ .component.invoke.args.etsi.AOCECurrency.currency_info.specific.recorded.amount.multiplier = 3,
++ .component.invoke.args.etsi.AOCECurrency.currency_info.specific.billing_id_present = 1,
++ .component.invoke.args.etsi.AOCECurrency.currency_info.specific.billing_id = 2,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_AOCECurrency,
++ .component.invoke.invoke_id = 129,
++ .component.invoke.args.etsi.AOCECurrency.type = 1,
++ .component.invoke.args.etsi.AOCECurrency.currency_info.free_of_charge = 0,
++ .component.invoke.args.etsi.AOCECurrency.currency_info.specific.recorded.currency = "Francs",
++ .component.invoke.args.etsi.AOCECurrency.currency_info.specific.recorded.amount.currency = 674,
++ .component.invoke.args.etsi.AOCECurrency.currency_info.specific.recorded.amount.multiplier = 3,
++ .component.invoke.args.etsi.AOCECurrency.currency_info.specific.billing_id_present = 1,
++ .component.invoke.args.etsi.AOCECurrency.currency_info.specific.billing_id = 2,
++ .component.invoke.args.etsi.AOCECurrency.currency_info.charging_association_present = 1,
++ .component.invoke.args.etsi.AOCECurrency.currency_info.charging_association.type = 0,
++ .component.invoke.args.etsi.AOCECurrency.currency_info.charging_association.id = -37,
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_AOCEChargingUnit,
++ .component.invoke.invoke_id = 130,
++ .component.invoke.args.etsi.AOCEChargingUnit.type = 0,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_AOCEChargingUnit,
++ .component.invoke.invoke_id = 131,
++ .component.invoke.args.etsi.AOCEChargingUnit.type = 1,
++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.free_of_charge = 1,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_AOCEChargingUnit,
++ .component.invoke.invoke_id = 132,
++ .component.invoke.args.etsi.AOCEChargingUnit.type = 1,
++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.free_of_charge = 1,
++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.charging_association_present = 1,
++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.charging_association.type = 0,
++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.charging_association.id = -37,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_AOCEChargingUnit,
++ .component.invoke.invoke_id = 133,
++ .component.invoke.args.etsi.AOCEChargingUnit.type = 1,
++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.free_of_charge = 0,
++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.specific.recorded.num_records = 1,
++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.specific.recorded.list[0].not_available = 1,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_AOCEChargingUnit,
++ .component.invoke.invoke_id = 134,
++ .component.invoke.args.etsi.AOCEChargingUnit.type = 1,
++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.free_of_charge = 0,
++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.specific.recorded.num_records = 1,
++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.specific.recorded.list[0].not_available = 1,
++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.charging_association_present = 1,
++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.charging_association.type = 0,
++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.charging_association.id = -37,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_AOCEChargingUnit,
++ .component.invoke.invoke_id = 135,
++ .component.invoke.args.etsi.AOCEChargingUnit.type = 1,
++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.free_of_charge = 0,
++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.specific.recorded.num_records = 1,
++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.specific.recorded.list[0].not_available = 1,
++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.specific.billing_id_present = 1,
++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.specific.billing_id = 2,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_AOCEChargingUnit,
++ .component.invoke.invoke_id = 136,
++ .component.invoke.args.etsi.AOCEChargingUnit.type = 1,
++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.free_of_charge = 0,
++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.specific.recorded.num_records = 1,
++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.specific.recorded.list[0].not_available = 1,
++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.specific.billing_id_present = 1,
++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.specific.billing_id = 2,
++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.charging_association_present = 1,
++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.charging_association.type = 0,
++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.charging_association.id = -37,
++ },
++
++ /* Call diversion */
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_ActivationDiversion,
++ .component.invoke.invoke_id = 67,
++ .component.invoke.linked_id_present = 1,
++ .component.invoke.linked_id = 27,
++ .component.invoke.args.etsi.ActivationDiversion.procedure = 2,
++ .component.invoke.args.etsi.ActivationDiversion.basic_service = 3,
++ .component.invoke.args.etsi.ActivationDiversion.forwarded_to.number.plan = 4,
++ .component.invoke.args.etsi.ActivationDiversion.forwarded_to.number.length = 4,
++ .component.invoke.args.etsi.ActivationDiversion.forwarded_to.number.str = "1803",
++ .component.invoke.args.etsi.ActivationDiversion.served_user_number.plan = 4,
++ .component.invoke.args.etsi.ActivationDiversion.served_user_number.length = 4,
++ .component.invoke.args.etsi.ActivationDiversion.served_user_number.str = "5398",
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_ActivationDiversion,
++ .component.invoke.invoke_id = 68,
++ .component.invoke.args.etsi.ActivationDiversion.procedure = 1,
++ .component.invoke.args.etsi.ActivationDiversion.basic_service = 5,
++ .component.invoke.args.etsi.ActivationDiversion.forwarded_to.number.plan = 4,
++ .component.invoke.args.etsi.ActivationDiversion.forwarded_to.number.length = 4,
++ .component.invoke.args.etsi.ActivationDiversion.forwarded_to.number.str = "1803",
++ },
++ {
++ .type = ROSE_COMP_TYPE_RESULT,
++ .component.result.operation = ROSE_ETSI_ActivationDiversion,
++ .component.result.invoke_id = 69,
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_DeactivationDiversion,
++ .component.invoke.invoke_id = 70,
++ .component.invoke.args.etsi.DeactivationDiversion.procedure = 1,
++ .component.invoke.args.etsi.DeactivationDiversion.basic_service = 5,
++ },
++ {
++ .type = ROSE_COMP_TYPE_RESULT,
++ .component.result.operation = ROSE_ETSI_DeactivationDiversion,
++ .component.result.invoke_id = 71,
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_ActivationStatusNotificationDiv,
++ .component.invoke.invoke_id = 72,
++ .component.invoke.args.etsi.ActivationStatusNotificationDiv.procedure = 1,
++ .component.invoke.args.etsi.ActivationStatusNotificationDiv.basic_service = 5,
++ .component.invoke.args.etsi.ActivationStatusNotificationDiv.forwarded_to.number.plan = 4,
++ .component.invoke.args.etsi.ActivationStatusNotificationDiv.forwarded_to.number.length = 4,
++ .component.invoke.args.etsi.ActivationStatusNotificationDiv.forwarded_to.number.str = "1803",
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_DeactivationStatusNotificationDiv,
++ .component.invoke.invoke_id = 73,
++ .component.invoke.args.etsi.DeactivationStatusNotificationDiv.procedure = 1,
++ .component.invoke.args.etsi.DeactivationStatusNotificationDiv.basic_service = 5,
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_InterrogationDiversion,
++ .component.invoke.invoke_id = 74,
++ .component.invoke.args.etsi.InterrogationDiversion.procedure = 1,
++ .component.invoke.args.etsi.InterrogationDiversion.basic_service = 5,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_InterrogationDiversion,
++ .component.invoke.invoke_id = 75,
++ .component.invoke.args.etsi.InterrogationDiversion.procedure = 1,
++ },
++ {
++ .type = ROSE_COMP_TYPE_RESULT,
++ .component.result.operation = ROSE_ETSI_InterrogationDiversion,
++ .component.result.invoke_id = 76,
++ .component.result.args.etsi.InterrogationDiversion.num_records = 2,
++ .component.result.args.etsi.InterrogationDiversion.list[0].procedure = 2,
++ .component.result.args.etsi.InterrogationDiversion.list[0].basic_service = 5,
++ .component.result.args.etsi.InterrogationDiversion.list[0].forwarded_to.number.plan = 4,
++ .component.result.args.etsi.InterrogationDiversion.list[0].forwarded_to.number.length = 4,
++ .component.result.args.etsi.InterrogationDiversion.list[0].forwarded_to.number.str = "1803",
++ .component.result.args.etsi.InterrogationDiversion.list[1].procedure = 1,
++ .component.result.args.etsi.InterrogationDiversion.list[1].basic_service = 3,
++ .component.result.args.etsi.InterrogationDiversion.list[1].forwarded_to.number.plan = 4,
++ .component.result.args.etsi.InterrogationDiversion.list[1].forwarded_to.number.length = 4,
++ .component.result.args.etsi.InterrogationDiversion.list[1].forwarded_to.number.str = "1903",
++ .component.result.args.etsi.InterrogationDiversion.list[1].served_user_number.plan = 4,
++ .component.result.args.etsi.InterrogationDiversion.list[1].served_user_number.length = 4,
++ .component.result.args.etsi.InterrogationDiversion.list[1].served_user_number.str = "5398",
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_DiversionInformation,
++ .component.invoke.invoke_id = 77,
++ .component.invoke.args.etsi.DiversionInformation.diversion_reason = 3,
++ .component.invoke.args.etsi.DiversionInformation.basic_service = 5,
++ .component.invoke.args.etsi.DiversionInformation.served_user_subaddress.type = 1,
++ .component.invoke.args.etsi.DiversionInformation.served_user_subaddress.length = 4,
++ .component.invoke.args.etsi.DiversionInformation.served_user_subaddress.u.nsap = "6492",
++ .component.invoke.args.etsi.DiversionInformation.calling_present = 1,
++ .component.invoke.args.etsi.DiversionInformation.calling.presentation = 0,
++ .component.invoke.args.etsi.DiversionInformation.calling.screened.screening_indicator = 3,
++ .component.invoke.args.etsi.DiversionInformation.calling.screened.number.plan = 4,
++ .component.invoke.args.etsi.DiversionInformation.calling.screened.number.length = 4,
++ .component.invoke.args.etsi.DiversionInformation.calling.screened.number.str = "1803",
++ .component.invoke.args.etsi.DiversionInformation.original_called_present = 1,
++ .component.invoke.args.etsi.DiversionInformation.original_called.presentation = 1,
++ .component.invoke.args.etsi.DiversionInformation.last_diverting_present = 1,
++ .component.invoke.args.etsi.DiversionInformation.last_diverting.presentation = 2,
++ .component.invoke.args.etsi.DiversionInformation.last_diverting_reason_present = 1,
++ .component.invoke.args.etsi.DiversionInformation.last_diverting_reason = 3,
++ .component.invoke.args.etsi.DiversionInformation.q931ie.length = 5,
++ .component.invoke.args.etsi.DiversionInformation.q931ie_contents = "79828",
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_DiversionInformation,
++ .component.invoke.invoke_id = 78,
++ .component.invoke.args.etsi.DiversionInformation.diversion_reason = 3,
++ .component.invoke.args.etsi.DiversionInformation.basic_service = 5,
++ .component.invoke.args.etsi.DiversionInformation.calling_present = 1,
++ .component.invoke.args.etsi.DiversionInformation.calling.presentation = 1,
++ .component.invoke.args.etsi.DiversionInformation.original_called_present = 1,
++ .component.invoke.args.etsi.DiversionInformation.original_called.presentation = 2,
++ .component.invoke.args.etsi.DiversionInformation.last_diverting_present = 1,
++ .component.invoke.args.etsi.DiversionInformation.last_diverting.presentation = 1,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_DiversionInformation,
++ .component.invoke.invoke_id = 79,
++ .component.invoke.args.etsi.DiversionInformation.diversion_reason = 2,
++ .component.invoke.args.etsi.DiversionInformation.basic_service = 3,
++ .component.invoke.args.etsi.DiversionInformation.calling_present = 1,
++ .component.invoke.args.etsi.DiversionInformation.calling.presentation = 2,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_DiversionInformation,
++ .component.invoke.invoke_id = 80,
++ .component.invoke.args.etsi.DiversionInformation.diversion_reason = 3,
++ .component.invoke.args.etsi.DiversionInformation.basic_service = 5,
++ .component.invoke.args.etsi.DiversionInformation.calling_present = 1,
++ .component.invoke.args.etsi.DiversionInformation.calling.presentation = 3,
++ .component.invoke.args.etsi.DiversionInformation.calling.screened.screening_indicator = 2,
++ .component.invoke.args.etsi.DiversionInformation.calling.screened.number.plan = 4,
++ .component.invoke.args.etsi.DiversionInformation.calling.screened.number.length = 4,
++ .component.invoke.args.etsi.DiversionInformation.calling.screened.number.str = "1803",
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_DiversionInformation,
++ .component.invoke.invoke_id = 81,
++ .component.invoke.args.etsi.DiversionInformation.diversion_reason = 2,
++ .component.invoke.args.etsi.DiversionInformation.basic_service = 4,
++ .component.invoke.args.etsi.DiversionInformation.q931ie.length = 5,
++ .component.invoke.args.etsi.DiversionInformation.q931ie_contents = "79828",
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_DiversionInformation,
++ .component.invoke.invoke_id = 82,
++ .component.invoke.args.etsi.DiversionInformation.diversion_reason = 2,
++ .component.invoke.args.etsi.DiversionInformation.basic_service = 4,
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_CallDeflection,
++ .component.invoke.invoke_id = 83,
++ .component.invoke.args.etsi.CallDeflection.deflection.number.plan = 4,
++ .component.invoke.args.etsi.CallDeflection.deflection.number.length = 4,
++ .component.invoke.args.etsi.CallDeflection.deflection.number.str = "1803",
++ .component.invoke.args.etsi.CallDeflection.presentation_allowed_to_diverted_to_user_present = 1,
++ .component.invoke.args.etsi.CallDeflection.presentation_allowed_to_diverted_to_user = 1,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_CallDeflection,
++ .component.invoke.invoke_id = 84,
++ .component.invoke.args.etsi.CallDeflection.deflection.number.plan = 4,
++ .component.invoke.args.etsi.CallDeflection.deflection.number.length = 4,
++ .component.invoke.args.etsi.CallDeflection.deflection.number.str = "1803",
++ .component.invoke.args.etsi.CallDeflection.presentation_allowed_to_diverted_to_user_present = 1,
++ .component.invoke.args.etsi.CallDeflection.presentation_allowed_to_diverted_to_user = 0,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_CallDeflection,
++ .component.invoke.invoke_id = 85,
++ .component.invoke.args.etsi.CallDeflection.deflection.number.plan = 4,
++ .component.invoke.args.etsi.CallDeflection.deflection.number.length = 4,
++ .component.invoke.args.etsi.CallDeflection.deflection.number.str = "1803",
++ },
++ {
++ .type = ROSE_COMP_TYPE_RESULT,
++ .component.result.operation = ROSE_ETSI_CallDeflection,
++ .component.result.invoke_id = 86,
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_CallRerouting,
++ .component.invoke.invoke_id = 87,
++ .component.invoke.args.etsi.CallRerouting.rerouting_reason = 3,
++ .component.invoke.args.etsi.CallRerouting.rerouting_counter = 2,
++ .component.invoke.args.etsi.CallRerouting.called_address.number.plan = 4,
++ .component.invoke.args.etsi.CallRerouting.called_address.number.length = 4,
++ .component.invoke.args.etsi.CallRerouting.called_address.number.str = "1803",
++ .component.invoke.args.etsi.CallRerouting.q931ie.length = 129,
++ .component.invoke.args.etsi.CallRerouting.q931ie_contents =
++ "YEHAW."
++ " The quick brown fox jumped over the lazy dog test."
++ " Now is the time for all good men to come to the aid of their country.",
++ .component.invoke.args.etsi.CallRerouting.last_rerouting.presentation = 1,
++ .component.invoke.args.etsi.CallRerouting.subscription_option = 2,
++ .component.invoke.args.etsi.CallRerouting.calling_subaddress.type = 1,
++ .component.invoke.args.etsi.CallRerouting.calling_subaddress.length = 4,
++ .component.invoke.args.etsi.CallRerouting.calling_subaddress.u.nsap = "6492",
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_CallRerouting,
++ .component.invoke.invoke_id = 88,
++ .component.invoke.args.etsi.CallRerouting.rerouting_reason = 3,
++ .component.invoke.args.etsi.CallRerouting.rerouting_counter = 2,
++ .component.invoke.args.etsi.CallRerouting.called_address.number.plan = 4,
++ .component.invoke.args.etsi.CallRerouting.called_address.number.length = 4,
++ .component.invoke.args.etsi.CallRerouting.called_address.number.str = "1803",
++ .component.invoke.args.etsi.CallRerouting.q931ie.length = 2,
++ .component.invoke.args.etsi.CallRerouting.q931ie_contents = "RT",
++ .component.invoke.args.etsi.CallRerouting.last_rerouting.presentation = 1,
++ .component.invoke.args.etsi.CallRerouting.subscription_option = 2,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_CallRerouting,
++ .component.invoke.invoke_id = 89,
++ .component.invoke.args.etsi.CallRerouting.rerouting_reason = 3,
++ .component.invoke.args.etsi.CallRerouting.rerouting_counter = 2,
++ .component.invoke.args.etsi.CallRerouting.called_address.number.plan = 4,
++ .component.invoke.args.etsi.CallRerouting.called_address.number.length = 4,
++ .component.invoke.args.etsi.CallRerouting.called_address.number.str = "1803",
++ .component.invoke.args.etsi.CallRerouting.q931ie.length = 2,
++ .component.invoke.args.etsi.CallRerouting.q931ie_contents = "RT",
++ .component.invoke.args.etsi.CallRerouting.last_rerouting.presentation = 2,
++ },
++ {
++ .type = ROSE_COMP_TYPE_RESULT,
++ .component.result.operation = ROSE_ETSI_CallRerouting,
++ .component.result.invoke_id = 90,
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_InterrogateServedUserNumbers,
++ .component.invoke.invoke_id = 91,
++ },
++ {
++ .type = ROSE_COMP_TYPE_RESULT,
++ .component.result.operation = ROSE_ETSI_InterrogateServedUserNumbers,
++ .component.result.invoke_id = 92,
++ .component.result.args.etsi.InterrogateServedUserNumbers.num_records = 2,
++ .component.result.args.etsi.InterrogateServedUserNumbers.number[0].plan = 4,
++ .component.result.args.etsi.InterrogateServedUserNumbers.number[0].length = 4,
++ .component.result.args.etsi.InterrogateServedUserNumbers.number[0].str = "1803",
++ .component.result.args.etsi.InterrogateServedUserNumbers.number[1].plan = 4,
++ .component.result.args.etsi.InterrogateServedUserNumbers.number[1].length = 4,
++ .component.result.args.etsi.InterrogateServedUserNumbers.number[1].str = "5786",
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_DivertingLegInformation1,
++ .component.invoke.invoke_id = 93,
++ .component.invoke.args.etsi.DivertingLegInformation1.diversion_reason = 4,
++ .component.invoke.args.etsi.DivertingLegInformation1.subscription_option = 1,
++ .component.invoke.args.etsi.DivertingLegInformation1.diverted_to_present = 1,
++ .component.invoke.args.etsi.DivertingLegInformation1.diverted_to.presentation = 2,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_DivertingLegInformation1,
++ .component.invoke.invoke_id = 94,
++ .component.invoke.args.etsi.DivertingLegInformation1.diversion_reason = 4,
++ .component.invoke.args.etsi.DivertingLegInformation1.subscription_option = 1,
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_DivertingLegInformation2,
++ .component.invoke.invoke_id = 95,
++ .component.invoke.args.etsi.DivertingLegInformation2.diversion_counter = 3,
++ .component.invoke.args.etsi.DivertingLegInformation2.diversion_reason = 2,
++ .component.invoke.args.etsi.DivertingLegInformation2.diverting_present = 1,
++ .component.invoke.args.etsi.DivertingLegInformation2.diverting.presentation = 2,
++ .component.invoke.args.etsi.DivertingLegInformation2.original_called_present = 1,
++ .component.invoke.args.etsi.DivertingLegInformation2.original_called.presentation = 1,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_DivertingLegInformation2,
++ .component.invoke.invoke_id = 96,
++ .component.invoke.args.etsi.DivertingLegInformation2.diversion_counter = 3,
++ .component.invoke.args.etsi.DivertingLegInformation2.diversion_reason = 2,
++ .component.invoke.args.etsi.DivertingLegInformation2.original_called_present = 1,
++ .component.invoke.args.etsi.DivertingLegInformation2.original_called.presentation = 1,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_DivertingLegInformation2,
++ .component.invoke.invoke_id = 97,
++ .component.invoke.args.etsi.DivertingLegInformation2.diversion_counter = 1,
++ .component.invoke.args.etsi.DivertingLegInformation2.diversion_reason = 2,
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_DivertingLegInformation3,
++ .component.invoke.invoke_id = 98,
++ .component.invoke.args.etsi.DivertingLegInformation3.presentation_allowed_indicator = 1,
++ },
++
++ /* Explicit Call Transfer (ECT) */
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_EctExecute,
++ .component.invoke.invoke_id = 54,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_ExplicitEctExecute,
++ .component.invoke.invoke_id = 55,
++ .component.invoke.args.etsi.ExplicitEctExecute.link_id = 23,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_RequestSubaddress,
++ .component.invoke.invoke_id = 56,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_SubaddressTransfer,
++ .component.invoke.invoke_id = 57,
++ .component.invoke.args.etsi.SubaddressTransfer.subaddress.type = 1,
++ .component.invoke.args.etsi.SubaddressTransfer.subaddress.length = 4,
++ .component.invoke.args.etsi.SubaddressTransfer.subaddress.u.nsap = "6492",
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_EctLinkIdRequest,
++ .component.invoke.invoke_id = 58,
++ },
++ {
++ .type = ROSE_COMP_TYPE_RESULT,
++ .component.result.operation = ROSE_ETSI_EctLinkIdRequest,
++ .component.result.invoke_id = 59,
++ .component.result.args.etsi.EctLinkIdRequest.link_id = 76,
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_EctInform,
++ .component.invoke.invoke_id = 60,
++ .component.invoke.args.etsi.EctInform.status = 1,
++ .component.invoke.args.etsi.EctInform.redirection_present = 1,
++ .component.invoke.args.etsi.EctInform.redirection.presentation = 0,
++ .component.invoke.args.etsi.EctInform.redirection.number.plan = 8,
++ .component.invoke.args.etsi.EctInform.redirection.number.length = 4,
++ .component.invoke.args.etsi.EctInform.redirection.number.str = "6229",
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_EctInform,
++ .component.invoke.invoke_id = 61,
++ .component.invoke.args.etsi.EctInform.status = 1,
++ .component.invoke.args.etsi.EctInform.redirection_present = 1,
++ .component.invoke.args.etsi.EctInform.redirection.presentation = 1,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_EctInform,
++ .component.invoke.invoke_id = 62,
++ .component.invoke.args.etsi.EctInform.status = 1,
++ .component.invoke.args.etsi.EctInform.redirection_present = 1,
++ .component.invoke.args.etsi.EctInform.redirection.presentation = 2,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_EctInform,
++ .component.invoke.invoke_id = 63,
++ .component.invoke.args.etsi.EctInform.status = 1,
++ .component.invoke.args.etsi.EctInform.redirection_present = 1,
++ .component.invoke.args.etsi.EctInform.redirection.presentation = 3,
++ .component.invoke.args.etsi.EctInform.redirection.number.plan = 8,
++ .component.invoke.args.etsi.EctInform.redirection.number.length = 4,
++ .component.invoke.args.etsi.EctInform.redirection.number.str = "3340",
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_EctInform,
++ .component.invoke.invoke_id = 64,
++ .component.invoke.args.etsi.EctInform.status = 1,
++ .component.invoke.args.etsi.EctInform.redirection_present = 0,
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_EctLoopTest,
++ .component.invoke.invoke_id = 65,
++ .component.invoke.args.etsi.EctLoopTest.call_transfer_id = 7,
++ },
++ {
++ .type = ROSE_COMP_TYPE_RESULT,
++ .component.result.operation = ROSE_ETSI_EctLoopTest,
++ .component.result.invoke_id = 66,
++ .component.result.args.etsi.EctLoopTest.loop_result = 2,
++ },
++/* *INDENT-ON* */
++};
++
++static unsigned char rose_etsi_indefinite_len[] = {
++/* *INDENT-OFF* */
++/*
++ * Context Specific/C [1 0x01] <A1> Len:24 <80>
++ * Integer(2 0x02) <02> Len:1 <01>
++ * <44>
++ * Integer(2 0x02) <02> Len:1 <01>
++ * <07>
++ * Sequence/C(48 0x30) <30> Len:16 <80>
++ * Enumerated(10 0x0A) <0A> Len:1 <01>
++ * <01>
++ * Enumerated(10 0x0A) <0A> Len:1 <01>
++ * <05>
++ * Sequence/C(48 0x30) <30> Len:6 <80>
++ * Context Specific [4 0x04] <84> Len:4 <80>
++ * <31 38 30 33>
++ * 0x00, 0x00,
++ * 0x00, 0x00,
++ * NULL(5 0x05) <05> Len:0 <00>
++ * 0x00, 0x00,
++ * 0x00, 0x00
++ */
++ 0x91,
++ 0xA1, 0x80,
++ 0x02, 0x01,
++ 0x44,
++ 0x02, 0x01,
++ 0x07,
++ 0x30, 0x80,
++ 0x0A, 0x01,
++ 0x01,
++ 0x0A, 0x01,
++ 0x05,
++ 0x30, 0x80,
++ 0x84, 0x80,
++ 0x31, 0x38, 0x30, 0x33,
++ 0x00, 0x00,
++ 0x00, 0x00,
++ 0x05, 0x00,
++ 0x00, 0x00,
++ 0x00, 0x00,
++ 0x00, 0x00
++/* *INDENT-ON* */
++};
++
++static unsigned char rose_etsi_unused_indefinite_len[] = {
++/* *INDENT-OFF* */
++/*
++ * Context Specific/C [1 0x01] <A1> Len:24 <80>
++ * Integer(2 0x02) <02> Len:1 <01>
++ * <44>
++ * Integer(2 0x02) <02> Len:1 <01>
++ * <06> -- EctExecute
++ * Sequence/C(48 0x30) <30> Len:16 <80>
++ * Enumerated(10 0x0A) <0A> Len:1 <01>
++ * <01>
++ * Enumerated(10 0x0A) <0A> Len:1 <01>
++ * <05>
++ * Sequence/C(48 0x30) <30> Len:6 <80>
++ * Context Specific [4 0x04] <84> Len:4 <80>
++ * <31 38 30 33>
++ * 0x00, 0x00,
++ * 0x00, 0x00,
++ * NULL(5 0x05) <05> Len:0 <00>
++ * 0x00, 0x00,
++ * 0x00, 0x00
++ */
++ 0x91,
++ 0xA1, 0x80,
++ 0x02, 0x01,
++ 0x44,
++ 0x02, 0x01,
++ 0x06,
++ 0x30, 0x80,
++ 0x0A, 0x01,
++ 0x01,
++ 0x0A, 0x01,
++ 0x05,
++ 0x30, 0x80,
++ 0x84, 0x80,
++ 0x31, 0x38, 0x30, 0x33,
++ 0x00, 0x00,
++ 0x00, 0x00,
++ 0x05, 0x00,
++ 0x00, 0x00,
++ 0x00, 0x00,
++ 0x00, 0x00
++/* *INDENT-ON* */
++};
++
++static unsigned char rose_etsi_unused[] = {
++/* *INDENT-OFF* */
++/*
++ * Context Specific/C [1 0x01] <A1> Len:24 <18>
++ * Integer(2 0x02) <02> Len:1 <01>
++ * <44>
++ * Integer(2 0x02) <02> Len:1 <01>
++ * <06> -- EctExecute
++ * Sequence/C(48 0x30) <30> Len:16 <10>
++ * Enumerated(10 0x0A) <0A> Len:1 <01>
++ * <01>
++ * Enumerated(10 0x0A) <0A> Len:1 <01>
++ * <05>
++ * Sequence/C(48 0x30) <30> Len:6 <06>
++ * Context Specific [4 0x04] <84> Len:4 <04>
++ * <31 38 30 33>
++ * NULL(5 0x05) <05> Len:0 <00>
++ */
++ 0x91,
++ 0xA1, 0x18,
++ 0x02, 0x01,
++ 0x44,
++ 0x02, 0x01,
++ 0x06,
++ 0x30, 0x10,
++ 0x0A, 0x01,
++ 0x01,
++ 0x0A, 0x01,
++ 0x05,
++ 0x30, 0x06,
++ 0x84, 0x04,
++ 0x31, 0x38, 0x30, 0x33,
++ 0x05, 0x00,
++ 0x00, 0x00
++/* *INDENT-ON* */
++};
++
++static unsigned char rose_etsi_extra[] = {
++/* *INDENT-OFF* */
++/*
++ * Context Specific/C [1 0x01] <A1> Len:24 <18>
++ * Integer(2 0x02) <02> Len:1 <01>
++ * <44>
++ * Integer(2 0x02) <02> Len:1 <01>
++ * <07>
++ * Sequence/C(48 0x30) <30> Len:16 <10>
++ * Enumerated(10 0x0A) <0A> Len:1 <01>
++ * <01>
++ * Enumerated(10 0x0A) <0A> Len:1 <01>
++ * <05>
++ * Sequence/C(48 0x30) <30> Len:6 <06>
++ * Context Specific [4 0x04] <84> Len:4 <04>
++ * <31 38 30 33>
++ * NULL(5 0x05) <05> Len:0 <00>
++ */
++ 0x91,
++ 0xA1, 0x18,
++ 0x02, 0x01,
++ 0x44,
++ 0x02, 0x01,
++ 0x07,
++ 0x30, 0x10,
++ 0x0A, 0x01,
++ 0x01,
++ 0x0A, 0x01,
++ 0x05,
++ 0x30, 0x06,
++ 0x84, 0x04,
++ 0x31, 0x38, 0x30, 0x33,
++ 0x05, 0x00,
++ 0x00, 0x00
++/* *INDENT-ON* */
++};
++
++
++static const struct rose_message rose_qsig_msgs[] = {
++/* *INDENT-OFF* */
++ /* Q.SIG Name-Operations */
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_CallingName,
++ .component.invoke.invoke_id = 2,
++ .component.invoke.args.qsig.CallingName.name.presentation = 1,
++ .component.invoke.args.qsig.CallingName.name.char_set = 1,
++ .component.invoke.args.qsig.CallingName.name.length = 7,
++ .component.invoke.args.qsig.CallingName.name.data = "Alphred",
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_CallingName,
++ .component.invoke.invoke_id = 3,
++ .component.invoke.args.qsig.CallingName.name.presentation = 1,
++ .component.invoke.args.qsig.CallingName.name.char_set = 3,
++ .component.invoke.args.qsig.CallingName.name.length = 7,
++ .component.invoke.args.qsig.CallingName.name.data = "Alphred",
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_CallingName,
++ .component.invoke.invoke_id = 4,
++ .component.invoke.args.qsig.CallingName.name.presentation = 2,
++ .component.invoke.args.qsig.CallingName.name.char_set = 1,
++ .component.invoke.args.qsig.CallingName.name.length = 7,
++ .component.invoke.args.qsig.CallingName.name.data = "Alphred",
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_CallingName,
++ .component.invoke.invoke_id = 5,
++ .component.invoke.args.qsig.CallingName.name.presentation = 2,
++ .component.invoke.args.qsig.CallingName.name.char_set = 3,
++ .component.invoke.args.qsig.CallingName.name.length = 7,
++ .component.invoke.args.qsig.CallingName.name.data = "Alphred",
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_CallingName,
++ .component.invoke.invoke_id = 6,
++ .component.invoke.args.qsig.CallingName.name.presentation = 3,
++ .component.invoke.args.qsig.CallingName.name.char_set = 1,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_CallingName,
++ .component.invoke.invoke_id = 7,
++ .component.invoke.args.qsig.CallingName.name.presentation = 4,
++ .component.invoke.args.qsig.CallingName.name.char_set = 1,
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_CalledName,
++ .component.invoke.invoke_id = 8,
++ .component.invoke.args.qsig.CallingName.name.presentation = 4,
++ .component.invoke.args.qsig.CallingName.name.char_set = 1,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_ConnectedName,
++ .component.invoke.invoke_id = 9,
++ .component.invoke.args.qsig.CallingName.name.presentation = 4,
++ .component.invoke.args.qsig.CallingName.name.char_set = 1,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_BusyName,
++ .component.invoke.invoke_id = 10,
++ .component.invoke.args.qsig.CallingName.name.presentation = 4,
++ .component.invoke.args.qsig.CallingName.name.char_set = 1,
++ },
++
++ /* Q.SIG SS-AOC-Operations */
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_ChargeRequest,
++ .component.invoke.invoke_id = 11,
++ .component.invoke.args.qsig.ChargeRequest.num_records = 0,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_ChargeRequest,
++ .component.invoke.invoke_id = 12,
++ .component.invoke.args.qsig.ChargeRequest.num_records = 1,
++ .component.invoke.args.qsig.ChargeRequest.advice_mode_combinations[0] = 3,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_ChargeRequest,
++ .component.invoke.invoke_id = 13,
++ .component.invoke.args.qsig.ChargeRequest.num_records = 2,
++ .component.invoke.args.qsig.ChargeRequest.advice_mode_combinations[0] = 4,
++ .component.invoke.args.qsig.ChargeRequest.advice_mode_combinations[1] = 3,
++ },
++ {
++ .type = ROSE_COMP_TYPE_RESULT,
++ .component.result.operation = ROSE_QSIG_ChargeRequest,
++ .component.result.invoke_id = 14,
++ .component.result.args.qsig.ChargeRequest.advice_mode_combination = 3,
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_GetFinalCharge,
++ .component.invoke.invoke_id = 15,
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_AocFinal,
++ .component.invoke.invoke_id = 16,
++ .component.invoke.args.qsig.AocFinal.type = 0,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_AocFinal,
++ .component.invoke.invoke_id = 17,
++ .component.invoke.args.qsig.AocFinal.type = 1,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_AocFinal,
++ .component.invoke.invoke_id = 18,
++ .component.invoke.args.qsig.AocFinal.type = 2,
++ .component.invoke.args.qsig.AocFinal.specific.recorded.amount.currency = 800,
++ .component.invoke.args.qsig.AocFinal.specific.recorded.amount.multiplier = 2,
++ .component.invoke.args.qsig.AocFinal.specific.recorded.currency = "Rupies",
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_AocFinal,
++ .component.invoke.invoke_id = 19,
++ .component.invoke.args.qsig.AocFinal.type = 2,
++ .component.invoke.args.qsig.AocFinal.specific.recorded.amount.currency = 800,
++ .component.invoke.args.qsig.AocFinal.specific.recorded.amount.multiplier = 2,
++ .component.invoke.args.qsig.AocFinal.specific.recorded.currency = "Rupies",
++ .component.invoke.args.qsig.AocFinal.specific.billing_id_present = 1,
++ .component.invoke.args.qsig.AocFinal.specific.billing_id = 2,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_AocFinal,
++ .component.invoke.invoke_id = 20,
++ .component.invoke.args.qsig.AocFinal.type = 2,
++ .component.invoke.args.qsig.AocFinal.specific.recorded.amount.currency = 800,
++ .component.invoke.args.qsig.AocFinal.specific.recorded.amount.multiplier = 2,
++ .component.invoke.args.qsig.AocFinal.specific.recorded.currency = "Rupies",
++ .component.invoke.args.qsig.AocFinal.charging_association_present = 1,
++ .component.invoke.args.qsig.AocFinal.charging_association.type = 0,
++ .component.invoke.args.qsig.AocFinal.charging_association.id = 200,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_AocFinal,
++ .component.invoke.invoke_id = 21,
++ .component.invoke.args.qsig.AocFinal.type = 2,
++ .component.invoke.args.qsig.AocFinal.specific.recorded.amount.currency = 800,
++ .component.invoke.args.qsig.AocFinal.specific.recorded.amount.multiplier = 2,
++ .component.invoke.args.qsig.AocFinal.specific.recorded.currency = "Rupies",
++ .component.invoke.args.qsig.AocFinal.specific.billing_id_present = 1,
++ .component.invoke.args.qsig.AocFinal.specific.billing_id = 2,
++ .component.invoke.args.qsig.AocFinal.charging_association_present = 1,
++ .component.invoke.args.qsig.AocFinal.charging_association.type = 0,
++ .component.invoke.args.qsig.AocFinal.charging_association.id = 200,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_AocFinal,
++ .component.invoke.invoke_id = 22,
++ .component.invoke.args.qsig.AocFinal.type = 2,
++ .component.invoke.args.qsig.AocFinal.specific.recorded.amount.currency = 800,
++ .component.invoke.args.qsig.AocFinal.specific.recorded.amount.multiplier = 2,
++ .component.invoke.args.qsig.AocFinal.specific.recorded.currency = "Rupies",
++ .component.invoke.args.qsig.AocFinal.charging_association_present = 1,
++ .component.invoke.args.qsig.AocFinal.charging_association.type = 1,
++ .component.invoke.args.qsig.AocFinal.charging_association.number.plan = 4,
++ .component.invoke.args.qsig.AocFinal.charging_association.number.length = 4,
++ .component.invoke.args.qsig.AocFinal.charging_association.number.str = "1802",
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_AocInterim,
++ .component.invoke.invoke_id = 23,
++ .component.invoke.args.qsig.AocInterim.type = 0,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_AocInterim,
++ .component.invoke.invoke_id = 24,
++ .component.invoke.args.qsig.AocInterim.type = 1,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_AocInterim,
++ .component.invoke.invoke_id = 25,
++ .component.invoke.args.qsig.AocInterim.type = 2,
++ .component.invoke.args.qsig.AocInterim.specific.recorded.amount.currency = 800,
++ .component.invoke.args.qsig.AocInterim.specific.recorded.amount.multiplier = 2,
++ .component.invoke.args.qsig.AocInterim.specific.recorded.currency = "Rupies",
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_AocInterim,
++ .component.invoke.invoke_id = 26,
++ .component.invoke.args.qsig.AocInterim.type = 2,
++ .component.invoke.args.qsig.AocInterim.specific.recorded.amount.currency = 800,
++ .component.invoke.args.qsig.AocInterim.specific.recorded.amount.multiplier = 2,
++ .component.invoke.args.qsig.AocInterim.specific.recorded.currency = "Rupies",
++ .component.invoke.args.qsig.AocInterim.specific.billing_id_present = 1,
++ .component.invoke.args.qsig.AocInterim.specific.billing_id = 2,
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_AocRate,
++ .component.invoke.invoke_id = 27,
++ .component.invoke.args.qsig.AocRate.type = 0,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_AocRate,
++ .component.invoke.invoke_id = 28,
++ .component.invoke.args.qsig.AocRate.type = 1,
++ .component.invoke.args.qsig.AocRate.currency_info.num_records = 1,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].charged_item = 4,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].currency_type = 0,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.special_charging_code = 3,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_AocRate,
++ .component.invoke.invoke_id = 29,
++ .component.invoke.args.qsig.AocRate.type = 1,
++ .component.invoke.args.qsig.AocRate.currency_info.num_records = 1,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].charged_item = 4,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].currency_type = 1,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.duration.currency = "Dollars",
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.duration.amount.currency = 7,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.duration.amount.multiplier = 1,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.duration.charging_type = 1,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.duration.time.length = 8,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.duration.time.scale = 4,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_AocRate,
++ .component.invoke.invoke_id = 30,
++ .component.invoke.args.qsig.AocRate.type = 1,
++ .component.invoke.args.qsig.AocRate.currency_info.num_records = 1,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].charged_item = 4,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].currency_type = 1,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.duration.currency = "Dollars",
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.duration.amount.currency = 7,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.duration.amount.multiplier = 1,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.duration.charging_type = 1,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.duration.time.length = 8,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.duration.time.scale = 4,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.duration.granularity_present = 1,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.duration.granularity.length = 20,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.duration.granularity.scale = 3,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_AocRate,
++ .component.invoke.invoke_id = 31,
++ .component.invoke.args.qsig.AocRate.type = 1,
++ .component.invoke.args.qsig.AocRate.currency_info.num_records = 1,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].charged_item = 4,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].currency_type = 2,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.flat_rate.currency = "Euros",
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.flat_rate.amount.currency = 4,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.flat_rate.amount.multiplier = 1,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_AocRate,
++ .component.invoke.invoke_id = 32,
++ .component.invoke.args.qsig.AocRate.type = 1,
++ .component.invoke.args.qsig.AocRate.currency_info.num_records = 1,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].charged_item = 4,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].currency_type = 3,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.volume_rate.currency = "Yen",
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.volume_rate.amount.currency = 300,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.volume_rate.amount.multiplier = 5,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.volume_rate.unit = 2,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_AocRate,
++ .component.invoke.invoke_id = 33,
++ .component.invoke.args.qsig.AocRate.type = 1,
++ .component.invoke.args.qsig.AocRate.currency_info.num_records = 2,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].charged_item = 4,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].currency_type = 2,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.flat_rate.currency = "Euros",
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.flat_rate.amount.currency = 4,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.flat_rate.amount.multiplier = 1,
++ .component.invoke.args.qsig.AocRate.currency_info.list[1].charged_item = 4,
++ .component.invoke.args.qsig.AocRate.currency_info.list[1].currency_type = 3,
++ .component.invoke.args.qsig.AocRate.currency_info.list[1].u.volume_rate.currency = "Yen",
++ .component.invoke.args.qsig.AocRate.currency_info.list[1].u.volume_rate.amount.currency = 300,
++ .component.invoke.args.qsig.AocRate.currency_info.list[1].u.volume_rate.amount.multiplier = 5,
++ .component.invoke.args.qsig.AocRate.currency_info.list[1].u.volume_rate.unit = 2,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_AocRate,
++ .component.invoke.invoke_id = 34,
++ .component.invoke.args.qsig.AocRate.type = 1,
++ .component.invoke.args.qsig.AocRate.currency_info.num_records = 1,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].charged_item = 4,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].currency_type = 4,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_AocRate,
++ .component.invoke.invoke_id = 35,
++ .component.invoke.args.qsig.AocRate.type = 1,
++ .component.invoke.args.qsig.AocRate.currency_info.num_records = 1,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].charged_item = 4,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].currency_type = 5,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_AocRate,
++ .component.invoke.invoke_id = 36,
++ .component.invoke.args.qsig.AocRate.type = 1,
++ .component.invoke.args.qsig.AocRate.currency_info.num_records = 1,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].charged_item = 4,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].currency_type = 6,
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_AocComplete,
++ .component.invoke.invoke_id = 37,
++ .component.invoke.args.qsig.AocComplete.charged_user_number.plan = 4,
++ .component.invoke.args.qsig.AocComplete.charged_user_number.length = 4,
++ .component.invoke.args.qsig.AocComplete.charged_user_number.str = "8340",
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_AocComplete,
++ .component.invoke.invoke_id = 38,
++ .component.invoke.args.qsig.AocComplete.charged_user_number.plan = 4,
++ .component.invoke.args.qsig.AocComplete.charged_user_number.length = 4,
++ .component.invoke.args.qsig.AocComplete.charged_user_number.str = "8340",
++ .component.invoke.args.qsig.AocComplete.charging_association_present = 1,
++ .component.invoke.args.qsig.AocComplete.charging_association.type = 0,
++ .component.invoke.args.qsig.AocComplete.charging_association.id = 8298,
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_RESULT,
++ .component.result.operation = ROSE_QSIG_AocComplete,
++ .component.result.invoke_id = 39,
++ .component.result.args.qsig.AocComplete.charging_option = 2,
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_AocDivChargeReq,
++ .component.invoke.invoke_id = 40,
++ .component.invoke.args.qsig.AocDivChargeReq.diverting_user_number.plan = 4,
++ .component.invoke.args.qsig.AocDivChargeReq.diverting_user_number.length = 4,
++ .component.invoke.args.qsig.AocDivChargeReq.diverting_user_number.str = "8340",
++ .component.invoke.args.qsig.AocDivChargeReq.diversion_type = 3,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_AocDivChargeReq,
++ .component.invoke.invoke_id = 41,
++ .component.invoke.args.qsig.AocDivChargeReq.diverting_user_number.plan = 4,
++ .component.invoke.args.qsig.AocDivChargeReq.diverting_user_number.length = 4,
++ .component.invoke.args.qsig.AocDivChargeReq.diverting_user_number.str = "8340",
++ .component.invoke.args.qsig.AocDivChargeReq.charging_association_present = 1,
++ .component.invoke.args.qsig.AocDivChargeReq.charging_association.type = 0,
++ .component.invoke.args.qsig.AocDivChargeReq.charging_association.id = 8298,
++ .component.invoke.args.qsig.AocDivChargeReq.diversion_type = 3,
++ },
++
++ /* Q.SIG Call-Transfer-Operations (CT) */
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_CallTransferIdentify,
++ .component.invoke.invoke_id = 42,
++ },
++ {
++ .type = ROSE_COMP_TYPE_RESULT,
++ .component.result.operation = ROSE_QSIG_CallTransferIdentify,
++ .component.result.invoke_id = 43,
++ .component.result.args.qsig.CallTransferIdentify.call_id = "2345",
++ .component.result.args.qsig.CallTransferIdentify.rerouting_number.plan = 4,
++ .component.result.args.qsig.CallTransferIdentify.rerouting_number.length = 4,
++ .component.result.args.qsig.CallTransferIdentify.rerouting_number.str = "8340",
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_CallTransferAbandon,
++ .component.invoke.invoke_id = 44,
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_CallTransferInitiate,
++ .component.invoke.invoke_id = 45,
++ .component.invoke.args.qsig.CallTransferInitiate.call_id = "2345",
++ .component.invoke.args.qsig.CallTransferInitiate.rerouting_number.plan = 4,
++ .component.invoke.args.qsig.CallTransferInitiate.rerouting_number.length = 4,
++ .component.invoke.args.qsig.CallTransferInitiate.rerouting_number.str = "8340",
++ },
++ {
++ .type = ROSE_COMP_TYPE_RESULT,
++ .component.result.operation = ROSE_QSIG_CallTransferInitiate,
++ .component.result.invoke_id = 46,
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_CallTransferSetup,
++ .component.invoke.invoke_id = 47,
++ .component.invoke.args.qsig.CallTransferSetup.call_id = "23",
++ },
++ {
++ .type = ROSE_COMP_TYPE_RESULT,
++ .component.result.operation = ROSE_QSIG_CallTransferSetup,
++ .component.result.invoke_id = 48,
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_CallTransferActive,
++ .component.invoke.invoke_id = 49,
++ .component.invoke.args.qsig.CallTransferActive.connected.presentation = 1,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_CallTransferActive,
++ .component.invoke.invoke_id = 50,
++ .component.invoke.args.qsig.CallTransferActive.connected.presentation = 1,
++ .component.invoke.args.qsig.CallTransferActive.q931ie.length = 2,
++ .component.invoke.args.qsig.CallTransferActive.q931ie_contents = "RT",
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_CallTransferActive,
++ .component.invoke.invoke_id = 51,
++ .component.invoke.args.qsig.CallTransferActive.connected.presentation = 1,
++ .component.invoke.args.qsig.CallTransferActive.connected_name_present = 1,
++ .component.invoke.args.qsig.CallTransferActive.connected_name.presentation = 1,
++ .component.invoke.args.qsig.CallTransferActive.connected_name.char_set = 1,
++ .component.invoke.args.qsig.CallTransferActive.connected_name.length = 7,
++ .component.invoke.args.qsig.CallTransferActive.connected_name.data = "Alphred",
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_CallTransferActive,
++ .component.invoke.invoke_id = 52,
++ .component.invoke.args.qsig.CallTransferActive.connected.presentation = 1,
++ .component.invoke.args.qsig.CallTransferActive.q931ie.length = 2,
++ .component.invoke.args.qsig.CallTransferActive.q931ie_contents = "RT",
++ .component.invoke.args.qsig.CallTransferActive.connected_name_present = 1,
++ .component.invoke.args.qsig.CallTransferActive.connected_name.presentation = 1,
++ .component.invoke.args.qsig.CallTransferActive.connected_name.char_set = 1,
++ .component.invoke.args.qsig.CallTransferActive.connected_name.length = 7,
++ .component.invoke.args.qsig.CallTransferActive.connected_name.data = "Alphred",
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_CallTransferComplete,
++ .component.invoke.invoke_id = 53,
++ .component.invoke.args.qsig.CallTransferComplete.end_designation = 1,
++ .component.invoke.args.qsig.CallTransferComplete.redirection.presentation = 0,
++ .component.invoke.args.qsig.CallTransferComplete.redirection.screened.screening_indicator = 3,
++ .component.invoke.args.qsig.CallTransferComplete.redirection.screened.number.plan = 4,
++ .component.invoke.args.qsig.CallTransferComplete.redirection.screened.number.length = 4,
++ .component.invoke.args.qsig.CallTransferComplete.redirection.screened.number.str = "8340",
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_CallTransferComplete,
++ .component.invoke.invoke_id = 54,
++ .component.invoke.args.qsig.CallTransferComplete.end_designation = 1,
++ .component.invoke.args.qsig.CallTransferComplete.redirection.presentation = 1,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_CallTransferComplete,
++ .component.invoke.invoke_id = 55,
++ .component.invoke.args.qsig.CallTransferComplete.end_designation = 1,
++ .component.invoke.args.qsig.CallTransferComplete.redirection.presentation = 2,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_CallTransferComplete,
++ .component.invoke.invoke_id = 56,
++ .component.invoke.args.qsig.CallTransferComplete.end_designation = 1,
++ .component.invoke.args.qsig.CallTransferComplete.redirection.presentation = 3,
++ .component.invoke.args.qsig.CallTransferComplete.redirection.screened.screening_indicator = 3,
++ .component.invoke.args.qsig.CallTransferComplete.redirection.screened.number.plan = 4,
++ .component.invoke.args.qsig.CallTransferComplete.redirection.screened.number.length = 4,
++ .component.invoke.args.qsig.CallTransferComplete.redirection.screened.number.str = "8340",
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_CallTransferComplete,
++ .component.invoke.invoke_id = 57,
++ .component.invoke.args.qsig.CallTransferComplete.end_designation = 1,
++ .component.invoke.args.qsig.CallTransferComplete.redirection.presentation = 2,
++ .component.invoke.args.qsig.CallTransferComplete.q931ie.length = 2,
++ .component.invoke.args.qsig.CallTransferComplete.q931ie_contents = "RT",
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_CallTransferComplete,
++ .component.invoke.invoke_id = 58,
++ .component.invoke.args.qsig.CallTransferComplete.end_designation = 1,
++ .component.invoke.args.qsig.CallTransferComplete.redirection.presentation = 2,
++ .component.invoke.args.qsig.CallTransferComplete.redirection_name_present = 1,
++ .component.invoke.args.qsig.CallTransferComplete.redirection_name.presentation = 1,
++ .component.invoke.args.qsig.CallTransferComplete.redirection_name.char_set = 1,
++ .component.invoke.args.qsig.CallTransferComplete.redirection_name.length = 7,
++ .component.invoke.args.qsig.CallTransferComplete.redirection_name.data = "Alphred",
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_CallTransferComplete,
++ .component.invoke.invoke_id = 59,
++ .component.invoke.args.qsig.CallTransferComplete.end_designation = 1,
++ .component.invoke.args.qsig.CallTransferComplete.redirection.presentation = 2,
++ .component.invoke.args.qsig.CallTransferComplete.call_status = 1,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_CallTransferComplete,
++ .component.invoke.invoke_id = 60,
++ .component.invoke.args.qsig.CallTransferComplete.end_designation = 1,
++ .component.invoke.args.qsig.CallTransferComplete.redirection.presentation = 2,
++ .component.invoke.args.qsig.CallTransferComplete.q931ie.length = 2,
++ .component.invoke.args.qsig.CallTransferComplete.q931ie_contents = "RT",
++ .component.invoke.args.qsig.CallTransferComplete.call_status = 1,
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_CallTransferUpdate,
++ .component.invoke.invoke_id = 61,
++ .component.invoke.args.qsig.CallTransferUpdate.redirection.presentation = 2,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_CallTransferUpdate,
++ .component.invoke.invoke_id = 62,
++ .component.invoke.args.qsig.CallTransferUpdate.redirection.presentation = 2,
++ .component.invoke.args.qsig.CallTransferUpdate.redirection_name_present = 1,
++ .component.invoke.args.qsig.CallTransferUpdate.redirection_name.presentation = 1,
++ .component.invoke.args.qsig.CallTransferUpdate.redirection_name.char_set = 1,
++ .component.invoke.args.qsig.CallTransferUpdate.redirection_name.length = 7,
++ .component.invoke.args.qsig.CallTransferUpdate.redirection_name.data = "Alphred",
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_CallTransferUpdate,
++ .component.invoke.invoke_id = 63,
++ .component.invoke.args.qsig.CallTransferUpdate.redirection.presentation = 2,
++ .component.invoke.args.qsig.CallTransferUpdate.q931ie.length = 2,
++ .component.invoke.args.qsig.CallTransferUpdate.q931ie_contents = "RT",
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_CallTransferUpdate,
++ .component.invoke.invoke_id = 64,
++ .component.invoke.args.qsig.CallTransferUpdate.redirection.presentation = 2,
++ .component.invoke.args.qsig.CallTransferUpdate.redirection_name_present = 1,
++ .component.invoke.args.qsig.CallTransferUpdate.redirection_name.presentation = 1,
++ .component.invoke.args.qsig.CallTransferUpdate.redirection_name.char_set = 1,
++ .component.invoke.args.qsig.CallTransferUpdate.redirection_name.length = 7,
++ .component.invoke.args.qsig.CallTransferUpdate.redirection_name.data = "Alphred",
++ .component.invoke.args.qsig.CallTransferUpdate.q931ie.length = 2,
++ .component.invoke.args.qsig.CallTransferUpdate.q931ie_contents = "RT",
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_SubaddressTransfer,
++ .component.invoke.invoke_id = 65,
++ .component.invoke.args.qsig.SubaddressTransfer.redirection_subaddress.type = 1,
++ .component.invoke.args.qsig.SubaddressTransfer.redirection_subaddress.length = 4,
++ .component.invoke.args.qsig.SubaddressTransfer.redirection_subaddress.u.nsap = "4356",
++ },
++
++ /* Q.SIG Call-Diversion-Operations */
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_ActivateDiversionQ,
++ .component.invoke.invoke_id = 66,
++ .component.invoke.args.qsig.ActivateDiversionQ.procedure = 1,
++ .component.invoke.args.qsig.ActivateDiversionQ.basic_service = 3,
++ .component.invoke.args.qsig.ActivateDiversionQ.diverted_to.number.plan = 4,
++ .component.invoke.args.qsig.ActivateDiversionQ.diverted_to.number.length = 4,
++ .component.invoke.args.qsig.ActivateDiversionQ.diverted_to.number.str = "8340",
++ .component.invoke.args.qsig.ActivateDiversionQ.served_user_number.plan = 4,
++ .component.invoke.args.qsig.ActivateDiversionQ.served_user_number.length = 4,
++ .component.invoke.args.qsig.ActivateDiversionQ.served_user_number.str = "8340",
++ .component.invoke.args.qsig.ActivateDiversionQ.activating_user_number.plan = 4,
++ .component.invoke.args.qsig.ActivateDiversionQ.activating_user_number.length = 4,
++ .component.invoke.args.qsig.ActivateDiversionQ.activating_user_number.str = "8340",
++ },
++ {
++ .type = ROSE_COMP_TYPE_RESULT,
++ .component.result.operation = ROSE_QSIG_ActivateDiversionQ,
++ .component.result.invoke_id = 67,
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_DeactivateDiversionQ,
++ .component.invoke.invoke_id = 68,
++ .component.invoke.args.qsig.DeactivateDiversionQ.procedure = 1,
++ .component.invoke.args.qsig.DeactivateDiversionQ.basic_service = 3,
++ .component.invoke.args.qsig.DeactivateDiversionQ.served_user_number.plan = 4,
++ .component.invoke.args.qsig.DeactivateDiversionQ.served_user_number.length = 4,
++ .component.invoke.args.qsig.DeactivateDiversionQ.served_user_number.str = "8340",
++ .component.invoke.args.qsig.DeactivateDiversionQ.deactivating_user_number.plan = 4,
++ .component.invoke.args.qsig.DeactivateDiversionQ.deactivating_user_number.length = 4,
++ .component.invoke.args.qsig.DeactivateDiversionQ.deactivating_user_number.str = "8340",
++ },
++ {
++ .type = ROSE_COMP_TYPE_RESULT,
++ .component.result.operation = ROSE_QSIG_DeactivateDiversionQ,
++ .component.result.invoke_id = 69,
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_InterrogateDiversionQ,
++ .component.invoke.invoke_id = 70,
++ .component.invoke.args.qsig.InterrogateDiversionQ.procedure = 1,
++ .component.invoke.args.qsig.InterrogateDiversionQ.basic_service = 3,
++ .component.invoke.args.qsig.InterrogateDiversionQ.served_user_number.plan = 4,
++ .component.invoke.args.qsig.InterrogateDiversionQ.served_user_number.length = 4,
++ .component.invoke.args.qsig.InterrogateDiversionQ.served_user_number.str = "8340",
++ .component.invoke.args.qsig.InterrogateDiversionQ.interrogating_user_number.plan = 4,
++ .component.invoke.args.qsig.InterrogateDiversionQ.interrogating_user_number.length = 4,
++ .component.invoke.args.qsig.InterrogateDiversionQ.interrogating_user_number.str = "8340",
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_InterrogateDiversionQ,
++ .component.invoke.invoke_id = 71,
++ .component.invoke.args.qsig.InterrogateDiversionQ.procedure = 1,
++ .component.invoke.args.qsig.InterrogateDiversionQ.basic_service = 0,/* default */
++ .component.invoke.args.qsig.InterrogateDiversionQ.served_user_number.plan = 4,
++ .component.invoke.args.qsig.InterrogateDiversionQ.served_user_number.length = 4,
++ .component.invoke.args.qsig.InterrogateDiversionQ.served_user_number.str = "8340",
++ .component.invoke.args.qsig.InterrogateDiversionQ.interrogating_user_number.plan = 4,
++ .component.invoke.args.qsig.InterrogateDiversionQ.interrogating_user_number.length = 4,
++ .component.invoke.args.qsig.InterrogateDiversionQ.interrogating_user_number.str = "8340",
++ },
++ {
++ .type = ROSE_COMP_TYPE_RESULT,
++ .component.result.operation = ROSE_QSIG_InterrogateDiversionQ,
++ .component.result.invoke_id = 72,
++ .component.result.args.qsig.InterrogateDiversionQ.num_records = 0,
++ },
++ {
++ .type = ROSE_COMP_TYPE_RESULT,
++ .component.result.operation = ROSE_QSIG_InterrogateDiversionQ,
++ .component.result.invoke_id = 73,
++ .component.result.args.qsig.InterrogateDiversionQ.num_records = 1,
++ .component.result.args.qsig.InterrogateDiversionQ.list[0].served_user_number.plan = 4,
++ .component.result.args.qsig.InterrogateDiversionQ.list[0].served_user_number.length = 4,
++ .component.result.args.qsig.InterrogateDiversionQ.list[0].served_user_number.str = "8340",
++ .component.result.args.qsig.InterrogateDiversionQ.list[0].basic_service = 3,
++ .component.result.args.qsig.InterrogateDiversionQ.list[0].procedure = 2,
++ .component.result.args.qsig.InterrogateDiversionQ.list[0].diverted_to.number.plan = 4,
++ .component.result.args.qsig.InterrogateDiversionQ.list[0].diverted_to.number.length = 4,
++ .component.result.args.qsig.InterrogateDiversionQ.list[0].diverted_to.number.str = "8340",
++ .component.result.args.qsig.InterrogateDiversionQ.list[0].remote_enabled = 0,
++ },
++ {
++ .type = ROSE_COMP_TYPE_RESULT,
++ .component.result.operation = ROSE_QSIG_InterrogateDiversionQ,
++ .component.result.invoke_id = 74,
++ .component.result.args.qsig.InterrogateDiversionQ.num_records = 1,
++ .component.result.args.qsig.InterrogateDiversionQ.list[0].served_user_number.plan = 4,
++ .component.result.args.qsig.InterrogateDiversionQ.list[0].served_user_number.length = 4,
++ .component.result.args.qsig.InterrogateDiversionQ.list[0].served_user_number.str = "8340",
++ .component.result.args.qsig.InterrogateDiversionQ.list[0].basic_service = 3,
++ .component.result.args.qsig.InterrogateDiversionQ.list[0].procedure = 2,
++ .component.result.args.qsig.InterrogateDiversionQ.list[0].diverted_to.number.plan = 4,
++ .component.result.args.qsig.InterrogateDiversionQ.list[0].diverted_to.number.length = 4,
++ .component.result.args.qsig.InterrogateDiversionQ.list[0].diverted_to.number.str = "8340",
++ .component.result.args.qsig.InterrogateDiversionQ.list[0].remote_enabled = 1,
++ },
++ {
++ .type = ROSE_COMP_TYPE_RESULT,
++ .component.result.operation = ROSE_QSIG_InterrogateDiversionQ,
++ .component.result.invoke_id = 75,
++ .component.result.args.qsig.InterrogateDiversionQ.num_records = 2,
++ .component.result.args.qsig.InterrogateDiversionQ.list[0].served_user_number.plan = 4,
++ .component.result.args.qsig.InterrogateDiversionQ.list[0].served_user_number.length = 4,
++ .component.result.args.qsig.InterrogateDiversionQ.list[0].served_user_number.str = "8340",
++ .component.result.args.qsig.InterrogateDiversionQ.list[0].basic_service = 3,
++ .component.result.args.qsig.InterrogateDiversionQ.list[0].procedure = 2,
++ .component.result.args.qsig.InterrogateDiversionQ.list[0].diverted_to.number.plan = 4,
++ .component.result.args.qsig.InterrogateDiversionQ.list[0].diverted_to.number.length = 4,
++ .component.result.args.qsig.InterrogateDiversionQ.list[0].diverted_to.number.str = "8340",
++ .component.result.args.qsig.InterrogateDiversionQ.list[1].served_user_number.plan = 4,
++ .component.result.args.qsig.InterrogateDiversionQ.list[1].served_user_number.length = 4,
++ .component.result.args.qsig.InterrogateDiversionQ.list[1].served_user_number.str = "8340",
++ .component.result.args.qsig.InterrogateDiversionQ.list[1].basic_service = 3,
++ .component.result.args.qsig.InterrogateDiversionQ.list[1].procedure = 2,
++ .component.result.args.qsig.InterrogateDiversionQ.list[1].diverted_to.number.plan = 4,
++ .component.result.args.qsig.InterrogateDiversionQ.list[1].diverted_to.number.length = 4,
++ .component.result.args.qsig.InterrogateDiversionQ.list[1].diverted_to.number.str = "8340",
++ .component.result.args.qsig.InterrogateDiversionQ.list[1].remote_enabled = 1,
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_CheckRestriction,
++ .component.invoke.invoke_id = 76,
++ .component.invoke.args.qsig.CheckRestriction.served_user_number.plan = 4,
++ .component.invoke.args.qsig.CheckRestriction.served_user_number.length = 4,
++ .component.invoke.args.qsig.CheckRestriction.served_user_number.str = "8340",
++ .component.invoke.args.qsig.CheckRestriction.basic_service = 3,
++ .component.invoke.args.qsig.CheckRestriction.diverted_to_number.plan = 4,
++ .component.invoke.args.qsig.CheckRestriction.diverted_to_number.length = 4,
++ .component.invoke.args.qsig.CheckRestriction.diverted_to_number.str = "8340",
++ },
++ {
++ .type = ROSE_COMP_TYPE_RESULT,
++ .component.result.operation = ROSE_QSIG_CheckRestriction,
++ .component.result.invoke_id = 77,
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_CallRerouting,
++ .component.invoke.invoke_id = 78,
++ .component.invoke.args.qsig.CallRerouting.rerouting_reason = 3,
++ .component.invoke.args.qsig.CallRerouting.called.number.plan = 4,
++ .component.invoke.args.qsig.CallRerouting.called.number.length = 4,
++ .component.invoke.args.qsig.CallRerouting.called.number.str = "8340",
++ .component.invoke.args.qsig.CallRerouting.diversion_counter = 5,
++ .component.invoke.args.qsig.CallRerouting.q931ie.length = 2,
++ .component.invoke.args.qsig.CallRerouting.q931ie_contents = "RT",
++ .component.invoke.args.qsig.CallRerouting.last_rerouting.presentation = 1,
++ .component.invoke.args.qsig.CallRerouting.subscription_option = 2,
++ .component.invoke.args.qsig.CallRerouting.calling.presentation = 1,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_CallRerouting,
++ .component.invoke.invoke_id = 79,
++ .component.invoke.args.qsig.CallRerouting.rerouting_reason = 3,
++ .component.invoke.args.qsig.CallRerouting.original_rerouting_reason_present = 1,
++ .component.invoke.args.qsig.CallRerouting.original_rerouting_reason = 2,
++ .component.invoke.args.qsig.CallRerouting.called.number.plan = 4,
++ .component.invoke.args.qsig.CallRerouting.called.number.length = 4,
++ .component.invoke.args.qsig.CallRerouting.called.number.str = "8340",
++ .component.invoke.args.qsig.CallRerouting.diversion_counter = 5,
++ .component.invoke.args.qsig.CallRerouting.q931ie.length = 2,
++ .component.invoke.args.qsig.CallRerouting.q931ie_contents = "RT",
++ .component.invoke.args.qsig.CallRerouting.last_rerouting.presentation = 1,
++ .component.invoke.args.qsig.CallRerouting.subscription_option = 2,
++ .component.invoke.args.qsig.CallRerouting.calling_subaddress.type = 1,
++ .component.invoke.args.qsig.CallRerouting.calling_subaddress.length = 4,
++ .component.invoke.args.qsig.CallRerouting.calling_subaddress.u.nsap = "3253",
++ .component.invoke.args.qsig.CallRerouting.calling.presentation = 1,
++ .component.invoke.args.qsig.CallRerouting.calling_name_present = 1,
++ .component.invoke.args.qsig.CallRerouting.calling_name.presentation = 4,
++ .component.invoke.args.qsig.CallRerouting.calling_name.char_set = 1,
++ .component.invoke.args.qsig.CallRerouting.original_called_present = 1,
++ .component.invoke.args.qsig.CallRerouting.original_called.presentation = 2,
++ .component.invoke.args.qsig.CallRerouting.redirecting_name_present = 1,
++ .component.invoke.args.qsig.CallRerouting.redirecting_name.presentation = 4,
++ .component.invoke.args.qsig.CallRerouting.redirecting_name.char_set = 1,
++ .component.invoke.args.qsig.CallRerouting.original_called_name_present = 1,
++ .component.invoke.args.qsig.CallRerouting.original_called_name.presentation = 4,
++ .component.invoke.args.qsig.CallRerouting.original_called_name.char_set = 1,
++ },
++ {
++ .type = ROSE_COMP_TYPE_RESULT,
++ .component.result.operation = ROSE_QSIG_CallRerouting,
++ .component.result.invoke_id = 80,
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_DivertingLegInformation1,
++ .component.invoke.invoke_id = 81,
++ .component.invoke.args.qsig.DivertingLegInformation1.diversion_reason = 3,
++ .component.invoke.args.qsig.DivertingLegInformation1.subscription_option = 1,
++ .component.invoke.args.qsig.DivertingLegInformation1.nominated_number.plan = 4,
++ .component.invoke.args.qsig.DivertingLegInformation1.nominated_number.length = 4,
++ .component.invoke.args.qsig.DivertingLegInformation1.nominated_number.str = "8340",
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_DivertingLegInformation2,
++ .component.invoke.invoke_id = 82,
++ .component.invoke.args.qsig.DivertingLegInformation2.diversion_counter = 6,
++ .component.invoke.args.qsig.DivertingLegInformation2.diversion_reason = 3,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_DivertingLegInformation2,
++ .component.invoke.invoke_id = 83,
++ .component.invoke.args.qsig.DivertingLegInformation2.diversion_counter = 6,
++ .component.invoke.args.qsig.DivertingLegInformation2.diversion_reason = 3,
++ .component.invoke.args.qsig.DivertingLegInformation2.original_diversion_reason_present = 1,
++ .component.invoke.args.qsig.DivertingLegInformation2.original_diversion_reason = 2,
++ .component.invoke.args.qsig.DivertingLegInformation2.diverting_present = 1,
++ .component.invoke.args.qsig.DivertingLegInformation2.diverting.presentation = 2,
++ .component.invoke.args.qsig.DivertingLegInformation2.original_called_present = 1,
++ .component.invoke.args.qsig.DivertingLegInformation2.original_called.presentation = 2,
++ .component.invoke.args.qsig.DivertingLegInformation2.redirecting_name_present = 1,
++ .component.invoke.args.qsig.DivertingLegInformation2.redirecting_name.presentation = 4,
++ .component.invoke.args.qsig.DivertingLegInformation2.redirecting_name.char_set = 1,
++ .component.invoke.args.qsig.DivertingLegInformation2.original_called_name_present = 1,
++ .component.invoke.args.qsig.DivertingLegInformation2.original_called_name.presentation = 4,
++ .component.invoke.args.qsig.DivertingLegInformation2.original_called_name.char_set = 1,
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_DivertingLegInformation3,
++ .component.invoke.invoke_id = 84,
++ .component.invoke.args.qsig.DivertingLegInformation3.presentation_allowed_indicator = 1,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_DivertingLegInformation3,
++ .component.invoke.invoke_id = 85,
++ .component.invoke.args.qsig.DivertingLegInformation3.presentation_allowed_indicator = 1,
++ .component.invoke.args.qsig.DivertingLegInformation3.redirection_name_present = 1,
++ .component.invoke.args.qsig.DivertingLegInformation3.redirection_name.presentation = 4,
++ .component.invoke.args.qsig.DivertingLegInformation3.redirection_name.char_set = 1,
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_CfnrDivertedLegFailed,
++ .component.invoke.invoke_id = 86,
++ },
++
++ /* Q.SIG SS-MWI-Operations */
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_MWIActivate,
++ .component.invoke.invoke_id = 102,
++ .component.invoke.args.qsig.MWIActivate.served_user_number.plan = 4,
++ .component.invoke.args.qsig.MWIActivate.served_user_number.length = 4,
++ .component.invoke.args.qsig.MWIActivate.served_user_number.str = "9838",
++ .component.invoke.args.qsig.MWIActivate.basic_service = 1,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_MWIActivate,
++ .component.invoke.invoke_id = 103,
++ .component.invoke.args.qsig.MWIActivate.served_user_number.plan = 4,
++ .component.invoke.args.qsig.MWIActivate.served_user_number.length = 4,
++ .component.invoke.args.qsig.MWIActivate.served_user_number.str = "9838",
++ .component.invoke.args.qsig.MWIActivate.basic_service = 1,
++ .component.invoke.args.qsig.MWIActivate.msg_centre_id_present = 1,
++ .component.invoke.args.qsig.MWIActivate.msg_centre_id.type = 0,
++ .component.invoke.args.qsig.MWIActivate.msg_centre_id.u.integer = 532,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_MWIActivate,
++ .component.invoke.invoke_id = 104,
++ .component.invoke.args.qsig.MWIActivate.served_user_number.plan = 4,
++ .component.invoke.args.qsig.MWIActivate.served_user_number.length = 4,
++ .component.invoke.args.qsig.MWIActivate.served_user_number.str = "9838",
++ .component.invoke.args.qsig.MWIActivate.basic_service = 1,
++ .component.invoke.args.qsig.MWIActivate.msg_centre_id_present = 1,
++ .component.invoke.args.qsig.MWIActivate.msg_centre_id.type = 1,
++ .component.invoke.args.qsig.MWIActivate.msg_centre_id.u.number.plan = 4,
++ .component.invoke.args.qsig.MWIActivate.msg_centre_id.u.number.length = 4,
++ .component.invoke.args.qsig.MWIActivate.msg_centre_id.u.number.str = "9838",
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_MWIActivate,
++ .component.invoke.invoke_id = 105,
++ .component.invoke.args.qsig.MWIActivate.served_user_number.plan = 4,
++ .component.invoke.args.qsig.MWIActivate.served_user_number.length = 4,
++ .component.invoke.args.qsig.MWIActivate.served_user_number.str = "9838",
++ .component.invoke.args.qsig.MWIActivate.basic_service = 1,
++ .component.invoke.args.qsig.MWIActivate.msg_centre_id_present = 1,
++ .component.invoke.args.qsig.MWIActivate.msg_centre_id.type = 2,
++ .component.invoke.args.qsig.MWIActivate.msg_centre_id.u.str = "123456",
++ .component.invoke.args.qsig.MWIActivate.number_of_messages_present = 1,
++ .component.invoke.args.qsig.MWIActivate.number_of_messages = 6548,
++ .component.invoke.args.qsig.MWIActivate.originating_number.plan = 4,
++ .component.invoke.args.qsig.MWIActivate.originating_number.length = 4,
++ .component.invoke.args.qsig.MWIActivate.originating_number.str = "9838",
++ .component.invoke.args.qsig.MWIActivate.timestamp_present = 1,
++ .component.invoke.args.qsig.MWIActivate.timestamp = "19970621194530",
++ .component.invoke.args.qsig.MWIActivate.priority_present = 1,
++ .component.invoke.args.qsig.MWIActivate.priority = 7,
++ },
++ {
++ .type = ROSE_COMP_TYPE_RESULT,
++ .component.result.operation = ROSE_QSIG_MWIActivate,
++ .component.result.invoke_id = 106,
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_MWIDeactivate,
++ .component.invoke.invoke_id = 107,
++ .component.invoke.args.qsig.MWIDeactivate.served_user_number.plan = 4,
++ .component.invoke.args.qsig.MWIDeactivate.served_user_number.length = 4,
++ .component.invoke.args.qsig.MWIDeactivate.served_user_number.str = "9838",
++ .component.invoke.args.qsig.MWIDeactivate.basic_service = 1,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_MWIDeactivate,
++ .component.invoke.invoke_id = 108,
++ .component.invoke.args.qsig.MWIDeactivate.served_user_number.plan = 4,
++ .component.invoke.args.qsig.MWIDeactivate.served_user_number.length = 4,
++ .component.invoke.args.qsig.MWIDeactivate.served_user_number.str = "9838",
++ .component.invoke.args.qsig.MWIDeactivate.basic_service = 1,
++ .component.invoke.args.qsig.MWIDeactivate.msg_centre_id_present = 1,
++ .component.invoke.args.qsig.MWIDeactivate.msg_centre_id.type = 0,
++ .component.invoke.args.qsig.MWIDeactivate.msg_centre_id.u.integer = 532,
++ },
++ {
++ .type = ROSE_COMP_TYPE_RESULT,
++ .component.result.operation = ROSE_QSIG_MWIDeactivate,
++ .component.result.invoke_id = 109,
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_MWIInterrogate,
++ .component.invoke.invoke_id = 110,
++ .component.invoke.args.qsig.MWIInterrogate.served_user_number.plan = 4,
++ .component.invoke.args.qsig.MWIInterrogate.served_user_number.length = 4,
++ .component.invoke.args.qsig.MWIInterrogate.served_user_number.str = "9838",
++ .component.invoke.args.qsig.MWIInterrogate.basic_service = 1,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_MWIInterrogate,
++ .component.invoke.invoke_id = 111,
++ .component.invoke.args.qsig.MWIInterrogate.served_user_number.plan = 4,
++ .component.invoke.args.qsig.MWIInterrogate.served_user_number.length = 4,
++ .component.invoke.args.qsig.MWIInterrogate.served_user_number.str = "9838",
++ .component.invoke.args.qsig.MWIInterrogate.basic_service = 1,
++ .component.invoke.args.qsig.MWIInterrogate.msg_centre_id_present = 1,
++ .component.invoke.args.qsig.MWIInterrogate.msg_centre_id.type = 0,
++ .component.invoke.args.qsig.MWIInterrogate.msg_centre_id.u.integer = 532,
++ },
++ {
++ .type = ROSE_COMP_TYPE_RESULT,
++ .component.result.operation = ROSE_QSIG_MWIInterrogate,
++ .component.result.invoke_id = 112,
++ .component.result.args.qsig.MWIInterrogate.num_records = 1,
++ .component.result.args.qsig.MWIInterrogate.list[0].basic_service = 1,
++ },
++ {
++ .type = ROSE_COMP_TYPE_RESULT,
++ .component.result.operation = ROSE_QSIG_MWIInterrogate,
++ .component.result.invoke_id = 113,
++ .component.result.args.qsig.MWIInterrogate.num_records = 2,
++ .component.result.args.qsig.MWIInterrogate.list[0].basic_service = 1,
++ .component.result.args.qsig.MWIInterrogate.list[0].msg_centre_id_present = 1,
++ .component.result.args.qsig.MWIInterrogate.list[0].msg_centre_id.type = 0,
++ .component.result.args.qsig.MWIInterrogate.list[0].msg_centre_id.u.integer = 987,
++ .component.result.args.qsig.MWIInterrogate.list[0].number_of_messages_present = 1,
++ .component.result.args.qsig.MWIInterrogate.list[0].number_of_messages = 6548,
++ .component.result.args.qsig.MWIInterrogate.list[0].originating_number.plan = 4,
++ .component.result.args.qsig.MWIInterrogate.list[0].originating_number.length = 4,
++ .component.result.args.qsig.MWIInterrogate.list[0].originating_number.str = "9838",
++ .component.result.args.qsig.MWIInterrogate.list[0].timestamp_present = 1,
++ .component.result.args.qsig.MWIInterrogate.list[0].timestamp = "19970621194530",
++ .component.result.args.qsig.MWIInterrogate.list[0].priority_present = 1,
++ .component.result.args.qsig.MWIInterrogate.list[0].priority = 7,
++ .component.result.args.qsig.MWIInterrogate.list[1].basic_service = 1,
++ },
++/* *INDENT-ON* */
++};
++
++
++static const struct rose_message rose_dms100_msgs[] = {
++/* *INDENT-OFF* */
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_DMS100_RLT_OperationInd,
++ .component.invoke.invoke_id = ROSE_DMS100_RLT_OPERATION_IND,
++ },
++ {
++ .type = ROSE_COMP_TYPE_RESULT,
++ .component.result.operation = ROSE_DMS100_RLT_OperationInd,
++ .component.result.invoke_id = ROSE_DMS100_RLT_OPERATION_IND,
++ .component.result.args.dms100.RLT_OperationInd.call_id = 130363,
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_DMS100_RLT_ThirdParty,
++ .component.invoke.invoke_id = ROSE_DMS100_RLT_THIRD_PARTY,
++ .component.invoke.args.dms100.RLT_ThirdParty.call_id = 120047,
++ .component.invoke.args.dms100.RLT_ThirdParty.reason = 1,
++ },
++ {
++ .type = ROSE_COMP_TYPE_RESULT,
++ .component.result.operation = ROSE_DMS100_RLT_ThirdParty,
++ .component.result.invoke_id = ROSE_DMS100_RLT_THIRD_PARTY,
++ },
++/* *INDENT-ON* */
++};
++
++
++static const struct rose_message rose_ni2_msgs[] = {
++/* *INDENT-OFF* */
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_NI2_InformationFollowing,
++ .component.invoke.invoke_id = 1,
++ .component.invoke.args.ni2.InformationFollowing.value = 7,
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_NI2_InitiateTransfer,
++ .component.invoke.invoke_id = 2,
++ .component.invoke.args.ni2.InitiateTransfer.call_reference = 5,
++ },
++/* *INDENT-ON* */
++};
++
++/* ------------------------------------------------------------------- */
++
++static void rose_pri_message(struct pri *ctrl, char *stuff)
++{
++ fprintf(stdout, "%s", stuff);
++}
++
++static void rose_pri_error(struct pri *ctrl, char *stuff)
++{
++ fprintf(stdout, "%s", stuff);
++ fprintf(stderr, "%s", stuff);
++}
++
++/*!
++ * \internal
++ * \brief Test ROSE encoding and decoding the given message.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param index Message number to report.
++ * \param header Facility message header data to encode.
++ * \param encode_msg Message data to encode.
++ *
++ * \return Nothing
++ */
++static void rose_test_msg(struct pri *ctrl, unsigned index,
++ const struct fac_extension_header *header, const struct rose_message *encode_msg)
++{
++ struct fac_extension_header decoded_header;
++ struct rose_message decoded_msg;
++ unsigned char *enc_pos;
++ unsigned char *enc_end;
++ const unsigned char *dec_pos;
++ const unsigned char *dec_end;
++
++ static unsigned char buf[1024];
++
++ pri_message(ctrl, "\n\n");
++ enc_end = buf + sizeof(buf);
++ enc_pos = facility_encode_header(ctrl, buf, enc_end, header);
++ if (!enc_pos) {
++ pri_error(ctrl, "Error: Message:%u failed to encode header\n", index);
++ } else {
++ enc_pos = rose_encode(ctrl, enc_pos, enc_end, encode_msg);
++ if (!enc_pos) {
++ pri_error(ctrl, "Error: Message:%u failed to encode ROSE\n", index);
++ } else {
++ pri_message(ctrl, "Message %u encoded length is %u\n", index,
++ (unsigned) (enc_pos - buf));
++
++ /* Clear the decoded message contents for comparison. */
++ memset(&decoded_header, 0, sizeof(decoded_header));
++ memset(&decoded_msg, 0, sizeof(decoded_msg));
++
++ dec_end = enc_pos;
++ dec_pos = facility_decode_header(ctrl, buf, dec_end, &decoded_header);
++ if (!dec_pos) {
++ pri_error(ctrl, "Error: Message:%u failed to decode header\n", index);
++ } else {
++ dec_pos = rose_decode(ctrl, dec_pos, dec_end, &decoded_msg);
++ if (!dec_pos) {
++ pri_error(ctrl, "Error: Message:%u failed to decode ROSE\n", index);
++ } else {
++ if (header
++ && memcmp(header, &decoded_header, sizeof(decoded_header))) {
++ pri_error(ctrl, "Error: Message:%u Header did not match\n",
++ index);
++ }
++ if (memcmp(encode_msg, &decoded_msg, sizeof(decoded_msg))) {
++ pri_error(ctrl, "Error: Message:%u ROSE did not match\n", index);
++ }
++ }
++ }
++ }
++ }
++ pri_message(ctrl, "\n\n"
++ "************************************************************\n");
++}
++
++/*!
++ * \internal
++ * \brief Test ROSE decoding messages of unusual encodings.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param name Test name for the encoded message.
++ * \param msg_buf Encoded message to decode.
++ * \param msg_len Length of encoded message buffer.
++ *
++ * \return Nothing
++ */
++static void rose_test_exception(struct pri *ctrl, const char *name,
++ const unsigned char *msg, size_t msg_len)
++{
++ const unsigned char *pos;
++ const unsigned char *end;
++ struct fac_extension_header header;
++ struct rose_message decoded_msg;
++
++ pri_message(ctrl, "\n\n"
++ "%s test: Message encoded length is %u\n", name, (unsigned) msg_len);
++
++ pos = msg;
++ end = msg + msg_len;
++ pos = facility_decode_header(ctrl, pos, end, &header);
++ if (!pos) {
++ pri_error(ctrl, "Error: %s test: Message failed to decode header\n", name);
++ } else {
++ pos = rose_decode(ctrl, pos, end, &decoded_msg);
++ if (!pos) {
++ pri_error(ctrl, "Error: %s test: Message failed to decode ROSE\n", name);
++ }
++ }
++
++ pri_message(ctrl, "\n\n"
++ "************************************************************\n");
++}
++
++/*!
++ * \brief ROSE encode/decode test program.
++ *
++ * \param argc Program argument count.
++ * \param argv Program argument string array.
++ *
++ * \retval 0 on success.
++ * \retval Nonzero on error.
++ */
++int main(int argc, char *argv[])
++{
++ unsigned index;
++ unsigned offset;
++ static struct pri dummy_ctrl;
++
++ pri_set_message(rose_pri_message);
++ pri_set_error(rose_pri_error);
++
++ memset(&dummy_ctrl, 0, sizeof(dummy_ctrl));
++ dummy_ctrl.debug = PRI_DEBUG_APDU;
++
++ offset = 0;
++ pri_message(&dummy_ctrl, "Encode/decode message(s)\n");
++ if (argc <= 1) {
++ dummy_ctrl.switchtype = PRI_SWITCH_EUROISDN_E1;
++ for (index = 0; index < ARRAY_LEN(rose_etsi_msgs); ++index) {
++ rose_test_msg(&dummy_ctrl, index + offset, &fac_headers[0],
++ &rose_etsi_msgs[index]);
++ }
++ offset += ARRAY_LEN(rose_etsi_msgs);
++
++ dummy_ctrl.switchtype = PRI_SWITCH_QSIG;
++ for (index = 0; index < ARRAY_LEN(rose_qsig_msgs); ++index) {
++ rose_test_msg(&dummy_ctrl, index + offset,
++ &fac_headers[index % ARRAY_LEN(fac_headers)], &rose_qsig_msgs[index]);
++ }
++ offset += ARRAY_LEN(rose_qsig_msgs);
++
++ dummy_ctrl.switchtype = PRI_SWITCH_DMS100;
++ for (index = 0; index < ARRAY_LEN(rose_dms100_msgs); ++index) {
++ rose_test_msg(&dummy_ctrl, index + offset, &fac_headers[0],
++ &rose_dms100_msgs[index]);
++ }
++ offset += ARRAY_LEN(rose_dms100_msgs);
++
++ dummy_ctrl.switchtype = PRI_SWITCH_NI2;
++ for (index = 0; index < ARRAY_LEN(rose_ni2_msgs); ++index) {
++ rose_test_msg(&dummy_ctrl, index + offset, &fac_headers[0],
++ &rose_ni2_msgs[index]);
++ }
++ //offset += ARRAY_LEN(rose_ni2_msgs);
++ } else {
++ index = atoi(argv[1]);
++
++ if (index < ARRAY_LEN(rose_etsi_msgs)) {
++ dummy_ctrl.switchtype = PRI_SWITCH_EUROISDN_E1;
++ rose_test_msg(&dummy_ctrl, index + offset, &fac_headers[0],
++ &rose_etsi_msgs[index]);
++ return 0;
++ }
++ offset += ARRAY_LEN(rose_etsi_msgs);
++ index -= ARRAY_LEN(rose_etsi_msgs);
++
++ if (index < ARRAY_LEN(rose_qsig_msgs)) {
++ dummy_ctrl.switchtype = PRI_SWITCH_QSIG;
++ rose_test_msg(&dummy_ctrl, index + offset,
++ &fac_headers[index % ARRAY_LEN(fac_headers)], &rose_qsig_msgs[index]);
++ return 0;
++ }
++ offset += ARRAY_LEN(rose_qsig_msgs);
++ index -= ARRAY_LEN(rose_qsig_msgs);
++
++ if (index < ARRAY_LEN(rose_dms100_msgs)) {
++ dummy_ctrl.switchtype = PRI_SWITCH_DMS100;
++ rose_test_msg(&dummy_ctrl, index + offset, &fac_headers[0],
++ &rose_dms100_msgs[index]);
++ return 0;
++ }
++ offset += ARRAY_LEN(rose_dms100_msgs);
++ index -= ARRAY_LEN(rose_dms100_msgs);
++
++ if (index < ARRAY_LEN(rose_ni2_msgs)) {
++ dummy_ctrl.switchtype = PRI_SWITCH_NI2;
++ rose_test_msg(&dummy_ctrl, index + offset, &fac_headers[0],
++ &rose_ni2_msgs[index]);
++ return 0;
++ }
++ //offset += ARRAY_LEN(rose_ni2_msgs);
++ //index -= ARRAY_LEN(rose_ni2_msgs);
++
++ fprintf(stderr, "Invalid option\n");
++ return 0;
++ }
++
++/* ------------------------------------------------------------------- */
++
++ pri_message(&dummy_ctrl, "\n\n"
++ "Decode unusually encoded messages\n");
++
++ dummy_ctrl.switchtype = PRI_SWITCH_EUROISDN_E1;
++
++ rose_test_exception(&dummy_ctrl, "Extra bytes on end", rose_etsi_extra,
++ sizeof(rose_etsi_extra));
++
++ rose_test_exception(&dummy_ctrl, "Indefinite length", rose_etsi_indefinite_len,
++ sizeof(rose_etsi_indefinite_len) - 2);
++ rose_test_exception(&dummy_ctrl, "Indefinite length (extra)",
++ rose_etsi_indefinite_len, sizeof(rose_etsi_indefinite_len));
++
++ rose_test_exception(&dummy_ctrl, "Unused components (indefinite length)",
++ rose_etsi_unused_indefinite_len, sizeof(rose_etsi_unused_indefinite_len) - 2);
++ rose_test_exception(&dummy_ctrl, "Unused components (indefinite length, extra)",
++ rose_etsi_unused_indefinite_len, sizeof(rose_etsi_unused_indefinite_len));
++
++ rose_test_exception(&dummy_ctrl, "Unused components", rose_etsi_unused,
++ sizeof(rose_etsi_unused) - 2);
++ rose_test_exception(&dummy_ctrl, "Unused components (extra)", rose_etsi_unused,
++ sizeof(rose_etsi_unused));
++
++/* ------------------------------------------------------------------- */
++
++ pri_message(&dummy_ctrl, "\n\n"
++ "List of operation codes:\n");
++ for (index = 0; index < ROSE_Num_Operation_Codes; ++index) {
++ pri_message(&dummy_ctrl, "%d: %s\n", index, rose_operation2str(index));
++ }
++ pri_message(&dummy_ctrl, "\n\n"
++ "************************************************************\n");
++
++/* ------------------------------------------------------------------- */
++
++ pri_message(&dummy_ctrl, "\n\n"
++ "List of error codes:\n");
++ for (index = 0; index < ROSE_ERROR_Num_Codes; ++index) {
++ pri_message(&dummy_ctrl, "%d: %s\n", index, rose_error2str(index));
++ }
++ pri_message(&dummy_ctrl, "\n\n"
++ "************************************************************\n");
++
++/* ------------------------------------------------------------------- */
++
++ pri_message(&dummy_ctrl, "\n\n");
++ pri_message(&dummy_ctrl, "sizeof(struct rose_message) = %u\n",
++ (unsigned) sizeof(struct rose_message));
++ pri_message(&dummy_ctrl, "sizeof(struct rose_msg_invoke) = %u\n",
++ (unsigned) sizeof(struct rose_msg_invoke));
++ pri_message(&dummy_ctrl, "sizeof(struct rose_msg_result) = %u\n",
++ (unsigned) sizeof(struct rose_msg_result));
++ pri_message(&dummy_ctrl, "sizeof(struct rose_msg_error) = %u\n",
++ (unsigned) sizeof(struct rose_msg_error));
++ pri_message(&dummy_ctrl, "sizeof(struct rose_msg_reject) = %u\n",
++ (unsigned) sizeof(struct rose_msg_reject));
++ pri_message(&dummy_ctrl, "sizeof(union rose_msg_invoke_args) = %u\n",
++ (unsigned) sizeof(union rose_msg_invoke_args));
++ pri_message(&dummy_ctrl, "sizeof(union rose_msg_result_args) = %u\n",
++ (unsigned) sizeof(union rose_msg_result_args));
++
++ pri_message(&dummy_ctrl, "\n");
++ pri_message(&dummy_ctrl, "sizeof(struct roseQsigForwardingList) = %u\n",
++ (unsigned) sizeof(struct roseQsigForwardingList));
++
++ pri_message(&dummy_ctrl, "\n");
++ pri_message(&dummy_ctrl, "sizeof(struct roseQsigCallRerouting_ARG) = %u\n",
++ (unsigned) sizeof(struct roseQsigCallRerouting_ARG));
++ pri_message(&dummy_ctrl, "sizeof(struct roseQsigAocRateArg_ARG) = %u\n",
++ (unsigned) sizeof(struct roseQsigAocRateArg_ARG));
++ pri_message(&dummy_ctrl, "sizeof(struct roseQsigMWIInterrogateRes) = %u\n",
++ (unsigned) sizeof(struct roseQsigMWIInterrogateRes));
++
++ pri_message(&dummy_ctrl, "\n");
++ pri_message(&dummy_ctrl, "sizeof(struct roseEtsiForwardingList) = %u\n",
++ (unsigned) sizeof(struct roseEtsiForwardingList));
++ pri_message(&dummy_ctrl, "sizeof(struct roseEtsiServedUserNumberList) = %u\n",
++ (unsigned) sizeof(struct roseEtsiServedUserNumberList));
++
++ pri_message(&dummy_ctrl, "\n");
++ pri_message(&dummy_ctrl, "sizeof(struct roseEtsiCallRerouting_ARG) = %u\n",
++ (unsigned) sizeof(struct roseEtsiCallRerouting_ARG));
++ pri_message(&dummy_ctrl, "sizeof(struct roseEtsiDiversionInformation_ARG) = %u\n",
++ (unsigned) sizeof(struct roseEtsiDiversionInformation_ARG));
++ pri_message(&dummy_ctrl, "sizeof(struct roseEtsiAOCSCurrencyInfoList) = %u\n",
++ (unsigned) sizeof(struct roseEtsiAOCSCurrencyInfoList));
++
++/* ------------------------------------------------------------------- */
++
++ return 0;
++}
++
++/* ------------------------------------------------------------------- */
++/* end rosetest.c */
+
+Property changes on: rosetest.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+Added: svn:mime-type
+ + text/plain
+Added: svn:keywords
+ + 'Author Date Id Revision'
+
+Index: rose_internal.h
+===================================================================
+--- a/rose_internal.h (.../tags/1.4.10.2) (revision 0)
++++ b/rose_internal.h (.../branches/1.4) (revision 1357)
+@@ -0,0 +1,477 @@
++/*
++ * 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 Internal definitions and prototypes for ROSE.
++ *
++ * \author Richard Mudgett <rmudgett@digium.com>
++ */
++
++#ifndef _LIBPRI_ROSE_INTERNAL_H
++#define _LIBPRI_ROSE_INTERNAL_H
++
++#include "rose.h"
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++
++/* ------------------------------------------------------------------- */
++
++
++/* Embedded-Q931-Types */
++unsigned char *rose_enc_Q931ie(struct pri *ctrl, unsigned char *pos, unsigned char *end,
++ unsigned tag, const struct roseQ931ie *q931ie);
++
++const unsigned char *rose_dec_Q931ie(struct pri *ctrl, const char *name, unsigned tag,
++ const unsigned char *pos, const unsigned char *end, struct roseQ931ie *q931ie,
++ size_t contents_size);
++
++/* Addressing-Data-Elements */
++unsigned char *rose_enc_PartyNumber(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const struct rosePartyNumber *party_number);
++unsigned char *rose_enc_PartySubaddress(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const struct rosePartySubaddress *party_subaddress);
++unsigned char *rose_enc_Address(struct pri *ctrl, unsigned char *pos, unsigned char *end,
++ unsigned tag, const struct roseAddress *address);
++unsigned char *rose_enc_PresentedNumberUnscreened(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const struct rosePresentedNumberUnscreened *party);
++unsigned char *rose_enc_NumberScreened(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, unsigned tag, const struct roseNumberScreened *screened);
++unsigned char *rose_enc_PresentedNumberScreened(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const struct rosePresentedNumberScreened *party);
++unsigned char *rose_enc_AddressScreened(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, unsigned tag, const struct roseAddressScreened *screened);
++unsigned char *rose_enc_PresentedAddressScreened(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const struct rosePresentedAddressScreened *party);
++
++const unsigned char *rose_dec_PartyNumber(struct pri *ctrl, const char *name,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ struct rosePartyNumber *party_number);
++const unsigned char *rose_dec_PartySubaddress(struct pri *ctrl, const char *name,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ struct rosePartySubaddress *party_subaddress);
++const unsigned char *rose_dec_Address(struct pri *ctrl, const char *name, unsigned tag,
++ const unsigned char *pos, const unsigned char *end, struct roseAddress *address);
++const unsigned char *rose_dec_PresentedNumberUnscreened(struct pri *ctrl,
++ const char *name, unsigned tag, const unsigned char *pos, const unsigned char *end,
++ struct rosePresentedNumberUnscreened *party);
++const unsigned char *rose_dec_NumberScreened(struct pri *ctrl, const char *name,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ struct roseNumberScreened *screened);
++const unsigned char *rose_dec_PresentedNumberScreened(struct pri *ctrl, const char *name,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ struct rosePresentedNumberScreened *party);
++const unsigned char *rose_dec_AddressScreened(struct pri *ctrl, const char *name,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ struct roseAddressScreened *screened);
++const unsigned char *rose_dec_PresentedAddressScreened(struct pri *ctrl,
++ const char *name, unsigned tag, const unsigned char *pos, const unsigned char *end,
++ struct rosePresentedAddressScreened *party);
++
++/* ETSI Advice-of-Charge (AOC) */
++unsigned char *rose_enc_etsi_ChargingRequest_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_etsi_ChargingRequest_RES(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_result_args *args);
++unsigned char *rose_enc_etsi_AOCSCurrency_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_etsi_AOCSSpecialArr_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_etsi_AOCDCurrency_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_etsi_AOCDChargingUnit_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_etsi_AOCECurrency_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_etsi_AOCEChargingUnit_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args);
++
++const unsigned char *rose_dec_etsi_ChargingRequest_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_etsi_ChargingRequest_RES(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_result_args *args);
++const unsigned char *rose_dec_etsi_AOCSCurrency_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_etsi_AOCSSpecialArr_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_etsi_AOCDCurrency_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_etsi_AOCDChargingUnit_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_etsi_AOCECurrency_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_etsi_AOCEChargingUnit_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++
++/* ETSI Call Diversion */
++unsigned char *rose_enc_etsi_ActivationDiversion_ARG(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_etsi_DeactivationDiversion_ARG(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_etsi_ActivationStatusNotificationDiv_ARG(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_etsi_DeactivationStatusNotificationDiv_ARG(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_etsi_InterrogationDiversion_ARG(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_etsi_InterrogationDiversion_RES(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, const union rose_msg_result_args *args);
++unsigned char *rose_enc_etsi_DiversionInformation_ARG(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_etsi_CallDeflection_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_etsi_CallRerouting_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_etsi_InterrogateServedUserNumbers_RES(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, const union rose_msg_result_args *args);
++unsigned char *rose_enc_etsi_DivertingLegInformation1_ARG(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_etsi_DivertingLegInformation2_ARG(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_etsi_DivertingLegInformation3_ARG(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, const union rose_msg_invoke_args *args);
++
++const unsigned char *rose_dec_etsi_ActivationDiversion_ARG(struct pri *ctrl,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_etsi_DeactivationDiversion_ARG(struct pri *ctrl,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_etsi_ActivationStatusNotificationDiv_ARG(struct pri *ctrl,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_etsi_DeactivationStatusNotificationDiv_ARG(struct pri
++ *ctrl, unsigned tag, const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_etsi_InterrogationDiversion_ARG(struct pri *ctrl,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_etsi_InterrogationDiversion_RES(struct pri *ctrl,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ union rose_msg_result_args *args);
++const unsigned char *rose_dec_etsi_DiversionInformation_ARG(struct pri *ctrl,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_etsi_CallDeflection_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_etsi_CallRerouting_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_etsi_InterrogateServedUserNumbers_RES(struct pri *ctrl,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ union rose_msg_result_args *args);
++const unsigned char *rose_dec_etsi_DivertingLegInformation1_ARG(struct pri *ctrl,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_etsi_DivertingLegInformation2_ARG(struct pri *ctrl,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_etsi_DivertingLegInformation3_ARG(struct pri *ctrl,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++
++/* ETSI Explicit Call Transfer (ECT) */
++unsigned char *rose_enc_etsi_ExplicitEctExecute_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_etsi_SubaddressTransfer_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_etsi_EctLinkIdRequest_RES(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_result_args *args);
++unsigned char *rose_enc_etsi_EctInform_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_etsi_EctLoopTest_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_etsi_EctLoopTest_RES(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_result_args *args);
++
++const unsigned char *rose_dec_etsi_ExplicitEctExecute_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_etsi_SubaddressTransfer_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_etsi_EctLinkIdRequest_RES(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_result_args *args);
++const unsigned char *rose_dec_etsi_EctInform_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_etsi_EctLoopTest_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_etsi_EctLoopTest_RES(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_result_args *args);
++
++/* Q.SIG Name-Operations */
++unsigned char *rose_enc_qsig_Name(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const struct roseQsigName *name);
++
++const unsigned char *rose_dec_qsig_Name(struct pri *ctrl, const char *fname,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ struct roseQsigName *name);
++
++unsigned char *rose_enc_qsig_CallingName_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_qsig_CalledName_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_qsig_ConnectedName_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_qsig_BusyName_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args);
++
++const unsigned char *rose_dec_qsig_CallingName_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_qsig_CalledName_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_qsig_ConnectedName_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_qsig_BusyName_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++
++/*
++ * Q.SIG Dummy invoke/result argument used by:
++ * SS-AOC-Operations,
++ * Call-Transfer-Operations,
++ * Call-Diversion-Operations,
++ * and SS-MWI-Operations.
++ */
++unsigned char *rose_enc_qsig_DummyArg_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_qsig_DummyRes_RES(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_result_args *args);
++
++const unsigned char *rose_dec_qsig_DummyArg_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_qsig_DummyRes_RES(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_result_args *args);
++
++/* Q.SIG SS-AOC-Operations */
++unsigned char *rose_enc_qsig_ChargeRequest_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_qsig_ChargeRequest_RES(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_result_args *args);
++unsigned char *rose_enc_qsig_AocFinal_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_qsig_AocInterim_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_qsig_AocRate_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_qsig_AocComplete_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_qsig_AocComplete_RES(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_result_args *args);
++unsigned char *rose_enc_qsig_AocDivChargeReq_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args);
++
++const unsigned char *rose_dec_qsig_ChargeRequest_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_qsig_ChargeRequest_RES(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_result_args *args);
++const unsigned char *rose_dec_qsig_AocFinal_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_qsig_AocInterim_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_qsig_AocRate_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_qsig_AocComplete_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_qsig_AocComplete_RES(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_result_args *args);
++const unsigned char *rose_dec_qsig_AocDivChargeReq_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++
++/* Q.SIG Call-Diversion-Operations */
++unsigned char *rose_enc_qsig_ActivateDiversionQ_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_qsig_DeactivateDiversionQ_ARG(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_qsig_InterrogateDiversionQ_ARG(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_qsig_InterrogateDiversionQ_RES(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, const union rose_msg_result_args *args);
++unsigned char *rose_enc_qsig_CheckRestriction_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_qsig_CallRerouting_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_qsig_DivertingLegInformation1_ARG(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_qsig_DivertingLegInformation2_ARG(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_qsig_DivertingLegInformation3_ARG(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, const union rose_msg_invoke_args *args);
++
++const unsigned char *rose_dec_qsig_ActivateDiversionQ_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_qsig_DeactivateDiversionQ_ARG(struct pri *ctrl,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_qsig_InterrogateDiversionQ_ARG(struct pri *ctrl,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_qsig_InterrogateDiversionQ_RES(struct pri *ctrl,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ union rose_msg_result_args *args);
++const unsigned char *rose_dec_qsig_CheckRestriction_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_qsig_CallRerouting_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_qsig_DivertingLegInformation1_ARG(struct pri *ctrl,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_qsig_DivertingLegInformation2_ARG(struct pri *ctrl,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_qsig_DivertingLegInformation3_ARG(struct pri *ctrl,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++
++/* Q.SIG Call-Transfer-Operations (CT) */
++unsigned char *rose_enc_qsig_CallTransferIdentify_RES(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, const union rose_msg_result_args *args);
++unsigned char *rose_enc_qsig_CallTransferInitiate_ARG(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_qsig_CallTransferSetup_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_qsig_CallTransferActive_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_qsig_CallTransferComplete_ARG(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_qsig_CallTransferUpdate_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_qsig_SubaddressTransfer_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args);
++
++const unsigned char *rose_dec_qsig_CallTransferIdentify_RES(struct pri *ctrl,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ union rose_msg_result_args *args);
++const unsigned char *rose_dec_qsig_CallTransferInitiate_ARG(struct pri *ctrl,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_qsig_CallTransferSetup_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_qsig_CallTransferActive_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_qsig_CallTransferComplete_ARG(struct pri *ctrl,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_qsig_CallTransferUpdate_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_qsig_SubaddressTransfer_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++
++/* Q.SIG SS-MWI-Operations */
++unsigned char *rose_enc_qsig_MWIActivate_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_qsig_MWIDeactivate_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_qsig_MWIInterrogate_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_qsig_MWIInterrogate_RES(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_result_args *args);
++
++const unsigned char *rose_dec_qsig_MWIActivate_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_qsig_MWIDeactivate_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_qsig_MWIInterrogate_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_qsig_MWIInterrogate_RES(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_result_args *args);
++
++/* Northern Telecom DMS-100 operations */
++unsigned char *rose_enc_dms100_RLT_OperationInd_RES(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_result_args *args);
++unsigned char *rose_enc_dms100_RLT_ThirdParty_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args);
++
++const unsigned char *rose_dec_dms100_RLT_OperationInd_RES(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_result_args *args);
++const unsigned char *rose_dec_dms100_RLT_ThirdParty_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++
++/* National ISDN 2 (NI2) operations */
++unsigned char *rose_enc_ni2_InformationFollowing_ARG(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_ni2_InitiateTransfer_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args);
++
++const unsigned char *rose_dec_ni2_InformationFollowing_ARG(struct pri *ctrl,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_ni2_InitiateTransfer_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++
++
++/* ------------------------------------------------------------------- */
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* _LIBPRI_ROSE_INTERNAL_H */
++/* ------------------------------------------------------------------- */
++/* end rose_internal.h */
+
+Property changes on: rose_internal.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+Added: svn:mime-type
+ + text/plain
+Added: svn:keywords
+ + 'Author Date Id Revision'
+
+Index: pri_q921.h
+===================================================================
+--- a/pri_q921.h (.../tags/1.4.10.2) (revision 1357)
++++ b/pri_q921.h (.../branches/1.4) (revision 1357)
+@@ -192,4 +192,10 @@
+
+ extern int q921_transmit_iframe(struct pri *pri, void *buf, int len, int cr);
+
++extern int q921_transmit_uiframe(struct pri *pri, void *buf, int len);
++
++extern pri_event *q921_dchannel_up(struct pri *pri);
++
++extern pri_event *q921_dchannel_down(struct pri *pri);
++
+ #endif
+Index: pri_facility.c
+===================================================================
+--- a/pri_facility.c (.../tags/1.4.10.2) (revision 1357)
++++ b/pri_facility.c (.../branches/1.4) (revision 1357)
+@@ -33,872 +33,1340 @@
+ #include "pri_q921.h"
+ #include "pri_q931.h"
+ #include "pri_facility.h"
++#include "rose.h"
+
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
+ #include <limits.h>
+
+-static char *asn1id2text(int id)
++static short get_invokeid(struct pri *ctrl)
+ {
+- static char data[32];
+- static char *strings[] = {
+- "none",
+- "Boolean",
+- "Integer",
+- "Bit String",
+- "Octet String",
+- "NULL",
+- "Object Identifier",
+- "Object Descriptor",
+- "External Reference",
+- "Real Number",
+- "Enumerated",
+- "Embedded PDV",
+- "UTF-8 String",
+- "Relative Object ID",
+- "Reserved (0e)",
+- "Reserved (0f)",
+- "Sequence",
+- "Set",
+- "Numeric String",
+- "Printable String",
+- "Tele-Text String",
+- "IA-5 String",
+- "UTC Time",
+- "Generalized Time",
+- };
+- if (id > 0 && id <= 0x18) {
+- return strings[id];
+- } else {
+- sprintf(data, "Unknown (%02x)", id);
+- return data;
+- }
++ ctrl = PRI_MASTER(ctrl);
++ return ++ctrl->last_invoke;
+ }
+
+-static int asn1_dumprecursive(struct pri *pri, void *comp_ptr, int len, int level)
++static int redirectingreason_from_q931(struct pri *ctrl, int redirectingreason)
+ {
+- unsigned char *vdata = (unsigned char *)comp_ptr;
+- struct rose_component *comp;
+- int i = 0;
+- int j, k, l;
+- int clen = 0;
++ int value;
+
+- while (len > 0) {
+- GET_COMPONENT(comp, i, vdata, len);
+- pri_message(pri, "%*s%02X %04X", 2 * level, "", comp->type, comp->len);
+- if ((comp->type == 0) && (comp->len == 0))
+- return clen + 2;
+- if ((comp->type & ASN1_PC_MASK) == ASN1_PRIMITIVE) {
+- for (j = 0; j < comp->len; ++j)
+- pri_message(pri, " %02X", comp->data[j]);
++ switch (ctrl->switchtype) {
++ case PRI_SWITCH_QSIG:
++ switch (redirectingreason) {
++ case PRI_REDIR_UNKNOWN:
++ value = QSIG_DIVERT_REASON_UNKNOWN;
++ break;
++ case PRI_REDIR_FORWARD_ON_BUSY:
++ value = QSIG_DIVERT_REASON_CFB;
++ break;
++ case PRI_REDIR_FORWARD_ON_NO_REPLY:
++ value = QSIG_DIVERT_REASON_CFNR;
++ break;
++ case PRI_REDIR_UNCONDITIONAL:
++ value = QSIG_DIVERT_REASON_CFU;
++ break;
++ case PRI_REDIR_DEFLECTION:
++ case PRI_REDIR_DTE_OUT_OF_ORDER:
++ case PRI_REDIR_FORWARDED_BY_DTE:
++ pri_message(ctrl,
++ "!! Don't know how to convert Q.931 redirection reason %d to Q.SIG\n",
++ redirectingreason);
++ /* Fall through */
++ default:
++ value = QSIG_DIVERT_REASON_UNKNOWN;
++ break;
+ }
+- if ((comp->type & ASN1_CLAN_MASK) == ASN1_UNIVERSAL) {
+- switch (comp->type & ASN1_TYPE_MASK) {
+- case 0:
+- pri_message(pri, " (none)");
+- break;
+- case ASN1_BOOLEAN:
+- pri_message(pri, " (BOOLEAN: %d)", comp->data[0]);
+- break;
+- case ASN1_INTEGER:
+- for (k = l = 0; k < comp->len; ++k)
+- l = (l << 8) | comp->data[k];
+- pri_message(pri, " (INTEGER: %d)", l);
+- break;
+- case ASN1_BITSTRING:
+- pri_message(pri, " (BITSTRING:");
+- for (k = 0; k < comp->len; ++k)
+- pri_message(pri, " %02x", comp->data[k]);
+- pri_message(pri, ")");
+- break;
+- case ASN1_OCTETSTRING:
+- pri_message(pri, " (OCTETSTRING:");
+- for (k = 0; k < comp->len; ++k)
+- pri_message(pri, " %02x", comp->data[k]);
+- pri_message(pri, ")");
+- break;
+- case ASN1_NULL:
+- pri_message(pri, " (NULL)");
+- break;
+- case ASN1_OBJECTIDENTIFIER:
+- pri_message(pri, " (OBJECTIDENTIFIER:");
+- for (k = 0; k < comp->len; ++k)
+- pri_message(pri, " %02x", comp->data[k]);
+- pri_message(pri, ")");
+- break;
+- case ASN1_ENUMERATED:
+- for (k = l = 0; k < comp->len; ++k)
+- l = (l << 8) | comp->data[k];
+- pri_message(pri, " (ENUMERATED: %d)", l);
+- break;
+- case ASN1_SEQUENCE:
+- pri_message(pri, " (SEQUENCE)");
+- break;
+- default:
+- pri_message(pri, " (component %02x - %s)", comp->type, asn1id2text(comp->type & ASN1_TYPE_MASK));
+- break;
+- }
++ break;
++ default:
++ switch (redirectingreason) {
++ case PRI_REDIR_UNKNOWN:
++ value = Q952_DIVERT_REASON_UNKNOWN;
++ break;
++ case PRI_REDIR_FORWARD_ON_BUSY:
++ value = Q952_DIVERT_REASON_CFB;
++ break;
++ case PRI_REDIR_FORWARD_ON_NO_REPLY:
++ value = Q952_DIVERT_REASON_CFNR;
++ break;
++ case PRI_REDIR_DEFLECTION:
++ value = Q952_DIVERT_REASON_CD;
++ break;
++ case PRI_REDIR_UNCONDITIONAL:
++ value = Q952_DIVERT_REASON_CFU;
++ break;
++ case PRI_REDIR_DTE_OUT_OF_ORDER:
++ case PRI_REDIR_FORWARDED_BY_DTE:
++ pri_message(ctrl,
++ "!! Don't know how to convert Q.931 redirection reason %d to Q.952\n",
++ redirectingreason);
++ /* Fall through */
++ default:
++ value = Q952_DIVERT_REASON_UNKNOWN;
++ break;
+ }
+- else if ((comp->type & ASN1_CLAN_MASK) == ASN1_CONTEXT_SPECIFIC) {
+- pri_message(pri, " (CONTEXT SPECIFIC [%d])", comp->type & ASN1_TYPE_MASK);
++ break;
++ }
++
++ return value;
++}
++
++static int redirectingreason_for_q931(struct pri *ctrl, int redirectingreason)
++{
++ int value;
++
++ switch (ctrl->switchtype) {
++ case PRI_SWITCH_QSIG:
++ switch (redirectingreason) {
++ case QSIG_DIVERT_REASON_UNKNOWN:
++ value = PRI_REDIR_UNKNOWN;
++ break;
++ case QSIG_DIVERT_REASON_CFU:
++ value = PRI_REDIR_UNCONDITIONAL;
++ break;
++ case QSIG_DIVERT_REASON_CFB:
++ value = PRI_REDIR_FORWARD_ON_BUSY;
++ break;
++ case QSIG_DIVERT_REASON_CFNR:
++ value = PRI_REDIR_FORWARD_ON_NO_REPLY;
++ break;
++ default:
++ pri_message(ctrl, "!! Unknown Q.SIG diversion reason %d\n",
++ redirectingreason);
++ value = PRI_REDIR_UNKNOWN;
++ break;
+ }
+- else {
+- pri_message(pri, " (component %02x)", comp->type);
++ break;
++ default:
++ switch (redirectingreason) {
++ case Q952_DIVERT_REASON_UNKNOWN:
++ value = PRI_REDIR_UNKNOWN;
++ break;
++ case Q952_DIVERT_REASON_CFU:
++ value = PRI_REDIR_UNCONDITIONAL;
++ break;
++ case Q952_DIVERT_REASON_CFB:
++ value = PRI_REDIR_FORWARD_ON_BUSY;
++ break;
++ case Q952_DIVERT_REASON_CFNR:
++ value = PRI_REDIR_FORWARD_ON_NO_REPLY;
++ break;
++ case Q952_DIVERT_REASON_CD:
++ value = PRI_REDIR_DEFLECTION;
++ break;
++ case Q952_DIVERT_REASON_IMMEDIATE:
++ pri_message(ctrl,
++ "!! Dont' know how to convert Q.952 diversion reason IMMEDIATE to PRI analog\n");
++ value = PRI_REDIR_UNKNOWN; /* ??? */
++ break;
++ default:
++ pri_message(ctrl, "!! Unknown Q.952 diversion reason %d\n",
++ redirectingreason);
++ value = PRI_REDIR_UNKNOWN;
++ break;
+ }
+- pri_message(pri, "\n");
+- if ((comp->type & ASN1_PC_MASK) == ASN1_CONSTRUCTOR)
+- j = asn1_dumprecursive(pri, comp->data, (comp->len ? comp->len : INT_MAX), level+1);
+- else
+- j = comp->len;
+- j += 2;
+- len -= j;
+- vdata += j;
+- clen += j;
++ break;
+ }
+- return clen;
++
++ return value;
+ }
+
+-int asn1_dump(struct pri *pri, void *comp, int len)
++/*!
++ * \brief Convert the Q.931 type-of-number field to facility.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param ton Q.931 ton/plan octet.
++ *
++ * \return PartyNumber enumeration value.
++ */
++static int typeofnumber_from_q931(struct pri *ctrl, int ton)
+ {
+- return asn1_dumprecursive(pri, comp, len, 0);
++ int value;
++
++ switch ((ton >> 4) & 0x03) {
++ default:
++ pri_message(ctrl, "!! Unsupported Q.931 TypeOfNumber value (%d)\n", ton);
++ /* fall through */
++ case PRI_TON_UNKNOWN:
++ value = Q932_TON_UNKNOWN;
++ break;
++ case PRI_TON_INTERNATIONAL:
++ value = Q932_TON_INTERNATIONAL;
++ break;
++ case PRI_TON_NATIONAL:
++ value = Q932_TON_NATIONAL;
++ break;
++ case PRI_TON_NET_SPECIFIC:
++ value = Q932_TON_NET_SPECIFIC;
++ break;
++ case PRI_TON_SUBSCRIBER:
++ value = Q932_TON_SUBSCRIBER;
++ break;
++ case PRI_TON_ABBREVIATED:
++ value = Q932_TON_ABBREVIATED;
++ break;
++ }
++
++ return value;
+ }
+
+-static unsigned char get_invokeid(struct pri *pri)
++static int typeofnumber_for_q931(struct pri *ctrl, int ton)
+ {
+- return ++pri->last_invoke;
++ int value;
++
++ switch (ton) {
++ default:
++ pri_message(ctrl, "!! Invalid TypeOfNumber %d\n", ton);
++ /* fall through */
++ case Q932_TON_UNKNOWN:
++ value = PRI_TON_UNKNOWN;
++ break;
++ case Q932_TON_INTERNATIONAL:
++ value = PRI_TON_INTERNATIONAL;
++ break;
++ case Q932_TON_NATIONAL:
++ value = PRI_TON_NATIONAL;
++ break;
++ case Q932_TON_NET_SPECIFIC:
++ value = PRI_TON_NET_SPECIFIC;
++ break;
++ case Q932_TON_SUBSCRIBER:
++ value = PRI_TON_SUBSCRIBER;
++ break;
++ case Q932_TON_ABBREVIATED:
++ value = PRI_TON_ABBREVIATED;
++ break;
++ }
++
++ return value << 4;
+ }
+
+-struct addressingdataelements_presentednumberunscreened {
+- char partyaddress[21];
+- char partysubaddress[21];
+- int npi; /* Numbering Plan Indicator */
+- int ton; /* Type Of Number */
+- int pres; /* Presentation */
+-};
++/*!
++ * \internal
++ * \brief Convert the Q.931 numbering plan field to facility.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param plan Q.931 ton/plan octet.
++ *
++ * \return PartyNumber enumeration value.
++ */
++static int numbering_plan_from_q931(struct pri *ctrl, int plan)
++{
++ int value;
+
+-struct addressingdataelements_presentednumberscreened {
+- char partyaddress[21];
+- char partysubaddress[21];
+- int npi; /* Numbering Plan Indicator */
+- int ton; /* Type Of Number */
+- int pres; /* Presentation */
+- int scrind; /* Screening Indicator */
+-};
++ switch (plan & 0x0F) {
++ default:
++ pri_message(ctrl, "!! Unsupported Q.931 numbering plan value (%d)\n", plan);
++ /* fall through */
++ case PRI_NPI_UNKNOWN:
++ value = 0; /* unknown */
++ break;
++ case PRI_NPI_E163_E164:
++ value = 1; /* public */
++ break;
++ case PRI_NPI_X121:
++ value = 3; /* data */
++ break;
++ case PRI_NPI_F69:
++ value = 4; /* telex */
++ break;
++ case PRI_NPI_NATIONAL:
++ value = 8; /* nationalStandard */
++ break;
++ case PRI_NPI_PRIVATE:
++ value = 5; /* private */
++ break;
++ }
+
+-#define PRI_CHECKOVERFLOW(size) \
+- if (msgptr - message + (size) >= sizeof(message)) { \
+- *msgptr = '\0'; \
+- pri_message(pri, "%s", message); \
+- msgptr = message; \
+- }
++ return value;
++}
+
+-static void dump_apdu(struct pri *pri, unsigned char *c, int len)
++/*!
++ * \internal
++ * \brief Convert the PartyNumber numbering plan to Q.931 plan field value.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param plan PartyNumber enumeration value.
++ *
++ * \return Q.931 plan field value.
++ */
++static int numbering_plan_for_q931(struct pri *ctrl, int plan)
+ {
+- #define MAX_APDU_LENGTH 255
+- static char hexs[16] = "0123456789ABCDEF";
+- int i;
+- char message[(2 + MAX_APDU_LENGTH * 3 + 6 + MAX_APDU_LENGTH + 3)] = ""; /* please adjust here, if you make changes below! */
+- char *msgptr;
+-
+- msgptr = message;
+- *msgptr++ = ' ';
+- *msgptr++ = '[';
+- for (i=0; i<len; i++) {
+- PRI_CHECKOVERFLOW(3);
+- *msgptr++ = ' ';
+- *msgptr++ = hexs[(c[i] >> 4) & 0x0f];
+- *msgptr++ = hexs[(c[i]) & 0x0f];
++ int value;
++
++ switch (plan) {
++ default:
++ pri_message(ctrl,
++ "!! Unsupported PartyNumber to Q.931 numbering plan value (%d)\n", plan);
++ /* fall through */
++ case 0: /* unknown */
++ value = PRI_NPI_UNKNOWN;
++ break;
++ case 1: /* public */
++ value = PRI_NPI_E163_E164;
++ break;
++ case 3: /* data */
++ value = PRI_NPI_X121;
++ break;
++ case 4: /* telex */
++ value = PRI_NPI_F69;
++ break;
++ case 5: /* private */
++ value = PRI_NPI_PRIVATE;
++ break;
++ case 8: /* nationalStandard */
++ value = PRI_NPI_NATIONAL;
++ break;
+ }
+- PRI_CHECKOVERFLOW(6);
+- strcpy(msgptr, " ] - [");
+- msgptr += strlen(msgptr);
+- for (i=0; i<len; i++) {
+- PRI_CHECKOVERFLOW(1);
+- *msgptr++ = ((c[i] < ' ') || (c[i] > '~')) ? '.' : c[i];
++
++ return value;
++}
++
++/*!
++ * \internal
++ * \brief Convert the Q.931 number presentation field to facility.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param presentation Q.931 presentation/screening octet.
++ * \param number_present Non-zero if the number is available.
++ *
++ * \return Presented<Number/Address><Screened/Unscreened> enumeration value.
++ */
++static int presentation_from_q931(struct pri *ctrl, int presentation, int number_present)
++{
++ int value;
++
++ switch (presentation & PRI_PRES_RESTRICTION) {
++ case PRI_PRES_ALLOWED:
++ value = 0; /* presentationAllowed<Number/Address> */
++ break;
++ default:
++ pri_message(ctrl, "!! Unsupported Q.931 number presentation value (%d)\n",
++ presentation);
++ /* fall through */
++ case PRI_PRES_RESTRICTED:
++ if (number_present) {
++ value = 3; /* presentationRestricted<Number/Address> */
++ } else {
++ value = 1; /* presentationRestricted */
++ }
++ break;
++ case PRI_PRES_UNAVAILABLE:
++ value = 2; /* numberNotAvailableDueToInterworking */
++ break;
+ }
+- PRI_CHECKOVERFLOW(2);
+- *msgptr++ = ']';
+- *msgptr++ = '\n';
+- *msgptr = '\0';
+- pri_message(pri, "%s", message);
++
++ return value;
+ }
+-#undef PRI_CHECKOVERFLOW
+
+-int redirectingreason_from_q931(struct pri *pri, int redirectingreason)
++/*!
++ * \internal
++ * \brief Convert the Presented<Number/Address><Screened/Unscreened> presentation
++ * to Q.931 presentation field value.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param presentation Presented<Number/Address><Screened/Unscreened> value.
++ *
++ * \return Q.931 presentation field value.
++ */
++static int presentation_for_q931(struct pri *ctrl, int presentation)
+ {
+- switch(pri->switchtype) {
+- case PRI_SWITCH_QSIG:
+- switch(redirectingreason) {
+- case PRI_REDIR_UNKNOWN:
+- return QSIG_DIVERT_REASON_UNKNOWN;
+- case PRI_REDIR_FORWARD_ON_BUSY:
+- return QSIG_DIVERT_REASON_CFB;
+- case PRI_REDIR_FORWARD_ON_NO_REPLY:
+- return QSIG_DIVERT_REASON_CFNR;
+- case PRI_REDIR_UNCONDITIONAL:
+- return QSIG_DIVERT_REASON_CFU;
+- case PRI_REDIR_DEFLECTION:
+- case PRI_REDIR_DTE_OUT_OF_ORDER:
+- case PRI_REDIR_FORWARDED_BY_DTE:
+- pri_message(pri, "!! Don't know how to convert Q.931 redirection reason %d to Q.SIG\n", redirectingreason);
+- /* Fall through */
+- default:
+- return QSIG_DIVERT_REASON_UNKNOWN;
+- }
+- default:
+- switch(redirectingreason) {
+- case PRI_REDIR_UNKNOWN:
+- return Q952_DIVERT_REASON_UNKNOWN;
+- case PRI_REDIR_FORWARD_ON_BUSY:
+- return Q952_DIVERT_REASON_CFB;
+- case PRI_REDIR_FORWARD_ON_NO_REPLY:
+- return Q952_DIVERT_REASON_CFNR;
+- case PRI_REDIR_DEFLECTION:
+- return Q952_DIVERT_REASON_CD;
+- case PRI_REDIR_UNCONDITIONAL:
+- return Q952_DIVERT_REASON_CFU;
+- case PRI_REDIR_DTE_OUT_OF_ORDER:
+- case PRI_REDIR_FORWARDED_BY_DTE:
+- pri_message(pri, "!! Don't know how to convert Q.931 redirection reason %d to Q.952\n", redirectingreason);
+- /* Fall through */
+- default:
+- return Q952_DIVERT_REASON_UNKNOWN;
+- }
++ int value;
++
++ switch (presentation) {
++ case 0: /* presentationAllowed<Number/Address> */
++ value = PRI_PRES_ALLOWED;
++ break;
++ default:
++ pri_message(ctrl,
++ "!! Unsupported Presented<Number/Address><Screened/Unscreened> to Q.931 value (%d)\n",
++ presentation);
++ /* fall through */
++ case 1: /* presentationRestricted */
++ case 3: /* presentationRestricted<Number/Address> */
++ value = PRI_PRES_RESTRICTED;
++ break;
++ case 2: /* numberNotAvailableDueToInterworking */
++ value = PRI_PRES_UNAVAILABLE;
++ break;
+ }
++
++ return value;
+ }
+
+-static int redirectingreason_for_q931(struct pri *pri, int redirectingreason)
++/*!
++ * \internal
++ * \brief Convert the Q.931 number presentation field to Q.SIG name presentation.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param presentation Q.931 presentation/screening octet.
++ * \param name_present Non-zero if the name is available.
++ *
++ * \return Name presentation enumeration value.
++ */
++static int qsig_name_presentation_from_q931(struct pri *ctrl, int presentation, int name_present)
+ {
+- switch(pri->switchtype) {
+- case PRI_SWITCH_QSIG:
+- switch(redirectingreason) {
+- case QSIG_DIVERT_REASON_UNKNOWN:
+- return PRI_REDIR_UNKNOWN;
+- case QSIG_DIVERT_REASON_CFU:
+- return PRI_REDIR_UNCONDITIONAL;
+- case QSIG_DIVERT_REASON_CFB:
+- return PRI_REDIR_FORWARD_ON_BUSY;
+- case QSIG_DIVERT_REASON_CFNR:
+- return PRI_REDIR_FORWARD_ON_NO_REPLY;
+- default:
+- pri_message(pri, "!! Unknown Q.SIG diversion reason %d\n", redirectingreason);
+- return PRI_REDIR_UNKNOWN;
+- }
+- default:
+- switch(redirectingreason) {
+- case Q952_DIVERT_REASON_UNKNOWN:
+- return PRI_REDIR_UNKNOWN;
+- case Q952_DIVERT_REASON_CFU:
+- return PRI_REDIR_UNCONDITIONAL;
+- case Q952_DIVERT_REASON_CFB:
+- return PRI_REDIR_FORWARD_ON_BUSY;
+- case Q952_DIVERT_REASON_CFNR:
+- return PRI_REDIR_FORWARD_ON_NO_REPLY;
+- case Q952_DIVERT_REASON_CD:
+- return PRI_REDIR_DEFLECTION;
+- case Q952_DIVERT_REASON_IMMEDIATE:
+- pri_message(pri, "!! Dont' know how to convert Q.952 diversion reason IMMEDIATE to PRI analog\n");
+- return PRI_REDIR_UNKNOWN; /* ??? */
+- default:
+- pri_message(pri, "!! Unknown Q.952 diversion reason %d\n", redirectingreason);
+- return PRI_REDIR_UNKNOWN;
+- }
++ int value;
++
++ switch (presentation & PRI_PRES_RESTRICTION) {
++ case PRI_PRES_ALLOWED:
++ if (name_present) {
++ value = 1; /* presentation_allowed */
++ } else {
++ value = 4; /* name_not_available */
++ }
++ break;
++ default:
++ pri_message(ctrl, "!! Unsupported Q.931 number presentation value (%d)\n",
++ presentation);
++ /* fall through */
++ case PRI_PRES_RESTRICTED:
++ if (name_present) {
++ value = 2; /* presentation_restricted */
++ } else {
++ value = 3; /* presentation_restricted_null */
++ }
++ break;
++ case PRI_PRES_UNAVAILABLE:
++ value = 4; /* name_not_available */
++ break;
+ }
++
++ return value;
+ }
+
+-int typeofnumber_from_q931(struct pri *pri, int ton)
++/*!
++ * \internal
++ * \brief Convert the Q.SIG name presentation to Q.931 presentation field value.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param presentation Q.SIG name presentation value.
++ *
++ * \return Q.931 presentation field value.
++ */
++static int qsig_name_presentation_for_q931(struct pri *ctrl, int presentation)
+ {
+- switch(ton) {
+- case PRI_TON_INTERNATIONAL:
+- return Q932_TON_INTERNATIONAL;
+- case PRI_TON_NATIONAL:
+- return Q932_TON_NATIONAL;
+- case PRI_TON_NET_SPECIFIC:
+- return Q932_TON_NET_SPECIFIC;
+- case PRI_TON_SUBSCRIBER:
+- return Q932_TON_SUBSCRIBER;
+- case PRI_TON_ABBREVIATED:
+- return Q932_TON_ABBREVIATED;
+- case PRI_TON_RESERVED:
+- default:
+- pri_message(pri, "!! Unsupported Q.931 TypeOfNumber value (%d)\n", ton);
+- /* fall through */
+- case PRI_TON_UNKNOWN:
+- return Q932_TON_UNKNOWN;
++ int value;
++
++ switch (presentation) {
++ case 1: /* presentation_allowed */
++ value = PRI_PRES_ALLOWED;
++ break;
++ default:
++ pri_message(ctrl,
++ "!! Unsupported Q.SIG name presentation to Q.931 value (%d)\n",
++ presentation);
++ /* fall through */
++ case 2: /* presentation_restricted */
++ case 3: /* presentation_restricted_null */
++ value = PRI_PRES_RESTRICTED;
++ break;
++ case 0: /* optional_name_not_present */
++ case 4: /* name_not_available */
++ value = PRI_PRES_UNAVAILABLE;
++ break;
+ }
++
++ return value;
+ }
+
+-static int typeofnumber_for_q931(struct pri *pri, int ton)
++/*!
++ * \internal
++ * \brief Convert number presentation to Q.SIG diversion subscription notification.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param presentation Number presentation value.
++ *
++ * \return Q.SIG diversion subscription notification value.
++ */
++static int presentation_to_subscription(struct pri *ctrl, int presentation)
+ {
+- switch (ton) {
+- case Q932_TON_UNKNOWN:
+- return PRI_TON_UNKNOWN;
+- case Q932_TON_INTERNATIONAL:
+- return PRI_TON_INTERNATIONAL;
+- case Q932_TON_NATIONAL:
+- return PRI_TON_NATIONAL;
+- case Q932_TON_NET_SPECIFIC:
+- return PRI_TON_NET_SPECIFIC;
+- case Q932_TON_SUBSCRIBER:
+- return PRI_TON_SUBSCRIBER;
+- case Q932_TON_ABBREVIATED:
+- return PRI_TON_ABBREVIATED;
+- default:
+- pri_message(pri, "!! Invalid Q.932 TypeOfNumber %d\n", ton);
+- return PRI_TON_UNKNOWN;
++ /* derive subscription value from presentation value */
++
++ switch (presentation & PRI_PRES_RESTRICTION) {
++ case PRI_PRES_ALLOWED:
++ return QSIG_NOTIFICATION_WITH_DIVERTED_TO_NR;
++ case PRI_PRES_RESTRICTED:
++ return QSIG_NOTIFICATION_WITHOUT_DIVERTED_TO_NR;
++ case PRI_PRES_UNAVAILABLE: /* Number not available due to interworking */
++ return QSIG_NOTIFICATION_WITHOUT_DIVERTED_TO_NR; /* ?? QSIG_NO_NOTIFICATION */
++ default:
++ pri_message(ctrl, "!! Unknown Q.SIG presentationIndicator 0x%02x\n",
++ presentation);
++ return QSIG_NOTIFICATION_WITHOUT_DIVERTED_TO_NR;
+ }
+ }
+
+-int asn1_name_decode(void * data, int len, char *namebuf, int buflen)
++/*!
++ * \internal
++ * \brief Copy the given rose party number to the q931_party_number
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param q931_number Q.931 party number structure
++ * \param rose_number ROSE party number structure
++ *
++ * \note It is assumed that the q931_number has been initialized before calling.
++ *
++ * \return Nothing
++ */
++static void rose_copy_number_to_q931(struct pri *ctrl,
++ struct q931_party_number *q931_number, const struct rosePartyNumber *rose_number)
+ {
+- struct rose_component *comp = (struct rose_component*)data;
+- int datalen = 0, res = 0;
++ //q931_party_number_init(q931_number);
++ libpri_copy_string(q931_number->str, (char *) rose_number->str,
++ sizeof(q931_number->str));
++ q931_number->plan = numbering_plan_for_q931(ctrl, rose_number->plan)
++ | typeofnumber_for_q931(ctrl, rose_number->ton);
++ q931_number->valid = 1;
++}
+
+- if (comp->len == ASN1_LEN_INDEF) {
+- datalen = strlen((char *)comp->data);
+- res = datalen + 2;
+- } else
+- datalen = res = comp->len;
++/*!
++ * \internal
++ * \brief Copy the given rose subaddress to the q931_party_subaddress.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param q931_subaddress Q.931 party subaddress structure
++ * \param rose_subaddress ROSE subaddress structure
++ *
++ * \note It is assumed that the q931_subaddress has been initialized before calling.
++ *
++ * \return Nothing
++ */
++static void rose_copy_subaddress_to_q931(struct pri *ctrl,
++ struct q931_party_subaddress *q931_subaddress,
++ const struct rosePartySubaddress *rose_subaddress)
++{
++ //q931_party_subaddress_init(q931_subaddress);
++ if (!rose_subaddress->length) {
++ /* Subaddress is not present. */
++ return;
++ }
+
+- if (datalen > buflen) {
+- /* Truncate */
+- datalen = buflen;
++ switch (rose_subaddress->type) {
++ case 0:/* UserSpecified */
++ q931_subaddress->type = 2;/* user_specified */
++ q931_subaddress->valid = 1;
++ q931_subaddress->length = rose_subaddress->length;
++ if (sizeof(q931_subaddress->data) <= q931_subaddress->length) {
++ q931_subaddress->length = sizeof(q931_subaddress->data) - 1;
++ }
++ memcpy(q931_subaddress->data, rose_subaddress->u.user_specified.information,
++ q931_subaddress->length);
++ q931_subaddress->data[q931_subaddress->length] = '\0';
++ if (rose_subaddress->u.user_specified.odd_count_present) {
++ q931_subaddress->odd_even_indicator =
++ rose_subaddress->u.user_specified.odd_count;
++ }
++ break;
++ case 1:/* NSAP */
++ q931_subaddress->type = 0;/* nsap */
++ q931_subaddress->valid = 1;
++ libpri_copy_string((char *) q931_subaddress->data,
++ (char *) rose_subaddress->u.nsap, sizeof(q931_subaddress->data));
++ q931_subaddress->length = strlen((char *) q931_subaddress->data);
++ break;
++ default:
++ /* Don't know how to encode so assume it is not present. */
++ break;
+ }
+- memcpy(namebuf, comp->data, datalen);
+- return res + 2;
+ }
+
+-int asn1_string_encode(unsigned char asn1_type, void *data, int len, int max_len, void *src, int src_len)
++/*!
++ * \internal
++ * \brief Copy the given rose address to the q931_party_id address.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param q931_address Q.931 party id structure to fill address
++ * \param rose_address ROSE address structure
++ *
++ * \note It is assumed that the q931_address has been initialized before calling.
++ *
++ * \return Nothing
++ */
++static void rose_copy_address_to_q931(struct pri *ctrl,
++ struct q931_party_id *q931_address, const struct roseAddress *rose_address)
+ {
+- struct rose_component *comp = NULL;
+-
+- if (len < 2 + src_len)
+- return -1;
++ rose_copy_number_to_q931(ctrl, &q931_address->number, &rose_address->number);
++ rose_copy_subaddress_to_q931(ctrl, &q931_address->subaddress,
++ &rose_address->subaddress);
++}
+
+- if (max_len && (src_len > max_len))
+- src_len = max_len;
++/*!
++ * \internal
++ * \brief Copy the given rose presented screened party number to the q931_party_number
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param q931_number Q.931 party number structure
++ * \param rose_presented ROSE presented screened party number structure
++ *
++ * \return Nothing
++ */
++static void rose_copy_presented_number_screened_to_q931(struct pri *ctrl,
++ struct q931_party_number *q931_number,
++ const struct rosePresentedNumberScreened *rose_presented)
++{
++ q931_party_number_init(q931_number);
++ q931_number->valid = 1;
++ q931_number->presentation = presentation_for_q931(ctrl, rose_presented->presentation);
++ switch (rose_presented->presentation) {
++ case 0: /* presentationAllowedNumber */
++ case 3: /* presentationRestrictedNumber */
++ q931_number->presentation |=
++ (rose_presented->screened.screening_indicator & PRI_PRES_NUMBER_TYPE);
++ rose_copy_number_to_q931(ctrl, q931_number,
++ &rose_presented->screened.number);
++ break;
++ default:
++ q931_number->presentation |= PRI_PRES_USER_NUMBER_UNSCREENED;
++ break;
++ }
++}
+
+- comp = (struct rose_component *)data;
+- comp->type = asn1_type;
+- comp->len = src_len;
+- memcpy(comp->data, src, src_len);
+-
+- return 2 + src_len;
++/*!
++ * \internal
++ * \brief Copy the given rose presented unscreened party number to the q931_party_number
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param q931_number Q.931 party number structure
++ * \param rose_presented ROSE presented unscreened party number structure
++ *
++ * \return Nothing
++ */
++static void rose_copy_presented_number_unscreened_to_q931(struct pri *ctrl,
++ struct q931_party_number *q931_number,
++ const struct rosePresentedNumberUnscreened *rose_presented)
++{
++ q931_party_number_init(q931_number);
++ q931_number->valid = 1;
++ q931_number->presentation = presentation_for_q931(ctrl,
++ rose_presented->presentation) | PRI_PRES_USER_NUMBER_UNSCREENED;
++ switch (rose_presented->presentation) {
++ case 0: /* presentationAllowedNumber */
++ case 3: /* presentationRestrictedNumber */
++ rose_copy_number_to_q931(ctrl, q931_number, &rose_presented->number);
++ break;
++ default:
++ break;
++ }
+ }
+
+-int asn1_copy_string(char * buf, int buflen, struct rose_component *comp)
++/*!
++ * \internal
++ * \brief Copy the given rose presented screened party address to the q931_party_number
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param q931_address Q.931 party id structure to fill the address
++ * \param rose_presented ROSE presented screened party address structure
++ *
++ * \return Nothing
++ */
++static void rose_copy_presented_address_screened_to_q931(struct pri *ctrl,
++ struct q931_party_id *q931_address,
++ const struct rosePresentedAddressScreened *rose_presented)
+ {
+- int res;
+- int datalen;
++ q931_party_number_init(&q931_address->number);
++ q931_party_subaddress_init(&q931_address->subaddress);
++ q931_address->number.valid = 1;
++ q931_address->number.presentation = presentation_for_q931(ctrl,
++ rose_presented->presentation);
++ switch (rose_presented->presentation) {
++ case 0: /* presentationAllowedAddress */
++ case 3: /* presentationRestrictedAddress */
++ q931_address->number.presentation |=
++ (rose_presented->screened.screening_indicator & PRI_PRES_NUMBER_TYPE);
++ rose_copy_number_to_q931(ctrl, &q931_address->number,
++ &rose_presented->screened.number);
++ rose_copy_subaddress_to_q931(ctrl, &q931_address->subaddress,
++ &rose_presented->screened.subaddress);
++ break;
++ default:
++ q931_address->number.presentation |= PRI_PRES_USER_NUMBER_UNSCREENED;
++ break;
++ }
++}
+
+- if ((comp->len > buflen) && (comp->len != ASN1_LEN_INDEF))
+- return -1;
++/*!
++ * \internal
++ * \brief Copy the given rose party name to the q931_party_name
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param qsig_name Q.SIG party name structure
++ * \param rose_name Q.SIG ROSE party name structure
++ *
++ * \return Nothing
++ */
++static void rose_copy_name_to_q931(struct pri *ctrl,
++ struct q931_party_name *qsig_name, const struct roseQsigName *rose_name)
++{
++ //q931_party_name_init(qsig_name);
++ qsig_name->valid = 1;
++ qsig_name->presentation = qsig_name_presentation_for_q931(ctrl,
++ rose_name->presentation);
++ qsig_name->char_set = rose_name->char_set;
++ libpri_copy_string(qsig_name->str, (char *) rose_name->data, sizeof(qsig_name->str));
++}
+
+- if (comp->len == ASN1_LEN_INDEF) {
+- datalen = strlen((char*)comp->data);
+- res = datalen + 2;
+- } else
+- res = datalen = comp->len;
++/*!
++ * \internal
++ * \brief Copy the given q931_party_number to the rose party number
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param rose_number ROSE party number structure
++ * \param q931_number Q.931 party number structure
++ *
++ * \return Nothing
++ */
++static void q931_copy_number_to_rose(struct pri *ctrl,
++ struct rosePartyNumber *rose_number, const struct q931_party_number *q931_number)
++{
++ rose_number->plan = numbering_plan_from_q931(ctrl, q931_number->plan);
++ rose_number->ton = typeofnumber_from_q931(ctrl, q931_number->plan);
++ /* Truncate the q931_number->str if necessary. */
++ libpri_copy_string((char *) rose_number->str, q931_number->str,
++ sizeof(rose_number->str));
++ rose_number->length = strlen((char *) rose_number->str);
++}
+
+- memcpy(buf, comp->data, datalen);
+- buf[datalen] = 0;
++/*!
++ * \internal
++ * \brief Copy the given q931_party_subaddress to the rose subaddress.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param rose_subaddress ROSE subaddress structure
++ * \param q931_subaddress Q.931 party subaddress structure
++ *
++ * \return Nothing
++ */
++static void q931_copy_subaddress_to_rose(struct pri *ctrl,
++ struct rosePartySubaddress *rose_subaddress,
++ const struct q931_party_subaddress *q931_subaddress)
++{
++ if (!q931_subaddress->valid) {
++ /* Subaddress is not present. */
++ rose_subaddress->length = 0;
++ return;
++ }
+
+- return res;
++ switch (q931_subaddress->type) {
++ case 0: /* NSAP */
++ rose_subaddress->type = 1;/* NSAP */
++ libpri_copy_string((char *) rose_subaddress->u.nsap,
++ (char *) q931_subaddress->data, sizeof(rose_subaddress->u.nsap));
++ rose_subaddress->length = strlen((char *) rose_subaddress->u.nsap);
++ break;
++ case 2: /* user_specified */
++ rose_subaddress->type = 0;/* UserSpecified */
++ rose_subaddress->length = q931_subaddress->length;
++ if (sizeof(rose_subaddress->u.user_specified.information)
++ <= rose_subaddress->length) {
++ rose_subaddress->length =
++ sizeof(rose_subaddress->u.user_specified.information) - 1;
++ } else {
++ if (q931_subaddress->odd_even_indicator) {
++ rose_subaddress->u.user_specified.odd_count_present = 1;
++ rose_subaddress->u.user_specified.odd_count = 1;
++ }
++ }
++ memcpy(rose_subaddress->u.user_specified.information, q931_subaddress->data,
++ rose_subaddress->length);
++ rose_subaddress->u.user_specified.information[rose_subaddress->length] = '\0';
++ break;
++ default:
++ /* Don't know how to encode so assume it is not present. */
++ rose_subaddress->length = 0;
++ break;
++ }
+ }
+
+-static int rose_number_digits_decode(struct pri *pri, q931_call *call, unsigned char *data, int len, struct addressingdataelements_presentednumberunscreened *value)
++/*!
++ * \internal
++ * \brief Copy the given q931_party_id address to the rose address.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param rose_address ROSE address structure
++ * \param q931_address Q.931 party id structure to give address
++ *
++ * \return Nothing
++ */
++static void q931_copy_address_to_rose(struct pri *ctrl, struct roseAddress *rose_address,
++ const struct q931_party_id *q931_address)
+ {
+- int i = 0;
+- struct rose_component *comp = NULL;
+- unsigned char *vdata = data;
+- int datalen = 0;
+- int res = 0;
++ q931_copy_number_to_rose(ctrl, &rose_address->number, &q931_address->number);
++ q931_copy_subaddress_to_rose(ctrl, &rose_address->subaddress,
++ &q931_address->subaddress);
++}
+
+- do {
+- GET_COMPONENT(comp, i, vdata, len);
+- CHECK_COMPONENT(comp, ASN1_NUMERICSTRING, "Don't know what to do with PublicPartyNumber ROSE component type 0x%x\n");
+- if(comp->len > 20 && comp->len != ASN1_LEN_INDEF) {
+- pri_message(pri, "!! Oversized NumberDigits component (%d)\n", comp->len);
+- return -1;
+- }
+- if (comp->len == ASN1_LEN_INDEF) {
+- datalen = strlen((char *)comp->data);
+- res = datalen + 2;
+- } else
+- res = datalen = comp->len;
+-
+- memcpy(value->partyaddress, comp->data, datalen);
+- value->partyaddress[datalen] = '\0';
++/*!
++ * \internal
++ * \brief Copy the given q931_party_number to the rose presented screened party number
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param rose_presented ROSE presented screened party number structure
++ * \param q931_number Q.931 party number structure
++ *
++ * \return Nothing
++ */
++static void q931_copy_presented_number_screened_to_rose(struct pri *ctrl,
++ struct rosePresentedNumberScreened *rose_presented,
++ const struct q931_party_number *q931_number)
++{
++ if (q931_number->valid) {
++ rose_presented->presentation =
++ presentation_from_q931(ctrl, q931_number->presentation, q931_number->str[0]);
++ rose_presented->screened.screening_indicator =
++ q931_number->presentation & PRI_PRES_NUMBER_TYPE;
++ q931_copy_number_to_rose(ctrl, &rose_presented->screened.number, q931_number);
++ } else {
++ rose_presented->presentation = 2;/* numberNotAvailableDueToInterworking */
++ }
++}
+
+- return res + 2;
++/*!
++ * \internal
++ * \brief Copy the given q931_party_number to the rose presented unscreened party number
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param rose_presented ROSE presented unscreened party number structure
++ * \param q931_number Q.931 party number structure
++ *
++ * \return Nothing
++ */
++static void q931_copy_presented_number_unscreened_to_rose(struct pri *ctrl,
++ struct rosePresentedNumberUnscreened *rose_presented,
++ const struct q931_party_number *q931_number)
++{
++ if (q931_number->valid) {
++ rose_presented->presentation =
++ presentation_from_q931(ctrl, q931_number->presentation, q931_number->str[0]);
++ q931_copy_number_to_rose(ctrl, &rose_presented->number, q931_number);
++ } else {
++ rose_presented->presentation = 2;/* numberNotAvailableDueToInterworking */
+ }
+- while(0);
+-
+- return -1;
+ }
+
+-static int rose_public_party_number_decode(struct pri *pri, q931_call *call, unsigned char *data, int len, struct addressingdataelements_presentednumberunscreened *value)
++#if 0 /* In case it is needed in the future */
++/*!
++ * \internal
++ * \brief Copy the given q931_party_number to the rose presented screened party address
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param rose_presented ROSE presented screened party address structure
++ * \param q931_address Q.931 party id structure to get the address
++ *
++ * \return Nothing
++ */
++static void q931_copy_presented_address_screened_to_rose(struct pri *ctrl,
++ struct rosePresentedAddressScreened *rose_presented,
++ const struct q931_party_id *q931_address)
+ {
+- int i = 0;
+- struct rose_component *comp = NULL;
+- unsigned char *vdata = data;
+- int ton;
+- int res = 0;
++ if (q931_address->number.valid) {
++ rose_presented->presentation =
++ presentation_from_q931(ctrl, q931_address->number.presentation,
++ q931_address->number.str[0]);
++ rose_presented->screened.screening_indicator =
++ q931_address->number.presentation & PRI_PRES_NUMBER_TYPE;
++ q931_copy_number_to_rose(ctrl, &rose_presented->screened.number,
++ &q931_address->number);
++ q931_copy_subaddress_to_rose(ctrl, &rose_presented->screened.subaddress,
++ &q931_address->subaddress);
++ } else {
++ rose_presented->presentation = 2;/* numberNotAvailableDueToInterworking */
++ }
++}
++#endif /* In case it is needed in the future */
+
+- if (len < 2)
+- return -1;
++/*!
++ * \internal
++ * \brief Copy the given q931_party_name to the rose party name
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param rose_name Q.SIG ROSE party name structure
++ * \param qsig_name Q.SIG party name structure
++ *
++ * \return Nothing
++ */
++static void q931_copy_name_to_rose(struct pri *ctrl,
++ struct roseQsigName *rose_name, const struct q931_party_name *qsig_name)
++{
++ if (qsig_name->valid) {
++ rose_name->presentation = qsig_name_presentation_from_q931(ctrl,
++ qsig_name->presentation, qsig_name->str[0]);
++ rose_name->char_set = qsig_name->char_set;
++ /* Truncate the qsig_name->str if necessary. */
++ libpri_copy_string((char *) rose_name->data, qsig_name->str, sizeof(rose_name->data));
++ rose_name->length = strlen((char *) rose_name->data);
++ } else {
++ rose_name->presentation = 4;/* name_not_available */
++ }
++}
+
+- do {
+- GET_COMPONENT(comp, i, vdata, len);
+- CHECK_COMPONENT(comp, ASN1_ENUMERATED, "Don't know what to do with PublicPartyNumber ROSE component type 0x%x\n");
+- ASN1_GET_INTEGER(comp, ton);
+- NEXT_COMPONENT(comp, i);
+- ton = typeofnumber_for_q931(pri, ton);
++/*!
++ * \internal
++ * \brief Encode the Q.SIG DivertingLegInformation1 invoke 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 call Call leg from which to encode diversion leg 1.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *enc_qsig_diverting_leg_information1(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, q931_call *call)
++{
++ struct fac_extension_header header;
++ struct rose_msg_invoke msg;
+
+- res = rose_number_digits_decode(pri, call, &vdata[i], len-i, value);
+- if (res < 0)
+- return -1;
+- value->ton = ton;
++ 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;
++ }
+
+- return res + 3;
++ memset(&msg, 0, sizeof(msg));
++ msg.operation = ROSE_QSIG_DivertingLegInformation1;
++ msg.invoke_id = get_invokeid(ctrl);
++ msg.args.qsig.DivertingLegInformation1.diversion_reason =
++ redirectingreason_from_q931(ctrl, call->redirecting.reason);
+
+- } while(0);
+- return -1;
++ /* subscriptionOption is the redirecting.to.number.presentation */
++ msg.args.qsig.DivertingLegInformation1.subscription_option =
++ presentation_to_subscription(ctrl, call->redirecting.to.number.presentation);
++
++ /* nominatedNr is the redirecting.to.number */
++ q931_copy_number_to_rose(ctrl,
++ &msg.args.qsig.DivertingLegInformation1.nominated_number,
++ &call->redirecting.to.number);
++
++ pos = rose_encode_invoke(ctrl, pos, end, &msg);
++
++ return pos;
+ }
+
+-static int rose_private_party_number_decode(struct pri *pri, q931_call *call, unsigned char *data, int len, struct addressingdataelements_presentednumberunscreened *value)
++/*!
++ * \internal
++ * \brief Encode the ETSI DivertingLegInformation1 invoke 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 call Call leg from which to encode diversion leg 1.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *enc_etsi_diverting_leg_information1(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, q931_call *call)
+ {
+- int i = 0;
+- struct rose_component *comp = NULL;
+- unsigned char *vdata = data;
+- int ton;
+- int res = 0;
++ struct rose_msg_invoke msg;
+
+- if (len < 2)
+- return -1;
++ pos = facility_encode_header(ctrl, pos, end, NULL);
++ if (!pos) {
++ return NULL;
++ }
+
+- do {
+- GET_COMPONENT(comp, i, vdata, len);
+- CHECK_COMPONENT(comp, ASN1_ENUMERATED, "Don't know what to do with PrivatePartyNumber ROSE component type 0x%x\n");
+- ASN1_GET_INTEGER(comp, ton);
+- NEXT_COMPONENT(comp, i);
+- ton = typeofnumber_for_q931(pri, ton);
++ memset(&msg, 0, sizeof(msg));
++ msg.operation = ROSE_ETSI_DivertingLegInformation1;
++ msg.invoke_id = get_invokeid(ctrl);
++ msg.args.etsi.DivertingLegInformation1.diversion_reason =
++ redirectingreason_from_q931(ctrl, call->redirecting.reason);
+
+- res = rose_number_digits_decode(pri, call, &vdata[i], len-i, value);
+- if (res < 0)
+- return -1;
+- value->ton = ton;
++ if (call->redirecting.to.number.valid) {
++ msg.args.etsi.DivertingLegInformation1.subscription_option = 2;
+
+- return res + 3;
++ /* divertedToNumber is the redirecting.to.number */
++ msg.args.etsi.DivertingLegInformation1.diverted_to_present = 1;
++ q931_copy_presented_number_unscreened_to_rose(ctrl,
++ &msg.args.etsi.DivertingLegInformation1.diverted_to,
++ &call->redirecting.to.number);
++ } else {
++ msg.args.etsi.DivertingLegInformation1.subscription_option = 1;
++ }
++ pos = rose_encode_invoke(ctrl, pos, end, &msg);
+
+- } while(0);
+- return -1;
++ return pos;
+ }
+
+-static int rose_address_decode(struct pri *pri, q931_call *call, unsigned char *data, int len, struct addressingdataelements_presentednumberunscreened *value)
++/*!
++ * \brief Encode and queue the DivertingLegInformation1 invoke message.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param call Call leg from which to encode diversion leg 1.
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++int rose_diverting_leg_information1_encode(struct pri *ctrl, q931_call *call)
+ {
+- int i = 0;
+- struct rose_component *comp = NULL;
+- unsigned char *vdata = data;
+- int res = 0;
++ unsigned char buffer[256];
++ unsigned char *end;
+
+- do {
+- GET_COMPONENT(comp, i, vdata, len);
++ switch (ctrl->switchtype) {
++ case PRI_SWITCH_EUROISDN_E1:
++ case PRI_SWITCH_EUROISDN_T1:
++ end = enc_etsi_diverting_leg_information1(ctrl, buffer, buffer + sizeof(buffer),
++ call);
++ break;
++ case PRI_SWITCH_QSIG:
++ end = enc_qsig_diverting_leg_information1(ctrl, buffer, buffer + sizeof(buffer),
++ call);
++ break;
++ default:
++ return -1;
++ }
++ if (!end) {
++ return -1;
++ }
+
+- switch(comp->type) {
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_0): /* [0] unknownPartyNumber */
+- res = rose_number_digits_decode(pri, call, comp->data, comp->len, value);
+- if (res < 0)
+- return -1;
+- value->npi = PRI_NPI_UNKNOWN;
+- value->ton = PRI_TON_UNKNOWN;
+- break;
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0): /* [0] unknownPartyNumber */
+- res = asn1_copy_string(value->partyaddress, sizeof(value->partyaddress), comp);
+- if (res < 0)
+- return -1;
+- value->npi = PRI_NPI_UNKNOWN;
+- value->ton = PRI_TON_UNKNOWN;
+- break;
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1): /* [1] publicPartyNumber */
+- res = rose_public_party_number_decode(pri, call, comp->data, comp->len, value);
+- if (res < 0)
+- return -1;
+- value->npi = PRI_NPI_E163_E164;
+- break;
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_2): /* [2] nsapEncodedNumber */
+- pri_message(pri, "!! NsapEncodedNumber isn't handled\n");
+- return -1;
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_3): /* [3] dataPartyNumber */
+- if(rose_number_digits_decode(pri, call, comp->data, comp->len, value))
+- return -1;
+- value->npi = PRI_NPI_X121 /* ??? */;
+- value->ton = PRI_TON_UNKNOWN /* ??? */;
+- pri_message(pri, "!! dataPartyNumber isn't handled\n");
+- return -1;
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_4): /* [4] telexPartyNumber */
+- res = rose_number_digits_decode(pri, call, comp->data, comp->len, value);
+- if (res < 0)
+- return -1;
+- value->npi = PRI_NPI_F69 /* ??? */;
+- value->ton = PRI_TON_UNKNOWN /* ??? */;
+- pri_message(pri, "!! telexPartyNumber isn't handled\n");
+- return -1;
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_5): /* [5] priavePartyNumber */
+- res = rose_private_party_number_decode(pri, call, comp->data, comp->len, value);
+- if (res < 0)
+- return -1;
+- value->npi = PRI_NPI_PRIVATE;
+- break;
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_8): /* [8] nationalStandardPartyNumber */
+- res = rose_number_digits_decode(pri, call, comp->data, comp->len, value);
+- if (res < 0)
+- return -1;
+- value->npi = PRI_NPI_NATIONAL;
+- value->ton = PRI_TON_NATIONAL;
+- break;
+- default:
+- pri_message(pri, "!! Unknown Party number component received 0x%X\n", comp->type);
+- return -1;
++ return pri_call_apdu_queue(call, Q931_FACILITY, buffer, end - buffer, NULL);
++}
++
++/*!
++ * \internal
++ * \brief Encode the Q.SIG DivertingLegInformation2 invoke 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 call Call leg from which to encode diversion leg 2.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *enc_qsig_diverting_leg_information2(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, q931_call *call)
++{
++ 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 = 0; /* discardAnyUnrecognisedInvokePdu */
++ pos = facility_encode_header(ctrl, pos, end, &header);
++ if (!pos) {
++ return NULL;
++ }
++
++ memset(&msg, 0, sizeof(msg));
++ msg.operation = ROSE_QSIG_DivertingLegInformation2;
++ msg.invoke_id = get_invokeid(ctrl);
++
++ /* diversionCounter is the redirecting.count */
++ msg.args.qsig.DivertingLegInformation2.diversion_counter = call->redirecting.count;
++
++ msg.args.qsig.DivertingLegInformation2.diversion_reason =
++ redirectingreason_from_q931(ctrl, call->redirecting.reason);
++
++ /* divertingNr is the redirecting.from.number */
++ msg.args.qsig.DivertingLegInformation2.diverting_present = 1;
++ q931_copy_presented_number_unscreened_to_rose(ctrl,
++ &msg.args.qsig.DivertingLegInformation2.diverting,
++ &call->redirecting.from.number);
++
++ /* redirectingName is the redirecting.from.name */
++ if (call->redirecting.from.name.valid) {
++ msg.args.qsig.DivertingLegInformation2.redirecting_name_present = 1;
++ q931_copy_name_to_rose(ctrl,
++ &msg.args.qsig.DivertingLegInformation2.redirecting_name,
++ &call->redirecting.from.name);
++ }
++
++ if (1 < call->redirecting.count) {
++ /* originalCalledNr is the redirecting.orig_called.number */
++ msg.args.qsig.DivertingLegInformation2.original_called_present = 1;
++ q931_copy_presented_number_unscreened_to_rose(ctrl,
++ &msg.args.qsig.DivertingLegInformation2.original_called,
++ &call->redirecting.orig_called.number);
++
++ msg.args.qsig.DivertingLegInformation2.original_diversion_reason_present = 1;
++ if (call->redirecting.orig_called.number.valid) {
++ msg.args.qsig.DivertingLegInformation2.original_diversion_reason =
++ redirectingreason_from_q931(ctrl, call->redirecting.orig_reason);
++ } else {
++ msg.args.qsig.DivertingLegInformation2.original_diversion_reason =
++ QSIG_DIVERT_REASON_UNKNOWN;
+ }
+- ASN1_FIXUP_LEN(comp, res);
+- NEXT_COMPONENT(comp, i);
+- if(i < len)
+- pri_message(pri, "!! not all information is handled from Address component\n");
+- return res + 2;
++
++ /* originalCalledName is the redirecting.orig_called.name */
++ if (call->redirecting.orig_called.name.valid) {
++ msg.args.qsig.DivertingLegInformation2.original_called_name_present = 1;
++ q931_copy_name_to_rose(ctrl,
++ &msg.args.qsig.DivertingLegInformation2.original_called_name,
++ &call->redirecting.orig_called.name);
++ }
+ }
+- while (0);
+
+- return -1;
++ pos = rose_encode_invoke(ctrl, pos, end, &msg);
++
++ return pos;
+ }
+
+-static int rose_presented_number_unscreened_decode(struct pri *pri, q931_call *call, unsigned char *data, int len, struct addressingdataelements_presentednumberunscreened *value)
++/*!
++ * \internal
++ * \brief Encode the ETSI DivertingLegInformation2 invoke 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 call Call leg from which to encode diversion leg 2.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *enc_etsi_diverting_leg_information2(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, q931_call *call)
+ {
+- int i = 0;
+- int size = 0;
+- struct rose_component *comp = NULL;
+- unsigned char *vdata = data;
++ struct rose_msg_invoke msg;
+
+- /* Fill in default values */
+- value->ton = PRI_TON_UNKNOWN;
+- value->npi = PRI_NPI_E163_E164;
+- value->pres = -1; /* Data is not available */
++ pos = facility_encode_header(ctrl, pos, end, NULL);
++ if (!pos) {
++ return NULL;
++ }
+
+- do {
+- GET_COMPONENT(comp, i, vdata, len);
++ memset(&msg, 0, sizeof(msg));
++ msg.operation = ROSE_ETSI_DivertingLegInformation2;
++ msg.invoke_id = get_invokeid(ctrl);
+
+- switch(comp->type) {
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_0): /* [0] presentationAllowedNumber */
+- value->pres = PRES_ALLOWED_USER_NUMBER_NOT_SCREENED;
+- size = rose_address_decode(pri, call, comp->data, comp->len, value);
+- ASN1_FIXUP_LEN(comp, size);
+- return size + 2;
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_1): /* [1] IMPLICIT presentationRestricted */
+- if (comp->len != 0) { /* must be NULL */
+- pri_error(pri, "!! Invalid PresentationRestricted component received (len != 0)\n");
+- return -1;
+- }
+- value->pres = PRES_PROHIB_USER_NUMBER_NOT_SCREENED;
+- return 2;
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2): /* [2] IMPLICIT numberNotAvailableDueToInterworking */
+- if (comp->len != 0) { /* must be NULL */
+- pri_error(pri, "!! Invalid NumberNotAvailableDueToInterworking component received (len != 0)\n");
+- return -1;
+- }
+- value->pres = PRES_NUMBER_NOT_AVAILABLE;
+- return 2;
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_3): /* [3] presentationRestrictedNumber */
+- value->pres = PRES_PROHIB_USER_NUMBER_NOT_SCREENED;
+- size = rose_address_decode(pri, call, comp->data, comp->len, value) + 2;
+- ASN1_FIXUP_LEN(comp, size);
+- return size + 2;
+- default:
+- pri_message(pri, "Invalid PresentedNumberUnscreened component 0x%X\n", comp->type);
+- }
+- return -1;
++ /* diversionCounter is the redirecting.count */
++ msg.args.etsi.DivertingLegInformation2.diversion_counter = call->redirecting.count;
++
++ msg.args.etsi.DivertingLegInformation2.diversion_reason =
++ redirectingreason_from_q931(ctrl, call->redirecting.reason);
++
++ /* divertingNr is the redirecting.from.number */
++ msg.args.etsi.DivertingLegInformation2.diverting_present = 1;
++ q931_copy_presented_number_unscreened_to_rose(ctrl,
++ &msg.args.etsi.DivertingLegInformation2.diverting,
++ &call->redirecting.from.number);
++
++ if (1 < call->redirecting.count) {
++ /* originalCalledNr is the redirecting.orig_called.number */
++ msg.args.etsi.DivertingLegInformation2.original_called_present = 1;
++ q931_copy_presented_number_unscreened_to_rose(ctrl,
++ &msg.args.etsi.DivertingLegInformation2.original_called,
++ &call->redirecting.orig_called.number);
+ }
+- while (0);
+
+- return -1;
++ pos = rose_encode_invoke(ctrl, pos, end, &msg);
++
++ return pos;
+ }
+
+-static int rose_diverting_leg_information2_decode(struct pri *pri, q931_call *call, struct rose_component *sequence, int len)
++/*!
++ * \internal
++ * \brief Encode and queue the DivertingLegInformation2 invoke message.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param call Call leg from which to encode diversion leg 2.
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++static int rose_diverting_leg_information2_encode(struct pri *ctrl, q931_call *call)
+ {
+- int i = 0;
+- int diversion_counter;
+- int diversion_reason;
+- char origcalledname[50] = "", redirectingname[50] = "";
+- struct addressingdataelements_presentednumberunscreened divertingnr;
+- struct addressingdataelements_presentednumberunscreened originalcallednr;
+- struct rose_component *comp = NULL;
+- unsigned char *vdata = sequence->data;
+- int res = 0;
+- memset(&divertingnr, 0, sizeof(divertingnr));
+- memset(&originalcallednr, 0, sizeof(originalcallednr));
++ unsigned char buffer[256];
++ unsigned char *end;
+
+- /* Data checks */
+- if (sequence->type != (ASN1_CONSTRUCTOR | ASN1_SEQUENCE)) { /* Constructed Sequence */
+- pri_message(pri, "Invalid DivertingLegInformation2Type argument\n");
++ switch (ctrl->switchtype) {
++ case PRI_SWITCH_EUROISDN_E1:
++ case PRI_SWITCH_EUROISDN_T1:
++ end = enc_etsi_diverting_leg_information2(ctrl, buffer, buffer + sizeof(buffer),
++ call);
++ break;
++ case PRI_SWITCH_QSIG:
++ end = enc_qsig_diverting_leg_information2(ctrl, buffer, buffer + sizeof(buffer),
++ call);
++ break;
++ default:
+ return -1;
+ }
++ if (!end) {
++ return -1;
++ }
+
+- if (sequence->len == ASN1_LEN_INDEF) {
+- len -= 4; /* For the 2 extra characters at the end
+- * and two characters of header */
+- } else
+- len -= 2;
++ return pri_call_apdu_queue(call, Q931_SETUP, buffer, end - buffer, NULL);
++}
+
+- do {
+- /* diversionCounter stuff */
+- GET_COMPONENT(comp, i, vdata, len);
+- CHECK_COMPONENT(comp, ASN1_INTEGER, "Don't know what to do it diversionCounter is of type 0x%x\n");
+- ASN1_GET_INTEGER(comp, diversion_counter);
+- NEXT_COMPONENT(comp, i);
++/*!
++ * \internal
++ * \brief Encode the Q.SIG DivertingLegInformation3 invoke 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 call Call leg from which to encode diversion leg 3.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *enc_qsig_diverting_leg_information3(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, q931_call *call)
++{
++ struct fac_extension_header header;
++ struct rose_msg_invoke msg;
+
+- /* diversionReason stuff */
+- GET_COMPONENT(comp, i, vdata, len);
+- CHECK_COMPONENT(comp, ASN1_ENUMERATED, "Invalid diversionReason type 0x%X of ROSE divertingLegInformation2 component received\n");
+- ASN1_GET_INTEGER(comp, diversion_reason);
+- NEXT_COMPONENT(comp, i);
++ 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;
++ }
+
+- diversion_reason = redirectingreason_for_q931(pri, diversion_reason);
+-
+- if(pri->debug & PRI_DEBUG_APDU)
+- pri_message(pri, " Redirection reason: %d, total diversions: %d\n", diversion_reason, diversion_counter);
+- pri_message(NULL, "Length of message is %d\n", len);
++ memset(&msg, 0, sizeof(msg));
++ msg.operation = ROSE_QSIG_DivertingLegInformation3;
++ msg.invoke_id = get_invokeid(ctrl);
+
+- for(; i < len; NEXT_COMPONENT(comp, i)) {
+- GET_COMPONENT(comp, i, vdata, len);
+- switch(comp->type) {
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0):
+- call->origredirectingreason = redirectingreason_for_q931(pri, comp->data[0]);
+- if (pri->debug & PRI_DEBUG_APDU)
+- pri_message(pri, " Received reason for original redirection %d\n", call->origredirectingreason);
+- break;
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1):
+- res = rose_presented_number_unscreened_decode(pri, call, comp->data, comp->len, &divertingnr);
+- /* TODO: Fix indefinite length form hacks */
+- ASN1_FIXUP_LEN(comp, res);
+- comp->len = res;
+- if (res < 0)
+- return -1;
+- if (pri->debug & PRI_DEBUG_APDU) {
+- pri_message(pri, " Received divertingNr '%s'\n", divertingnr.partyaddress);
+- pri_message(pri, " ton = %d, pres = %d, npi = %d\n", divertingnr.ton, divertingnr.pres, divertingnr.npi);
+- }
+- break;
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_2):
+- res = rose_presented_number_unscreened_decode(pri, call, comp->data, comp->len, &originalcallednr);
+- if (res < 0)
+- return -1;
+- ASN1_FIXUP_LEN(comp, res);
+- comp->len = res;
+- if (pri->debug & PRI_DEBUG_APDU) {
+- pri_message(pri, " Received originalcallednr '%s'\n", originalcallednr.partyaddress);
+- pri_message(pri, " ton = %d, pres = %d, npi = %d\n", originalcallednr.ton, originalcallednr.pres, originalcallednr.npi);
+- }
+- break;
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_3):
+- res = asn1_name_decode(comp->data, comp->len, redirectingname, sizeof(redirectingname));
+- if (res < 0)
+- return -1;
+- ASN1_FIXUP_LEN(comp, res);
+- comp->len = res;
+- if (pri->debug & PRI_DEBUG_APDU)
+- pri_message(pri, " Received RedirectingName '%s'\n", redirectingname);
+- break;
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_4):
+- res = asn1_name_decode(comp->data, comp->len, origcalledname, sizeof(origcalledname));
+- if (res < 0)
+- return -1;
+- ASN1_FIXUP_LEN(comp, res);
+- comp->len = res;
+- if (pri->debug & PRI_DEBUG_APDU)
+- pri_message(pri, " Received Originally Called Name '%s'\n", origcalledname);
+- break;
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_5):
+- pri_message(pri, "!! Ignoring DivertingLegInformation2 component 0x%X\n", comp->type);
+- break;
+- default:
+- if (comp->type == 0 && comp->len == 0) {
+- break; /* Found termination characters */
+- }
+- pri_message(pri, "!! Invalid DivertingLegInformation2 component received 0x%X\n", comp->type);
+- return -1;
+- }
+- }
++ /* redirecting.to.number.presentation also indicates if name presentation is allowed */
++ if ((call->redirecting.to.number.presentation & PRI_PRES_RESTRICTION) == PRI_PRES_ALLOWED) {
++ msg.args.qsig.DivertingLegInformation3.presentation_allowed_indicator = 1; /* TRUE */
+
+- if (divertingnr.pres >= 0) {
+- call->redirectingplan = divertingnr.npi;
+- call->redirectingpres = divertingnr.pres;
+- call->redirectingreason = diversion_reason;
+- libpri_copy_string(call->redirectingnum, divertingnr.partyaddress, sizeof(call->redirectingnum));
+- pri_message(pri, " Received redirectingnum '%s' (%d)\n", call->redirectingnum, (int)call->redirectingnum[0]);
++ /* redirectionName is the redirecting.to.name */
++ if (call->redirecting.to.name.valid) {
++ msg.args.qsig.DivertingLegInformation3.redirection_name_present = 1;
++ q931_copy_name_to_rose(ctrl,
++ &msg.args.qsig.DivertingLegInformation3.redirection_name,
++ &call->redirecting.to.name);
+ }
+- if (originalcallednr.pres >= 0) {
+- call->origcalledplan = originalcallednr.npi;
+- call->origcalledpres = originalcallednr.pres;
+- libpri_copy_string(call->origcallednum, originalcallednr.partyaddress, sizeof(call->origcallednum));
+- pri_message(pri, " Received origcallednum '%s' (%d)\n", call->origcallednum, (int)call->origcallednum[0]);
+- }
+- libpri_copy_string(call->redirectingname, redirectingname, sizeof(call->redirectingname));
+- libpri_copy_string(call->origcalledname, origcalledname, sizeof(call->origcalledname));
+- return 0;
+ }
+- while (0);
+
+- return -1;
++ pos = rose_encode_invoke(ctrl, pos, end, &msg);
++
++ return pos;
+ }
+-
+-static int rose_diverting_leg_information2_encode(struct pri *pri, q931_call *call)
++
++/*!
++ * \internal
++ * \brief Encode the ETSI DivertingLegInformation3 invoke 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 call Call leg from which to encode diversion leg 3.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *enc_etsi_diverting_leg_information3(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, q931_call *call)
+ {
+- int i = 0, j, compsp = 0;
+- struct rose_component *comp, *compstk[10];
+- unsigned char buffer[256];
+- int len = 253;
+-
+-#if 0 /* This is not required by specifications */
+- if (!strlen(call->callername)) {
+- return -1;
++ struct rose_msg_invoke msg;
++
++ pos = facility_encode_header(ctrl, pos, end, NULL);
++ if (!pos) {
++ return NULL;
+ }
+-#endif
+
+- buffer[i] = (ASN1_CONTEXT_SPECIFIC | Q932_PROTOCOL_EXTENSIONS);
+- i++;
+- /* Interpretation component */
+- ASN1_ADD_BYTECOMP(comp, COMP_TYPE_INTERPRETATION, buffer, i, 0x00 /* Discard unrecognized invokes */);
+-
+- ASN1_ADD_SIMPLE(comp, COMP_TYPE_INVOKE, buffer, i);
+-
+- ASN1_PUSH(compstk, compsp, comp);
+- /* Invoke component contents */
+- /* Invoke ID */
+- ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, get_invokeid(pri));
+- /* Operation Tag */
+-
+- /* ROSE operationId component */
+- ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, ROSE_DIVERTING_LEG_INFORMATION2);
++ memset(&msg, 0, sizeof(msg));
++ msg.operation = ROSE_ETSI_DivertingLegInformation3;
++ msg.invoke_id = get_invokeid(ctrl);
+
+- /* ROSE ARGUMENT component */
+- ASN1_ADD_SIMPLE(comp, (ASN1_CONSTRUCTOR | ASN1_SEQUENCE), buffer, i);
+- ASN1_PUSH(compstk, compsp, comp);
+- /* ROSE DivertingLegInformation2.diversionCounter component */
+- /* Always is 1 because other isn't available in the current design */
+- ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, 1);
+-
+- /* ROSE DivertingLegInformation2.diversionReason component */
+- ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, buffer, i, redirectingreason_from_q931(pri, call->redirectingreason));
+-
+- /* ROSE DivertingLegInformation2.divertingNr component */
+- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1), buffer, i);
+-
+- ASN1_PUSH(compstk, compsp, comp);
+- /* Redirecting information always not screened */
+-
+- switch(call->redirectingpres) {
+- case PRES_ALLOWED_USER_NUMBER_NOT_SCREENED:
+- case PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN:
+- if (call->redirectingnum && strlen(call->redirectingnum)) {
+- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_0), buffer, i);
+- ASN1_PUSH(compstk, compsp, comp);
+- /* NPI of redirected number is not supported in the current design */
+- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1), buffer, i);
+- ASN1_PUSH(compstk, compsp, comp);
+- ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, buffer, i, typeofnumber_from_q931(pri, call->redirectingplan >> 4));
+- j = asn1_string_encode(ASN1_NUMERICSTRING, &buffer[i], len - i, 20, call->redirectingnum, strlen(call->redirectingnum));
+- if (j < 0)
+- return -1;
+-
+- i += j;
+- ASN1_FIXUP(compstk, compsp, buffer, i);
+- ASN1_FIXUP(compstk, compsp, buffer, i);
+- break;
+- }
+- /* fall through */
+- case PRES_PROHIB_USER_NUMBER_PASSED_SCREEN:
+- case PRES_PROHIB_USER_NUMBER_NOT_SCREENED:
+- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_1), buffer, i);
+- break;
+- /* Don't know how to handle this */
+- case PRES_ALLOWED_NETWORK_NUMBER:
+- case PRES_PROHIB_NETWORK_NUMBER:
+- case PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN:
+- case PRES_PROHIB_USER_NUMBER_FAILED_SCREEN:
+- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_1), buffer, i);
+- break;
+- default:
+- pri_message(pri, "!! Undefined presentation value for redirecting number: %d\n", call->redirectingpres);
+- case PRES_NUMBER_NOT_AVAILABLE:
+- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2), buffer, i);
+- break;
++ if ((call->redirecting.to.number.presentation & PRI_PRES_RESTRICTION) == PRI_PRES_ALLOWED) {
++ msg.args.etsi.DivertingLegInformation3.presentation_allowed_indicator = 1; /* TRUE */
+ }
+- ASN1_FIXUP(compstk, compsp, buffer, i);
+
+- /* ROSE DivertingLegInformation2.originalCalledNr component */
+- /* This information isn't supported by current design - duplicate divertingNr */
+- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_2), buffer, i);
+- ASN1_PUSH(compstk, compsp, comp);
+- /* Redirecting information always not screened */
+- switch(call->redirectingpres) {
+- case PRES_ALLOWED_USER_NUMBER_NOT_SCREENED:
+- case PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN:
+- if (call->redirectingnum && strlen(call->redirectingnum)) {
+- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_0), buffer, i);
+- ASN1_PUSH(compstk, compsp, comp);
+- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1), buffer, i);
+- ASN1_PUSH(compstk, compsp, comp);
+- ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, buffer, i, typeofnumber_from_q931(pri, call->redirectingplan >> 4));
+-
+- j = asn1_string_encode(ASN1_NUMERICSTRING, &buffer[i], len - i, 20, call->redirectingnum, strlen(call->redirectingnum));
+- if (j < 0)
+- return -1;
+-
+- i += j;
+- ASN1_FIXUP(compstk, compsp, buffer, i);
+- ASN1_FIXUP(compstk, compsp, buffer, i);
+- break;
+- }
+- /* fall through */
+- case PRES_PROHIB_USER_NUMBER_PASSED_SCREEN:
+- case PRES_PROHIB_USER_NUMBER_NOT_SCREENED:
+- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_1), buffer, i);
+- break;
+- /* Don't know how to handle this */
+- case PRES_ALLOWED_NETWORK_NUMBER:
+- case PRES_PROHIB_NETWORK_NUMBER:
+- case PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN:
+- case PRES_PROHIB_USER_NUMBER_FAILED_SCREEN:
+- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_1), buffer, i);
+- break;
+- default:
+- pri_message(pri, "!! Undefined presentation value for redirecting number: %d\n", call->redirectingpres);
+- case PRES_NUMBER_NOT_AVAILABLE:
+- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2), buffer, i);
+- break;
++ pos = rose_encode_invoke(ctrl, pos, end, &msg);
++
++ return pos;
++}
++
++/*!
++ * \brief Encode and queue the DivertingLegInformation3 invoke message.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param call Call leg from which to encode diversion leg 3.
++ * \param messagetype Q.931 message type to add facility ie to.
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++int rose_diverting_leg_information3_encode(struct pri *ctrl, q931_call *call,
++ int messagetype)
++{
++ unsigned char buffer[256];
++ unsigned char *end;
++
++ switch (ctrl->switchtype) {
++ case PRI_SWITCH_EUROISDN_E1:
++ case PRI_SWITCH_EUROISDN_T1:
++ end = enc_etsi_diverting_leg_information3(ctrl, buffer, buffer + sizeof(buffer),
++ call);
++ break;
++ case PRI_SWITCH_QSIG:
++ end = enc_qsig_diverting_leg_information3(ctrl, buffer, buffer + sizeof(buffer),
++ call);
++ break;
++ default:
++ return -1;
+ }
+- ASN1_FIXUP(compstk, compsp, buffer, i);
+-
+- /* Fix length of stacked components */
+- while(compsp > 0) {
+- ASN1_FIXUP(compstk, compsp, buffer, i);
++ if (!end) {
++ return -1;
+ }
+-
+- if (pri_call_apdu_queue(call, Q931_SETUP, buffer, i, NULL, NULL))
+- return -1;
+-
+- return 0;
++
++ return pri_call_apdu_queue(call, messagetype, buffer, end - buffer, NULL);
+ }
+
+-/* Send the rltThirdParty: Invoke */
+-int rlt_initiate_transfer(struct pri *pri, q931_call *c1, q931_call *c2)
++/*!
++ * \internal
++ * \brief Encode the rltThirdParty invoke 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 callwithid Call-ID information to encode.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *enc_dms100_rlt_initiate_transfer(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, const q931_call *callwithid)
+ {
+- int i = 0;
++ struct rose_msg_invoke msg;
++
++ pos = facility_encode_header(ctrl, pos, end, NULL);
++ if (!pos) {
++ return NULL;
++ }
++
++ memset(&msg, 0, sizeof(msg));
++ msg.operation = ROSE_DMS100_RLT_ThirdParty;
++ msg.invoke_id = ROSE_DMS100_RLT_THIRD_PARTY;
++ msg.args.dms100.RLT_ThirdParty.call_id = callwithid->rlt_call_id & 0xFFFFFF;
++ msg.args.dms100.RLT_ThirdParty.reason = 0; /* unused, set to 129 */
++ pos = rose_encode_invoke(ctrl, pos, end, &msg);
++
++ return pos;
++}
++
++/*!
++ * \brief Send the rltThirdParty: Invoke.
++ *
++ * \note For PRI_SWITCH_DMS100 only.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param c1 Q.931 call leg 1
++ * \param c2 Q.931 call leg 2
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++int rlt_initiate_transfer(struct pri *ctrl, q931_call *c1, q931_call *c2)
++{
+ unsigned char buffer[256];
+- struct rose_component *comp = NULL, *compstk[10];
+- const unsigned char rlt_3rd_pty = RLT_THIRD_PARTY;
+- q931_call *callwithid = NULL, *apdubearer = NULL;
+- int compsp = 0;
++ unsigned char *end;
++ q931_call *apdubearer;
++ q931_call *callwithid;
+
+ if (c2->transferable) {
+ apdubearer = c1;
+@@ -906,279 +1374,415 @@
+ } else if (c1->transferable) {
+ apdubearer = c2;
+ callwithid = c1;
+- } else
++ } else {
+ return -1;
++ }
+
+- buffer[i++] = (Q932_PROTOCOL_ROSE);
+- buffer[i++] = (0x80 | RLT_SERVICE_ID); /* Service Identifier octet */
++ end =
++ enc_dms100_rlt_initiate_transfer(ctrl, buffer, buffer + sizeof(buffer),
++ callwithid);
++ if (!end) {
++ return -1;
++ }
+
+- ASN1_ADD_SIMPLE(comp, COMP_TYPE_INVOKE, buffer, i);
+- ASN1_PUSH(compstk, compsp, comp);
+-
+- /* Invoke ID is set to the operation ID */
+- ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, rlt_3rd_pty);
+-
+- /* Operation Tag */
+- ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, rlt_3rd_pty);
+-
+- /* Additional RLT invoke info - Octet 12 */
+- ASN1_ADD_SIMPLE(comp, (ASN1_CONSTRUCTOR | ASN1_SEQUENCE), buffer, i);
+- ASN1_PUSH(compstk, compsp, comp);
+-
+- ASN1_ADD_WORDCOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0), buffer, i, callwithid->rlt_call_id & 0xFFFFFF); /* Length is 3 octets */
+- /* Reason for redirect - unused, set to 129 */
+- ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_1), buffer, i, 0);
+- ASN1_FIXUP(compstk, compsp, buffer, i);
+- ASN1_FIXUP(compstk, compsp, buffer, i);
+-
+- if (pri_call_apdu_queue(apdubearer, Q931_FACILITY, buffer, i, NULL, NULL))
++ if (pri_call_apdu_queue(apdubearer, Q931_FACILITY, buffer, end - buffer, NULL)) {
+ return -1;
++ }
+
+ if (q931_facility(apdubearer->pri, apdubearer)) {
+- pri_message(pri, "Could not schedule facility message for call %d\n", apdubearer->cr);
++ pri_message(ctrl, "Could not schedule facility message for call %d\n",
++ apdubearer->cr);
+ return -1;
+ }
+ return 0;
+ }
+
+-static int add_dms100_transfer_ability_apdu(struct pri *pri, q931_call *c)
++/*!
++ * \internal
++ * \brief Encode the rltOperationInd invoke 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.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *enc_dms100_rlt_transfer_ability(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end)
+ {
+- int i = 0;
+- unsigned char buffer[256];
+- struct rose_component *comp = NULL, *compstk[10];
+- const unsigned char rlt_op_ind = RLT_OPERATION_IND;
+- int compsp = 0;
++ struct rose_msg_invoke msg;
+
+- buffer[i++] = (Q932_PROTOCOL_ROSE); /* Note to self: DON'T set the EXT bit */
+- buffer[i++] = (0x80 | RLT_SERVICE_ID); /* Service Identifier octet */
++ pos = facility_encode_header(ctrl, pos, end, NULL);
++ if (!pos) {
++ return NULL;
++ }
+
+- ASN1_ADD_SIMPLE(comp, COMP_TYPE_INVOKE, buffer, i);
+- ASN1_PUSH(compstk, compsp, comp);
++ memset(&msg, 0, sizeof(msg));
++ msg.operation = ROSE_DMS100_RLT_OperationInd;
++ msg.invoke_id = ROSE_DMS100_RLT_OPERATION_IND;
++ pos = rose_encode_invoke(ctrl, pos, end, &msg);
+
+- /* Invoke ID is set to the operation ID */
+- ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, rlt_op_ind);
+-
+- /* Operation Tag - basically the same as the invoke ID tag */
+- ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, rlt_op_ind);
+- ASN1_FIXUP(compstk, compsp, buffer, i);
+-
+- if (pri_call_apdu_queue(c, Q931_SETUP, buffer, i, NULL, NULL))
+- return -1;
+- else
+- return 0;
++ return pos;
+ }
+
+-/* Sending callername information functions */
+-static int add_callername_facility_ies(struct pri *pri, q931_call *c, int cpe)
++/*!
++ * \internal
++ * \brief Send the rltOperationInd: Invoke.
++ *
++ * \note For PRI_SWITCH_DMS100 only.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param call Q.931 call leg
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++static int add_dms100_transfer_ability_apdu(struct pri *ctrl, q931_call *call)
+ {
+- int res = 0;
+- int i = 0;
+ unsigned char buffer[256];
+- unsigned char namelen = 0;
+- struct rose_component *comp = NULL, *compstk[10];
+- int compsp = 0;
+- int mymessage = 0;
+- static unsigned char op_tag[] = {
+- 0x2a, /* informationFollowing 42 */
+- 0x86,
+- 0x48,
+- 0xce,
+- 0x15,
+- 0x00,
+- 0x04
+- };
+-
+- if (!strlen(c->callername)) {
++ unsigned char *end;
++
++ end = enc_dms100_rlt_transfer_ability(ctrl, buffer, buffer + sizeof(buffer));
++ if (!end) {
+ return -1;
+ }
+
+- buffer[i++] = (ASN1_CONTEXT_SPECIFIC | Q932_PROTOCOL_EXTENSIONS);
+- /* Interpretation component */
++ return pri_call_apdu_queue(call, Q931_SETUP, buffer, end - buffer, NULL);
++}
+
+- if (pri->switchtype == PRI_SWITCH_QSIG) {
+- ASN1_ADD_SIMPLE(comp, COMP_TYPE_NFE, buffer, i);
+- ASN1_PUSH(compstk, compsp, comp);
+- ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0), buffer, i, 0);
+- ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2), buffer, i, 0);
+- ASN1_FIXUP(compstk, compsp, buffer, i);
++/*!
++ * \internal
++ * \brief Encode the NI2 InformationFollowing invoke 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.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *enc_ni2_information_following(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end)
++{
++ struct fac_extension_header header;
++ struct rose_msg_invoke msg;
++
++ memset(&header, 0, sizeof(header));
++ header.interpretation_present = 1;
++ header.interpretation = 0; /* discardAnyUnrecognisedInvokePdu */
++ pos = facility_encode_header(ctrl, pos, end, &header);
++ if (!pos) {
++ return NULL;
+ }
+
+- ASN1_ADD_BYTECOMP(comp, COMP_TYPE_INTERPRETATION, buffer, i, 0);
++ memset(&msg, 0, sizeof(msg));
++ msg.operation = ROSE_NI2_InformationFollowing;
++ msg.invoke_id = get_invokeid(ctrl);
++ msg.args.ni2.InformationFollowing.value = 0;
++ pos = rose_encode_invoke(ctrl, pos, end, &msg);
+
+- ASN1_ADD_SIMPLE(comp, COMP_TYPE_INVOKE, buffer, i);
+- ASN1_PUSH(compstk, compsp, comp);
+- /* Invoke ID */
+- ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, get_invokeid(pri));
++ return pos;
++}
+
+- /* Operation Tag */
+- res = asn1_string_encode(ASN1_OBJECTIDENTIFIER, &buffer[i], sizeof(buffer)-i, sizeof(op_tag), op_tag, sizeof(op_tag));
+- if (res < 0)
+- return -1;
+- i += res;
++/*!
++ * \internal
++ * \brief Encode the Q.SIG CallingName invoke 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 name Name data which to encode name.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *enc_qsig_calling_name(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const struct q931_party_name *name)
++{
++ struct fac_extension_header header;
++ struct rose_msg_invoke msg;
+
+- ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, buffer, i, 0);
+- ASN1_FIXUP(compstk, compsp, buffer, i);
+-
+- if (!cpe) {
+- if (pri_call_apdu_queue(c, Q931_SETUP, buffer, i, NULL, NULL))
+- return -1;
++ memset(&header, 0, sizeof(header));
++ if (ctrl->switchtype == PRI_SWITCH_QSIG) {
++ 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.operation = ROSE_QSIG_CallingName;
++ msg.invoke_id = get_invokeid(ctrl);
+
+- /* Now the APDU that contains the information that needs sent.
+- * We can reuse the buffer since the queue function doesn't
+- * need it. */
++ /* CallingName */
++ q931_copy_name_to_rose(ctrl, &msg.args.qsig.CallingName.name, name);
+
+- i = 0;
+- namelen = strlen(c->callername);
+- if (namelen > 50) {
+- namelen = 50; /* truncate the name */
+- }
++ pos = rose_encode_invoke(ctrl, pos, end, &msg);
+
+- buffer[i++] = (ASN1_CONTEXT_SPECIFIC | Q932_PROTOCOL_EXTENSIONS);
+- /* Interpretation component */
++ return pos;
++}
+
+- if (pri->switchtype == PRI_SWITCH_QSIG) {
+- ASN1_ADD_SIMPLE(comp, COMP_TYPE_NFE, buffer, i);
+- ASN1_PUSH(compstk, compsp, comp);
+- ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0), buffer, i, 0);
+- ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2), buffer, i, 0);
+- ASN1_FIXUP(compstk, compsp, buffer, i);
++/*!
++ * \internal
++ * \brief Send caller name information.
++ *
++ * \note For PRI_SWITCH_NI2 and PRI_SWITCH_QSIG.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param call Call leg from which to encode name.
++ * \param cpe TRUE if we are the CPE side.
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++static int add_callername_facility_ies(struct pri *ctrl, q931_call *call, int cpe)
++{
++ unsigned char buffer[256];
++ unsigned char *end;
++ int mymessage;
++
++ if (!call->local_id.name.valid) {
++ return 0;
+ }
+
+- ASN1_ADD_BYTECOMP(comp, COMP_TYPE_INTERPRETATION, buffer, i, 0);
++ if (ctrl->switchtype == PRI_SWITCH_NI2 && !cpe) {
++ end = enc_ni2_information_following(ctrl, buffer, buffer + sizeof(buffer));
++ if (!end) {
++ return -1;
++ }
+
+- ASN1_ADD_SIMPLE(comp, COMP_TYPE_INVOKE, buffer, i);
+- ASN1_PUSH(compstk, compsp, comp);
++ if (pri_call_apdu_queue(call, Q931_SETUP, buffer, end - buffer, NULL)) {
++ return -1;
++ }
+
+- /* Invoke ID */
+- ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, get_invokeid(pri));
++ /*
++ * We can reuse the buffer since the queue function doesn't
++ * need it.
++ */
++ }
+
+- /* Operation ID: Calling name */
+- ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, SS_CNID_CALLINGNAME);
+-
+- res = asn1_string_encode((ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0), &buffer[i], sizeof(buffer)-i, 50, c->callername, namelen);
+- if (res < 0)
++ /* CallingName is the local_id.name */
++ end = enc_qsig_calling_name(ctrl, buffer, buffer + sizeof(buffer),
++ &call->local_id.name);
++ if (!end) {
+ return -1;
+- i += res;
+- ASN1_FIXUP(compstk, compsp, buffer, i);
++ }
+
+- if (cpe)
++ if (cpe) {
+ mymessage = Q931_SETUP;
+- else
++ } else {
+ mymessage = Q931_FACILITY;
++ }
+
+- if (pri_call_apdu_queue(c, mymessage, buffer, i, NULL, NULL))
+- return -1;
+-
+- return 0;
++ return pri_call_apdu_queue(call, mymessage, buffer, end - buffer, NULL);
+ }
+ /* End Callername */
+
+ /* MWI related encode and decode functions */
+-static void mwi_activate_encode_cb(void *data)
++
++/*!
++ * \internal
++ * \brief Encode the Q.SIG MWIActivate invoke 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 req Served user setup request information.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *enc_qsig_mwi_activate_message(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, struct pri_sr *req)
+ {
+- return;
++ 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 = 0; /* discardAnyUnrecognisedInvokePdu */
++ pos = facility_encode_header(ctrl, pos, end, &header);
++ if (!pos) {
++ return NULL;
++ }
++
++ memset(&msg, 0, sizeof(msg));
++ msg.operation = ROSE_QSIG_MWIActivate;
++ msg.invoke_id = get_invokeid(ctrl);
++
++ /* The called.number is the served user */
++ q931_copy_number_to_rose(ctrl, &msg.args.qsig.MWIActivate.served_user_number,
++ &req->called.number);
++ /*
++ * For now, we will just force the numbering plan to unknown to preserve
++ * the original behaviour.
++ */
++ msg.args.qsig.MWIActivate.served_user_number.plan = 0; /* unknown */
++
++ msg.args.qsig.MWIActivate.basic_service = 1; /* speech */
++
++ pos = rose_encode_invoke(ctrl, pos, end, &msg);
++
++ return pos;
+ }
+
+-int mwi_message_send(struct pri* pri, q931_call *call, struct pri_sr *req, int activate)
++/*!
++ * \internal
++ * \brief Encode the Q.SIG MWIDeactivate invoke 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 req Served user setup request information.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *enc_qsig_mwi_deactivate_message(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, struct pri_sr *req)
+ {
+- int i = 0;
+- unsigned char buffer[255] = "";
+- int destlen = strlen(req->called);
+- struct rose_component *comp = NULL, *compstk[10];
+- int compsp = 0;
+- int res;
++ struct fac_extension_header header;
++ struct rose_msg_invoke msg;
+
+- if (destlen <= 0) {
+- return -1;
+- } else if (destlen > 20)
+- destlen = 20; /* Destination number cannot be greater then 20 digits */
++ 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;
++ }
+
+- buffer[i++] = (ASN1_CONTEXT_SPECIFIC | Q932_PROTOCOL_EXTENSIONS);
+- /* Interpretation component */
++ memset(&msg, 0, sizeof(msg));
++ msg.operation = ROSE_QSIG_MWIDeactivate;
++ msg.invoke_id = get_invokeid(ctrl);
+
+- ASN1_ADD_SIMPLE(comp, COMP_TYPE_NFE, buffer, i);
+- ASN1_PUSH(compstk, compsp, comp);
+- ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0), buffer, i, 0);
+- ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2), buffer, i, 0);
+- ASN1_FIXUP(compstk, compsp, buffer, i);
++ /* The called.number is the served user */
++ q931_copy_number_to_rose(ctrl, &msg.args.qsig.MWIDeactivate.served_user_number,
++ &req->called.number);
++ /*
++ * For now, we will just force the numbering plan to unknown to preserve
++ * the original behaviour.
++ */
++ msg.args.qsig.MWIDeactivate.served_user_number.plan = 0; /* unknown */
+
+- ASN1_ADD_BYTECOMP(comp, COMP_TYPE_INTERPRETATION, buffer, i, 0);
++ msg.args.qsig.MWIDeactivate.basic_service = 1; /* speech */
+
+- ASN1_ADD_SIMPLE(comp, COMP_TYPE_INVOKE, buffer, i);
+- ASN1_PUSH(compstk, compsp, comp);
++ pos = rose_encode_invoke(ctrl, pos, end, &msg);
+
+- ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, get_invokeid(pri));
++ return pos;
++}
+
+- ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, (activate) ? SS_MWI_ACTIVATE : SS_MWI_DEACTIVATE);
+- ASN1_ADD_SIMPLE(comp, (ASN1_CONSTRUCTOR | ASN1_SEQUENCE), buffer, i);
+- ASN1_PUSH(compstk, compsp, comp);
+- /* PartyNumber */
+- res = asn1_string_encode((ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0), &buffer[i], sizeof(buffer)-i, destlen, req->called, destlen);
+-
+- if (res < 0)
++/*!
++ * \brief Encode and queue the Q.SIG MWIActivate/MWIDeactivate invoke message.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param call Call leg to queue message.
++ * \param req Served user setup request information.
++ * \param activate Nonzero to do the activate message.
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++int mwi_message_send(struct pri *ctrl, q931_call *call, struct pri_sr *req, int activate)
++{
++ unsigned char buffer[255];
++ unsigned char *end;
++
++ if (!req->called.number.valid || !req->called.number.str[0]) {
+ return -1;
+- i += res;
++ }
+
+- /* Enumeration: basicService */
+- ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, buffer, i, 1 /* contents: Voice */);
+- ASN1_FIXUP(compstk, compsp, buffer, i);
+- ASN1_FIXUP(compstk, compsp, buffer, i);
++ if (activate) {
++ end = enc_qsig_mwi_activate_message(ctrl, buffer, buffer + sizeof(buffer), req);
++ } else {
++ end =
++ enc_qsig_mwi_deactivate_message(ctrl, buffer, buffer + sizeof(buffer), req);
++ }
++ if (!end) {
++ return -1;
++ }
+
+- return pri_call_apdu_queue(call, Q931_SETUP, buffer, i, mwi_activate_encode_cb, NULL);
++ return pri_call_apdu_queue(call, Q931_SETUP, buffer, end - buffer, NULL);
+ }
+ /* End MWI */
+
+ /* EECT functions */
+-int eect_initiate_transfer(struct pri *pri, q931_call *c1, q931_call *c2)
++/*!
++ * \internal
++ * \brief Encode the NI2 InitiateTransfer invoke 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 call Call leg from which to encode transfer information.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *enc_ni2_initiate_transfer(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, q931_call *call)
+ {
+- int i = 0;
+- int res = 0;
+- unsigned char buffer[255] = "";
+- short call_reference = c2->cr ^ 0x8000; /* Let's do the trickery to make sure the flag is correct */
+- struct rose_component *comp = NULL, *compstk[10];
+- int compsp = 0;
+- static unsigned char op_tag[] = {
+- 0x2A,
+- 0x86,
+- 0x48,
+- 0xCE,
+- 0x15,
+- 0x00,
+- 0x08,
+- };
++ struct rose_msg_invoke msg;
+
+- buffer[i++] = (ASN1_CONTEXT_SPECIFIC | Q932_PROTOCOL_ROSE);
++ pos = facility_encode_header(ctrl, pos, end, NULL);
++ if (!pos) {
++ return NULL;
++ }
+
+- ASN1_ADD_SIMPLE(comp, COMP_TYPE_INVOKE, buffer, i);
+- ASN1_PUSH(compstk, compsp, comp);
++ memset(&msg, 0, sizeof(msg));
++ msg.operation = ROSE_NI2_InitiateTransfer;
++ msg.invoke_id = get_invokeid(ctrl);
++ /* Let's do the trickery to make sure the flag is correct */
++ msg.args.ni2.InitiateTransfer.call_reference = call->cr ^ 0x8000;
++ pos = rose_encode_invoke(ctrl, pos, end, &msg);
+
+- ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, get_invokeid(pri));
++ return pos;
++}
+
+- res = asn1_string_encode(ASN1_OBJECTIDENTIFIER, &buffer[i], sizeof(buffer)-i, sizeof(op_tag), op_tag, sizeof(op_tag));
+- if (res < 0)
++/*!
++ * \brief Start a 2BCT
++ *
++ * \note Called for PRI_SWITCH_NI2, PRI_SWITCH_LUCENT5E, and PRI_SWITCH_ATT4ESS
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param c1 Q.931 call leg 1
++ * \param c2 Q.931 call leg 2
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++int eect_initiate_transfer(struct pri *ctrl, q931_call *c1, q931_call *c2)
++{
++ unsigned char buffer[255];
++ unsigned char *end;
++
++ end = enc_ni2_initiate_transfer(ctrl, buffer, buffer + sizeof(buffer), c2);
++ if (!end) {
+ return -1;
+- i += res;
++ }
+
+- ASN1_ADD_SIMPLE(comp, (ASN1_SEQUENCE | ASN1_CONSTRUCTOR), buffer, i);
+- ASN1_PUSH(compstk, compsp, comp);
+- ASN1_ADD_WORDCOMP(comp, ASN1_INTEGER, buffer, i, call_reference);
+- ASN1_FIXUP(compstk, compsp, buffer, i);
+- ASN1_FIXUP(compstk, compsp, buffer, i);
+-
+- res = pri_call_apdu_queue(c1, Q931_FACILITY, buffer, i, NULL, NULL);
+- if (res) {
+- pri_message(pri, "Could not queue APDU in facility message\n");
++ if (pri_call_apdu_queue(c1, Q931_FACILITY, buffer, end - buffer, NULL)) {
++ pri_message(ctrl, "Could not queue APDU in facility message\n");
+ return -1;
+ }
+
+ /* Remember that if we queue a facility IE for a facility message we
+ * have to explicitly send the facility message ourselves */
+
+- res = q931_facility(c1->pri, c1);
+- if (res) {
+- pri_message(pri, "Could not schedule facility message for call %d\n", c1->cr);
++ if (q931_facility(c1->pri, c1)) {
++ pri_message(ctrl, "Could not schedule facility message for call %d\n", c1->cr);
+ return -1;
+ }
+
+@@ -1187,1494 +1791,2316 @@
+ /* End EECT */
+
+ /* QSIG CF CallRerouting */
+-int qsig_cf_callrerouting(struct pri *pri, q931_call *c, const char* dest, const char* original, const char* reason)
++/*!
++ * \internal
++ * \brief Encode the Q.SIG CallRerouting invoke 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 call Q.931 call leg.
++ * \param calling Call rerouting/deflecting updated caller data.
++ * \param deflection Call rerouting/deflecting redirection data.
++ * \param subscription_option Diverting user subscription option to specify if caller is notified.
++ *
++ * \note
++ * deflection->to is the new called number and must always be present.
++ * \note
++ * subscription option:
++ * noNotification(0),
++ * notificationWithoutDivertedToNr(1),
++ * notificationWithDivertedToNr(2)
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *enc_qsig_call_rerouting(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, q931_call *call, const struct q931_party_id *calling,
++ const struct q931_party_redirecting *deflection, int subscription_option)
+ {
+-/*CallRerouting ::= OPERATION
+- -- Sent from the Served User PINX to the Rerouting PINX
+- ARGUMENT SEQUENCE
+- { reroutingReason DiversionReason,
+- originalReroutingReason [0] IMPLICIT DiversionReason OPTIONAL,
+- calledAddress Address,
+- diversionCounter INTEGER (1..15),
+- pSS1InfoElement PSS1InformationElement,
+- -- The basic call information elements Bearer capability, High layer compatibility, Low
+- -- layer compatibity, Progress indicator and Party category can be embedded in the
+- -- pSS1InfoElement in accordance with 6.5.3.1.5
+- lastReroutingNr [1] PresentedNumberUnscreened,
+- subscriptionOption [2] IMPLICIT SubscriptionOption,
++ struct fac_extension_header header;
++ struct rose_msg_invoke msg;
++ unsigned char *q931ie_pos;
+
+- callingPartySubaddress [3] PartySubaddress OPTIONAL,
++ 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 = 2; /* rejectAnyUnrecognisedInvokePdu */
++ pos = facility_encode_header(ctrl, pos, end, &header);
++ if (!pos) {
++ return NULL;
++ }
+
+- callingNumber [4] PresentedNumberScreened,
++ memset(&msg, 0, sizeof(msg));
++ msg.operation = ROSE_QSIG_CallRerouting;
++ msg.invoke_id = get_invokeid(ctrl);
+
+- callingName [5] Name OPTIONAL,
+- originalCalledNr [6] PresentedNumberUnscreened OPTIONAL,
+- redirectingName [7] Name OPTIONAL,
+- originalCalledName [8] Name OPTIONAL,
+- extension CHOICE {
+- [9] IMPLICIT Extension ,
+- [10] IMPLICIT SEQUENCE OF Extension } OPTIONAL }
+-*/
++ msg.args.qsig.CallRerouting.rerouting_reason =
++ redirectingreason_from_q931(ctrl, deflection->reason);
+
+- int i = 0, j;
+- int res = 0;
+- unsigned char buffer[255] = "";
+- int len = 253;
+- struct rose_component *comp = NULL, *compstk[10];
+- int compsp = 0;
+- static unsigned char op_tag[] = {
+- 0x13,
+- };
++ /* calledAddress is the passed in deflection->to address */
++ q931_copy_address_to_rose(ctrl, &msg.args.qsig.CallRerouting.called, &deflection->to);
+
+- buffer[i++] = (ASN1_CONTEXT_SPECIFIC | Q932_PROTOCOL_EXTENSIONS);
+- /* Interpretation component */
++ msg.args.qsig.CallRerouting.diversion_counter = deflection->count;
+
+- ASN1_ADD_SIMPLE(comp, COMP_TYPE_NFE, buffer, i);
+- ASN1_PUSH(compstk, compsp, comp);
+- ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0), buffer, i, 0);
+- ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2), buffer, i, 0);
+- ASN1_FIXUP(compstk, compsp, buffer, i);
++ /* pSS1InfoElement */
++ q931ie_pos = msg.args.qsig.CallRerouting.q931ie_contents;
++ *q931ie_pos++ = 0x04; /* Bearer Capability IE */
++ *q931ie_pos++ = 0x03; /* len */
++ *q931ie_pos++ = 0x80 | call->transcapability; /* Rxed transfer capability. */
++ *q931ie_pos++ = 0x90; /* circuit mode, 64kbit/s */
++ *q931ie_pos++ = 0xa3; /* level1 protocol, a-law */
++ *q931ie_pos++ = 0x95; /* locking shift to codeset 5 (national use) */
++ *q931ie_pos++ = 0x32; /* Unknown ie */
++ *q931ie_pos++ = 0x01; /* Unknown ie len */
++ *q931ie_pos++ = 0x81; /* Unknown ie body */
++ msg.args.qsig.CallRerouting.q931ie.length = q931ie_pos
++ - msg.args.qsig.CallRerouting.q931ie_contents;
+
+- ASN1_ADD_BYTECOMP(comp, COMP_TYPE_INTERPRETATION, buffer, i, 2); /* reject - to get feedback from QSIG switch */
++ /* lastReroutingNr is the passed in deflection->from.number */
++ q931_copy_presented_number_unscreened_to_rose(ctrl,
++ &msg.args.qsig.CallRerouting.last_rerouting, &deflection->from.number);
+
+- ASN1_ADD_SIMPLE(comp, COMP_TYPE_INVOKE, buffer, i);
+- ASN1_PUSH(compstk, compsp, comp);
++ msg.args.qsig.CallRerouting.subscription_option = subscription_option;
+
+- ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, get_invokeid(pri));
++ /* callingNumber is the passed in calling->number */
++ q931_copy_presented_number_screened_to_rose(ctrl,
++ &msg.args.qsig.CallRerouting.calling, &calling->number);
+
+- res = asn1_string_encode(ASN1_INTEGER, &buffer[i], sizeof(buffer)-i, sizeof(op_tag), op_tag, sizeof(op_tag));
+- if (res < 0)
+- return -1;
+- i += res;
++ /* callingPartySubaddress is the passed in calling->subaddress if valid */
++ q931_copy_subaddress_to_rose(ctrl, &msg.args.qsig.CallRerouting.calling_subaddress,
++ &calling->subaddress);
+
+- /* call rerouting argument */
+- ASN1_ADD_SIMPLE(comp, (ASN1_CONSTRUCTOR | ASN1_SEQUENCE), buffer, i);
+- ASN1_PUSH(compstk, compsp, comp);
++ /* callingName is the passed in calling->name if valid */
++ if (calling->name.valid) {
++ msg.args.qsig.CallRerouting.calling_name_present = 1;
++ q931_copy_name_to_rose(ctrl, &msg.args.qsig.CallRerouting.calling_name,
++ &calling->name);
++ }
+
+- /* reroutingReason DiversionReason */
++ if (1 < deflection->count) {
++ /* originalCalledNr is the deflection->orig_called.number */
++ msg.args.qsig.CallRerouting.original_called_present = 1;
++ q931_copy_presented_number_unscreened_to_rose(ctrl,
++ &msg.args.qsig.CallRerouting.original_called,
++ &deflection->orig_called.number);
+
+- if (reason) {
+- if (!strcasecmp(reason, "cfu"))
+- ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, buffer, i, 1); /* cfu */
+- else if (!strcasecmp(reason, "cfb"))
+- ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, buffer, i, 2); /* cfb */
+- else if (!strcasecmp(reason, "cfnr"))
+- ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, buffer, i, 3); /* cfnr */
+- } else {
+- ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, buffer, i, 0); /* unknown */
++ msg.args.qsig.CallRerouting.original_rerouting_reason_present = 1;
++ if (deflection->orig_called.number.valid) {
++ msg.args.qsig.CallRerouting.original_rerouting_reason =
++ redirectingreason_from_q931(ctrl, deflection->orig_reason);
++ } else {
++ msg.args.qsig.CallRerouting.original_rerouting_reason =
++ QSIG_DIVERT_REASON_UNKNOWN;
++ }
++
++ /* originalCalledName is the deflection->orig_called.name */
++ if (deflection->orig_called.name.valid) {
++ msg.args.qsig.CallRerouting.original_called_name_present = 1;
++ q931_copy_name_to_rose(ctrl,
++ &msg.args.qsig.CallRerouting.original_called_name,
++ &deflection->orig_called.name);
++ }
+ }
+
++ pos = rose_encode_invoke(ctrl, pos, end, &msg);
+
+- /* calledAddress Address */
+- /* explicit sequence tag for Address */
+- ASN1_ADD_SIMPLE(comp, (ASN1_CONSTRUCTOR | ASN1_SEQUENCE), buffer, i);
+- ASN1_PUSH(compstk, compsp, comp);
+- /* implicit choice public party number tag */
+- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1), buffer, i);
+- ASN1_PUSH(compstk, compsp, comp);
+- /* type of public party number = unknown */
+- ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, buffer, i, 0);
+- /* NumberDigits of public party number */
+- j = asn1_string_encode(ASN1_NUMERICSTRING, &buffer[i], len - i, 20, (char*)dest, strlen(dest));
+- if (j < 0)
+- return -1;
++ return pos;
++}
+
+- i += j;
+- ASN1_FIXUP(compstk, compsp, buffer, i);
+- ASN1_FIXUP(compstk, compsp, buffer, i);
++/*!
++ * \internal
++ * \brief Encode the ETSI CallRerouting invoke 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 call Q.931 call leg.
++ * \param calling Call rerouting/deflecting updated caller data.
++ * \param deflection Call rerouting/deflecting redirection data.
++ * \param subscription_option Diverting user subscription option to specify if caller is notified.
++ *
++ * \note
++ * deflection->to is the new called number and must always be present.
++ * \note
++ * subscription option:
++ * noNotification(0),
++ * notificationWithoutDivertedToNr(1),
++ * notificationWithDivertedToNr(2)
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *enc_etsi_call_rerouting(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, q931_call *call, const struct q931_party_id *calling,
++ const struct q931_party_redirecting *deflection, int subscription_option)
++{
++ struct rose_msg_invoke msg;
++ unsigned char *q931ie_pos;
+
+- /* diversionCounter INTEGER (1..15) */
+- ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, 1);
++ pos = facility_encode_header(ctrl, pos, end, NULL);
++ if (!pos) {
++ return NULL;
++ }
+
+- /* pSS1InfoElement */
+- ASN1_ADD_SIMPLE(comp, (ASN1_APPLICATION | ASN1_TAG_0 ), buffer, i);
+- ASN1_PUSH(compstk, compsp, comp);
+- buffer[i++] = (0x04); /* Bearer Capability IE */
+- buffer[i++] = (0x03); /* len */
+- buffer[i++] = (0x80); /* ETSI Standard, Speech */
+- buffer[i++] = (0x90); /* circuit mode, 64kbit/s */
+- buffer[i++] = (0xa3); /* level1 protocol, a-law */
+- buffer[i++] = (0x95); /* locking shift to codeset 5 (national use) */
+- buffer[i++] = (0x32); /* Unknown ie */
+- buffer[i++] = (0x01); /* Unknown ie len */
+- buffer[i++] = (0x81); /* Unknown ie body */
+- ASN1_FIXUP(compstk, compsp, buffer, i);
++ memset(&msg, 0, sizeof(msg));
++ msg.operation = ROSE_ETSI_CallRerouting;
++ msg.invoke_id = get_invokeid(ctrl);
+
+- /* lastReroutingNr [1]*/
+- /* implicit optional lastReroutingNr tag */
+- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1), buffer, i);
+- ASN1_PUSH(compstk, compsp, comp);
++ msg.args.etsi.CallRerouting.rerouting_reason =
++ redirectingreason_from_q931(ctrl, deflection->reason);
+
+- /* implicit choice presented number unscreened tag */
+- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_0), buffer, i);
+- ASN1_PUSH(compstk, compsp, comp);
++ /* calledAddress is the passed in deflection->to address */
++ q931_copy_address_to_rose(ctrl, &msg.args.etsi.CallRerouting.called_address,
++ &deflection->to);
+
+- /* implicit choice public party number tag */
+- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1), buffer, i);
+- ASN1_PUSH(compstk, compsp, comp);
+- /* type of public party number = unknown */
+- ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, buffer, i, 0);
+- j = asn1_string_encode(ASN1_NUMERICSTRING, &buffer[i], len - i, 20, original?(char*)original:c->callednum, original?strlen(original):strlen(c->callednum));
+- if (j < 0)
+- return -1;
++ msg.args.etsi.CallRerouting.rerouting_counter = deflection->count;
+
+- i += j;
+- ASN1_FIXUP(compstk, compsp, buffer, i);
+- ASN1_FIXUP(compstk, compsp, buffer, i);
+- ASN1_FIXUP(compstk, compsp, buffer, i);
++ /* q931InfoElement */
++ q931ie_pos = msg.args.etsi.CallRerouting.q931ie_contents;
++ *q931ie_pos++ = 0x04; /* Bearer Capability IE */
++ *q931ie_pos++ = 0x03; /* len */
++ *q931ie_pos++ = 0x80 | call->transcapability; /* Rxed transfer capability. */
++ *q931ie_pos++ = 0x90; /* circuit mode, 64kbit/s */
++ *q931ie_pos++ = 0xa3; /* level1 protocol, a-law */
++ msg.args.etsi.CallRerouting.q931ie.length = q931ie_pos
++ - msg.args.etsi.CallRerouting.q931ie_contents;
+
+- /* subscriptionOption [2]*/
+- /* implicit optional lastReroutingNr tag */
+- ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2), buffer, i, 0); /* noNotification */
++ /* lastReroutingNr is the passed in deflection->from.number */
++ q931_copy_presented_number_unscreened_to_rose(ctrl,
++ &msg.args.etsi.CallRerouting.last_rerouting, &deflection->from.number);
+
+- /* callingNumber [4]*/
+- /* implicit optional callingNumber tag */
+- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_4), buffer, i);
+- ASN1_PUSH(compstk, compsp, comp);
++ msg.args.etsi.CallRerouting.subscription_option = subscription_option;
+
+- /* implicit choice presented number screened tag */
+- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_0), buffer, i);
+- ASN1_PUSH(compstk, compsp, comp);
++ /* callingPartySubaddress is the passed in calling->subaddress if valid */
++ q931_copy_subaddress_to_rose(ctrl, &msg.args.etsi.CallRerouting.calling_subaddress,
++ &calling->subaddress);
+
+- /* implicit choice presentationAllowedAddress tag */
+- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1), buffer, i);
+- ASN1_PUSH(compstk, compsp, comp);
+- /* type of public party number = subscriber number */
+- ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, buffer, i, 4);
+- j = asn1_string_encode(ASN1_NUMERICSTRING, &buffer[i], len - i, 20, c->callernum, strlen(c->callernum));
+- if (j < 0)
+- return -1;
++ pos = rose_encode_invoke(ctrl, pos, end, &msg);
+
+- i += j;
+- ASN1_FIXUP(compstk, compsp, buffer, i);
++ return pos;
++}
+
+- /* Screeening Indicator network provided */
+- ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, buffer, i, 3);
++/*!
++ * \internal
++ * \brief Encode the ETSI CallDeflection invoke 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 call Q.931 call leg.
++ * \param deflection Call deflection address.
++ *
++ * \note
++ * deflection is the new called number and must always be present.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *enc_etsi_call_deflection(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, q931_call *call, const struct q931_party_id *deflection)
++{
++ struct rose_msg_invoke msg;
+
+- ASN1_FIXUP(compstk, compsp, buffer, i);
+- ASN1_FIXUP(compstk, compsp, buffer, i);
++ pos = facility_encode_header(ctrl, pos, end, NULL);
++ if (!pos) {
++ return NULL;
++ }
+
+- /**/
++ memset(&msg, 0, sizeof(msg));
++ msg.operation = ROSE_ETSI_CallDeflection;
++ msg.invoke_id = get_invokeid(ctrl);
+
+- ASN1_FIXUP(compstk, compsp, buffer, i);
+- ASN1_FIXUP(compstk, compsp, buffer, i);
++ /* deflectionAddress is the passed in deflection->to address */
++ q931_copy_address_to_rose(ctrl, &msg.args.etsi.CallDeflection.deflection,
++ deflection);
+
+- res = pri_call_apdu_queue(c, Q931_FACILITY, buffer, i, NULL, NULL);
+- if (res) {
+- pri_message(pri, "Could not queue ADPU in facility message\n");
++ msg.args.etsi.CallDeflection.presentation_allowed_to_diverted_to_user_present = 1;
++ switch (deflection->number.presentation & PRI_PRES_RESTRICTION) {
++ case PRI_PRES_ALLOWED:
++ msg.args.etsi.CallDeflection.presentation_allowed_to_diverted_to_user = 1;
++ break;
++ default:
++ case PRI_PRES_UNAVAILABLE:
++ case PRI_PRES_RESTRICTED:
++ break;
++ }
++
++ pos = rose_encode_invoke(ctrl, pos, end, &msg);
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Encode and queue the CallRerouting/CallDeflection message.
++ *
++ * \param ctrl D channel controller.
++ * \param call Q.931 call leg.
++ * \param caller Call rerouting/deflecting updated caller data. (NULL if data not updated.)
++ * \param deflection Call rerouting/deflecting redirection data.
++ * \param subscription_option Diverting user subscription option to specify if caller is notified.
++ *
++ * \note
++ * deflection->to is the new called number and must always be present.
++ * \note
++ * subscription option:
++ * noNotification(0),
++ * notificationWithoutDivertedToNr(1),
++ * notificationWithDivertedToNr(2)
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++static int rose_reroute_request_encode(struct pri *ctrl, q931_call *call,
++ const struct q931_party_id *caller, const struct q931_party_redirecting *deflection,
++ int subscription_option)
++{
++ unsigned char buffer[256];
++ unsigned char *end;
++
++ if (!caller) {
++ /*
++ * We are deflecting an incoming call back to the network.
++ * Therefore, the Caller-ID is the remote party.
++ */
++ caller = &call->remote_id;
++ }
++
++ switch (ctrl->switchtype) {
++ case PRI_SWITCH_EUROISDN_E1:
++ case PRI_SWITCH_EUROISDN_T1:
++ if (q931_is_ptmp(ctrl)) {
++ end =
++ enc_etsi_call_deflection(ctrl, buffer, buffer + sizeof(buffer), call,
++ &deflection->to);
++ } else {
++ end =
++ enc_etsi_call_rerouting(ctrl, buffer, buffer + sizeof(buffer), call,
++ caller, deflection, subscription_option);
++ }
++ break;
++ case PRI_SWITCH_QSIG:
++ end =
++ enc_qsig_call_rerouting(ctrl, buffer, buffer + sizeof(buffer), call, caller,
++ deflection, subscription_option);
++ break;
++ default:
+ return -1;
+ }
++ if (!end) {
++ return -1;
++ }
+
+- /* Remember that if we queue a facility IE for a facility message we
+- * have to explicitly send the facility message ourselves */
++ return pri_call_apdu_queue(call, Q931_FACILITY, buffer, end - buffer, NULL);
++}
+
+- res = q931_facility(c->pri, c);
+- if (res) {
+- pri_message(pri, "Could not schedule facility message for call %d\n", c->cr);
++/*!
++ * \brief Send the CallRerouting/CallDeflection message.
++ *
++ * \param ctrl D channel controller.
++ * \param call Q.931 call leg.
++ * \param caller Call rerouting/deflecting updated caller data. (NULL if data not updated.)
++ * \param deflection Call rerouting/deflecting redirection data.
++ * \param subscription_option Diverting user subscription option to specify if caller is notified.
++ *
++ * \note
++ * deflection->to is the new called number and must always be present.
++ * \note
++ * subscription option:
++ * noNotification(0),
++ * notificationWithoutDivertedToNr(1),
++ * notificationWithDivertedToNr(2)
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++int send_reroute_request(struct pri *ctrl, q931_call *call,
++ const struct q931_party_id *caller, const struct q931_party_redirecting *deflection,
++ int subscription_option)
++{
++ if (!deflection->to.number.str[0]) {
++ /* Must have a deflect to number. That is the point of deflection. */
+ return -1;
+ }
++ if (rose_reroute_request_encode(ctrl, call, caller, deflection, subscription_option)
++ || q931_facility(ctrl, call)) {
++ pri_message(ctrl,
++ "Could not schedule facility message for CallRerouting/CallDeflection message.\n");
++ return -1;
++ }
+
+ return 0;
+ }
++
++/*!
++ * \brief Send the Q.SIG CallRerouting invoke message.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param call Q.931 call leg.
++ * \param dest Destination number.
++ * \param original Original called number.
++ * \param reason Rerouting reason: cfu, cfb, cfnr
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++int qsig_cf_callrerouting(struct pri *ctrl, q931_call *call, const char *dest,
++ const char *original, const char *reason)
++{
++ struct q931_party_redirecting reroute;
++
++ q931_party_redirecting_init(&reroute);
++
++ /* Rerouting to the dest number. */
++ reroute.to.number.valid = 1;
++ reroute.to.number.plan = (PRI_TON_UNKNOWN << 4) | PRI_NPI_E163_E164;
++ reroute.to.number.presentation = PRI_PRES_ALLOWED | PRI_PRES_USER_NUMBER_UNSCREENED;
++ libpri_copy_string(reroute.to.number.str, dest, sizeof(reroute.to.number.str));
++
++ /* Rerouting from the original number. */
++ if (original) {
++ reroute.from.number.valid = 1;
++ reroute.from.number.plan = (PRI_TON_UNKNOWN << 4) | PRI_NPI_E163_E164;
++ libpri_copy_string(reroute.from.number.str, original, sizeof(reroute.from.number.str));
++ } else {
++ q931_party_address_to_id(&reroute.from, &call->called);
++ }
++ reroute.from.number.presentation = PRI_PRES_ALLOWED | PRI_PRES_USER_NUMBER_UNSCREENED;
++
++ /* Decode the rerouting reason. */
++ reroute.reason = PRI_REDIR_UNKNOWN;
++ if (!reason) {
++ /* No reason for rerouting given. */
++ } else if (!strcasecmp(reason, "cfu")) {
++ reroute.reason = PRI_REDIR_UNCONDITIONAL;
++ } else if (!strcasecmp(reason, "cfb")) {
++ reroute.reason = PRI_REDIR_FORWARD_ON_BUSY;
++ } else if (!strcasecmp(reason, "cfnr")) {
++ reroute.reason = PRI_REDIR_FORWARD_ON_NO_REPLY;
++ }
++
++ reroute.count = (call->redirecting.count < PRI_MAX_REDIRECTS)
++ ? call->redirecting.count + 1 : PRI_MAX_REDIRECTS;
++
++ if (!call->redirecting.orig_called.number.valid) {
++ /*
++ * Since we do not already have an originally called party, we
++ * must either be the first redirected to party or this call
++ * has not been redirected before.
++ *
++ * Preserve who redirected to us as the originally called party.
++ */
++ reroute.orig_called = call->redirecting.from;
++ reroute.orig_reason = call->redirecting.reason;
++ } else {
++ reroute.orig_called = call->redirecting.orig_called;
++ reroute.orig_reason = call->redirecting.orig_reason;
++ }
++
++ return send_reroute_request(ctrl, call, NULL, &reroute, 0 /* noNotification */);
++}
+ /* End QSIG CC-CallRerouting */
+
+-static int anfpr_pathreplacement_respond(struct pri *pri, q931_call *call, q931_ie *ie)
++/*
++ * From Mantis issue 7778 description: (ETS 300 258, ISO 13863)
++ * After both legs of the call are setup and Asterisk has a successful "tromboned" or bridged call ...
++ * Asterisk sees both 'B' channels (from trombone) are on same PRI/technology and initiates "Path Replacement" events
++ * a. Asterisk sends "Transfer Complete" messages to both call legs
++ * b. QSIG Switch sends "PathReplacement" message on one of the legs (random 1-10sec timer expires - 1st leg to send is it!)
++ * c. Asterisk rebroadcasts "PathReplacement" message to other call leg
++ * d. QSIG Switch sends "Disconnect" message on one of the legs (same random timer sequence as above)
++ * e. Asterisk rebroadcasts "Disconnect" message to other call leg
++ * f. QSIG Switch disconnects Asterisk call legs - callers are now within QSIG switch
++ *
++ * Just need to resend the message to the other tromboned leg of the call.
++ */
++static int anfpr_pathreplacement_respond(struct pri *ctrl, q931_call *call, q931_ie *ie)
+ {
+ int res;
+-
+- res = pri_call_apdu_queue_cleanup(call->bridged_call);
+- if (res) {
+- pri_message(pri, "Could not Clear queue ADPU\n");
+- return -1;
+- }
+-
++
++ pri_call_apdu_queue_cleanup(call->bridged_call);
++
+ /* Send message */
+- res = pri_call_apdu_queue(call->bridged_call, Q931_FACILITY, ie->data, ie->len, NULL, NULL);
++ res = pri_call_apdu_queue(call->bridged_call, Q931_FACILITY, ie->data, ie->len, NULL);
+ if (res) {
+- pri_message(pri, "Could not queue ADPU in facility message\n");
+- return -1;
++ pri_message(ctrl, "Could not queue ADPU in facility message\n");
++ return -1;
+ }
+-
++
+ /* Remember that if we queue a facility IE for a facility message we
+ * have to explicitly send the facility message ourselves */
+-
++
+ res = q931_facility(call->bridged_call->pri, call->bridged_call);
+ if (res) {
+- pri_message(pri, "Could not schedule facility message for call %d\n", call->bridged_call->cr);
++ pri_message(ctrl, "Could not schedule facility message for call %d\n",
++ call->bridged_call->cr);
+ return -1;
+ }
+
+ return 0;
+ }
++
+ /* AFN-PR */
+-int anfpr_initiate_transfer(struct pri *pri, q931_call *c1, q931_call *c2)
++/*!
++ * \brief Start a Q.SIG path replacement.
++ *
++ * \note Called for PRI_SWITCH_QSIG
++ *
++ * \note Did all the tests to see if we're on the same PRI and
++ * are on a compatible switchtype.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param c1 Q.931 call leg 1
++ * \param c2 Q.931 call leg 2
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++int anfpr_initiate_transfer(struct pri *ctrl, q931_call *c1, q931_call *c2)
+ {
+- /* Did all the tests to see if we're on the same PRI and
+- * are on a compatible switchtype */
+- /* TODO */
+- int i = 0;
+- int res = 0;
+- unsigned char buffer[255] = "";
+- unsigned short call_reference = c2->cr;
+- struct rose_component *comp = NULL, *compstk[10];
+- unsigned char buffer2[255] = "";
+- int compsp = 0;
+- static unsigned char op_tag[] = {
+- 0x0C,
+- };
+-
+- /* Channel 1 */
+- buffer[i++] = (ASN1_CONTEXT_SPECIFIC | Q932_PROTOCOL_EXTENSIONS);
+-
+- ASN1_ADD_SIMPLE(comp, COMP_TYPE_NFE, buffer, i);
+- ASN1_PUSH(compstk, compsp, comp);
+- ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0), buffer, i, 0);
+- ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2), buffer, i, 0);
+- ASN1_FIXUP(compstk, compsp, buffer, i);
+-
+- /* Interpretation component */
+- ASN1_ADD_BYTECOMP(comp, COMP_TYPE_INTERPRETATION, buffer, i, 2); /* reject - to get feedback from QSIG switch */
+-
+- ASN1_ADD_SIMPLE(comp, COMP_TYPE_INVOKE, buffer, i);
+- ASN1_PUSH(compstk, compsp, comp);
+-
+- ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, get_invokeid(pri));
+-
+- res = asn1_string_encode(ASN1_INTEGER, &buffer[i], sizeof(buffer)-i, sizeof(op_tag), op_tag, sizeof(op_tag));
+- if (res < 0)
++ unsigned char buffer[255];
++ unsigned char *pos;
++ unsigned char *end;
++ int res;
++ struct fac_extension_header header;
++ struct rose_msg_invoke msg;
++
++ end = buffer + sizeof(buffer);
++
++ 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 = 2; /* rejectAnyUnrecognisedInvokePdu */
++ pos = facility_encode_header(ctrl, buffer, end, &header);
++ if (!pos) {
+ return -1;
+- i += res;
+-
+- ASN1_ADD_SIMPLE(comp, (ASN1_SEQUENCE | ASN1_CONSTRUCTOR), buffer, i);
+- ASN1_PUSH(compstk, compsp, comp);
+- buffer[i++] = (0x0a);/* Enumeration endDesignation */
+- buffer[i++] = (0x01);/* Len */
+- buffer[i++] = (0x00);/* primaryEnd */
+- buffer[i++] = (0x81);/* redirectionNumber = presentationRestricted */
+- buffer[i++] = (0x00);/* Len */
+- buffer[i++] = (0x0a);/* Enumeration callStatus */
+- buffer[i++] = (0x01);/* Len */
+- buffer[i++] = (0x01);/* alerting */
++ }
+
+- /*
+- * Where does this element come from? It is not in Q.SIG ECMA-178.
+- * We send this but we will not accept it.
+- * This seems to be a cut and paste error from eect_initiate_transfer().
+- */
+- ASN1_ADD_WORDCOMP(comp, ASN1_INTEGER, buffer, i, call_reference);
++ memset(&msg, 0, sizeof(msg));
++ msg.operation = ROSE_QSIG_CallTransferComplete;
++ msg.invoke_id = get_invokeid(ctrl);
++ msg.args.qsig.CallTransferComplete.end_designation = 0; /* primaryEnd */
++ msg.args.qsig.CallTransferComplete.redirection.presentation = 1; /* presentationRestricted */
++ msg.args.qsig.CallTransferComplete.call_status = 1; /* alerting */
++ pos = rose_encode_invoke(ctrl, pos, end, &msg);
++ if (!pos) {
++ return -1;
++ }
+
+- ASN1_FIXUP(compstk, compsp, buffer, i);
+- ASN1_FIXUP(compstk, compsp, buffer, i);
+-
+- res = pri_call_apdu_queue(c1, Q931_FACILITY, buffer, i, NULL, NULL);
++ res = pri_call_apdu_queue(c1, Q931_FACILITY, buffer, pos - buffer, NULL);
+ if (res) {
+- pri_message(pri, "Could not queue ADPU in facility message\n");
++ pri_message(ctrl, "Could not queue ADPU in facility message\n");
+ return -1;
+ }
+-
++
+ /* Remember that if we queue a facility IE for a facility message we
+ * have to explicitly send the facility message ourselves */
+-
++
+ res = q931_facility(c1->pri, c1);
+ if (res) {
+- pri_message(pri, "Could not schedule facility message for call %d\n", c1->cr);
++ pri_message(ctrl, "Could not schedule facility message for call %d\n", c1->cr);
+ return -1;
+ }
+-
+- /* Channel 2 */
+- i = 0;
+- res = 0;
+- compsp = 0;
+-
+- buffer2[i++] = (ASN1_CONTEXT_SPECIFIC | Q932_PROTOCOL_EXTENSIONS);
+-
+- ASN1_ADD_SIMPLE(comp, COMP_TYPE_NFE, buffer2, i);
+- ASN1_PUSH(compstk, compsp, comp);
+- ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0), buffer2, i, 0);
+- ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2), buffer2, i, 0);
+- ASN1_FIXUP(compstk, compsp, buffer2, i);
+-
+- /* Interpretation component */
+- ASN1_ADD_BYTECOMP(comp, COMP_TYPE_INTERPRETATION, buffer2, i, 2); /* reject */
+-
+- ASN1_ADD_SIMPLE(comp, COMP_TYPE_INVOKE, buffer2, i);
+- ASN1_PUSH(compstk, compsp, comp);
+-
+- ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer2, i, get_invokeid(pri));
+-
+- res = asn1_string_encode(ASN1_INTEGER, &buffer2[i], sizeof(buffer2)-i, sizeof(op_tag), op_tag, sizeof(op_tag));
+- if (res < 0)
++
++ /* Reuse the previous message header */
++ pos = facility_encode_header(ctrl, buffer, end, &header);
++ if (!pos) {
+ return -1;
+- i += res;
+-
+- ASN1_ADD_SIMPLE(comp, (ASN1_SEQUENCE | ASN1_CONSTRUCTOR), buffer2, i);
+- ASN1_PUSH(compstk, compsp, comp);
+- buffer2[i++] = (0x0a);/* Enumeration endDesignation */
+- buffer2[i++] = (0x01);/* Len */
+- buffer2[i++] = (0x01);/* secondaryEnd */
+- buffer2[i++] = (0x81);/* redirectionNumber = presentationRestricted */
+- buffer2[i++] = (0x00);/* Len */
+- buffer2[i++] = (0x0a);/* Enumeration callStatus */
+- buffer2[i++] = (0x01);/* Len */
+- buffer2[i++] = (0x01);/* alerting */
++ }
+
+- /*
+- * Where does this element come from? It is not in Q.SIG ECMA-178.
+- * We send this but we will not accept it.
+- * This seems to be a cut and paste error from eect_initiate_transfer().
+- */
+- ASN1_ADD_WORDCOMP(comp, ASN1_INTEGER, buffer2, i, call_reference);
++ /* Update the previous message */
++ msg.invoke_id = get_invokeid(ctrl);
++ msg.args.qsig.CallTransferComplete.end_designation = 1; /* secondaryEnd */
++ pos = rose_encode_invoke(ctrl, pos, end, &msg);
++ if (!pos) {
++ return -1;
++ }
+
+- ASN1_FIXUP(compstk, compsp, buffer2, i);
+- ASN1_FIXUP(compstk, compsp, buffer2, i);
+-
+-
+- res = pri_call_apdu_queue(c2, Q931_FACILITY, buffer2, i, NULL, NULL);
++ res = pri_call_apdu_queue(c2, Q931_FACILITY, buffer, pos - buffer, NULL);
+ if (res) {
+- pri_message(pri, "Could not queue ADPU in facility message\n");
++ pri_message(ctrl, "Could not queue ADPU in facility message\n");
+ return -1;
+ }
+-
++
+ /* Remember that if we queue a facility IE for a facility message we
+ * have to explicitly send the facility message ourselves */
+-
++
+ res = q931_facility(c2->pri, c2);
+ if (res) {
+- pri_message(pri, "Could not schedule facility message for call %d\n", c1->cr);
++ pri_message(ctrl, "Could not schedule facility message for call %d\n", c2->cr);
+ return -1;
+ }
+-
++
+ return 0;
+ }
+ /* End AFN-PR */
+
+ /* AOC */
+-static int aoc_aoce_charging_request_decode(struct pri *pri, q931_call *call, unsigned char *data, int len)
++/*!
++ * \internal
++ * \brief Encode the ETSI AOCEChargingUnit invoke 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 chargedunits Number of units charged to encode.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *enc_etsi_aoce_charging_unit(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, long chargedunits)
+ {
+- int chargingcase = -1;
+- unsigned char *vdata = data;
+- struct rose_component *comp = NULL;
+- int pos1 = 0;
++ struct rose_msg_invoke msg;
+
+- if (pri->debug & PRI_DEBUG_AOC)
+- dump_apdu (pri, data, len);
++ pos = facility_encode_header(ctrl, pos, end, NULL);
++ if (!pos) {
++ return NULL;
++ }
+
+- do {
+- GET_COMPONENT(comp, pos1, vdata, len);
+- CHECK_COMPONENT(comp, ASN1_ENUMERATED, "!! Invalid AOC Charging Request argument. Expected Enumerated (0x0A) but Received 0x%02X\n");
+- ASN1_GET_INTEGER(comp, chargingcase);
+- if (chargingcase >= 0 && chargingcase <= 2) {
+- if (pri->debug & PRI_DEBUG_APDU)
+- pri_message(pri, "Channel %d/%d, Call %d - received AOC charging request - charging case: %i\n",
+- call->ds1no, call->channelno, call->cr, chargingcase);
+- } else {
+- pri_message(pri, "!! unkown AOC ChargingCase: 0x%02X", chargingcase);
+- chargingcase = -1;
+- }
+- NEXT_COMPONENT(comp, pos1);
+- } while (pos1 < len);
+- if (pos1 < len) {
+- pri_message(pri, "!! Only reached position %i in %i bytes long AOC-E structure:", pos1, len );
+- dump_apdu (pri, data, len);
+- return -1; /* Aborted before */
++ memset(&msg, 0, sizeof(msg));
++ msg.operation = ROSE_ETSI_AOCEChargingUnit;
++ msg.invoke_id = get_invokeid(ctrl);
++ msg.args.etsi.AOCEChargingUnit.type = 1; /* charging_unit */
++ if (chargedunits <= 0) {
++ msg.args.etsi.AOCEChargingUnit.charging_unit.free_of_charge = 1;
++ } else {
++ msg.args.etsi.AOCEChargingUnit.charging_unit.specific.recorded.num_records = 1;
++ msg.args.etsi.AOCEChargingUnit.charging_unit.specific.recorded.list[0].
++ number_of_units = chargedunits;
+ }
+- return 0;
++ pos = rose_encode_invoke(ctrl, pos, end, &msg);
++
++ return pos;
+ }
+-
+
+-static int aoc_aoce_charging_unit_decode(struct pri *pri, q931_call *call, unsigned char *data, int len)
++/*!
++ * \internal
++ * \brief Send the ETSI AOCEChargingUnit invoke message.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param call Call leg from which to encode AOC.
++ * \param chargedunits Number of units charged to encode.
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++static int aoc_aoce_charging_unit_encode(struct pri *ctrl, q931_call *call,
++ long chargedunits)
+ {
+- long chargingunits = 0, chargetype = -1, temp, chargeIdentifier = -1;
+- unsigned char *vdata = data;
+- struct rose_component *comp1 = NULL, *comp2 = NULL, *comp3 = NULL;
+- int pos1 = 0, pos2, pos3, sublen2, sublen3;
+- struct addressingdataelements_presentednumberunscreened chargednr;
++ unsigned char buffer[255];
++ unsigned char *end;
+
+- if (pri->debug & PRI_DEBUG_AOC)
+- dump_apdu (pri, data, len);
++ /* sample data: [ 91 a1 12 02 02 3a 78 02 01 24 30 09 30 07 a1 05 30 03 02 01 01 ] */
+
+- do {
+- GET_COMPONENT(comp1, pos1, vdata, len); /* AOCEChargingUnitInfo */
+- CHECK_COMPONENT(comp1, ASN1_SEQUENCE, "!! Invalid AOC-E Charging Unit argument. Expected Sequence (0x30) but Received 0x%02X\n");
+- SUB_COMPONENT(comp1, pos1);
+- GET_COMPONENT(comp1, pos1, vdata, len);
+- switch (comp1->type) {
+- case (ASN1_SEQUENCE | ASN1_CONSTRUCTOR): /* specificChargingUnits */
+- sublen2 = comp1->len;
+- pos2 = pos1;
+- comp2 = comp1;
+- SUB_COMPONENT(comp2, pos2);
+- do {
+- GET_COMPONENT(comp2, pos2, vdata, len);
+- switch (comp2->type) {
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1): /* RecordedUnitsList (0xA1) */
+- SUB_COMPONENT(comp2, pos2);
+- GET_COMPONENT(comp2, pos2, vdata, len);
+- CHECK_COMPONENT(comp2, ASN1_SEQUENCE, "!! Invalid AOC-E Charging Unit argument. Expected Sequence (0x30) but received 0x02%X\n"); /* RecordedUnits */
+- sublen3 = pos2 + comp2->len;
+- pos3 = pos2;
+- comp3 = comp2;
+- SUB_COMPONENT(comp3, pos3);
+- do {
+- GET_COMPONENT(comp3, pos3, vdata, len);
+- switch (comp3->type) {
+- case ASN1_INTEGER: /* numberOfUnits */
+- ASN1_GET_INTEGER(comp3, temp);
+- chargingunits += temp;
+- case ASN1_NULL: /* notAvailable */
+- break;
+- default:
+- pri_message(pri, "!! Don't know how to handle 0x%02X in AOC-E RecordedUnits\n", comp3->type);
+- }
+- NEXT_COMPONENT(comp3, pos3);
+- } while (pos3 < sublen3);
+- if (pri->debug & PRI_DEBUG_AOC)
+- pri_message(pri, "Channel %d/%d, Call %d - received AOC-E charging: %i unit%s\n",
+- call->ds1no, call->channelno, call->cr, chargingunits, (chargingunits == 1) ? "" : "s");
+- break;
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_2): /* AOCEBillingID (0xA2) */
+- SUB_COMPONENT(comp2, pos2);
+- GET_COMPONENT(comp2, pos2, vdata, len);
+- ASN1_GET_INTEGER(comp2, chargetype);
+- pri_message(pri, "!! not handled: Channel %d/%d, Call %d - received AOC-E billing ID: %i\n",
+- call->ds1no, call->channelno, call->cr, chargetype);
+- break;
+- default:
+- pri_message(pri, "!! Don't know how to handle 0x%02X in AOC-E RecordedUnitsList\n", comp2->type);
+- }
+- NEXT_COMPONENT(comp2, pos2);
+- } while (pos2 < sublen2);
+- break;
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_1): /* freeOfCharge (0x81) */
+- if (pri->debug & PRI_DEBUG_AOC)
+- pri_message(pri, "Channel %d/%d, Call %d - received AOC-E free of charge\n", call->ds1no, call->channelno, call->cr);
+- chargingunits = 0;
+- break;
+- default:
+- pri_message(pri, "!! Invalid AOC-E specificChargingUnits. Expected Sequence (0x30) or Object Identifier (0x81/0x01) but received 0x%02X\n", comp1->type);
+- }
+- NEXT_COMPONENT(comp1, pos1);
+- GET_COMPONENT(comp1, pos1, vdata, len); /* get optional chargingAssociation. will 'break' when reached end of structure */
+- switch (comp1->type) {
+- /* TODO: charged number is untested - please report! */
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_0): /* chargedNumber (0xA0) */
+- if(rose_presented_number_unscreened_decode(pri, call, comp1->data, comp1->len, &chargednr) != 0)
+- return -1;
+- pri_message(pri, "!! not handled: Received ChargedNr '%s' \n", chargednr.partyaddress);
+- pri_message(pri, " ton = %d, pres = %d, npi = %d\n", chargednr.ton, chargednr.pres, chargednr.npi);
+- break;
+- case ASN1_INTEGER:
+- ASN1_GET_INTEGER(comp1, chargeIdentifier);
+- break;
+- default:
+- pri_message(pri, "!! Invalid AOC-E chargingAssociation. Expected Object Identifier (0xA0) or Integer (0x02) but received 0x%02X\n", comp1->type);
+- }
+- NEXT_COMPONENT(comp1, pos1);
+- } while (pos1 < len);
++ end =
++ enc_etsi_aoce_charging_unit(ctrl, buffer, buffer + sizeof(buffer), chargedunits);
++ if (!end) {
++ return -1;
++ }
+
+- if (pos1 < len) {
+- pri_message(pri, "!! Only reached position %i in %i bytes long AOC-E structure:", pos1, len );
+- dump_apdu (pri, data, len);
+- return -1; /* oops - aborted before */
++ /* Remember that if we queue a facility IE for a facility message we
++ * have to explicitly send the facility message ourselves */
++ if (pri_call_apdu_queue(call, Q931_FACILITY, buffer, end - buffer, NULL)
++ || q931_facility(call->pri, call)) {
++ pri_message(ctrl, "Could not schedule facility message for call %d\n", call->cr);
++ return -1;
+ }
+- call->aoc_units = chargingunits;
+-
++
+ return 0;
+ }
++/* End AOC */
+
+-static int aoc_aoce_charging_unit_encode(struct pri *pri, q931_call *c, long chargedunits)
++/* ===== Call Transfer Supplementary Service (ECMA-178) ===== */
++
++/*!
++ * \internal
++ * \brief Encode the Q.SIG CallTransferComplete invoke 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 call Call leg from which to encode call transfer.
++ * \param call_status TRUE if call is alerting.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *enc_qsig_call_transfer_complete(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, q931_call *call, int call_status)
+ {
+- /* sample data: [ 91 a1 12 02 02 3a 78 02 01 24 30 09 30 07 a1 05 30 03 02 01 01 ] */
+- int i = 0, res = 0, compsp = 0;
+- unsigned char buffer[255] = "";
+- struct rose_component *comp = NULL, *compstk[10];
++ struct fac_extension_header header;
++ struct rose_msg_invoke msg;
+
+- /* ROSE protocol (0x91)*/
+- buffer[i++] = (ASN1_CONTEXT_SPECIFIC | Q932_PROTOCOL_ROSE);
++ 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;
++ }
+
+- /* ROSE Component (0xA1,len)*/
+- ASN1_ADD_SIMPLE(comp, COMP_TYPE_INVOKE, buffer, i);
+- ASN1_PUSH(compstk, compsp, comp);
++ memset(&msg, 0, sizeof(msg));
++ msg.operation = ROSE_QSIG_CallTransferComplete;
++ msg.invoke_id = get_invokeid(ctrl);
++ msg.args.qsig.CallTransferComplete.end_designation = 0; /* primaryEnd */
+
+- /* ROSE invokeId component (0x02,len,id)*/
+- ASN1_ADD_WORDCOMP(comp, INVOKE_IDENTIFIER, buffer, i, ++pri->last_invoke);
++ /* redirectionNumber is the local_id.number */
++ q931_copy_presented_number_screened_to_rose(ctrl,
++ &msg.args.qsig.CallTransferComplete.redirection, &call->local_id.number);
+
+- /* ROSE operationId component (0x02,0x01,0x24)*/
+- ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, ROSE_AOC_AOCE_CHARGING_UNIT);
++ /* redirectionName is the local_id.name */
++ if (call->local_id.name.valid) {
++ msg.args.qsig.CallTransferComplete.redirection_name_present = 1;
++ q931_copy_name_to_rose(ctrl,
++ &msg.args.qsig.CallTransferComplete.redirection_name,
++ &call->local_id.name);
++ }
+
+- /* AOCEChargingUnitInfo (0x30,len) */
+- ASN1_ADD_SIMPLE(comp, (ASN1_CONSTRUCTOR | ASN1_SEQUENCE), buffer, i);
+- ASN1_PUSH(compstk, compsp, comp);
++ if (call_status) {
++ msg.args.qsig.CallTransferComplete.call_status = 1; /* alerting */
++ }
++ pos = rose_encode_invoke(ctrl, pos, end, &msg);
+
+- if (chargedunits > 0) {
+- /* SpecificChargingUnits (0x30,len) */
+- ASN1_ADD_SIMPLE(comp, (ASN1_CONSTRUCTOR | ASN1_SEQUENCE), buffer, i);
+- ASN1_PUSH(compstk, compsp, comp);
++ return pos;
++}
+
+- /* RecordedUnitsList (0xA1,len) */
+- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1), buffer, i);
+- ASN1_PUSH(compstk, compsp, comp);
+-
+- /* RecordedUnits (0x30,len) */
+- ASN1_ADD_SIMPLE(comp, (ASN1_CONSTRUCTOR | ASN1_SEQUENCE), buffer, i);
+- ASN1_PUSH(compstk, compsp, comp);
+-
+- /* NumberOfUnits (0x02,len,charge) */
+- ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, chargedunits);
++/*!
++ * \internal
++ * \brief Encode the ETSI EctInform invoke 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 call Call leg from which to encode inform message.
++ * \param call_status TRUE if call is alerting.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *enc_etsi_ect_inform(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, q931_call *call, int call_status)
++{
++ struct rose_msg_invoke msg;
+
+- ASN1_FIXUP(compstk, compsp, buffer, i);
+- ASN1_FIXUP(compstk, compsp, buffer, i);
+- ASN1_FIXUP(compstk, compsp, buffer, i);
+- } else {
+- /* freeOfCharge (0x81,0) */
+- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_1), buffer, i);
++ pos = facility_encode_header(ctrl, pos, end, NULL);
++ if (!pos) {
++ return NULL;
+ }
+- ASN1_FIXUP(compstk, compsp, buffer, i);
+- ASN1_FIXUP(compstk, compsp, buffer, i);
+-
+- if (pri->debug & PRI_DEBUG_AOC)
+- dump_apdu (pri, buffer, i);
+-
+- /* code below is untested */
+- res = pri_call_apdu_queue(c, Q931_FACILITY, buffer, i, NULL, NULL);
+- if (res) {
+- pri_message(pri, "Could not queue APDU in facility message\n");
+- return -1;
++
++ memset(&msg, 0, sizeof(msg));
++ msg.operation = ROSE_ETSI_EctInform;
++ msg.invoke_id = get_invokeid(ctrl);
++
++ if (!call_status) {
++ msg.args.etsi.EctInform.status = 1;/* active */
++
++ /*
++ * EctInform(active) contains the redirectionNumber
++ * redirectionNumber is the local_id.number
++ */
++ msg.args.etsi.EctInform.redirection_present = 1;
++ q931_copy_presented_number_unscreened_to_rose(ctrl,
++ &msg.args.etsi.EctInform.redirection, &call->local_id.number);
+ }
+
+- /* Remember that if we queue a facility IE for a facility message we
+- * have to explicitly send the facility message ourselves */
+- res = q931_facility(c->pri, c);
+- if (res) {
+- pri_message(pri, "Could not schedule facility message for call %d\n", c->cr);
++ pos = rose_encode_invoke(ctrl, pos, end, &msg);
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Encode and queue the CallTransferComplete/EctInform invoke message.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param call Call leg from which to encode call transfer.
++ * \param call_status TRUE if call is alerting.
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++static int rose_call_transfer_complete_encode(struct pri *ctrl, q931_call *call,
++ int call_status)
++{
++ unsigned char buffer[256];
++ unsigned char *end;
++
++ switch (ctrl->switchtype) {
++ case PRI_SWITCH_EUROISDN_E1:
++ case PRI_SWITCH_EUROISDN_T1:
++ end =
++ enc_etsi_ect_inform(ctrl, buffer, buffer + sizeof(buffer), call, call_status);
++ break;
++ case PRI_SWITCH_QSIG:
++ end =
++ enc_qsig_call_transfer_complete(ctrl, buffer, buffer + sizeof(buffer), call,
++ call_status);
++ break;
++ default:
+ return -1;
+ }
++ if (!end) {
++ return -1;
++ }
+
+- return 0;
++ return pri_call_apdu_queue(call, Q931_FACILITY, buffer, end - buffer, NULL);
+ }
+-/* End AOC */
+
+-static int rose_calling_name_decode(struct pri *pri, q931_call *call, struct rose_component *choice, int len)
++/* ===== End Call Transfer Supplementary Service (ECMA-178) ===== */
++
++/*!
++ * \internal
++ * \brief Encode the Q.SIG CalledName invoke 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 name Name data which to encode name.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *enc_qsig_called_name(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const struct q931_party_name *name)
+ {
+- int i = 0;
+- struct rose_component *comp = NULL;
+- unsigned char *vdata = choice->data;
+- int characterSet = 1;
+- switch (choice->type) {
+- case ROSE_NAME_PRESENTATION_ALLOWED_SIMPLE:
+- memcpy(call->callername, choice->data, choice->len);
+- call->callername[choice->len] = 0;
+- if (pri->debug & PRI_DEBUG_APDU)
+- pri_message(pri, " Received simple calling name '%s'\n", call->callername);
+- return 0;
++ struct fac_extension_header header;
++ struct rose_msg_invoke msg;
+
+- case ROSE_NAME_PRESENTATION_ALLOWED_EXTENDED:
+- do {
+- GET_COMPONENT(comp, i, vdata, len);
+- CHECK_COMPONENT(comp, ASN1_OCTETSTRING, "Don't know what to do if nameData is of type 0x%x\n");
+- memcpy(call->callername, comp->data, comp->len);
+- call->callername[comp->len] = 0;
+- NEXT_COMPONENT(comp, i);
++ 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;
++ }
+
+- GET_COMPONENT(comp, i, vdata, len);
+- CHECK_COMPONENT(comp, ASN1_INTEGER, "Don't know what to do if CharacterSet is of type 0x%x\n");
+- ASN1_GET_INTEGER(comp, characterSet);
+- }
+- while (0);
++ memset(&msg, 0, sizeof(msg));
++ msg.operation = ROSE_QSIG_CalledName;
++ msg.invoke_id = get_invokeid(ctrl);
+
+- if (pri->debug & PRI_DEBUG_APDU)
+- pri_message(pri, " Received extended calling name '%s', characterset %d\n", call->callername, characterSet);
+- return 0;
+- case ROSE_NAME_PRESENTATION_RESTRICTED_SIMPLE:
+- case ROSE_NAME_PRESENTATION_RESTRICTED_EXTENDED:
+- case ROSE_NAME_PRESENTATION_RESTRICTED_NULL:
+- case ROSE_NAME_NOT_AVAIL:
+- default:
+- if (pri->debug & PRI_DEBUG_APDU)
+- pri_message(pri, "Do not handle argument of type 0x%X\n", choice->type);
+- return -1;
+- }
++ /* CalledName */
++ q931_copy_name_to_rose(ctrl, &msg.args.qsig.CalledName.name, name);
++
++ pos = rose_encode_invoke(ctrl, pos, end, &msg);
++
++ return pos;
+ }
+-/* ===== Call Transfer Supplementary Service (ECMA-178) ===== */
+
+-static int rose_party_number_decode(struct pri *pri, q931_call *call, unsigned char *data, int len, struct addressingdataelements_presentednumberunscreened *value)
++/*!
++ * \internal
++ * \brief Encode and queue the Q.SIG CalledName invoke message.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param call Call leg from which to encode name.
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++int rose_called_name_encode(struct pri *ctrl, q931_call *call, int messagetype)
+ {
+- int i = 0;
+- int size = 0;
+- struct rose_component *comp = NULL;
+- unsigned char *vdata = data;
++ unsigned char buffer[256];
++ unsigned char *end;
+
++ /* CalledName is the local_id.name */
++ end = enc_qsig_called_name(ctrl, buffer, buffer + sizeof(buffer),
++ &call->local_id.name);
++ if (!end) {
++ return -1;
++ }
+
+- do {
+- GET_COMPONENT(comp, i, vdata, len);
++ return pri_call_apdu_queue(call, messagetype, buffer, end - buffer, NULL);
++}
+
+- switch(comp->type) {
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_0): /* [0] IMPLICIT NumberDigits -- default: unknownPartyNumber */
+- if (pri->debug & PRI_DEBUG_APDU)
+- pri_message(pri, " PartyNumber: UnknownPartyNumber len=%d\n", len);
+- size = rose_number_digits_decode(pri, call, comp->data, comp->len, value);
+- if (size < 0)
+- return -1;
+- value->npi = PRI_NPI_UNKNOWN;
+- value->ton = PRI_TON_UNKNOWN;
+- break;
++/*!
++ * \internal
++ * \brief Encode the Q.SIG ConnectedName invoke 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 name Name data which to encode name.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *enc_qsig_connected_name(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const struct q931_party_name *name)
++{
++ struct fac_extension_header header;
++ struct rose_msg_invoke msg;
+
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1): /* [1] IMPLICIT PublicPartyNumber */
+- if (pri->debug & PRI_DEBUG_APDU)
+- pri_message(pri, " PartyNumber: PublicPartyNumber len=%d\n", len);
+- size = rose_public_party_number_decode(pri, call, comp->data, comp->len, value);
+- if (size < 0)
+- return -1;
+- value->npi = PRI_NPI_E163_E164;
+- break;
++ 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;
++ }
+
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_3): /* [3] IMPLICIT NumberDigits -- not used: dataPartyNumber */
+- pri_message(pri, "!! PartyNumber: dataPartyNumber is reserved!\n");
+- size = rose_number_digits_decode(pri, call, comp->data, comp->len, value);
+- if (size < 0)
+- return -1;
+- value->npi = PRI_NPI_X121 /* ??? */;
+- value->ton = PRI_TON_UNKNOWN /* ??? */;
+- break;
++ memset(&msg, 0, sizeof(msg));
++ msg.operation = ROSE_QSIG_ConnectedName;
++ msg.invoke_id = get_invokeid(ctrl);
+
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_4): /* [4] IMPLICIT NumberDigits -- not used: telexPartyNumber */
+- pri_message(pri, "!! PartyNumber: telexPartyNumber is reserved!\n");
+- size = rose_number_digits_decode(pri, call, comp->data, comp->len, value);
+- if (size < 0)
+- return -1;
+- value->npi = PRI_NPI_F69 /* ??? */;
+- value->ton = PRI_TON_UNKNOWN /* ??? */;
+- break;
++ /* ConnectedName */
++ q931_copy_name_to_rose(ctrl, &msg.args.qsig.ConnectedName.name, name);
+
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_5): /* [5] IMPLICIT PrivatePartyNumber */
+- if (pri->debug & PRI_DEBUG_APDU)
+- pri_message(pri, " PartyNumber: PrivatePartyNumber len=%d\n", len);
+- size = rose_private_party_number_decode(pri, call, comp->data, comp->len, value);
+- if (size < 0)
+- return -1;
+- value->npi = PRI_NPI_PRIVATE;
+- break;
++ pos = rose_encode_invoke(ctrl, pos, end, &msg);
+
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_8): /* [8] IMPLICIT NumberDigits -- not used: nationalStandatdPartyNumber */
+- pri_message(pri, "!! PartyNumber: nationalStandardPartyNumber is reserved!\n");
+- size = rose_number_digits_decode(pri, call, comp->data, comp->len, value);
+- if (size < 0)
+- return -1;
+- value->npi = PRI_NPI_NATIONAL;
+- value->ton = PRI_TON_NATIONAL;
+- break;
++ return pos;
++}
+
+- default:
+- pri_message(pri, "Invalid PartyNumber component 0x%X\n", comp->type);
+- return -1;
+- }
+- ASN1_FIXUP_LEN(comp, size);
+- if (pri->debug & PRI_DEBUG_APDU)
+- pri_message(pri, " PartyNumber: '%s' size=%d len=%d\n", value->partyaddress, size, len);
+- return size;
++/*!
++ * \internal
++ * \brief Encode and queue the Q.SIG ConnectedName invoke message.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param call Call leg from which to encode name.
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++int rose_connected_name_encode(struct pri *ctrl, q931_call *call, int messagetype)
++{
++ unsigned char buffer[256];
++ unsigned char *end;
++
++ /* ConnectedName is the local_id.name */
++ end = enc_qsig_connected_name(ctrl, buffer, buffer + sizeof(buffer),
++ &call->local_id.name);
++ if (!end) {
++ return -1;
+ }
+- while (0);
+
+- return -1;
++ return pri_call_apdu_queue(call, messagetype, buffer, end - buffer, NULL);
+ }
+
+-
+-static int rose_number_screened_decode(struct pri *pri, q931_call *call, unsigned char *data, int len, struct addressingdataelements_presentednumberscreened *value)
++/*!
++ * \brief Put the APDU on the call queue.
++ *
++ * \param call Call to enqueue message.
++ * \param messagetype Q.931 message type.
++ * \param apdu Facility ie contents buffer.
++ * \param apdu_len Length of the contents buffer.
++ * \param response Sender supplied information to handle APDU response messages.
++ * NULL if don't care about responses.
++ *
++ * \note
++ * Only APDU messages with an invoke component can supply a response pointer.
++ * If any other APDU messages supply a response pointer then aliasing of the
++ * invoke_id can occur.
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++int pri_call_apdu_queue(q931_call *call, int messagetype, const unsigned char *apdu, int apdu_len, struct apdu_callback_data *response)
+ {
+- int i = 0;
+- int size = 0;
+- struct rose_component *comp = NULL;
+- unsigned char *vdata = data;
++ struct apdu_event *cur = NULL;
++ struct apdu_event *new_event = NULL;
+
+- int scrind = -1;
+-
+- do {
+- /* Party Number */
+- GET_COMPONENT(comp, i, vdata, len);
+- size = rose_party_number_decode(pri, call, (u_int8_t *)comp, comp->len + 2, (struct addressingdataelements_presentednumberunscreened*) value);
+- if (size < 0)
++ if (!call || !messagetype || !apdu
++ || apdu_len < 1 || sizeof(new_event->apdu) < apdu_len) {
++ return -1;
++ }
++ switch (messagetype) {
++ case Q931_FACILITY:
++ break;
++ default:
++ if (q931_is_dummy_call(call)) {
++ pri_error(call->pri, "!! Cannot send %s message on dummy call reference.\n",
++ msg2str(messagetype));
+ return -1;
+- comp->len = size;
+- NEXT_COMPONENT(comp, i);
++ }
++ break;
++ }
+
+- /* Screening Indicator */
+- GET_COMPONENT(comp, i, vdata, len);
+- CHECK_COMPONENT(comp, ASN1_ENUMERATED, "Don't know what to do with NumberScreened ROSE component type 0x%x\n");
+- ASN1_GET_INTEGER(comp, scrind);
+- // Todo: scrind = screeningindicator_for_q931(pri, scrind);
+- NEXT_COMPONENT(comp, i);
++ new_event = calloc(1, sizeof(*new_event));
++ if (!new_event) {
++ pri_error(call->pri, "!! Malloc failed!\n");
++ return -1;
++ }
+
+- value->scrind = scrind;
++ /* Fill in the APDU event */
++ new_event->message = messagetype;
++ if (response) {
++ new_event->response = *response;
++ }
++ new_event->call = call;
++ new_event->apdu_len = apdu_len;
++ memcpy(new_event->apdu, apdu, apdu_len);
+
+- if (pri->debug & PRI_DEBUG_APDU)
+- pri_message(pri, " NumberScreened: '%s' ScreeningIndicator=%d i=%d len=%d\n", value->partyaddress, scrind, i, len);
+-
+- return i-2; // We do not have a sequence header here.
++ /* Append APDU event to the end of the list. */
++ if (call->apdus) {
++ for (cur = call->apdus; cur->next; cur = cur->next) {
++ }
++ cur->next = new_event;
++ } else {
++ call->apdus = new_event;
+ }
+- while (0);
+
+- return -1;
++ return 0;
+ }
+
+-
+-static int rose_presented_number_screened_decode(struct pri *pri, q931_call *call, unsigned char *data, int len, struct addressingdataelements_presentednumberscreened *value)
++/* Used by q931.c to cleanup the apdu queue upon destruction of a call */
++void pri_call_apdu_queue_cleanup(q931_call *call)
+ {
+- int i = 0;
+- int size = 0;
+- struct rose_component *comp = NULL;
+- unsigned char *vdata = data;
++ struct apdu_event *cur_event;
++ struct apdu_event *free_event;
+
+- /* Fill in default values */
+- value->ton = PRI_TON_UNKNOWN;
+- value->npi = PRI_NPI_UNKNOWN;
+- value->pres = -1; /* Data is not available */
++ if (call) {
++ cur_event = call->apdus;
++ call->apdus = NULL;
++ while (cur_event) {
++ if (cur_event->response.callback) {
++ /* Indicate to callback that the APDU is being cleaned up. */
++ cur_event->response.callback(APDU_CALLBACK_REASON_CLEANUP, call->pri,
++ call, cur_event, NULL);
+
+- do {
+- GET_COMPONENT(comp, i, vdata, len);
++ /* Stop any response timeout. */
++ pri_schedule_del(call->pri, cur_event->timer);
++ }
++ free_event = cur_event;
++ cur_event = cur_event->next;
++ free(free_event);
++ }
++ }
++}
+
+- switch(comp->type) {
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_0): /* [0] IMPLICIT presentationAllowedNumber */
+- if (pri->debug & PRI_DEBUG_APDU)
+- pri_message(pri, " PresentedNumberScreened: presentationAllowedNumber comp->len=%d\n", comp->len);
+- value->pres = PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN;
+- size = rose_number_screened_decode(pri, call, comp->data, comp->len, value);
+- if (size < 0)
+- return -1;
+- ASN1_FIXUP_LEN(comp, size);
+- return size + 2;
++/*!
++ * \internal
++ * \brief Find an outstanding APDU with the given invoke id.
++ *
++ * \param call Call to find APDU.
++ * \param invoke_id Invoke id to match outstanding APDUs in queue.
++ *
++ * \retval apdu_event if found.
++ * \retval NULL if not found.
++ */
++static struct apdu_event *pri_call_apdu_find(struct q931_call *call, int invoke_id)
++{
++ struct apdu_event *apdu;
+
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_1): /* [1] IMPLICIT presentationRestricted */
+- if (pri->debug & PRI_DEBUG_APDU)
+- pri_message(pri, " PresentedNumberScreened: presentationRestricted comp->len=%d\n", comp->len);
+- if (comp->len != 0) { /* must be NULL */
+- pri_error(pri, "!! Invalid PresentationRestricted component received (len != 0)\n");
+- return -1;
+- }
+- value->pres = PRES_PROHIB_USER_NUMBER_PASSED_SCREEN;
+- return 2;
++ for (apdu = call->apdus; apdu; apdu = apdu->next) {
++ /*
++ * Note: The APDU cannot be sent and still in the queue without a
++ * callback and timeout timer active. Therefore, an invoke_id of
++ * zero is valid and not just the result of a memset().
++ */
++ if (apdu->response.invoke_id == invoke_id && apdu->sent) {
++ break;
++ }
++ }
++ return apdu;
++}
+
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2): /* [2] IMPLICIT numberNotAvailableDueToInterworking */
+- if (pri->debug & PRI_DEBUG_APDU)
+- pri_message(pri, " PresentedNumberScreened: NumberNotAvailableDueToInterworking comp->len=%d\n", comp->len);
+- if (comp->len != 0) { /* must be NULL */
+- pri_error(pri, "!! Invalid NumberNotAvailableDueToInterworking component received (len != 0)\n");
+- return -1;
+- }
+- value->pres = PRES_NUMBER_NOT_AVAILABLE;
+- if (pri->debug & PRI_DEBUG_APDU)
+- pri_message(pri, " PresentedNumberScreened: numberNotAvailableDueToInterworking Type=0x%X i=%d len=%d size=%d\n", comp->type, i, len);
+- return 2;
++/*!
++ * \brief Delete the given APDU event from the given call.
++ *
++ * \param call Call to remove the APDU.
++ * \param doomed APDU event to delete.
++ *
++ * \return Nothing
++ */
++void pri_call_apdu_delete(struct q931_call *call, struct apdu_event *doomed)
++{
++ struct apdu_event **prev;
++ struct apdu_event *cur;
+
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_3): /* [3] IMPLICIT presentationRestrictedNumber */
+- if (pri->debug & PRI_DEBUG_APDU)
+- pri_message(pri, " PresentedNumberScreened: presentationRestrictedNumber comp->len=%d\n", comp->len);
+- value->pres = PRES_PROHIB_USER_NUMBER_PASSED_SCREEN;
+- size = rose_number_screened_decode(pri, call, comp->data, comp->len, value);
+- if (size < 0)
+- return -1;
+- ASN1_FIXUP_LEN(comp, size);
+- return size + 2;
++ /* Find APDU in list. */
++ for (prev = &call->apdus, cur = call->apdus;
++ cur;
++ prev = &cur->next, cur = cur->next) {
++ if (cur == doomed) {
++ /* Stop any response timeout. */
++ pri_schedule_del(call->pri, cur->timer);
+
+- default:
+- pri_message(pri, "Invalid PresentedNumberScreened component 0x%X\n", comp->type);
++ /* Remove APDU from list. */
++ *prev = cur->next;
++ free(cur);
++ break;
+ }
+- return -1;
+ }
+- while (0);
+-
+- return -1;
+ }
+
+-
+-static int rose_call_transfer_complete_decode(struct pri *pri, q931_call *call, struct rose_component *sequence, int len)
++/*! \note Only called when sending the SETUP message. */
++int pri_call_add_standard_apdus(struct pri *ctrl, q931_call *call)
+ {
+- int i = 0;
+- struct rose_component *comp = NULL;
+- unsigned char *vdata = sequence->data;
+- int res = 0;
++ if (!ctrl->sendfacility) {
++ return 0;
++ }
+
+- int end_designation = 0;
+- struct addressingdataelements_presentednumberscreened redirection_number;
+- char redirection_name[50] = "";
+- int call_status = 0;
+- redirection_number.partyaddress[0] = 0;
+- redirection_number.partysubaddress[0] = 0;
+- call->callername[0] = 0;
+- call->callernum[0] = 0;
++ switch (ctrl->switchtype) {
++ case PRI_SWITCH_EUROISDN_E1:
++ case PRI_SWITCH_EUROISDN_T1:
++ if (q931_is_ptmp(ctrl)) {
++ /* PTMP mode */
++ break;
++ }
++ /* PTP mode */
++ if (call->redirecting.count) {
++ rose_diverting_leg_information2_encode(ctrl, call);
+
++ /*
++ * Expect a DivertingLegInformation3 to update the COLR of the
++ * redirecting-to party we are attempting to call now.
++ */
++ call->redirecting.state = Q931_REDIRECTING_STATE_EXPECTING_RX_DIV_LEG_3;
++ }
++ break;
++ case PRI_SWITCH_QSIG:
++ /* For Q.SIG it does network and cpe operations */
++ if (call->redirecting.count) {
++ rose_diverting_leg_information2_encode(ctrl, call);
+
+- /* Data checks */
+- if (sequence->type != (ASN1_CONSTRUCTOR | ASN1_SEQUENCE)) { /* Constructed Sequence */
+- pri_message(pri, "Invalid callTransferComplete argument. (Not a sequence)\n");
+- return -1;
++ /*
++ * Expect a DivertingLegInformation3 to update the COLR of the
++ * redirecting-to party we are attempting to call now.
++ */
++ call->redirecting.state = Q931_REDIRECTING_STATE_EXPECTING_RX_DIV_LEG_3;
++ }
++ add_callername_facility_ies(ctrl, call, 1);
++ break;
++ case PRI_SWITCH_NI2:
++ add_callername_facility_ies(ctrl, call, (ctrl->localtype == PRI_CPE));
++ break;
++ case PRI_SWITCH_DMS100:
++ if (ctrl->localtype == PRI_CPE) {
++ add_dms100_transfer_ability_apdu(ctrl, call);
++ }
++ break;
++ default:
++ break;
+ }
+
+- if (sequence->len == ASN1_LEN_INDEF) {
+- len -= 4; /* For the 2 extra characters at the end
+- * and two characters of header */
+- } else
+- len -= 2;
++ return 0;
++}
+
+- if (pri->debug & PRI_DEBUG_APDU)
+- pri_message(pri, " CT-Complete: len=%d\n", len);
++/*!
++ * \brief Send the CallTransferComplete/EctInform invoke message.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param call Call leg from which to encode call transfer.
++ * \param call_status TRUE if call is alerting.
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++int send_call_transfer_complete(struct pri *ctrl, q931_call *call, int call_status)
++{
++ if (rose_call_transfer_complete_encode(ctrl, call, call_status)
++ || q931_facility(ctrl, call)) {
++ pri_message(ctrl,
++ "Could not schedule facility message for call transfer completed.\n");
++ return -1;
++ }
+
+- do {
+- /* End Designation */
+- GET_COMPONENT(comp, i, vdata, len);
+- CHECK_COMPONENT(comp, ASN1_ENUMERATED, "Invalid endDesignation type 0x%X of ROSE callTransferComplete component received\n");
+- ASN1_GET_INTEGER(comp, end_designation);
+- NEXT_COMPONENT(comp, i);
+- if (pri->debug & PRI_DEBUG_APDU)
+- pri_message(pri, " CT-Complete: Received endDesignation=%d\n", end_designation);
++ return 0;
++}
+
++/*!
++ * \internal
++ * \brief Encode a plain facility ETSI error code.
++ *
++ * \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 call Call leg from which to encode error message response.
++ * \param invoke_id Invoke id to put in error message response.
++ * \param code Error code to put in error message response.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *enc_etsi_error(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, q931_call *call, int invoke_id, enum rose_error_code code)
++{
++ struct rose_msg_error msg;
+
+- /* Redirection Number */
+- GET_COMPONENT(comp, i, vdata, len);
+- res = rose_presented_number_screened_decode(pri, call, (u_int8_t *)comp, comp->len + 2, &redirection_number);
+- if (res < 0)
+- return -1;
+- comp->len = res;
+- if (res > 2) {
+- if (pri->debug & PRI_DEBUG_APDU)
+- pri_message(pri, " CT-Complete: Received redirectionNumber=%s\n", redirection_number.partyaddress);
+- strncpy(call->callernum, redirection_number.partyaddress, 20);
+- call->callernum[20] = 0;
+- }
+- NEXT_COMPONENT(comp, i);
++ pos = facility_encode_header(ctrl, pos, end, NULL);
++ if (!pos) {
++ return NULL;
++ }
+
++ memset(&msg, 0, sizeof(msg));
++ msg.invoke_id = invoke_id;
++ msg.code = code;
+
+-#if 0 /* This one is optional. How do we check if it is there? */
+- /* Basic Call Info Elements */
+- GET_COMPONENT(comp, i, vdata, len);
+- NEXT_COMPONENT(comp, i);
+-#endif
++ pos = rose_encode_error(ctrl, pos, end, &msg);
+
++ return pos;
++}
+
+- /* Redirection Name */
+- GET_COMPONENT(comp, i, vdata, len);
+- res = asn1_name_decode((u_int8_t *)comp, comp->len + 2, redirection_name, sizeof(redirection_name));
+- if (res < 0)
+- return -1;
+- memcpy(call->callername, comp->data, comp->len);
+- call->callername[comp->len] = 0;
+- ASN1_FIXUP_LEN(comp, res);
+- comp->len = res;
+- NEXT_COMPONENT(comp, i);
+- if (pri->debug & PRI_DEBUG_APDU)
+- pri_message(pri, " CT-Complete: Received redirectionName '%s'\n", redirection_name);
++/*!
++ * \internal
++ * \brief Encode a plain facility Q.SIG error code.
++ *
++ * \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 call Call leg from which to encode error message response.
++ * \param invoke_id Invoke id to put in error message response.
++ * \param code Error code to put in error message response.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *enc_qsig_error(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, q931_call *call, int invoke_id, enum rose_error_code code)
++{
++ struct fac_extension_header header;
++ struct rose_msg_error 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;
++ }
+
+- /* Call Status */
+- GET_COMPONENT(comp, i, vdata, len);
+- CHECK_COMPONENT(comp, ASN1_ENUMERATED, "Invalid callStatus type 0x%X of ROSE callTransferComplete component received\n");
+- ASN1_GET_INTEGER(comp, call_status);
+- NEXT_COMPONENT(comp, i);
+- if (pri->debug & PRI_DEBUG_APDU)
+- pri_message(pri, " CT-Complete: Received callStatus=%d\n", call_status);
++ memset(&msg, 0, sizeof(msg));
++ msg.invoke_id = invoke_id;
++ msg.code = code;
+
++ pos = rose_encode_error(ctrl, pos, end, &msg);
+
+- /* Argument Extension */
+-#if 0 /* Not supported */
+- GET_COMPONENT(comp, i, vdata, len);
+- switch (comp->type) {
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_9): /* [9] IMPLICIT Extension */
+- res = rose_extension_decode(pri, call, comp->data, comp->len, &redirection_number);
+- if (res < 0)
+- return -1;
+- ASN1_FIXUP_LEN(comp, res);
+- comp->len = res;
++ return pos;
++}
+
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_10): /* [10] IMPLICIT SEQUENCE OF Extension */
+- res = rose_sequence_of_extension_decode(pri, call, comp->data, comp->len, &redirection_number);
+- if (res < 0)
+- return -1;
+- ASN1_FIXUP_LEN(comp, res);
+- comp->len = res;
++/*!
++ * \internal
++ * \brief Encode and queue a plain facility error code.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param call Call leg from which to encode error message response.
++ * \param invoke_id Invoke id to put in error message response.
++ * \param code Error code to put in error message response.
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++static int rose_facility_error_encode(struct pri *ctrl, q931_call *call, int invoke_id,
++ enum rose_error_code code)
++{
++ unsigned char buffer[256];
++ unsigned char *end;
+
+- default:
+- pri_message(pri, " CT-Complete: !! Unknown argumentExtension received 0x%X\n", comp->type);
+- return -1;
+- }
+-#else
+- GET_COMPONENT(comp, i, vdata, len);
+- ASN1_FIXUP_LEN(comp, res);
+- NEXT_COMPONENT(comp, i);
+-#endif
++ switch (ctrl->switchtype) {
++ case PRI_SWITCH_EUROISDN_E1:
++ case PRI_SWITCH_EUROISDN_T1:
++ end =
++ enc_etsi_error(ctrl, buffer, buffer + sizeof(buffer), call, invoke_id, code);
++ break;
++ case PRI_SWITCH_QSIG:
++ end =
++ enc_qsig_error(ctrl, buffer, buffer + sizeof(buffer), call, invoke_id, code);
++ break;
++ default:
++ return -1;
++ }
++ if (!end) {
++ return -1;
++ }
+
+- if(i < len)
+- pri_message(pri, " CT-Complete: !! not all information is handled !! i=%d / len=%d\n", i, len);
++ return pri_call_apdu_queue(call, Q931_FACILITY, buffer, end - buffer, NULL);
++}
+
+- return 0;
++/*!
++ * \brief Encode and send a plain facility error code.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param call Call leg from which to encode error message response.
++ * \param invoke_id Invoke id to put in error message response.
++ * \param code Error code to put in error message response.
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++static int send_facility_error(struct pri *ctrl, q931_call *call, int invoke_id,
++ enum rose_error_code code)
++{
++ if (rose_facility_error_encode(ctrl, call, invoke_id, code)
++ || q931_facility(ctrl, call)) {
++ pri_message(ctrl,
++ "Could not schedule facility message for error message.\n");
++ return -1;
+ }
+- while (0);
+
+- return -1;
++ return 0;
+ }
+
+-
+-static int rose_call_transfer_update_decode(struct pri *pri, q931_call *call, struct rose_component *sequence, int len)
++/*!
++ * \internal
++ * \brief Encode a plain facility ETSI result ok.
++ *
++ * \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 call Call leg from which to encode result ok message response.
++ * \param invoke_id Invoke id to put in result ok message response.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *enc_etsi_result_ok(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, q931_call *call, int invoke_id)
+ {
+- int i = 0;
+- struct rose_component *comp = NULL;
+- unsigned char *vdata = sequence->data;
+- int res = 0;
++ struct rose_msg_result msg;
+
+- struct addressingdataelements_presentednumberscreened redirection_number;
+- redirection_number.partyaddress[0] = 0;
+- redirection_number.partysubaddress[0] = 0;
+- char redirection_name[50] = "";
+- call->callername[0] = 0;
+- call->callernum[0] = 0;
++ pos = facility_encode_header(ctrl, pos, end, NULL);
++ if (!pos) {
++ return NULL;
++ }
+
++ memset(&msg, 0, sizeof(msg));
++ msg.invoke_id = invoke_id;
++ msg.operation = ROSE_None;
+
+- /* Data checks */
+- if (sequence->type != (ASN1_CONSTRUCTOR | ASN1_SEQUENCE)) { /* Constructed Sequence */
+- pri_message(pri, "Invalid callTransferComplete argument. (Not a sequence)\n");
+- return -1;
++ pos = rose_encode_result(ctrl, pos, end, &msg);
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Encode a plain facility Q.SIG result ok.
++ *
++ * \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 call Call leg from which to encode result ok message response.
++ * \param invoke_id Invoke id to put in result ok message response.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *enc_qsig_result_ok(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, q931_call *call, int invoke_id)
++{
++ 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;
+ }
+
+- if (sequence->len == ASN1_LEN_INDEF) {
+- len -= 4; /* For the 2 extra characters at the end
+- * and two characters of header */
+- } else
+- len -= 2;
++ memset(&msg, 0, sizeof(msg));
++ msg.invoke_id = invoke_id;
++ msg.operation = ROSE_None;
+
+- if (pri->debug & PRI_DEBUG_APDU)
+- pri_message(pri, " CT-Complete: len=%d\n", len);
++ pos = rose_encode_result(ctrl, pos, end, &msg);
+
+- do {
+- /* Redirection Number */
+- GET_COMPONENT(comp, i, vdata, len);
+- res = rose_presented_number_screened_decode(pri, call, (u_int8_t *)comp, comp->len + 2, &redirection_number);
+- if (res < 0)
+- return -1;
+- comp->len = res;
+- if (res > 2) {
+- if (pri->debug & PRI_DEBUG_APDU)
+- pri_message(pri, " CT-Complete: Received redirectionNumber=%s\n", redirection_number.partyaddress);
+- strncpy(call->callernum, redirection_number.partyaddress, 20);
+- call->callernum[20] = 0;
+- }
+- NEXT_COMPONENT(comp, i);
++ return pos;
++}
+
+- /* Redirection Name */
+- GET_COMPONENT(comp, i, vdata, len);
+- res = asn1_name_decode((u_int8_t *)comp, comp->len + 2, redirection_name, sizeof(redirection_name));
+- if (res < 0)
+- return -1;
+- memcpy(call->callername, comp->data, comp->len);
+- call->callername[comp->len] = 0;
+- ASN1_FIXUP_LEN(comp, res);
+- comp->len = res;
+- NEXT_COMPONENT(comp, i);
+- if (pri->debug & PRI_DEBUG_APDU)
+- pri_message(pri, " CT-Complete: Received redirectionName '%s'\n", redirection_name);
++/*!
++ * \internal
++ * \brief Encode and queue a plain ROSE result ok.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param call Call leg from which to encode result ok message response.
++ * \param msgtype Q.931 message type to put facility ie in.
++ * \param invoke_id Invoke id to put in result ok message response.
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++static int rose_result_ok_encode(struct pri *ctrl, q931_call *call, int msgtype, int invoke_id)
++{
++ unsigned char buffer[256];
++ unsigned char *end;
+
++ switch (ctrl->switchtype) {
++ case PRI_SWITCH_EUROISDN_E1:
++ case PRI_SWITCH_EUROISDN_T1:
++ end =
++ enc_etsi_result_ok(ctrl, buffer, buffer + sizeof(buffer), call, invoke_id);
++ break;
++ case PRI_SWITCH_QSIG:
++ end =
++ enc_qsig_result_ok(ctrl, buffer, buffer + sizeof(buffer), call, invoke_id);
++ break;
++ default:
++ return -1;
++ }
++ if (!end) {
++ return -1;
++ }
+
+-#if 0 /* This one is optional. How do we check if it is there? */
+- /* Basic Call Info Elements */
+- GET_COMPONENT(comp, i, vdata, len);
+- NEXT_COMPONENT(comp, i);
+-#endif
++ return pri_call_apdu_queue(call, msgtype, buffer, end - buffer, NULL);
++}
+
++/*!
++ * \brief Encode and send a FACILITY message with a plain ROSE result ok.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param call Call leg from which to encode result ok message response.
++ * \param invoke_id Invoke id to put in result ok message response.
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++static int send_facility_result_ok(struct pri *ctrl, q931_call *call, int invoke_id)
++{
++ if (rose_result_ok_encode(ctrl, call, Q931_FACILITY, invoke_id)
++ || q931_facility(ctrl, call)) {
++ pri_message(ctrl,
++ "Could not schedule facility message for result OK message.\n");
++ return -1;
++ }
+
+- /* Argument Extension */
+-#if 0 /* Not supported */
+- GET_COMPONENT(comp, i, vdata, len);
+- switch (comp->type) {
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_9): /* [9] IMPLICIT Extension */
+- res = rose_extension_decode(pri, call, comp->data, comp->len, &redirection_number);
+- if (res < 0)
+- return -1;
+- ASN1_FIXUP_LEN(comp, res);
+- comp->len = res;
++ return 0;
++}
+
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_10): /* [10] IMPLICIT SEQUENCE OF Extension */
+- res = rose_sequence_of_extension_decode(pri, call, comp->data, comp->len, &redirection_number);
+- if (res < 0)
+- return -1;
+- ASN1_FIXUP_LEN(comp, res);
+- comp->len = res;
++int pri_rerouting_rsp(struct pri *ctrl, q931_call *call, int invoke_id, enum PRI_REROUTING_RSP_CODE code)
++{
++ enum rose_error_code rose_err;
+
+- default:
+- pri_message(pri, " CT-Complete: !! Unknown argumentExtension received 0x%X\n", comp->type);
+- return -1;
+- }
+-#else
+- GET_COMPONENT(comp, i, vdata, len);
+- ASN1_FIXUP_LEN(comp, res);
+- NEXT_COMPONENT(comp, i);
+-#endif
++ if (!ctrl || !call) {
++ return -1;
++ }
+
+- if(i < len)
+- pri_message(pri, " CT-Complete: !! not all information is handled !! i=%d / len=%d\n", i, len);
++ /* Convert the public rerouting response code to an error code or result ok. */
++ rose_err = ROSE_ERROR_Gen_ResourceUnavailable;
++ switch (code) {
++ case PRI_REROUTING_RSP_OK_CLEAR:
++ return rose_result_ok_encode(ctrl, call, Q931_DISCONNECT, invoke_id);
++ case PRI_REROUTING_RSP_OK_RETAIN:
++ return send_facility_result_ok(ctrl, call, invoke_id);
++ case PRI_REROUTING_RSP_NOT_SUBSCRIBED:
++ rose_err = ROSE_ERROR_Gen_NotSubscribed;
++ break;
++ case PRI_REROUTING_RSP_NOT_AVAILABLE:
++ rose_err = ROSE_ERROR_Gen_NotAvailable;
++ break;
++ case PRI_REROUTING_RSP_NOT_ALLOWED:
++ rose_err = ROSE_ERROR_Gen_SupplementaryServiceInteractionNotAllowed;
++ break;
++ case PRI_REROUTING_RSP_INVALID_NUMBER:
++ rose_err = ROSE_ERROR_Div_InvalidDivertedToNr;
++ break;
++ case PRI_REROUTING_RSP_SPECIAL_SERVICE_NUMBER:
++ rose_err = ROSE_ERROR_Div_SpecialServiceNr;
++ break;
++ case PRI_REROUTING_RSP_DIVERSION_TO_SELF:
++ rose_err = ROSE_ERROR_Div_DiversionToServedUserNr;
++ break;
++ case PRI_REROUTING_RSP_MAX_DIVERSIONS_EXCEEDED:
++ rose_err = ROSE_ERROR_Div_NumberOfDiversionsExceeded;
++ break;
++ case PRI_REROUTING_RSP_RESOURCE_UNAVAILABLE:
++ rose_err = ROSE_ERROR_Gen_ResourceUnavailable;
++ break;
++ }
++ return send_facility_error(ctrl, call, invoke_id, rose_err);
++}
+
+- return 0;
++/*!
++ * \brief Handle the ROSE reject 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 ie Raw ie contents.
++ * \param header Decoded facility header before ROSE.
++ * \param reject Decoded ROSE reject message contents.
++ *
++ * \return Nothing
++ */
++void rose_handle_reject(struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie,
++ const struct fac_extension_header *header, const struct rose_msg_reject *reject)
++{
++ struct apdu_event *apdu;
++ union apdu_msg_data msg;
++
++ /* Gripe to the user about getting rejected. */
++ pri_error(ctrl, "ROSE REJECT:\n");
++ if (reject->invoke_id_present) {
++ pri_error(ctrl, "\tINVOKE ID: %d\n", reject->invoke_id);
+ }
+- while (0);
++ pri_error(ctrl, "\tPROBLEM: %s\n", rose_reject2str(reject->code));
+
+- return -1;
++ switch (ctrl->switchtype) {
++ case PRI_SWITCH_DMS100:
++ /* The DMS-100 switch apparently handles invoke_id as an invoke operation. */
++ return;
++ default:
++ break;
++ }
++
++ if (!reject->invoke_id_present) {
++ /*
++ * No invoke id to look up so we cannot match it to any outstanding APDUs.
++ * This REJECT is apparently meant for someone monitoring the link.
++ */
++ return;
++ }
++ apdu = pri_call_apdu_find(call, reject->invoke_id);
++ if (!apdu) {
++ return;
++ }
++ msg.reject = reject;
++ if (apdu->response.callback(APDU_CALLBACK_REASON_MSG_REJECT, ctrl, call, apdu, &msg)) {
++ pri_call_apdu_delete(call, apdu);
++ }
+ }
+
++/*!
++ * \brief Handle the ROSE error 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 ie Raw ie contents.
++ * \param header Decoded facility header before ROSE.
++ * \param error Decoded ROSE error message contents.
++ *
++ * \return Nothing
++ */
++void rose_handle_error(struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie,
++ const struct fac_extension_header *header, const struct rose_msg_error *error)
++{
++ const char *dms100_operation;
++ struct apdu_event *apdu;
++ union apdu_msg_data msg;
+
+-/* ===== End Call Transfer Supplementary Service (ECMA-178) ===== */
++ /* Gripe to the user about getting an error. */
++ pri_error(ctrl, "ROSE RETURN ERROR:\n");
++ switch (ctrl->switchtype) {
++ case PRI_SWITCH_DMS100:
++ switch (error->invoke_id) {
++ case ROSE_DMS100_RLT_OPERATION_IND:
++ dms100_operation = "RLT_OPERATION_IND";
++ break;
++ case ROSE_DMS100_RLT_THIRD_PARTY:
++ dms100_operation = "RLT_THIRD_PARTY";
++ break;
++ default:
++ dms100_operation = NULL;
++ break;
++ }
++ if (dms100_operation) {
++ pri_error(ctrl, "\tOPERATION: %s\n", dms100_operation);
++ break;
++ }
++ /* fall through */
++ default:
++ pri_error(ctrl, "\tINVOKE ID: %d\n", error->invoke_id);
++ break;
++ }
++ pri_error(ctrl, "\tERROR: %s\n", rose_error2str(error->code));
+
++ switch (ctrl->switchtype) {
++ case PRI_SWITCH_DMS100:
++ /* The DMS-100 switch apparently handles invoke_id as an invoke operation. */
++ return;
++ default:
++ break;
++ }
+
++ apdu = pri_call_apdu_find(call, error->invoke_id);
++ if (!apdu) {
++ return;
++ }
++ msg.error = error;
++ if (apdu->response.callback(APDU_CALLBACK_REASON_MSG_ERROR, ctrl, call, apdu, &msg)) {
++ pri_call_apdu_delete(call, apdu);
++ }
++}
+
+-int rose_reject_decode(struct pri *pri, q931_call *call, q931_ie *ie, unsigned char *data, int len)
++/*!
++ * \brief Handle the ROSE result 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 ie Raw ie contents.
++ * \param header Decoded facility header before ROSE.
++ * \param result Decoded ROSE result message contents.
++ *
++ * \return Nothing
++ */
++void rose_handle_result(struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie,
++ const struct fac_extension_header *header, const struct rose_msg_result *result)
+ {
+- int i = 0;
+- int problemtag = -1;
+- int problem = -1;
+- int invokeidvalue = -1;
+- unsigned char *vdata = data;
+- struct rose_component *comp = NULL;
+- char *problemtagstr, *problemstr;
+-
+- do {
+- /* Invoke ID stuff */
+- GET_COMPONENT(comp, i, vdata, len);
+- CHECK_COMPONENT(comp, INVOKE_IDENTIFIER, "Don't know what to do if first ROSE component is of type 0x%x\n");
+- ASN1_GET_INTEGER(comp, invokeidvalue);
+- NEXT_COMPONENT(comp, i);
++ struct apdu_event *apdu;
++ union apdu_msg_data msg;
+
+- GET_COMPONENT(comp, i, vdata, len);
+- problemtag = comp->type;
+- problem = comp->data[0];
+-
+- if (pri->switchtype == PRI_SWITCH_DMS100) {
+- switch (problemtag) {
+- case 0x80:
+- problemtagstr = "General problem";
++ switch (ctrl->switchtype) {
++ case PRI_SWITCH_DMS100:
++ /* The DMS-100 switch apparently handles invoke_id as an invoke operation. */
++ switch (result->invoke_id) {
++ case ROSE_DMS100_RLT_OPERATION_IND:
++ if (result->operation != ROSE_DMS100_RLT_OperationInd) {
++ pri_message(ctrl, "Invalid Operation value in return result! %s\n",
++ rose_operation2str(result->operation));
+ break;
+- case 0x81:
+- problemtagstr = "Invoke problem";
+- break;
+- case 0x82:
+- problemtagstr = "Return result problem";
+- break;
+- case 0x83:
+- problemtagstr = "Return error problem";
+- break;
+- default:
+- problemtagstr = "Unknown";
+ }
+
+- switch (problem) {
+- case 0x00:
+- problemstr = "Unrecognized component";
+- break;
+- case 0x01:
+- problemstr = "Mistyped component";
+- break;
+- case 0x02:
+- problemstr = "Badly structured component";
+- break;
+- default:
+- problemstr = "Unknown";
++ /* We have enough data to transfer the call */
++ call->rlt_call_id = result->args.dms100.RLT_OperationInd.call_id;
++ call->transferable = 1;
++ break;
++ case ROSE_DMS100_RLT_THIRD_PARTY:
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, "Successfully completed RLT transfer!\n");
+ }
+-
+- pri_error(pri, "ROSE REJECT:\n");
+- pri_error(pri, "\tINVOKE ID: 0x%X\n", invokeidvalue);
+- pri_error(pri, "\tPROBLEM TYPE: %s (0x%x)\n", problemtagstr, problemtag);
+- pri_error(pri, "\tPROBLEM: %s (0x%x)\n", problemstr, problem);
+-
+- return 0;
+- } else {
+- pri_message(pri, "Unable to handle reject on switchtype %d!\n", pri->switchtype);
+- return -1;
++ break;
++ default:
++ pri_message(ctrl, "Could not parse invoke of type %d!\n", result->invoke_id);
++ break;
+ }
++ return;
++ default:
++ break;
++ }
+
+- } while(0);
+-
+- return -1;
++ apdu = pri_call_apdu_find(call, result->invoke_id);
++ if (!apdu) {
++ return;
++ }
++ msg.result = result;
++ if (apdu->response.callback(APDU_CALLBACK_REASON_MSG_RESULT, ctrl, call, apdu, &msg)) {
++ pri_call_apdu_delete(call, apdu);
++ }
+ }
+-int rose_return_error_decode(struct pri *pri, q931_call *call, q931_ie *ie, unsigned char *data, int len)
++
++/*!
++ * \brief Handle the ROSE 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 ie Raw ie contents.
++ * \param header Decoded facility header before ROSE.
++ * \param invoke Decoded ROSE invoke message contents.
++ *
++ * \return Nothing
++ */
++void rose_handle_invoke(struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie,
++ const struct fac_extension_header *header, const struct rose_msg_invoke *invoke)
+ {
+- int i = 0;
+- int errorvalue = -1;
+- int invokeidvalue = -1;
+- unsigned char *vdata = data;
+- struct rose_component *comp = NULL;
+- char *invokeidstr, *errorstr;
+-
+- do {
+- /* Invoke ID stuff */
+- GET_COMPONENT(comp, i, vdata, len);
+- CHECK_COMPONENT(comp, INVOKE_IDENTIFIER, "Don't know what to do if first ROSE component is of type 0x%x\n");
+- ASN1_GET_INTEGER(comp, invokeidvalue);
+- NEXT_COMPONENT(comp, i);
++ struct pri_subcommand *subcmd;
++ struct q931_party_id party_id;
++ struct q931_party_redirecting deflection;
+
+- GET_COMPONENT(comp, i, vdata, len);
+- CHECK_COMPONENT(comp, ASN1_INTEGER, "Don't know what to do if second component in return error is 0x%x\n");
+- ASN1_GET_INTEGER(comp, errorvalue);
++ switch (invoke->operation) {
++#if 0 /* Not handled yet */
++ case ROSE_ETSI_ActivationDiversion:
++ break;
++ case ROSE_ETSI_DeactivationDiversion:
++ break;
++ case ROSE_ETSI_ActivationStatusNotificationDiv:
++ break;
++ case ROSE_ETSI_DeactivationStatusNotificationDiv:
++ break;
++ case ROSE_ETSI_InterrogationDiversion:
++ break;
++ case ROSE_ETSI_DiversionInformation:
++ break;
++#endif /* Not handled yet */
++ case ROSE_ETSI_CallDeflection:
++ if (!PRI_MASTER(ctrl)->deflection_support) {
++ send_facility_error(ctrl, call, invoke->invoke_id,
++ ROSE_ERROR_Gen_NotSubscribed);
++ break;
++ }
++ if (!q931_master_pass_event(ctrl, call, msgtype)) {
++ /* Some other user is further along to connecting than this call. */
++ send_facility_error(ctrl, call, invoke->invoke_id,
++ ROSE_ERROR_Div_IncomingCallAccepted);
++ break;
++ }
++ if (call->master_call->deflection_in_progress) {
++ /* Someone else is already doing a call deflection. */
++ send_facility_error(ctrl, call, invoke->invoke_id,
++ ROSE_ERROR_Div_RequestAlreadyAccepted);
++ break;
++ }
++ subcmd = q931_alloc_subcommand(ctrl);
++ if (!subcmd) {
++ /*
++ * ROSE_ERROR_Gen_ResourceUnavailable was not in the list of allowed codes,
++ * but we will send it anyway.
++ */
++ send_facility_error(ctrl, call, invoke->invoke_id,
++ ROSE_ERROR_Gen_ResourceUnavailable);
++ pri_error(ctrl, "ERROR: Too many facility subcommands\n");
++ break;
++ }
+
+- if (pri->switchtype == PRI_SWITCH_DMS100) {
+- switch (invokeidvalue) {
+- case RLT_OPERATION_IND:
+- invokeidstr = "RLT_OPERATION_IND";
+- break;
+- case RLT_THIRD_PARTY:
+- invokeidstr = "RLT_THIRD_PARTY";
+- break;
+- default:
+- invokeidstr = "Unknown";
+- }
++ call->master_call->deflection_in_progress = 1;
+
+- switch (errorvalue) {
+- case 0x10:
+- errorstr = "RLT Bridge Fail";
+- break;
+- case 0x11:
+- errorstr = "RLT Call ID Not Found";
+- break;
+- case 0x12:
+- errorstr = "RLT Not Allowed";
+- break;
+- case 0x13:
+- errorstr = "RLT Switch Equip Congs";
+- break;
+- default:
+- errorstr = "Unknown";
+- }
++ q931_party_redirecting_init(&deflection);
+
+- pri_error(pri, "ROSE RETURN ERROR:\n");
+- pri_error(pri, "\tOPERATION: %s\n", invokeidstr);
+- pri_error(pri, "\tERROR: %s\n", errorstr);
++ /* Deflecting from the called address. */
++ q931_party_address_to_id(&deflection.from, &call->called);
++ if (invoke->args.etsi.CallDeflection.presentation_allowed_to_diverted_to_user_present) {
++ deflection.from.number.presentation =
++ invoke->args.etsi.CallDeflection.presentation_allowed_to_diverted_to_user
++ ? PRI_PRES_ALLOWED | PRI_PRES_USER_NUMBER_UNSCREENED
++ : PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_UNSCREENED;
++ } else {
++ deflection.from.number.presentation =
++ PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_UNSCREENED;
++ }
+
+- return 0;
++ /* Deflecting to the new address. */
++ rose_copy_address_to_q931(ctrl, &deflection.to,
++ &invoke->args.etsi.CallDeflection.deflection);
++ deflection.to.number.presentation = deflection.from.number.presentation;
++
++ deflection.count = (call->redirecting.count < PRI_MAX_REDIRECTS)
++ ? call->redirecting.count + 1 : PRI_MAX_REDIRECTS;
++ deflection.reason = PRI_REDIR_DEFLECTION;
++ if (deflection.count == 1) {
++ deflection.orig_called = deflection.from;
++ deflection.orig_reason = deflection.reason;
+ } else {
+- pri_message(pri, "Unable to handle return error on switchtype %d!\n", pri->switchtype);
++ deflection.orig_called = call->redirecting.orig_called;
++ deflection.orig_reason = call->redirecting.orig_reason;
+ }
+
+- } while(0);
+-
+- return -1;
+-}
++ subcmd->cmd = PRI_SUBCMD_REROUTING;
++ subcmd->u.rerouting.invoke_id = invoke->invoke_id;
++ subcmd->u.rerouting.subscription_option = 3;/* notApplicable */
++ q931_party_id_copy_to_pri(&subcmd->u.rerouting.caller, &call->local_id);
++ q931_party_redirecting_copy_to_pri(&subcmd->u.rerouting.deflection,
++ &deflection);
++ break;
++ case ROSE_ETSI_CallRerouting:
++ if (!PRI_MASTER(ctrl)->deflection_support) {
++ send_facility_error(ctrl, call, invoke->invoke_id,
++ ROSE_ERROR_Gen_NotSubscribed);
++ break;
++ }
++ subcmd = q931_alloc_subcommand(ctrl);
++ if (!subcmd) {
++ send_facility_error(ctrl, call, invoke->invoke_id,
++ ROSE_ERROR_Gen_ResourceUnavailable);
++ pri_error(ctrl, "ERROR: Too many facility subcommands\n");
++ break;
++ }
+
+-int rose_return_result_decode(struct pri *pri, q931_call *call, q931_ie *ie, unsigned char *data, int len)
+-{
+- int i = 0;
+- int operationidvalue = -1;
+- int invokeidvalue = -1;
+- unsigned char *vdata = data;
+- struct rose_component *comp = NULL;
+-
+- do {
+- /* Invoke ID stuff */
+- GET_COMPONENT(comp, i, vdata, len);
+- CHECK_COMPONENT(comp, INVOKE_IDENTIFIER, "Don't know what to do if first ROSE component is of type 0x%x\n");
+- ASN1_GET_INTEGER(comp, invokeidvalue);
+- NEXT_COMPONENT(comp, i);
++ q931_party_redirecting_init(&deflection);
+
+- if (pri->switchtype == PRI_SWITCH_DMS100) {
+- switch (invokeidvalue) {
+- case RLT_THIRD_PARTY:
+- if (pri->debug & PRI_DEBUG_APDU) pri_message(pri, "Successfully completed RLT transfer!\n");
+- return 0;
+- case RLT_OPERATION_IND:
+- if (pri->debug & PRI_DEBUG_APDU) pri_message(pri, "Received RLT_OPERATION_IND\n");
+- /* Have to take out the rlt_call_id */
+- GET_COMPONENT(comp, i, vdata, len);
+- CHECK_COMPONENT(comp, ASN1_SEQUENCE, "Protocol error detected in parsing RLT_OPERATION_IND return result!\n");
++ /* Rerouting from the last address. */
++ rose_copy_presented_number_unscreened_to_q931(ctrl, &deflection.from.number,
++ &invoke->args.etsi.CallRerouting.last_rerouting);
+
+- /* Traverse the contents of this sequence */
+- /* First is the Operation Value */
+- SUB_COMPONENT(comp, i);
+- GET_COMPONENT(comp, i, vdata, len);
+- CHECK_COMPONENT(comp, ASN1_INTEGER, "RLT_OPERATION_IND should be of type ASN1_INTEGER!\n");
+- ASN1_GET_INTEGER(comp, operationidvalue);
++ /* Rerouting to the new address. */
++ rose_copy_address_to_q931(ctrl, &deflection.to,
++ &invoke->args.etsi.CallRerouting.called_address);
++ switch (invoke->args.etsi.CallRerouting.subscription_option) {
++ default:
++ case 0: /* noNotification */
++ case 1: /* notificationWithoutDivertedToNr */
++ deflection.to.number.presentation =
++ PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_UNSCREENED;
++ break;
++ case 2: /* notificationWithDivertedToNr */
++ deflection.to.number.presentation =
++ PRI_PRES_ALLOWED | PRI_PRES_USER_NUMBER_UNSCREENED;
++ break;
++ }
+
+- if (operationidvalue != RLT_OPERATION_IND) {
+- pri_message(pri, "Invalid Operation ID value (0x%x) in return result!\n", operationidvalue);
+- return -1;
+- }
++ /* Calling party subaddress update. */
++ party_id = call->local_id;
+
+- /* Next is the Call ID */
+- NEXT_COMPONENT(comp, i);
+- GET_COMPONENT(comp, i, vdata, len);
+- CHECK_COMPONENT(comp, ASN1_TAG_0, "Error check failed on Call ID!\n");
+- ASN1_GET_INTEGER(comp, call->rlt_call_id);
+- /* We have enough data to transfer the call */
+- call->transferable = 1;
++ deflection.count = invoke->args.etsi.CallRerouting.rerouting_counter;
++ deflection.reason = redirectingreason_for_q931(ctrl,
++ invoke->args.etsi.CallRerouting.rerouting_reason);
++ if (deflection.count == 1) {
++ deflection.orig_called = deflection.from;
++ deflection.orig_reason = deflection.reason;
++ } else {
++ deflection.orig_called = call->redirecting.orig_called;
++ deflection.orig_reason = call->redirecting.orig_reason;
++ }
+
+- return 0;
+-
+- default:
+- pri_message(pri, "Could not parse invoke of type 0x%x!\n", invokeidvalue);
+- return -1;
++ subcmd->cmd = PRI_SUBCMD_REROUTING;
++ subcmd->u.rerouting.invoke_id = invoke->invoke_id;
++ subcmd->u.rerouting.subscription_option =
++ invoke->args.etsi.CallRerouting.subscription_option;
++ q931_party_id_copy_to_pri(&subcmd->u.rerouting.caller, &party_id);
++ q931_party_redirecting_copy_to_pri(&subcmd->u.rerouting.deflection,
++ &deflection);
++ break;
++#if 0 /* Not handled yet */
++ case ROSE_ETSI_InterrogateServedUserNumbers:
++ break;
++#endif /* Not handled yet */
++ case ROSE_ETSI_DivertingLegInformation1:
++ if (invoke->args.etsi.DivertingLegInformation1.diverted_to_present) {
++ rose_copy_presented_number_unscreened_to_q931(ctrl, &party_id.number,
++ &invoke->args.etsi.DivertingLegInformation1.diverted_to);
++ /*
++ * We set the presentation value since the sender cannot know the
++ * presentation value preference of the destination party.
++ */
++ if (party_id.number.str[0]) {
++ party_id.number.presentation =
++ PRI_PRES_ALLOWED | PRI_PRES_USER_NUMBER_UNSCREENED;
++ } else {
++ party_id.number.presentation =
++ PRI_PRES_UNAVAILABLE | PRI_PRES_USER_NUMBER_UNSCREENED;
+ }
+- } else if (pri->switchtype == PRI_SWITCH_QSIG) {
+- switch (invokeidvalue) {
+- case 0x13:
+- if (pri->debug & PRI_DEBUG_APDU) pri_message(pri, "Successfully completed QSIG CF callRerouting!\n");
+- return 0;
+- }
+ } else {
+- pri_message(pri, "Unable to handle return result on switchtype %d!\n", pri->switchtype);
+- return -1;
++ q931_party_number_init(&party_id.number);
++ party_id.number.valid = 1;
+ }
+
+- } while(0);
+-
+- return -1;
+-}
++ /*
++ * Unless otherwise indicated by CONNECT, the divertedToNumber will be
++ * the remote_id.number.
++ */
++ if (!call->connected_number_in_message) {
++ call->remote_id.number = party_id.number;
++ }
+
+-int rose_invoke_decode(struct pri *pri, q931_call *call, q931_ie *ie, unsigned char *data, int len)
+-{
+- int i = 0;
+- int res = 0;
+- int operation_tag;
+- unsigned char *vdata = data;
+- struct rose_component *comp = NULL, *invokeid = NULL, *operationid = NULL;
+-
+- do {
+- /* Invoke ID stuff */
+- GET_COMPONENT(comp, i, vdata, len);
+-#if 0
+- CHECK_COMPONENT(comp, INVOKE_IDENTIFIER, "Don't know what to do if first ROSE component is of type 0x%x\n");
+-#endif
+- invokeid = comp;
+- NEXT_COMPONENT(comp, i);
++ /* divertedToNumber is put in redirecting.to.number */
++ switch (invoke->args.etsi.DivertingLegInformation1.subscription_option) {
++ default:
++ case 0: /* noNotification */
++ case 1: /* notificationWithoutDivertedToNr */
++ q931_party_number_init(&call->redirecting.to.number);
++ call->redirecting.to.number.valid = 1;
++ call->redirecting.to.number.presentation =
++ PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_UNSCREENED;
++ break;
++ case 2: /* notificationWithDivertedToNr */
++ call->redirecting.to.number = party_id.number;
++ break;
++ }
+
+- /* Operation Tag */
+- GET_COMPONENT(comp, i, vdata, len);
+-#if 0
+- CHECK_COMPONENT(comp, ASN1_INTEGER, "Don't know what to do if second ROSE component is of type 0x%x\n");
+-#endif
+- operationid = comp;
+- ASN1_GET_INTEGER(comp, operation_tag);
+- NEXT_COMPONENT(comp, i);
++ call->redirecting.reason = redirectingreason_for_q931(ctrl,
++ invoke->args.etsi.DivertingLegInformation1.diversion_reason);
++ if (call->redirecting.count < PRI_MAX_REDIRECTS) {
++ ++call->redirecting.count;
++ }
++ call->redirecting.state = Q931_REDIRECTING_STATE_EXPECTING_RX_DIV_LEG_3;
++ break;
++ case ROSE_ETSI_DivertingLegInformation2:
++ call->redirecting.state = Q931_REDIRECTING_STATE_PENDING_TX_DIV_LEG_3;
++ call->redirecting.count =
++ invoke->args.etsi.DivertingLegInformation2.diversion_counter;
++ if (!call->redirecting.count) {
++ /* To be safe, make sure that the count is non-zero. */
++ call->redirecting.count = 1;
++ }
++ call->redirecting.reason = redirectingreason_for_q931(ctrl,
++ invoke->args.etsi.DivertingLegInformation2.diversion_reason);
+
+- /* No argument - return with error */
+- if (i >= len)
+- return -1;
++ /* divertingNr is put in redirecting.from.number */
++ if (invoke->args.etsi.DivertingLegInformation2.diverting_present) {
++ rose_copy_presented_number_unscreened_to_q931(ctrl,
++ &call->redirecting.from.number,
++ &invoke->args.etsi.DivertingLegInformation2.diverting);
++ } else if (!call->redirecting_number_in_message) {
++ q931_party_number_init(&call->redirecting.from.number);
++ call->redirecting.from.number.valid = 1;
++ }
+
+- /* Arguement Tag */
+- GET_COMPONENT(comp, i, vdata, len);
+- if (!comp->type)
+- return -1;
++ call->redirecting.orig_reason = PRI_REDIR_UNKNOWN;
+
+- if (pri->debug & PRI_DEBUG_APDU)
+- pri_message(pri, " [ Handling operation %d ]\n", operation_tag);
+- switch (operation_tag) {
+- case SS_CNID_CALLINGNAME:
+- if (pri->debug & PRI_DEBUG_APDU)
+- pri_message(pri, " Handle Name display operation\n");
+- return rose_calling_name_decode(pri, call, comp, len-i);
+- case ROSE_CALL_TRANSFER_IDENTIFY:
+- if (pri->debug & PRI_DEBUG_APDU)
+- pri_message(pri, "ROSE %i: CallTransferIdentify - not handled!\n", operation_tag);
+- dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
+- return -1;
+- case ROSE_CALL_TRANSFER_ABANDON:
+- if (pri->debug & PRI_DEBUG_APDU)
+- pri_message(pri, "ROSE %i: CallTransferAbandon - not handled!\n", operation_tag);
+- dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
+- return -1;
+- case ROSE_CALL_TRANSFER_INITIATE:
+- if (pri->debug & PRI_DEBUG_APDU)
+- pri_message(pri, "ROSE %i: CallTransferInitiate - not handled!\n", operation_tag);
+- dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
+- return -1;
+- case ROSE_CALL_TRANSFER_SETUP:
+- if (pri->debug & PRI_DEBUG_APDU)
+- pri_message(pri, "ROSE %i: CallTransferSetup - not handled!\n", operation_tag);
+- dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
+- return -1;
+- case ROSE_CALL_TRANSFER_ACTIVE:
+- if (pri->debug & PRI_DEBUG_APDU)
+- pri_message(pri, "ROSE %i: CallTransferActive - not handled!\n", operation_tag);
+- dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
+- return -1;
+- case ROSE_CALL_TRANSFER_COMPLETE:
+- if (pri->debug & PRI_DEBUG_APDU)
+- {
+- pri_message(pri, "ROSE %i: Handle CallTransferComplete\n", operation_tag);
+- dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
++ /* originalCalledNr is put in redirecting.orig_called.number */
++ if (invoke->args.etsi.DivertingLegInformation2.original_called_present) {
++ rose_copy_presented_number_unscreened_to_q931(ctrl,
++ &call->redirecting.orig_called.number,
++ &invoke->args.etsi.DivertingLegInformation2.original_called);
++ } else {
++ q931_party_number_init(&call->redirecting.orig_called.number);
++ }
++ break;
++ case ROSE_ETSI_DivertingLegInformation3:
++ /*
++ * Unless otherwise indicated by CONNECT, this will be the
++ * remote_id.number.presentation.
++ */
++ if (!invoke->args.etsi.DivertingLegInformation3.presentation_allowed_indicator) {
++ call->redirecting.to.number.presentation =
++ PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_UNSCREENED;
++ if (!call->connected_number_in_message) {
++ call->remote_id.number.presentation =
++ PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_UNSCREENED;
+ }
+- return rose_call_transfer_complete_decode(pri, call, comp, len-i);
+- case ROSE_CALL_TRANSFER_UPDATE:
+- if (pri->debug & PRI_DEBUG_APDU)
+- {
+- pri_message(pri, "ROSE %i: Handle CallTransferUpdate\n", operation_tag);
+- dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
++ }
++
++ switch (call->redirecting.state) {
++ case Q931_REDIRECTING_STATE_EXPECTING_RX_DIV_LEG_3:
++ call->redirecting.state = Q931_REDIRECTING_STATE_IDLE;
++ subcmd = q931_alloc_subcommand(ctrl);
++ if (!subcmd) {
++ pri_error(ctrl, "ERROR: Too many facility subcommands\n");
++ break;
+ }
+- return rose_call_transfer_update_decode(pri, call, comp, len-i);
+- case ROSE_SUBADDRESS_TRANSFER:
+- if (pri->debug & PRI_DEBUG_APDU)
+- pri_message(pri, "ROSE %i: SubaddressTransfer - not handled!\n", operation_tag);
+- dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
+- return -1;
+- case ROSE_DIVERTING_LEG_INFORMATION2:
+- if (pri->debug & PRI_DEBUG_APDU) {
+- pri_message(pri, "ROSE %i: Handle CallingName\n", operation_tag);
+- dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
+- }
+- return rose_diverting_leg_information2_decode(pri, call, comp, len-i);
+- case ROSE_AOC_NO_CHARGING_INFO_AVAILABLE:
+- if (pri->debug & PRI_DEBUG_APDU) {
+- pri_message(pri, "ROSE %i: AOC No Charging Info Available - not handled!", operation_tag);
+- dump_apdu (pri, comp->data, comp->len);
+- }
+- return -1;
+- case ROSE_AOC_CHARGING_REQUEST:
+- return aoc_aoce_charging_request_decode(pri, call, (u_int8_t *)comp, comp->len + 2);
+- case ROSE_AOC_AOCS_CURRENCY:
+- if (pri->debug & PRI_DEBUG_APDU) {
+- pri_message(pri, "ROSE %i: AOC-S Currency - not handled!", operation_tag);
+- dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
+- }
+- return -1;
+- case ROSE_AOC_AOCS_SPECIAL_ARR:
+- if (pri->debug & PRI_DEBUG_APDU) {
+- pri_message(pri, "ROSE %i: AOC-S Special Array - not handled!", operation_tag);
+- dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
+- }
+- return -1;
+- case ROSE_AOC_AOCD_CURRENCY:
+- if (pri->debug & PRI_DEBUG_APDU) {
+- pri_message(pri, "ROSE %i: AOC-D Currency - not handled!", operation_tag);
+- dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
+- }
+- return -1;
+- case ROSE_AOC_AOCD_CHARGING_UNIT:
+- if (pri->debug & PRI_DEBUG_APDU) {
+- pri_message(pri, "ROSE %i: AOC-D Charging Unit - not handled!", operation_tag);
+- dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
+- }
+- return -1;
+- case ROSE_AOC_AOCE_CURRENCY:
+- if (pri->debug & PRI_DEBUG_APDU) {
+- pri_message(pri, "ROSE %i: AOC-E Currency - not handled!", operation_tag);
+- dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
+- }
+- return -1;
+- case ROSE_AOC_AOCE_CHARGING_UNIT:
+- return aoc_aoce_charging_unit_decode(pri, call, (u_int8_t *)comp, comp->len + 2);
+- if (0) { /* the following function is currently not used - just to make the compiler happy */
+- aoc_aoce_charging_unit_encode(pri, call, call->aoc_units); /* use this function to forward the aoc-e on a bridged channel */
+- return 0;
+- }
+- case ROSE_AOC_IDENTIFICATION_OF_CHARGE:
+- if (pri->debug & PRI_DEBUG_APDU) {
+- pri_message(pri, "ROSE %i: AOC Identification Of Charge - not handled!", operation_tag);
+- dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
+- }
+- return -1;
+- case SS_ANFPR_PATHREPLACEMENT:
+- /* Clear Queue */
+- res = pri_call_apdu_queue_cleanup(call->bridged_call);
+- if (res) {
+- pri_message(pri, "Could not Clear queue ADPU\n");
+- return -1;
+- }
+- anfpr_pathreplacement_respond(pri, call, ie);
+- break;
++ /* Setup redirecting subcommand */
++ subcmd->cmd = PRI_SUBCMD_REDIRECTING;
++ q931_party_redirecting_copy_to_pri(&subcmd->u.redirecting,
++ &call->redirecting);
++ break;
+ default:
+- if (pri->debug & PRI_DEBUG_APDU) {
+- pri_message(pri, "!! Unable to handle ROSE operation %d", operation_tag);
+- dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
++ break;
++ }
++ break;
++ case ROSE_ETSI_ChargingRequest:
++ /* Ignore messsage */
++ break;
++#if 0 /* Not handled yet */
++ case ROSE_ETSI_AOCSCurrency:
++ break;
++ case ROSE_ETSI_AOCSSpecialArr:
++ break;
++ case ROSE_ETSI_AOCDCurrency:
++ break;
++ case ROSE_ETSI_AOCDChargingUnit:
++ break;
++ case ROSE_ETSI_AOCECurrency:
++ break;
++#endif /* Not handled yet */
++ case ROSE_ETSI_AOCEChargingUnit:
++ call->aoc_units = 0;
++ if (invoke->args.etsi.AOCEChargingUnit.type == 1
++ && !invoke->args.etsi.AOCEChargingUnit.charging_unit.free_of_charge) {
++ unsigned index;
++
++ for (index =
++ invoke->args.etsi.AOCEChargingUnit.charging_unit.specific.recorded.
++ num_records; index--;) {
++ if (!invoke->args.etsi.AOCEChargingUnit.charging_unit.specific.recorded.
++ list[index].not_available) {
++ call->aoc_units +=
++ invoke->args.etsi.AOCEChargingUnit.charging_unit.specific.
++ recorded.list[index].number_of_units;
++ }
+ }
+- return -1;
+ }
+- } while(0);
+-
+- return -1;
+-}
++ /* the following function is currently not used - just to make the compiler happy */
++ if (0) {
++ /* use this function to forward the aoc-e on a bridged channel */
++ aoc_aoce_charging_unit_encode(ctrl, call, call->aoc_units);
++ }
++ break;
++#if 0 /* Not handled yet */
++ case ROSE_ITU_IdentificationOfCharge:
++ break;
++#endif /* Not handled yet */
++#if 0 /* Not handled yet */
++ case ROSE_ETSI_EctExecute:
++ break;
++ case ROSE_ETSI_ExplicitEctExecute:
++ break;
++#endif /* Not handled yet */
++ case ROSE_ETSI_RequestSubaddress:
++ /* Ignore since we are not handling subaddresses yet. */
++ break;
++#if 0 /* Not handled yet */
++ case ROSE_ETSI_SubaddressTransfer:
++ break;
++ case ROSE_ETSI_EctLinkIdRequest:
++ break;
++#endif /* Not handled yet */
++ case ROSE_ETSI_EctInform:
++ /* redirectionNumber is put in remote_id.number */
++ if (invoke->args.etsi.EctInform.redirection_present) {
++ rose_copy_presented_number_unscreened_to_q931(ctrl,
++ &call->remote_id.number, &invoke->args.etsi.EctInform.redirection);
++ }
++ if (!invoke->args.etsi.EctInform.status) {
++ /* The remote party for the transfer has not answered yet. */
++ call->incoming_ct_state = INCOMING_CT_STATE_EXPECT_CT_ACTIVE;
++ } else {
++ call->incoming_ct_state = INCOMING_CT_STATE_POST_CONNECTED_LINE;
++ }
++ break;
++#if 0 /* Not handled yet */
++ case ROSE_ETSI_EctLoopTest:
++ break;
++#endif /* Not handled yet */
++ case ROSE_QSIG_CallingName:
++ /* CallingName is put in remote_id.name */
++ rose_copy_name_to_q931(ctrl, &call->remote_id.name,
++ &invoke->args.qsig.CallingName.name);
++ break;
++ case ROSE_QSIG_CalledName:
++ /* CalledName is put in remote_id.name */
++ rose_copy_name_to_q931(ctrl, &call->remote_id.name,
++ &invoke->args.qsig.CalledName.name);
+
+-int pri_call_apdu_queue(q931_call *call, int messagetype, void *apdu, int apdu_len, void (*function)(void *data), void *data)
+-{
+- struct apdu_event *cur = NULL;
+- struct apdu_event *new_event = NULL;
++ /* Setup connected line subcommand */
++ subcmd = q931_alloc_subcommand(ctrl);
++ if (!subcmd) {
++ pri_error(ctrl, "ERROR: Too many facility subcommands\n");
++ break;
++ }
++ subcmd->cmd = PRI_SUBCMD_CONNECTED_LINE;
++ q931_party_id_copy_to_pri(&subcmd->u.connected_line.id, &call->remote_id);
++ break;
++ case ROSE_QSIG_ConnectedName:
++ /* ConnectedName is put in remote_id.name */
++ rose_copy_name_to_q931(ctrl, &call->remote_id.name,
++ &invoke->args.qsig.ConnectedName.name);
++ break;
++#if 0 /* Not handled yet */
++ case ROSE_QSIG_BusyName:
++ break;
++#endif /* Not handled yet */
++#if 0 /* Not handled yet */
++ case ROSE_QSIG_ChargeRequest:
++ break;
++ case ROSE_QSIG_GetFinalCharge:
++ break;
++ case ROSE_QSIG_AocFinal:
++ break;
++ case ROSE_QSIG_AocInterim:
++ break;
++ case ROSE_QSIG_AocRate:
++ break;
++ case ROSE_QSIG_AocComplete:
++ break;
++ case ROSE_QSIG_AocDivChargeReq:
++ break;
++#endif /* Not handled yet */
++#if 0 /* Not handled yet */
++ case ROSE_QSIG_CallTransferIdentify:
++ break;
++ case ROSE_QSIG_CallTransferAbandon:
++ break;
++ case ROSE_QSIG_CallTransferInitiate:
++ break;
++ case ROSE_QSIG_CallTransferSetup:
++ break;
++#endif /* Not handled yet */
++ case ROSE_QSIG_CallTransferActive:
++ call->incoming_ct_state = INCOMING_CT_STATE_POST_CONNECTED_LINE;
+
+- if (!call || !messagetype || !apdu || (apdu_len < 1) || (apdu_len > 255))
+- return -1;
++ /* connectedAddress is put in remote_id */
++ rose_copy_presented_address_screened_to_q931(ctrl, &call->remote_id,
++ &invoke->args.qsig.CallTransferActive.connected);
+
+- if (!(new_event = calloc(1, sizeof(*new_event)))) {
+- pri_error(call->pri, "!! Malloc failed!\n");
+- return -1;
+- }
++ /* connectedName is put in remote_id.name */
++ if (invoke->args.qsig.CallTransferActive.connected_name_present) {
++ rose_copy_name_to_q931(ctrl, &call->remote_id.name,
++ &invoke->args.qsig.CallTransferActive.connected_name);
++ }
++ break;
++ case ROSE_QSIG_CallTransferComplete:
++ /* redirectionNumber is put in remote_id.number */
++ rose_copy_presented_number_screened_to_q931(ctrl, &call->remote_id.number,
++ &invoke->args.qsig.CallTransferComplete.redirection);
+
+- new_event->message = messagetype;
+- new_event->callback = function;
+- new_event->data = data;
+- memcpy(new_event->apdu, apdu, apdu_len);
+- new_event->apdu_len = apdu_len;
+-
+- if (call->apdus) {
+- cur = call->apdus;
+- while (cur->next) {
+- cur = cur->next;
++ /* redirectionName is put in remote_id.name */
++ if (invoke->args.qsig.CallTransferComplete.redirection_name_present) {
++ rose_copy_name_to_q931(ctrl, &call->remote_id.name,
++ &invoke->args.qsig.CallTransferComplete.redirection_name);
+ }
+- cur->next = new_event;
+- } else
+- call->apdus = new_event;
+
+- return 0;
+-}
++ if (invoke->args.qsig.CallTransferComplete.call_status == 1) {
++ /* The remote party for the transfer has not answered yet. */
++ call->incoming_ct_state = INCOMING_CT_STATE_EXPECT_CT_ACTIVE;
++ } else {
++ call->incoming_ct_state = INCOMING_CT_STATE_POST_CONNECTED_LINE;
++ }
++ break;
++ case ROSE_QSIG_CallTransferUpdate:
++ party_id = call->remote_id;
+
+-int pri_call_apdu_queue_cleanup(q931_call *call)
+-{
+- struct apdu_event *cur_event = NULL, *free_event = NULL;
++ /* redirectionNumber is put in party_id.number */
++ rose_copy_presented_number_screened_to_q931(ctrl, &party_id.number,
++ &invoke->args.qsig.CallTransferUpdate.redirection);
+
+- if (call && call->apdus) {
+- cur_event = call->apdus;
+- while (cur_event) {
+- /* TODO: callbacks, some way of giving return res on status of apdu */
+- free_event = cur_event;
+- cur_event = cur_event->next;
+- free(free_event);
++ /* redirectionName is put in party_id.name */
++ if (invoke->args.qsig.CallTransferUpdate.redirection_name_present) {
++ rose_copy_name_to_q931(ctrl, &party_id.name,
++ &invoke->args.qsig.CallTransferUpdate.redirection_name);
+ }
+- call->apdus = NULL;
+- }
+
+- return 0;
+-}
+-
+-int pri_call_add_standard_apdus(struct pri *pri, q931_call *call)
+-{
+- if (!pri->sendfacility)
+- return 0;
+-
+- if (pri->switchtype == PRI_SWITCH_QSIG) { /* For Q.SIG it does network and cpe operations */
+- if (call->redirectingnum[0])
+- rose_diverting_leg_information2_encode(pri, call);
+- add_callername_facility_ies(pri, call, 1);
+- return 0;
+- }
+-
+-#if 0
+- if (pri->localtype == PRI_NETWORK) {
+- switch (pri->switchtype) {
+- case PRI_SWITCH_NI2:
+- add_callername_facility_ies(pri, call, 0);
++ if (q931_party_id_cmp(&party_id, &call->remote_id)) {
++ /* The remote_id data has changed. */
++ call->remote_id = party_id;
++ switch (call->incoming_ct_state) {
++ case INCOMING_CT_STATE_IDLE:
++ call->incoming_ct_state = INCOMING_CT_STATE_POST_CONNECTED_LINE;
+ break;
+ default:
+ break;
++ }
+ }
+- return 0;
+- } else if (pri->localtype == PRI_CPE) {
+- switch (pri->switchtype) {
+- case PRI_SWITCH_NI2:
+- add_callername_facility_ies(pri, call, 1);
+- break;
+- default:
+- break;
++ break;
++#if 0 /* Not handled yet */
++ case ROSE_QSIG_SubaddressTransfer:
++ break;
++#endif /* Not handled yet */
++ case ROSE_QSIG_PathReplacement:
++ anfpr_pathreplacement_respond(ctrl, call, ie);
++ break;
++#if 0 /* Not handled yet */
++ case ROSE_QSIG_ActivateDiversionQ:
++ break;
++ case ROSE_QSIG_DeactivateDiversionQ:
++ break;
++ case ROSE_QSIG_InterrogateDiversionQ:
++ break;
++ case ROSE_QSIG_CheckRestriction:
++ break;
++#endif /* Not handled yet */
++ case ROSE_QSIG_CallRerouting:
++ if (!PRI_MASTER(ctrl)->deflection_support) {
++ send_facility_error(ctrl, call, invoke->invoke_id,
++ ROSE_ERROR_Gen_NotSubscribed);
++ break;
+ }
+- return 0;
+- }
+-#else
+- if (pri->switchtype == PRI_SWITCH_NI2)
+- add_callername_facility_ies(pri, call, (pri->localtype == PRI_CPE));
+-#endif
++ subcmd = q931_alloc_subcommand(ctrl);
++ if (!subcmd) {
++ send_facility_error(ctrl, call, invoke->invoke_id,
++ ROSE_ERROR_Gen_ResourceUnavailable);
++ pri_error(ctrl, "ERROR: Too many facility subcommands\n");
++ break;
++ }
+
+- if ((pri->switchtype == PRI_SWITCH_DMS100) && (pri->localtype == PRI_CPE)) {
+- add_dms100_transfer_ability_apdu(pri, call);
+- }
++ q931_party_redirecting_init(&deflection);
+
++ /* Rerouting from the last address. */
++ rose_copy_presented_number_unscreened_to_q931(ctrl, &deflection.from.number,
++ &invoke->args.qsig.CallRerouting.last_rerouting);
++ if (invoke->args.qsig.CallRerouting.redirecting_name_present) {
++ rose_copy_name_to_q931(ctrl, &deflection.from.name,
++ &invoke->args.qsig.CallRerouting.redirecting_name);
++ }
+
++ /* Rerouting to the new address. */
++ rose_copy_address_to_q931(ctrl, &deflection.to,
++ &invoke->args.qsig.CallRerouting.called);
++ switch (invoke->args.qsig.CallRerouting.subscription_option) {
++ default:
++ case 0: /* noNotification */
++ case 1: /* notificationWithoutDivertedToNr */
++ deflection.to.number.presentation =
++ PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_UNSCREENED;
++ break;
++ case 2: /* notificationWithDivertedToNr */
++ deflection.to.number.presentation =
++ PRI_PRES_ALLOWED | PRI_PRES_USER_NUMBER_UNSCREENED;
++ break;
++ }
+
+- return 0;
++ /* Calling party update. */
++ party_id = call->local_id;
++ rose_copy_presented_number_screened_to_q931(ctrl, &party_id.number,
++ &invoke->args.qsig.CallRerouting.calling);
++ if (invoke->args.qsig.CallRerouting.calling_name_present) {
++ rose_copy_name_to_q931(ctrl, &party_id.name,
++ &invoke->args.qsig.CallRerouting.calling_name);
++ }
++
++ deflection.count = invoke->args.qsig.CallRerouting.diversion_counter;
++ deflection.reason = redirectingreason_for_q931(ctrl,
++ invoke->args.qsig.CallRerouting.rerouting_reason);
++
++ /* Original called party update. */
++ if (deflection.count == 1) {
++ deflection.orig_called = deflection.from;
++ deflection.orig_reason = deflection.reason;
++ } else {
++ deflection.orig_called = call->redirecting.orig_called;
++ deflection.orig_reason = call->redirecting.orig_reason;
++ }
++ if (invoke->args.qsig.CallRerouting.original_called_present) {
++ rose_copy_presented_number_unscreened_to_q931(ctrl,
++ &deflection.orig_called.number,
++ &invoke->args.qsig.CallRerouting.original_called);
++ }
++ if (invoke->args.qsig.CallRerouting.original_called_name_present) {
++ rose_copy_name_to_q931(ctrl, &deflection.orig_called.name,
++ &invoke->args.qsig.CallRerouting.original_called_name);
++ }
++ if (invoke->args.qsig.CallRerouting.original_rerouting_reason_present) {
++ deflection.orig_reason = redirectingreason_for_q931(ctrl,
++ invoke->args.qsig.CallRerouting.original_rerouting_reason);
++ }
++
++ subcmd->cmd = PRI_SUBCMD_REROUTING;
++ subcmd->u.rerouting.invoke_id = invoke->invoke_id;
++ subcmd->u.rerouting.subscription_option =
++ invoke->args.qsig.CallRerouting.subscription_option;
++ q931_party_id_copy_to_pri(&subcmd->u.rerouting.caller, &party_id);
++ q931_party_redirecting_copy_to_pri(&subcmd->u.rerouting.deflection,
++ &deflection);
++ break;
++ case ROSE_QSIG_DivertingLegInformation1:
++ q931_party_number_init(&party_id.number);
++ rose_copy_number_to_q931(ctrl, &party_id.number,
++ &invoke->args.qsig.DivertingLegInformation1.nominated_number);
++ if (party_id.number.str[0]) {
++ party_id.number.presentation =
++ PRI_PRES_ALLOWED | PRI_PRES_USER_NUMBER_UNSCREENED;
++ }
++
++ /*
++ * Unless otherwise indicated by CONNECT, the nominatedNr will be
++ * the remote_id.number.
++ */
++ if (!call->connected_number_in_message) {
++ call->remote_id.number = party_id.number;
++ }
++
++ /* nominatedNr is put in redirecting.to.number */
++ switch (invoke->args.qsig.DivertingLegInformation1.subscription_option) {
++ default:
++ case QSIG_NO_NOTIFICATION:
++ case QSIG_NOTIFICATION_WITHOUT_DIVERTED_TO_NR:
++ q931_party_number_init(&call->redirecting.to.number);
++ call->redirecting.to.number.valid = 1;
++ call->redirecting.to.number.presentation =
++ PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_UNSCREENED;
++ break;
++ case QSIG_NOTIFICATION_WITH_DIVERTED_TO_NR:
++ call->redirecting.to.number = party_id.number;
++ break;
++ }
++
++ call->redirecting.reason = redirectingreason_for_q931(ctrl,
++ invoke->args.qsig.DivertingLegInformation1.diversion_reason);
++ if (call->redirecting.count < PRI_MAX_REDIRECTS) {
++ ++call->redirecting.count;
++ }
++ call->redirecting.state = Q931_REDIRECTING_STATE_EXPECTING_RX_DIV_LEG_3;
++ break;
++ case ROSE_QSIG_DivertingLegInformation2:
++ call->redirecting.state = Q931_REDIRECTING_STATE_PENDING_TX_DIV_LEG_3;
++ call->redirecting.count =
++ invoke->args.qsig.DivertingLegInformation2.diversion_counter;
++ if (!call->redirecting.count) {
++ /* To be safe, make sure that the count is non-zero. */
++ call->redirecting.count = 1;
++ }
++ call->redirecting.reason = redirectingreason_for_q931(ctrl,
++ invoke->args.qsig.DivertingLegInformation2.diversion_reason);
++
++ /* divertingNr is put in redirecting.from.number */
++ if (invoke->args.qsig.DivertingLegInformation2.diverting_present) {
++ rose_copy_presented_number_unscreened_to_q931(ctrl,
++ &call->redirecting.from.number,
++ &invoke->args.qsig.DivertingLegInformation2.diverting);
++ } else if (!call->redirecting_number_in_message) {
++ q931_party_number_init(&call->redirecting.from.number);
++ call->redirecting.from.number.valid = 1;
++ }
++
++ /* redirectingName is put in redirecting.from.name */
++ if (invoke->args.qsig.DivertingLegInformation2.redirecting_name_present) {
++ rose_copy_name_to_q931(ctrl, &call->redirecting.from.name,
++ &invoke->args.qsig.DivertingLegInformation2.redirecting_name);
++ } else {
++ q931_party_name_init(&call->redirecting.from.name);
++ }
++
++ call->redirecting.orig_reason = PRI_REDIR_UNKNOWN;
++ if (invoke->args.qsig.DivertingLegInformation2.original_diversion_reason_present) {
++ call->redirecting.orig_reason = redirectingreason_for_q931(ctrl,
++ invoke->args.qsig.DivertingLegInformation2.original_diversion_reason);
++ }
++
++ /* originalCalledNr is put in redirecting.orig_called.number */
++ if (invoke->args.qsig.DivertingLegInformation2.original_called_present) {
++ rose_copy_presented_number_unscreened_to_q931(ctrl,
++ &call->redirecting.orig_called.number,
++ &invoke->args.qsig.DivertingLegInformation2.original_called);
++ } else {
++ q931_party_number_init(&call->redirecting.orig_called.number);
++ }
++
++ /* originalCalledName is put in redirecting.orig_called.name */
++ if (invoke->args.qsig.DivertingLegInformation2.original_called_name_present) {
++ rose_copy_name_to_q931(ctrl, &call->redirecting.orig_called.name,
++ &invoke->args.qsig.DivertingLegInformation2.original_called_name);
++ } else {
++ q931_party_name_init(&call->redirecting.orig_called.name);
++ }
++ break;
++ case ROSE_QSIG_DivertingLegInformation3:
++ /*
++ * Unless otherwise indicated by CONNECT, this will be the
++ * remote_id.number.presentation.
++ */
++ if (!invoke->args.qsig.DivertingLegInformation3.presentation_allowed_indicator) {
++ call->redirecting.to.number.presentation =
++ PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_UNSCREENED;
++ if (!call->connected_number_in_message) {
++ call->remote_id.number.presentation =
++ PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_UNSCREENED;
++ }
++ }
++
++ /* redirectionName is put in redirecting.to.name */
++ if (invoke->args.qsig.DivertingLegInformation3.redirection_name_present) {
++ rose_copy_name_to_q931(ctrl, &call->redirecting.to.name,
++ &invoke->args.qsig.DivertingLegInformation3.redirection_name);
++ if (!invoke->args.qsig.DivertingLegInformation3.presentation_allowed_indicator) {
++ call->redirecting.to.name.presentation = PRI_PRES_RESTRICTED;
++ }
++ } else {
++ q931_party_name_init(&call->redirecting.to.name);
++ }
++
++ switch (call->redirecting.state) {
++ case Q931_REDIRECTING_STATE_EXPECTING_RX_DIV_LEG_3:
++ call->redirecting.state = Q931_REDIRECTING_STATE_IDLE;
++ subcmd = q931_alloc_subcommand(ctrl);
++ if (!subcmd) {
++ pri_error(ctrl, "ERROR: Too many facility subcommands\n");
++ break;
++ }
++ /* Setup redirecting subcommand */
++ subcmd->cmd = PRI_SUBCMD_REDIRECTING;
++ q931_party_redirecting_copy_to_pri(&subcmd->u.redirecting,
++ &call->redirecting);
++ break;
++ default:
++ break;
++ }
++ break;
++#if 0 /* Not handled yet */
++ case ROSE_QSIG_CfnrDivertedLegFailed:
++ break;
++#endif /* Not handled yet */
++#if 0 /* Not handled yet */
++ case ROSE_QSIG_MWIActivate:
++ break;
++ case ROSE_QSIG_MWIDeactivate:
++ break;
++ case ROSE_QSIG_MWIInterrogate:
++ break;
++#endif /* Not handled yet */
++ default:
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, "!! ROSE invoke operation not handled! %s\n",
++ rose_operation2str(invoke->operation));
++ }
++ break;
++ }
+ }
+-
+Index: pri_facility.h
+===================================================================
+--- a/pri_facility.h (.../tags/1.4.10.2) (revision 1357)
++++ b/pri_facility.h (.../branches/1.4) (revision 1357)
+@@ -31,123 +31,21 @@
+ #define _PRI_FACILITY_H
+ #include "pri_q931.h"
+
++/* Forward declare some structs */
++struct fac_extension_header;
++struct rose_msg_invoke;
++struct rose_msg_result;
++struct rose_msg_error;
++struct rose_msg_reject;
++
+ /* Protocol Profile field */
++#define Q932_PROTOCOL_MASK 0x1F
+ #define Q932_PROTOCOL_ROSE 0x11 /* X.219 & X.229 */
+ #define Q932_PROTOCOL_CMIP 0x12 /* Q.941 */
+ #define Q932_PROTOCOL_ACSE 0x13 /* X.217 & X.227 */
+ #define Q932_PROTOCOL_GAT 0x16
+ #define Q932_PROTOCOL_EXTENSIONS 0x1F
+
+-/* Argument values */
+-#define ROSE_NAME_PRESENTATION_ALLOWED_SIMPLE 0x80
+-#define ROSE_NAME_PRESENTATION_RESTRICTED_NULL 0x87
+-#define ROSE_NAME_PRESENTATION_ALLOWED_EXTENDED 0xA1
+-#define ROSE_NAME_PRESENTATION_RESTRICTED_SIMPLE 0xA2
+-#define ROSE_NAME_PRESENTATION_RESTRICTED_EXTENDED 0xA3
+-#define ROSE_NAME_NOT_AVAIL 0x84
+-
+-/* Component types */
+-#define COMP_TYPE_INTERPRETATION 0x8B
+-#define COMP_TYPE_NETWORK_PROTOCOL_PROFILE 0x92
+-#define COMP_TYPE_INVOKE 0xA1
+-#define COMP_TYPE_RETURN_RESULT 0xA2
+-#define COMP_TYPE_RETURN_ERROR 0xA3
+-#define COMP_TYPE_REJECT 0xA4
+-#define COMP_TYPE_NFE 0xAA
+-
+-/* Operation ID values */
+-/* Q.952.7 (ECMA-178) ROSE operations (Transfer) */
+-#define ROSE_CALL_TRANSFER_IDENTIFY 7
+-#define ROSE_CALL_TRANSFER_ABANDON 8
+-#define ROSE_CALL_TRANSFER_INITIATE 9
+-#define ROSE_CALL_TRANSFER_SETUP 10
+-#define ROSE_CALL_TRANSFER_ACTIVE 11
+-#define ROSE_CALL_TRANSFER_COMPLETE 12
+-#define ROSE_CALL_TRANSFER_UPDATE 13
+-#define ROSE_SUBADDRESS_TRANSFER 14
+-/* Q.952 ROSE operations (Diverting) */
+-#define ROSE_DIVERTING_LEG_INFORMATION1 18
+-#define ROSE_DIVERTING_LEG_INFORMATION2 0x15
+-#define ROSE_DIVERTING_LEG_INFORMATION3 19
+-/* Q.956 ROSE operations (Advice Of Charge) */
+-#define ROSE_AOC_NO_CHARGING_INFO_AVAILABLE 26
+-#define ROSE_AOC_CHARGING_REQUEST 30
+-#define ROSE_AOC_AOCS_CURRENCY 31
+-#define ROSE_AOC_AOCS_SPECIAL_ARR 32
+-#define ROSE_AOC_AOCD_CURRENCY 33
+-#define ROSE_AOC_AOCD_CHARGING_UNIT 34
+-#define ROSE_AOC_AOCE_CURRENCY 35
+-#define ROSE_AOC_AOCE_CHARGING_UNIT 36
+-#define ROSE_AOC_IDENTIFICATION_OF_CHARGE 37
+-/* Q.SIG operations */
+-#define SS_CNID_CALLINGNAME 0
+-#define SS_ANFPR_PATHREPLACEMENT 4
+-#define SS_DIVERTING_LEG_INFORMATION2 21
+-#define SS_MWI_ACTIVATE 80
+-#define SS_MWI_DEACTIVATE 81
+-#define SS_MWI_INTERROGATE 82
+-
+-/* ROSE definitions and data structures */
+-#define INVOKE_IDENTIFIER 0x02
+-#define INVOKE_LINKED_IDENTIFIER 0x80
+-#define INVOKE_NULL_IDENTIFIER __USE_ASN1_NULL
+-
+-/* ASN.1 Identifier Octet - Data types */
+-#define ASN1_TYPE_MASK 0x1f
+-#define ASN1_BOOLEAN 0x01
+-#define ASN1_INTEGER 0x02
+-#define ASN1_BITSTRING 0x03
+-#define ASN1_OCTETSTRING 0x04
+-#define ASN1_NULL 0x05
+-#define ASN1_OBJECTIDENTIFIER 0x06
+-#define ASN1_OBJECTDESCRIPTOR 0x07
+-#define ASN1_EXTERN 0x08
+-#define ASN1_REAL 0x09
+-#define ASN1_ENUMERATED 0x0a
+-#define ASN1_EMBEDDEDPDV 0x0b
+-#define ASN1_UTF8STRING 0x0c
+-#define ASN1_RELATIVEOBJECTID 0x0d
+-/* 0x0e & 0x0f are reserved for future ASN.1 editions */
+-#define ASN1_SEQUENCE 0x10
+-#define ASN1_SET 0x11
+-#define ASN1_NUMERICSTRING 0x12
+-#define ASN1_PRINTABLESTRING 0x13
+-#define ASN1_TELETEXSTRING 0x14
+-#define ASN1_IA5STRING 0x16
+-#define ASN1_UTCTIME 0x17
+-#define ASN1_GENERALIZEDTIME 0x18
+-
+-/* ASN.1 Identifier Octet - Tags */
+-#define ASN1_TAG_0 0x00
+-#define ASN1_TAG_1 0x01
+-#define ASN1_TAG_2 0x02
+-#define ASN1_TAG_3 0x03
+-#define ASN1_TAG_4 0x04
+-#define ASN1_TAG_5 0x05
+-#define ASN1_TAG_6 0x06
+-#define ASN1_TAG_7 0x07
+-#define ASN1_TAG_8 0x08
+-#define ASN1_TAG_9 0x09
+-
+-/* ASN.1 Identifier Octet - Primitive/Constructor Bit */
+-#define ASN1_PC_MASK 0x20
+-#define ASN1_PRIMITIVE 0x00
+-#define ASN1_CONSTRUCTOR 0x20
+-
+-/* ASN.1 Identifier Octet - Clan Bits */
+-#define ASN1_CLAN_MASK 0xc0
+-#define ASN1_UNIVERSAL 0x00
+-#define ASN1_APPLICATION 0x40
+-#define ASN1_CONTEXT_SPECIFIC 0x80
+-#define ASN1_PRIVATE 0xc0
+-
+-/* ASN.1 Length masks */
+-#define ASN1_LEN_INDEF 0x80
+-
+-
+-#define INVOKE_OPERATION_INT __USE_ASN1_INTEGER
+-#define INVOKE_OBJECT_ID __USE_ASN1_OBJECTIDENTIFIER
+-
+ /* Q.952 Divert cause */
+ #define Q952_DIVERT_REASON_UNKNOWN 0x00
+ #define Q952_DIVERT_REASON_CFU 0x01
+@@ -169,138 +67,112 @@
+ #define Q932_TON_SUBSCRIBER 0x04
+ #define Q932_TON_ABBREVIATED 0x06
+
+-/* RLT related Operations */
+-#define RLT_SERVICE_ID 0x3e
+-#define RLT_OPERATION_IND 0x01
+-#define RLT_THIRD_PARTY 0x02
++/* Q.SIG Subscription Option. Listed in ECMA-174 */
++#define QSIG_NO_NOTIFICATION 0x00
++#define QSIG_NOTIFICATION_WITHOUT_DIVERTED_TO_NR 0x01
++#define QSIG_NOTIFICATION_WITH_DIVERTED_TO_NR 0x02
+
+-struct rose_component {
+- u_int8_t type;
+- u_int8_t len;
+- u_int8_t data[0];
++/*! Reasons an APDU callback is called. */
++enum APDU_CALLBACK_REASON {
++ /*!
++ * \brief Send setup error. Abort and cleanup.
++ * \note The message may or may not actually get sent.
++ * \note The callback cannot generate an event subcmd.
++ * \note The callback should not send messages. Out of order messages will result.
++ */
++ APDU_CALLBACK_REASON_ERROR,
++ /*!
++ * \brief Abort and cleanup.
++ * \note The APDU queue is being destroyed.
++ * \note The callback cannot generate an event subcmd.
++ * \note The callback cannot send messages as the call is likely being destroyed.
++ */
++ APDU_CALLBACK_REASON_CLEANUP,
++ /*!
++ * \brief Timeout waiting for responses to the message.
++ * \note The callback can generate an event subcmd.
++ * \note The callback can send messages.
++ */
++ APDU_CALLBACK_REASON_TIMEOUT,
++ /*!
++ * \brief Received a facility response message.
++ * \note The callback can generate an event subcmd.
++ * \note The callback can send messages.
++ */
++ APDU_CALLBACK_REASON_MSG_RESULT,
++ /*!
++ * \brief Received a facility error message.
++ * \note The callback can generate an event subcmd.
++ * \note The callback can send messages.
++ */
++ APDU_CALLBACK_REASON_MSG_ERROR,
++ /*!
++ * \brief Received a facility reject message.
++ * \note The callback can generate an event subcmd.
++ * \note The callback can send messages.
++ */
++ APDU_CALLBACK_REASON_MSG_REJECT,
+ };
+
+-#if 1
+- #define GET_COMPONENT(component, idx, ptr, length) \
+- if ((idx)+2 > (length)) \
+- break; \
+- (component) = (struct rose_component*)&((ptr)[idx]); \
+- if ((idx)+(component)->len+2 > (length)) { \
+- if ((component)->len != ASN1_LEN_INDEF) \
+- pri_message(pri, "Length (%d) of 0x%X component is too long\n", (component)->len, (component)->type); \
+- }
+-#else /* Debugging */
+- #define GET_COMPONENT(component, idx, ptr, length) \
+- if ((idx)+2 > (length)) \
+- break; \
+- (component) = (struct rose_component*)&((ptr)[idx]); \
+- if ((idx)+(component)->len+2 > (length)) { \
+- if ((component)->len != 128) \
+- pri_message(pri, "Length (%d) of 0x%X component is too long\n", (component)->len, (component)->type); \
+- } \
+- pri_message(pri, "XX %s:%d Got component %d (0x%02X), length %d\n", __FUNCTION__, __LINE__, (component)->type, (component)->type, (component)->len); \
+- if ((component)->len > 0) { \
+- int zzz; \
+- pri_message(pri, "XX Data:"); \
+- for (zzz = 0; zzz < (component)->len; ++zzz) \
+- pri_message(pri, " %02X", (component)->data[zzz]); \
+- pri_message(pri, "\n"); \
+- }
+-#endif
++union apdu_msg_data {
++ const struct rose_msg_result *result;
++ const struct rose_msg_error *error;
++ const struct rose_msg_reject *reject;
++};
+
+-#define NEXT_COMPONENT(component, idx) \
+- (idx) += (component)->len + 2
++union apdu_callback_param {
++ void *ptr;
++ long value;
++ char pad[8];
++};
+
+-#define SUB_COMPONENT(component, idx) \
+- (idx) += 2
++struct apdu_callback_data {
++ /*! APDU invoke id to match with any response messages. (Result/Error/Reject) */
++ int invoke_id;
++ /*!
++ * \brief Time to wait for responses to APDU in ms.
++ * \note Set to 0 if send the message only.
++ * \note Set to less than 0 for PRI_TIMER_T_RESPONSE time.
++ */
++ int timeout_time;
++ /*!
++ * \brief APDU 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.)
++ *
++ * \note
++ * A callback must be supplied if the sender cares about any APDU_CALLBACK_REASON.
++ *
++ * \return TRUE if no more responses are expected.
++ */
++ int (*callback)(enum APDU_CALLBACK_REASON reason, struct pri *ctrl, struct q931_call *call, struct apdu_event *apdu, const union apdu_msg_data *msg);
++ /*! \brief Sender data for the callback function to identify the particular APDU. */
++ union apdu_callback_param user;
++};
+
+-#define CHECK_COMPONENT(component, comptype, message) \
+- if ((component)->type && ((component)->type & ASN1_TYPE_MASK) != (comptype)) { \
+- pri_message(pri, (message), (component)->type); \
+- asn1_dump(pri, (component), (component)->len+2); \
+- break; \
+- }
+-
+-#define ASN1_GET_INTEGER(component, variable) \
+- do { \
+- int comp_idx; \
+- (variable) = 0; \
+- for (comp_idx = 0; comp_idx < (component)->len; ++comp_idx) \
+- (variable) = ((variable) << 8) | (component)->data[comp_idx]; \
+- } while (0)
++struct apdu_event {
++ /*! Linked list pointer */
++ struct apdu_event *next;
++ /*! TRUE if this APDU has been sent. */
++ int sent;
++ /*! What message to send the ADPU in */
++ int message;
++ /*! Sender supplied information to handle APDU response messages. */
++ struct apdu_callback_data response;
++ /*! Q.931 call leg. (Needed for the APDU timeout.) */
++ struct q931_call *call;
++ /*! Response timeout timer. */
++ int timer;
++ /*! Length of ADPU */
++ int apdu_len;
++ /*! ADPU to send */
++ unsigned char apdu[255];
++};
+
+-#define ASN1_FIXUP_LEN(component, size) \
+- do { \
+- if ((component)->len == ASN1_LEN_INDEF) \
+- size += 2; \
+- } while (0)
+-
+-#define ASN1_ADD_SIMPLE(component, comptype, ptr, idx) \
+- do { \
+- (component) = (struct rose_component *)&((ptr)[(idx)]); \
+- (component)->type = (comptype); \
+- (component)->len = 0; \
+- (idx) += 2; \
+- } while (0)
+-
+-#define ASN1_ADD_BYTECOMP(component, comptype, ptr, idx, value) \
+- do { \
+- (component) = (struct rose_component *)&((ptr)[(idx)]); \
+- (component)->type = (comptype); \
+- (component)->len = 1; \
+- (component)->data[0] = (value); \
+- (idx) += 3; \
+- } while (0)
+-
+-#define ASN1_ADD_WORDCOMP(component, comptype, ptr, idx, value) \
+- do { \
+- int __val = (value); \
+- int __i = 0; \
+- (component) = (struct rose_component *)&((ptr)[(idx)]); \
+- (component)->type = (comptype); \
+- if ((__val >> 24)) \
+- (component)->data[__i++] = (__val >> 24) & 0xff; \
+- if ((__val >> 16)) \
+- (component)->data[__i++] = (__val >> 16) & 0xff; \
+- if ((__val >> 8)) \
+- (component)->data[__i++] = (__val >> 8) & 0xff; \
+- (component)->data[__i++] = __val & 0xff; \
+- (component)->len = __i; \
+- (idx) += 2 + __i; \
+- } while (0)
+-
+-#define ASN1_PUSH(stack, stackpointer, component) \
+- (stack)[(stackpointer)++] = (component)
+-
+-#define ASN1_FIXUP(stack, stackpointer, data, idx) \
+- do { \
+- --(stackpointer); \
+- (stack)[(stackpointer)]->len = (unsigned char *)&((data)[(idx)]) - (unsigned char *)(stack)[(stackpointer)] - 2; \
+- } while (0)
+-
+-/* Decoder for the invoke ROSE component */
+-int rose_invoke_decode(struct pri *pri, struct q931_call *call, q931_ie *ie, unsigned char *data, int len);
+-
+-/* Decoder for the return result ROSE component */
+-int rose_return_result_decode(struct pri *pri, struct q931_call *call, q931_ie *ie, unsigned char *data, int len);
+-
+-/* Decoder for the return error ROSE component */
+-int rose_return_error_decode(struct pri *pri, struct q931_call *call, q931_ie *ie, unsigned char *data, int len);
+-
+-/* Decoder for the reject ROSE component */
+-int rose_reject_decode(struct pri *pri, struct q931_call *call, q931_ie *ie, unsigned char *data, int len);
+-
+-int asn1_copy_string(char * buf, int buflen, struct rose_component *comp);
+-
+-int asn1_string_encode(unsigned char asn1_type, void *data, int len, int max_len, void *src, int src_len);
+-
+-/* Get Name types from ASN.1 */
+-int asn1_name_decode(void * data, int len, char *namebuf, int buflen);
+-
+-int typeofnumber_from_q931(struct pri *pri, int ton);
+-
+-int redirectingreason_from_q931(struct pri *pri, int redirectingreason);
+-
+ /* Queues an MWI apdu on a the given call */
+ int mwi_message_send(struct pri *pri, q931_call *call, struct pri_sr *req, int activate);
+
+@@ -310,21 +182,31 @@
+ int rlt_initiate_transfer(struct pri *pri, q931_call *c1, q931_call *c2);
+
+ int qsig_cf_callrerouting(struct pri *pri, q931_call *c, const char* dest, const char* original, const char* reason);
++int send_reroute_request(struct pri *ctrl, q931_call *call, const struct q931_party_id *caller, const struct q931_party_redirecting *deflection, int subscription_option);
+
+ /* starts a QSIG Path Replacement */
+ int anfpr_initiate_transfer(struct pri *pri, q931_call *c1, q931_call *c2);
+
+-/* Use this function to queue a facility-IE born APDU onto a call
+- * call is the call to use, messagetype is any one of the Q931 messages,
+- * apdu is the apdu data, apdu_len is the length of the apdu data */
+-int pri_call_apdu_queue(q931_call *call, int messagetype, void *apdu, int apdu_len, void (*function)(void *data), void *data);
++int send_call_transfer_complete(struct pri *pri, q931_call *call, int call_status);
+
+-/* Used by q931.c to cleanup the apdu queue upon destruction of a call */
+-int pri_call_apdu_queue_cleanup(q931_call *call);
++int rose_diverting_leg_information1_encode(struct pri *pri, q931_call *call);
++int rose_diverting_leg_information3_encode(struct pri *pri, q931_call *call, int messagetype);
+
++int rose_connected_name_encode(struct pri *pri, q931_call *call, int messagetype);
++int rose_called_name_encode(struct pri *pri, q931_call *call, int messagetype);
++
++int pri_call_apdu_queue(q931_call *call, int messagetype, const unsigned char *apdu, int apdu_len, struct apdu_callback_data *response);
++void pri_call_apdu_queue_cleanup(q931_call *call);
++void pri_call_apdu_delete(struct q931_call *call, struct apdu_event *doomed);
++
+ /* Adds the "standard" APDUs to a call */
+ int pri_call_add_standard_apdus(struct pri *pri, q931_call *call);
+
+-int asn1_dump(struct pri *pri, void *comp, int len);
++void asn1_dump(struct pri *ctrl, const unsigned char *start_asn1, const unsigned char *end);
+
++void rose_handle_invoke(struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, const struct fac_extension_header *header, const struct rose_msg_invoke *invoke);
++void rose_handle_result(struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, const struct fac_extension_header *header, const struct rose_msg_result *result);
++void rose_handle_error(struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, const struct fac_extension_header *header, const struct rose_msg_error *error);
++void rose_handle_reject(struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, const struct fac_extension_header *header, const struct rose_msg_reject *reject);
++
+ #endif /* _PRI_FACILITY_H */
+Index: libpri.h
+===================================================================
+--- a/libpri.h (.../tags/1.4.10.2) (revision 1357)
++++ b/libpri.h (.../branches/1.4) (revision 1357)
+@@ -26,7 +26,14 @@
+ * provided with that copy of Asterisk, instead of the license
+ * terms granted here.
+ */
+-
++
++/*
++ * NOTE:
++ * All new global identifiers that are added to this file MUST be
++ * prefixed with PRI_ or pri_ to indicate that they are part of this
++ * library and to reduce potential naming conflicts.
++ */
++
+ #ifndef _LIBPRI_H
+ #define _LIBPRI_H
+
+@@ -73,7 +80,8 @@
+ #define PRI_EVENT_ANSWER 8 /* Call has been answered (CONNECT) */
+ #define PRI_EVENT_HANGUP_ACK 9 /* Call hangup has been acknowledged */
+ #define PRI_EVENT_RESTART_ACK 10 /* Restart complete on a given channel (RESTART_ACKNOWLEDGE) */
+-#define PRI_EVENT_FACNAME 11 /* Caller*ID Name received on Facility */
++#define PRI_EVENT_FACNAME 11 /* Caller*ID Name received on Facility (DEPRECATED) */
++#define PRI_EVENT_FACILITY 11 /* Facility received (FACILITY) */
+ #define PRI_EVENT_INFO_RECEIVED 12 /* Additional info (digits) received (INFORMATION) */
+ #define PRI_EVENT_PROCEEDING 13 /* When we get CALL_PROCEEDING */
+ #define PRI_EVENT_SETUP_ACK 14 /* When we get SETUP_ACKNOWLEDGE */
+@@ -81,6 +89,14 @@
+ #define PRI_EVENT_NOTIFY 16 /* Notification received (NOTIFY) */
+ #define PRI_EVENT_PROGRESS 17 /* When we get PROGRESS */
+ #define PRI_EVENT_KEYPAD_DIGIT 18 /* When we receive during ACTIVE state (INFORMATION) */
++#define PRI_EVENT_SERVICE 19 /* SERVICE maintenance message */
++#define PRI_EVENT_SERVICE_ACK 20 /* SERVICE maintenance acknowledgement message */
++#define PRI_EVENT_HOLD 21 /* HOLD request received */
++#define PRI_EVENT_HOLD_ACK 22 /* HOLD_ACKNOWLEDGE received */
++#define PRI_EVENT_HOLD_REJ 23 /* HOLD_REJECT received */
++#define PRI_EVENT_RETRIEVE 24 /* RETRIEVE request received */
++#define PRI_EVENT_RETRIEVE_ACK 25 /* RETRIEVE_ACKNOWLEDGE received */
++#define PRI_EVENT_RETRIEVE_REJ 26 /* RETRIEVE_REJECT received */
+
+ /* Simple states */
+ #define PRI_STATE_DOWN 0
+@@ -101,13 +117,13 @@
+ #define PRI_PROG_CALLER_RETURNED_TO_ISDN (1 << 9)
+
+ /* Numbering plan identifier */
+-#define PRI_NPI_UNKNOWN 0x0
+-#define PRI_NPI_E163_E164 0x1
+-#define PRI_NPI_X121 0x3
+-#define PRI_NPI_F69 0x4
+-#define PRI_NPI_NATIONAL 0x8
+-#define PRI_NPI_PRIVATE 0x9
+-#define PRI_NPI_RESERVED 0xF
++#define PRI_NPI_UNKNOWN 0x0 /*!< Unknown numbering plan */
++#define PRI_NPI_E163_E164 0x1 /*!< ISDN/telephony numbering plan (public) */
++#define PRI_NPI_X121 0x3 /*!< Data numbering plan */
++#define PRI_NPI_F69 0x4 /*!< Telex numbering plan */
++#define PRI_NPI_NATIONAL 0x8 /*!< National standard numbering plan */
++#define PRI_NPI_PRIVATE 0x9 /*!< Private numbering plan */
++#define PRI_NPI_RESERVED 0xF /*!< Reserved for extension */
+
+ /* Type of number */
+ #define PRI_TON_UNKNOWN 0x0
+@@ -135,16 +151,49 @@
+ #define PRI_UNKNOWN 0x0
+
+ /* Presentation */
+-#define PRES_ALLOWED_USER_NUMBER_NOT_SCREENED 0x00
+-#define PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN 0x01
+-#define PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN 0x02
+-#define PRES_ALLOWED_NETWORK_NUMBER 0x03
+-#define PRES_PROHIB_USER_NUMBER_NOT_SCREENED 0x20
+-#define PRES_PROHIB_USER_NUMBER_PASSED_SCREEN 0x21
+-#define PRES_PROHIB_USER_NUMBER_FAILED_SCREEN 0x22
+-#define PRES_PROHIB_NETWORK_NUMBER 0x23
+-#define PRES_NUMBER_NOT_AVAILABLE 0x43
++#define PRI_PRES_NUMBER_TYPE 0x03
++#define PRI_PRES_USER_NUMBER_UNSCREENED 0x00
++#define PRI_PRES_USER_NUMBER_PASSED_SCREEN 0x01
++#define PRI_PRES_USER_NUMBER_FAILED_SCREEN 0x02
++#define PRI_PRES_NETWORK_NUMBER 0x03
+
++#define PRI_PRES_RESTRICTION 0x60
++#define PRI_PRES_ALLOWED 0x00
++#define PRI_PRES_RESTRICTED 0x20
++#define PRI_PRES_UNAVAILABLE 0x40
++#define PRI_PRES_RESERVED 0x60
++
++#define PRES_ALLOWED_USER_NUMBER_NOT_SCREENED \
++ (PRI_PRES_ALLOWED | PRI_PRES_USER_NUMBER_UNSCREENED)
++
++#define PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN \
++ (PRI_PRES_ALLOWED | PRI_PRES_USER_NUMBER_PASSED_SCREEN)
++
++#define PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN \
++ (PRI_PRES_ALLOWED | PRI_PRES_USER_NUMBER_FAILED_SCREEN)
++
++#define PRES_ALLOWED_NETWORK_NUMBER \
++ (PRI_PRES_ALLOWED | PRI_PRES_NETWORK_NUMBER)
++
++#define PRES_PROHIB_USER_NUMBER_NOT_SCREENED \
++ (PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_UNSCREENED)
++
++#define PRES_PROHIB_USER_NUMBER_PASSED_SCREEN \
++ (PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_PASSED_SCREEN)
++
++#define PRES_PROHIB_USER_NUMBER_FAILED_SCREEN \
++ (PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_FAILED_SCREEN)
++
++#define PRES_PROHIB_NETWORK_NUMBER \
++ (PRI_PRES_RESTRICTED | PRI_PRES_NETWORK_NUMBER)
++
++#define PRES_NUMBER_NOT_AVAILABLE \
++ (PRI_PRES_UNAVAILABLE | PRI_PRES_NETWORK_NUMBER)
++
++/* Reverse Charging Indication */
++#define PRI_REVERSECHARGE_NONE -1
++#define PRI_REVERSECHARGE_REQUESTED 1
++
+ /* Causes for disconnection */
+ #define PRI_CAUSE_UNALLOCATED 1
+ #define PRI_CAUSE_NO_ROUTE_TRANSIT_NET 2 /* !Q.SIG */
+@@ -157,6 +206,7 @@
+ #define PRI_CAUSE_NO_ANSWER 19
+ #define PRI_CAUSE_CALL_REJECTED 21
+ #define PRI_CAUSE_NUMBER_CHANGED 22
++#define PRI_CAUSE_NONSELECTED_USER_CLEARING 26
+ #define PRI_CAUSE_DESTINATION_OUT_OF_ORDER 27
+ #define PRI_CAUSE_INVALID_NUMBER_FORMAT 28
+ #define PRI_CAUSE_FACILITY_REJECTED 29 /* !Q.SIG */
+@@ -169,6 +219,7 @@
+ #define PRI_CAUSE_ACCESS_INFO_DISCARDED 43 /* !Q.SIG */
+ #define PRI_CAUSE_REQUESTED_CHAN_UNAVAIL 44
+ #define PRI_CAUSE_PRE_EMPTED 45 /* !Q.SIG */
++#define PRI_CAUSE_RESOURCE_UNAVAIL_UNSPECIFIED 47
+ #define PRI_CAUSE_FACILITY_NOT_SUBSCRIBED 50 /* !Q.SIG */
+ #define PRI_CAUSE_OUTGOING_CALL_BARRED 52 /* !Q.SIG */
+ #define PRI_CAUSE_INCOMING_CALL_BARRED 54 /* !Q.SIG */
+@@ -259,8 +310,8 @@
+ #define PRI_RATE_ADAPT_ASYNC 0x40
+
+ /* Notifications */
+-#define PRI_NOTIFY_USER_SUSPENDED 0x00 /* User suspended */
+-#define PRI_NOTIFY_USER_RESUMED 0x01 /* User resumed */
++#define PRI_NOTIFY_USER_SUSPENDED 0x00 /* User suspended (Q.931) (Call is placed on hold) */
++#define PRI_NOTIFY_USER_RESUMED 0x01 /* User resumed (Q.931) (Call is taken off hold) */
+ #define PRI_NOTIFY_BEARER_CHANGE 0x02 /* Bearer service change (DSS1) */
+ #define PRI_NOTIFY_ASN1_COMPONENT 0x03 /* ASN.1 encoded component (DSS1) */
+ #define PRI_NOTIFY_COMPLETION_DELAY 0x04 /* Call completion delay */
+@@ -275,12 +326,12 @@
+ #define PRI_NOTIFY_CONF_OTHER_DISCONNECTED 0x4a /* Other party disconnected */
+ #define PRI_NOTIFY_CONF_FLOATING 0x4b /* Conference floating */
+ #define PRI_NOTIFY_WAITING_CALL 0x60 /* Call is waiting call */
+-#define PRI_NOTIFY_DIVERSION_ACTIVATED 0x68 /* Diversion activated (DSS1) */
+-#define PRI_NOTIFY_TRANSFER_ALERTING 0x69 /* Call transfer, alerting */
+-#define PRI_NOTIFY_TRANSFER_ACTIVE 0x6a /* Call transfer, active */
++#define PRI_NOTIFY_DIVERSION_ACTIVATED 0x68 /* Diversion activated (DSS1) (cfu, cfb, cfnr) (EN 300 207-1 Section 7.2.1) */
++#define PRI_NOTIFY_TRANSFER_ALERTING 0x69 /* Call transfer, alerting (EN 300 369-1 Section 7.2) */
++#define PRI_NOTIFY_TRANSFER_ACTIVE 0x6a /* Call transfer, active(answered) (EN 300 369-1 Section 7.2) */
+ #define PRI_NOTIFY_REMOTE_HOLD 0x79 /* Remote hold */
+ #define PRI_NOTIFY_REMOTE_RETRIEVAL 0x7a /* Remote retrieval */
+-#define PRI_NOTIFY_CALL_DIVERTING 0x7b /* Call is diverting */
++#define PRI_NOTIFY_CALL_DIVERTING 0x7b /* Call is diverting (EN 300 207-1 Section 7.2.1) */
+
+ #define PRI_COPY_DIGITS_CALLED_NUMBER
+
+@@ -305,6 +356,200 @@
+
+ typedef struct q931_call q931_call;
+
++/* Name character set enumeration values */
++#define PRI_CHAR_SET_UNKNOWN 0
++#define PRI_CHAR_SET_ISO8859_1 1
++#define PRI_CHAR_SET_WITHDRAWN 2
++#define PRI_CHAR_SET_ISO8859_2 3
++#define PRI_CHAR_SET_ISO8859_3 4
++#define PRI_CHAR_SET_ISO8859_4 5
++#define PRI_CHAR_SET_ISO8859_5 6
++#define PRI_CHAR_SET_ISO8859_7 7
++#define PRI_CHAR_SET_ISO10646_BMPSTRING 8
++#define PRI_CHAR_SET_ISO10646_UTF_8STRING 9
++
++/*! \brief Q.SIG name information. */
++struct pri_party_name {
++ /*! \brief TRUE if the name information is valid/present */
++ int valid;
++ /*!
++ * \brief Q.931 presentation-indicator encoded field
++ * \note Must tollerate the Q.931 screening-indicator field values being present.
++ */
++ int presentation;
++ /*!
++ * \brief Character set the name is using.
++ * \details
++ * unknown(0),
++ * iso8859-1(1),
++ * enum-value-withdrawn-by-ITU-T(2)
++ * iso8859-2(3),
++ * iso8859-3(4),
++ * iso8859-4(5),
++ * iso8859-5(6),
++ * iso8859-7(7),
++ * iso10646-BmpString(8),
++ * iso10646-utf-8String(9)
++ * \details
++ * Set to iso8859-1(1) if unsure what to use.
++ */
++ int char_set;
++ /*! \brief Name data with null terminator. */
++ char str[64];
++};
++
++struct pri_party_number {
++ /*! \brief TRUE if the number information is valid/present */
++ int valid;
++ /*! \brief Q.931 presentation-indicator and screening-indicator encoded fields */
++ int presentation;
++ /*! \brief Q.931 Type-Of-Number and numbering-plan encoded fields */
++ int plan;
++ /*! \brief Number data with null terminator. */
++ char str[64];
++};
++
++/*!
++ * \note This structure is a place holder for possible future subaddress support
++ * to maintain ABI compatibility.
++ */
++struct pri_party_subaddress {
++ /*! \brief TRUE if the subaddress information is valid/present */
++ int valid;
++ /*!
++ * \brief Subaddress type.
++ * \details
++ * nsap(0),
++ * user_specified(2)
++ */
++ int type;
++ /*!
++ * \brief TRUE if odd number of address signals
++ * \note The odd/even indicator is used when the type of subaddress is
++ * user_specified and the coding is BCD.
++ */
++ int odd_even_indicator;
++ /*! \brief Length of the subaddress data */
++ int length;
++ /*!
++ * \brief Subaddress data with null terminator.
++ * \note The null terminator is a convenience only since the data could be
++ * BCD/binary and thus have a null byte as part of the contents.
++ */
++ unsigned char data[32];
++};
++
++/*! \brief Information needed to identify an endpoint in a call. */
++struct pri_party_id {
++ /*! \brief Subscriber name */
++ struct pri_party_name name;
++ /*! \brief Subscriber phone number */
++ struct pri_party_number number;
++ /*! \brief Subscriber subaddress */
++ struct pri_party_subaddress subaddress;
++};
++
++/*! \brief Connected Line/Party information */
++struct pri_party_connected_line {
++ /*! Connected party ID */
++ struct pri_party_id id;
++};
++
++/*!
++ * \brief Redirecting Line information.
++ * \details
++ * RDNIS (Redirecting Directory Number Information Service)
++ * Where a call diversion or transfer was invoked.
++ */
++struct pri_party_redirecting {
++ /*! Who is redirecting the call (Sent to the party the call is redirected toward) */
++ struct pri_party_id from;
++ /*! Call is redirecting to a new party (Sent to the caller) */
++ struct pri_party_id to;
++ /*! Originally called party (in cases of multiple redirects) */
++ struct pri_party_id orig_called;
++ /*! Number of times the call was redirected */
++ int count;
++ /*! Original reason for redirect (in cases of multiple redirects) */
++ int orig_reason;
++ /*! Redirection reason */
++ int reason;
++};
++
++/*!
++ * \brief Information for rerouting/deflecting the call.
++ */
++struct pri_rerouting_data {
++ /*!
++ * \brief Updated caller-id information.
++ * \note The information may have been altered by procedure in the private network.
++ */
++ struct pri_party_id caller;
++ /*!
++ * \note
++ * deflection.to is the new called number and must always be present.
++ */
++ struct pri_party_redirecting deflection;
++ /*!
++ * \brief Diverting user subscription option to specify if caller is notified.
++ * \details
++ * noNotification(0),
++ * notificationWithoutDivertedToNr(1),
++ * notificationWithDivertedToNr(2),
++ * notApplicable(3) (Status only.)
++ */
++ int subscription_option;
++ /*! Invocation ID to use when sending a reply to the call rerouting/deflection request. */
++ int invoke_id;
++};
++
++/* Subcommands derived from supplementary services. */
++#define PRI_SUBCMD_REDIRECTING 1
++#define PRI_SUBCMD_CONNECTED_LINE 2
++#define PRI_SUBCMD_REROUTING 3
++
++
++struct pri_subcommand {
++ /*! PRI_SUBCMD_xxx defined values */
++ int cmd;
++ union {
++ /*! Reserve room for possible expansion to maintain ABI compatibility. */
++ char reserve_space[512];
++ struct pri_party_connected_line connected_line;
++ struct pri_party_redirecting redirecting;
++ struct pri_rerouting_data rerouting;
++ } u;
++};
++
++/* Max number of subcommands per event message */
++#define PRI_MAX_SUBCOMMANDS 8
++
++struct pri_subcommands {
++ int counter_subcmd;
++ struct pri_subcommand subcmd[PRI_MAX_SUBCOMMANDS];
++};
++
++
++/*
++ * Event channel parameter encoding:
++ * 3322 2222 2222 1111 1111 1100 0000 0000
++ * 1098 7654 3210 9876 5432 1098 7654 3210
++ * xxxx xxxx xxxx xEDC BBBBBBBBB AAAAAAAAA
++ *
++ * Bit field
++ * A - B channel
++ * B - Span (DS1) (0 - 127)
++ * C - DS1 Explicit bit
++ * D - D channel (cis_call) bit (status only)
++ * E - Call is held bit (status only)
++ *
++ * B channel values:
++ * 0 - No channel (ISDN uses for call waiting feature)
++ * 1-127 - B channel #
++ * 0xFF - Any channel (Also if whole channel value is -1 in event)
++ */
++
++
+ typedef struct pri_event_generic {
+ /* Events with no additional information fall in this category */
+ int e;
+@@ -328,6 +573,7 @@
+ int progressmask;
+ q931_call *call;
+ char useruserinfo[260]; /* User->User info */
++ struct pri_subcommands *subcmds;
+ } pri_event_ringing;
+
+ typedef struct pri_event_answer {
+@@ -338,8 +584,10 @@
+ int progressmask;
+ q931_call *call;
+ char useruserinfo[260]; /* User->User info */
++ struct pri_subcommands *subcmds;
+ } pri_event_answer;
+
++/*! Deprecated replaced by struct pri_event_facility. */
+ typedef struct pri_event_facname {
+ int e;
+ char callingname[256];
+@@ -351,6 +599,24 @@
+ int callingplan; /* Dialing plan of Calling entity */
+ } pri_event_facname;
+
++struct pri_event_facility {
++ int e;
++ char callingname[256]; /*!< Deprecated, preserved for struct pri_event_facname compatibility */
++ char callingnum[256]; /*!< Deprecated, preserved for struct pri_event_facname compatibility */
++ int channel;
++ int cref;
++ /*!
++ * \brief Master call or normal call.
++ * \note Call pointer known about by upper layer.
++ * \note NULL if dummy call reference.
++ */
++ q931_call *call;
++ int callingpres; /*!< Presentation of Calling CallerID (Deprecated, preserved for struct pri_event_facname compatibility) */
++ int callingplan; /*!< Dialing plan of Calling entity (Deprecated, preserved for struct pri_event_facname compatibility) */
++ struct pri_subcommands *subcmds;
++ q931_call *subcall; /*!< Subcall to send any reply toward. */
++};
++
+ #define PRI_CALLINGPLANANI
+ #define PRI_CALLINGPLANRDNIS
+ typedef struct pri_event_ring {
+@@ -376,13 +642,18 @@
+ int layer1; /* User layer 1 */
+ int complete; /* Have we seen "Complete" i.e. no more number? */
+ q931_call *call; /* Opaque call pointer */
+- char callingsubaddr[256]; /* Calling parties subaddress */
++ char callingsubaddr[256]; /* Calling parties subaddress, backwards compatibility */
+ int progress;
+ int progressmask;
+ char origcalledname[256];
+ char origcallednum[256];
+ int callingplanorigcalled; /* Dialing plan of Originally Called Number */
+ int origredirectingreason;
++ int reversecharge;
++ struct pri_subcommands *subcmds;
++ struct pri_party_id calling; /* Calling Party's info, initially subaddress' */
++ struct pri_party_subaddress called_subaddress; /* Called party's subaddress */
++ char keypad_digits[64]; /* Keypad digits in the SETUP message. */
+ } pri_event_ring;
+
+ typedef struct pri_event_hangup {
+@@ -390,10 +661,23 @@
+ int channel; /* Channel requested */
+ int cause;
+ int cref;
+- q931_call *call; /* Opaque call pointer */
++ q931_call *call; /* Opaque call pointer of call hanging up. */
+ long aoc_units; /* Advise of Charge number of charged units */
+ char useruserinfo[260]; /* User->User info */
+-} pri_event_hangup;
++ struct pri_subcommands *subcmds;
++ /*!
++ * \brief Opaque held call pointer for possible transfer to active call.
++ * \note The call_held and call_active pointers must not be NULL if
++ * transfer held call on disconnect is available.
++ */
++ q931_call *call_held;
++ /*!
++ * \brief Opaque active call pointer for possible transfer with held call.
++ * \note The call_held and call_active pointers must not be NULL if
++ * transfer held call on disconnect is available.
++ */
++ q931_call *call_active;
++} pri_event_hangup;
+
+ typedef struct pri_event_restart_ack {
+ int e;
+@@ -409,18 +693,22 @@
+ int progressmask;
+ int cause;
+ q931_call *call;
++ struct pri_subcommands *subcmds;
+ } pri_event_proceeding;
+-
++
+ typedef struct pri_event_setup_ack {
+ int e;
+ int channel;
+ q931_call *call;
++ struct pri_subcommands *subcmds;
+ } pri_event_setup_ack;
+
+ typedef struct pri_event_notify {
+ int e;
+ int channel;
+ int info;
++ struct pri_subcommands *subcmds;
++ q931_call *call;
+ } pri_event_notify;
+
+ typedef struct pri_event_keypad_digit {
+@@ -428,14 +716,72 @@
+ int channel;
+ q931_call *call;
+ char digits[64];
++ struct pri_subcommands *subcmds;
+ } pri_event_keypad_digit;
+
++typedef struct pri_event_service {
++ int e;
++ int channel;
++ int changestatus;
++} pri_event_service;
++
++typedef struct pri_event_service_ack {
++ int e;
++ int channel;
++ int changestatus;
++} pri_event_service_ack;
++
++struct pri_event_hold {
++ int e;
++ int channel;
++ q931_call *call;
++ struct pri_subcommands *subcmds;
++};
++
++struct pri_event_hold_ack {
++ int e;
++ int channel;
++ q931_call *call;
++ struct pri_subcommands *subcmds;
++};
++
++struct pri_event_hold_rej {
++ int e;
++ int channel;
++ q931_call *call;
++ int cause;
++ struct pri_subcommands *subcmds;
++};
++
++struct pri_event_retrieve {
++ int e;
++ int channel;
++ q931_call *call;
++ int flexible; /* Are we flexible with our channel selection? */
++ struct pri_subcommands *subcmds;
++};
++
++struct pri_event_retrieve_ack {
++ int e;
++ int channel;
++ q931_call *call;
++ struct pri_subcommands *subcmds;
++};
++
++struct pri_event_retrieve_rej {
++ int e;
++ int channel;
++ q931_call *call;
++ int cause;
++ struct pri_subcommands *subcmds;
++};
++
+ typedef union {
+ int e;
+ pri_event_generic gen; /* Generic view */
+ pri_event_restart restart; /* Restart view */
+ pri_event_error err; /* Error view */
+- pri_event_facname facname; /* Caller*ID Name on Facility */
++ pri_event_facname facname; /* Caller*ID Name on Facility (Deprecated, use pri_event.facility) */
+ pri_event_ring ring; /* Ring */
+ pri_event_hangup hangup; /* Hang up */
+ pri_event_ringing ringing; /* Ringing */
+@@ -445,6 +791,15 @@
+ pri_event_setup_ack setup_ack; /* SETUP_ACKNOWLEDGE structure */
+ pri_event_notify notify; /* Notification */
+ pri_event_keypad_digit digit; /* Digits that come during a call */
++ pri_event_service service; /* service message */
++ pri_event_service_ack service_ack; /* service acknowledgement message */
++ struct pri_event_facility facility;
++ struct pri_event_hold hold;
++ struct pri_event_hold_ack hold_ack;
++ struct pri_event_hold_rej hold_rej;
++ struct pri_event_retrieve retrieve;
++ struct pri_event_retrieve_ack retrieve_ack;
++ struct pri_event_retrieve_rej retrieve_rej;
+ } pri_event;
+
+ struct pri;
+@@ -456,7 +811,7 @@
+
+ /* Create a D-channel on a given file descriptor. The file descriptor must be a
+ channel operating in HDLC mode with FCS computed by the fd's driver. Also it
+- must be NON-BLOCKING! Frames received on the fd should include FCS. Nodetype
++ must be NON-BLOCKING! Frames received on the fd should include FCS. Nodetype
+ must be one of PRI_NETWORK or PRI_CPE. switchtype should be PRI_SWITCH_* */
+ struct pri *pri_new(int fd, int nodetype, int switchtype);
+ struct pri *pri_new_bri(int fd, int ptpmode, int nodetype, int switchtype);
+@@ -521,7 +876,7 @@
+
+ #define PRI_KEYPAD_FACILITY_TX
+ /* Send a keypad facility string of digits */
+-int pri_keypad_facility(struct pri *pri, q931_call *call, char *digits);
++int pri_keypad_facility(struct pri *pri, q931_call *call, const char *digits);
+
+ /* Answer the incomplete(call without called number) call on the given channel.
+ Set non-isdn to non-zero if you are not connecting to ISDN equipment */
+@@ -531,6 +886,18 @@
+ Set non-isdn to non-zero if you are not connecting to ISDN equipment */
+ int pri_answer(struct pri *pri, q931_call *call, int channel, int nonisdn);
+
++/*!
++ * \brief Give connected line information to a call
++ * \note Could be used instead of pri_sr_set_caller_party() before calling pri_setup().
++ */
++int pri_connected_line_update(struct pri *pri, q931_call *call, const struct pri_party_connected_line *connected);
++
++/*!
++ * \brief Give redirection information to a call
++ * \note Could be used instead of pri_sr_set_redirecting_parties() before calling pri_setup().
++ */
++int pri_redirecting_update(struct pri *pri, q931_call *call, const struct pri_party_redirecting *redirecting);
++
+ /* Set CRV reference for GR-303 calls */
+
+
+@@ -556,9 +923,20 @@
+
+ int pri_reset(struct pri *pri, int channel);
+
++/* handle b-channel maintenance messages */
++extern int pri_maintenance_service(struct pri *pri, int span, int channel, int changestatus);
++
+ /* Create a new call */
+ q931_call *pri_new_call(struct pri *pri);
+
++/*!
++ * \brief Deterimine if the given call control pointer is a dummy call.
++ *
++ * \retval TRUE if given call is a dummy call.
++ * \retval FALSE otherwise.
++ */
++int pri_is_dummy_call(q931_call *call);
++
+ /* Retrieve CRV reference for GR-303 calls. Returns >0 on success. */
+ int pri_get_crv(struct pri *pri, q931_call *call, int *callmode);
+
+@@ -573,8 +951,8 @@
+ extern pri_event *pri_schedule_run_tv(struct pri *pri, const struct timeval *now);
+
+ int pri_call(struct pri *pri, q931_call *c, int transmode, int channel,
+- int exclusive, int nonisdn, char *caller, int callerplan, char *callername, int callerpres,
+- char *called,int calledplan, int ulayer1);
++ int exclusive, int nonisdn, char *caller, int callerplan, char *callername, int callerpres,
++ char *called, int calledplan, int ulayer1);
+
+ struct pri_sr *pri_sr_new(void);
+ void pri_sr_free(struct pri_sr *sr);
+@@ -582,25 +960,91 @@
+ int pri_sr_set_channel(struct pri_sr *sr, int channel, int exclusive, int nonisdn);
+ int pri_sr_set_bearer(struct pri_sr *sr, int transmode, int userl1);
+ int pri_sr_set_called(struct pri_sr *sr, char *called, int calledplan, int complete);
++
++/*!
++ * \brief Set the caller party ID information in the call SETUP record.
++ *
++ * \param sr New call SETUP record.
++ * \param caller Caller party ID information to set.
++ *
++ * \return Nothing
++ */
++void pri_sr_set_caller_party(struct pri_sr *sr, const struct pri_party_id *caller);
++/*! \note Use pri_sr_set_caller_party() instead to pass more precise caller information. */
+ int pri_sr_set_caller(struct pri_sr *sr, char *caller, char *callername, int callerplan, int callerpres);
++
++/*!
++ * \brief Set the calling subaddress information in the call SETUP record.
++ *
++ * \param sr New call SETUP record.
++ * \param subaddress information to set.
++ *
++ * \return Nothing
++ */
++void pri_sr_set_caller_subaddress(struct pri_sr *sr, const struct pri_party_subaddress *subaddress);
++
++/*!
++ * \brief Set the called subaddress information in the call SETUP record.
++ *
++ * \param sr New call SETUP record.
++ * \param subaddress information to set.
++ *
++ * \return Nothing
++ */
++void pri_sr_set_called_subaddress(struct pri_sr *sr, const struct pri_party_subaddress *subaddress);
++
++/*!
++ * \brief Set the redirecting information in the call SETUP record.
++ *
++ * \param sr New call SETUP record.
++ * \param caller Redirecting information to set.
++ *
++ * \return Nothing
++ */
++void pri_sr_set_redirecting_parties(struct pri_sr *sr, const struct pri_party_redirecting *redirecting);
++/*! \note Use pri_sr_set_redirecting_parties() instead to pass more precise redirecting information. */
+ int pri_sr_set_redirecting(struct pri_sr *sr, char *num, int plan, int pres, int reason);
++
++/*!
++ * \brief Set the keypad digits in the call SETUP record.
++ *
++ * \param sr New call SETUP record.
++ * \param keypad_digits Keypad digits to send.
++ *
++ * \return Nothing
++ */
++void pri_sr_set_keypad_digits(struct pri_sr *sr, const char *keypad_digits);
++
+ #define PRI_USER_USER_TX
+ /* Set the user user field. Warning! don't send binary data accross this field */
+ void pri_sr_set_useruser(struct pri_sr *sr, const char *userchars);
++void pri_sr_set_reversecharge(struct pri_sr *sr, int requested);
+
+ void pri_call_set_useruser(q931_call *sr, const char *userchars);
+
+ int pri_setup(struct pri *pri, q931_call *call, struct pri_sr *req);
+
+-/* Set a call has a call indpendent signalling connection (i.e. no bchan) */
++/*!
++ * \brief Set a call as a call indpendent signalling connection (i.e. no bchan)
++ * \note Call will automaticlly disconnect after signalling sent.
++ */
+ int pri_sr_set_connection_call_independent(struct pri_sr *req);
+
++/*!
++ * \brief Set a call as a call indpendent signalling connection (i.e. no bchan)
++ * \note Call will stay connected until explicitly disconnected.
++ */
++int pri_sr_set_no_channel_call(struct pri_sr *req);
++
+ /* Send an MWI indication to a remote location. If activate is non zero, activates, if zero, deactivates */
+ int pri_mwi_activate(struct pri *pri, q931_call *c, char *caller, int callerplan, char *callername, int callerpres, char *called, int calledplan);
+
+ /* Send an MWI deactivate request to a remote location */
+ int pri_mwi_deactivate(struct pri *pri, q931_call *c, char *caller, int callerplan, char *callername, int callerpres, char *called, int calledplan);
+
++/* Set service message support flag */
++int pri_set_service_message_support(struct pri *pri, int supportflag);
++
+ #define PRI_2BCT
+ /* Attempt to pass the channels back to the NET side if compatable and
+ * suscribed. Sometimes called 2 bchannel transfer (2BCT) */
+@@ -656,48 +1100,208 @@
+
+ int pri_callrerouting_facility(struct pri *pri, q931_call *call, const char *dest, const char* original, const char* reason);
+
++/*!
++ * \brief Set the call deflection/rerouting feature enable flag.
++ *
++ * \param ctrl D channel controller.
++ * \param enable TRUE to enable call deflection/rerouting feature.
++ *
++ * \return Nothing
++ */
++void pri_reroute_enable(struct pri *ctrl, int enable);
++
++/*!
++ * \brief Send the CallRerouting/CallDeflection message.
++ *
++ * \param ctrl D channel controller.
++ * \param call Q.931 call leg.
++ * \param caller Call rerouting/deflecting updated caller data. (NULL if data not updated.)
++ * \param deflection Call rerouting/deflecting redirection data.
++ * \param subscription_option Diverting user subscription option to specify if caller is notified.
++ *
++ * \note
++ * deflection->to is the new called number and must always be present.
++ * \note
++ * subscription option:
++ * noNotification(0),
++ * notificationWithoutDivertedToNr(1),
++ * notificationWithDivertedToNr(2)
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++int pri_reroute_call(struct pri *ctrl, q931_call *call, const struct pri_party_id *caller, const struct pri_party_redirecting *deflection, int subscription_option);
++
++enum PRI_REROUTING_RSP_CODE {
++ /*!
++ * Rerouting invocation accepted and the network provider option
++ * "served user call retention on invocation of diversion"
++ * is "clear call on invocation".
++ */
++ PRI_REROUTING_RSP_OK_CLEAR,
++ /*!
++ * Rerouting invocation accepted and the network provider option
++ * "served user call retention on invocation of diversion"
++ * is "retain call until alerting begins at the deflected-to user".
++ */
++ PRI_REROUTING_RSP_OK_RETAIN,
++ PRI_REROUTING_RSP_NOT_SUBSCRIBED,
++ PRI_REROUTING_RSP_NOT_AVAILABLE,
++ /*! Supplementary service interaction not allowed. */
++ PRI_REROUTING_RSP_NOT_ALLOWED,
++ PRI_REROUTING_RSP_INVALID_NUMBER,
++ /*! Deflection to prohibited number (e.g., operator, police, emergency). */
++ PRI_REROUTING_RSP_SPECIAL_SERVICE_NUMBER,
++ /*! Deflection to served user number. */
++ PRI_REROUTING_RSP_DIVERSION_TO_SELF,
++ PRI_REROUTING_RSP_MAX_DIVERSIONS_EXCEEDED,
++ PRI_REROUTING_RSP_RESOURCE_UNAVAILABLE,
++};
++
++/*!
++ * \brief Send the CallRerouteing/CallDeflection response message.
++ *
++ * \param ctrl D channel controller.
++ * \param call Q.931 call leg.
++ * \param invoke_id Value given by the initiating request.
++ * \param code The result to send.
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++int pri_rerouting_rsp(struct pri *ctrl, q931_call *call, int invoke_id, enum PRI_REROUTING_RSP_CODE code);
++
++/*!
++ * \brief Set the call hold feature enable flag.
++ *
++ * \param ctrl D channel controller.
++ * \param enable TRUE to enable call hold feature.
++ *
++ * \return Nothing
++ */
++void pri_hold_enable(struct pri *ctrl, int enable);
++
++/*!
++ * \brief Send the HOLD message.
++ *
++ * \param ctrl D channel controller.
++ * \param call Q.931 call leg
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++int pri_hold(struct pri *ctrl, q931_call *call);
++
++/*!
++ * \brief Send the HOLD ACKNOWLEDGE message.
++ *
++ * \param ctrl D channel controller.
++ * \param call Q.931 call leg
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++int pri_hold_ack(struct pri *ctrl, q931_call *call);
++
++/*!
++ * \brief Send the HOLD REJECT message.
++ *
++ * \param ctrl D channel controller.
++ * \param call Q.931 call leg
++ * \param cause Q.931 cause code for rejecting the hold request.
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++int pri_hold_rej(struct pri *ctrl, q931_call *call, int cause);
++
++/*!
++ * \brief Send the RETRIEVE message.
++ *
++ * \param ctrl D channel controller.
++ * \param call Q.931 call leg
++ * \param channel Encoded channel id to use. If zero do not send channel id.
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++int pri_retrieve(struct pri *ctrl, q931_call *call, int channel);
++
++/*!
++ * \brief Send the RETRIEVE ACKNOWLEDGE message.
++ *
++ * \param ctrl D channel controller.
++ * \param call Q.931 call leg
++ * \param channel Encoded channel id to use.
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++int pri_retrieve_ack(struct pri *ctrl, q931_call *call, int channel);
++
++/*!
++ * \brief Send the RETRIEVE REJECT message.
++ *
++ * \param ctrl D channel controller.
++ * \param call Q.931 call leg
++ * \param cause Q.931 cause code for rejecting the retrieve request.
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++int pri_retrieve_rej(struct pri *ctrl, q931_call *call, int cause);
++
+ /* Get/Set PRI Timers */
+ #define PRI_GETSET_TIMERS
+ int pri_set_timer(struct pri *pri, int timer, int value);
+ int pri_get_timer(struct pri *pri, int timer);
+-int pri_timer2idx(char *timer);
++int pri_timer2idx(const char *timer_name);
+
+-#define PRI_MAX_TIMERS 32
++/*! New configurable timers and counters must be added to the end of the list */
++enum PRI_TIMERS_AND_COUNTERS {
++ PRI_TIMER_N200, /*!< Maximum numer of Q.921 retransmissions */
++ PRI_TIMER_N201, /*!< Maximum numer of octets in an information field */
++ PRI_TIMER_N202, /*!< Maximum numer of transmissions of the TEI identity request message */
++ PRI_TIMER_K, /*!< Maximum number of outstanding I-frames */
+
+-#define PRI_TIMER_N200 0 /* Maximum numer of q921 retransmissions */
+-#define PRI_TIMER_N201 1 /* Maximum numer of octets in an information field */
+-#define PRI_TIMER_N202 2 /* Maximum numer of transmissions of the TEI identity request message */
+-#define PRI_TIMER_K 3 /* Maximum number of outstanding I-frames */
++ PRI_TIMER_T200, /*!< Time between SABME's */
++ PRI_TIMER_T201, /*!< Minimum time between retransmissions of the TEI Identity check messages */
++ PRI_TIMER_T202, /*!< Minimum time between transmission of TEI Identity request messages */
++ PRI_TIMER_T203, /*!< Maximum time without exchanging packets */
+
+-#define PRI_TIMER_T200 4 /* time between SABME's */
+-#define PRI_TIMER_T201 5 /* minimum time between retransmissions of the TEI Identity check messages */
+-#define PRI_TIMER_T202 6 /* minimum time between transmission of TEI Identity request messages */
+-#define PRI_TIMER_T203 7 /* maxiumum time without exchanging packets */
++ PRI_TIMER_T300,
++ PRI_TIMER_T301, /*!< Maximum time to respond to an ALERT */
++ PRI_TIMER_T302,
++ PRI_TIMER_T303, /*!< Maximum time to wait after sending a SETUP without a response */
++ PRI_TIMER_T304,
++ PRI_TIMER_T305, /*!< Wait for DISCONNECT acknowledge */
++ PRI_TIMER_T306,
++ PRI_TIMER_T307,
++ PRI_TIMER_T308, /*!< Wait for RELEASE acknowledge */
++ PRI_TIMER_T309, /*!< Time active calls can tollerate data link layer being down before clearing. */
++ PRI_TIMER_T310, /*!< Maximum time between receiving a CALL_PROCEEDING and receiving a ALERT/CONNECT/DISCONNECT/PROGRESS */
++ PRI_TIMER_T313, /*!< Wait for CONNECT acknowledge, CPE side only */
++ PRI_TIMER_T314,
++ PRI_TIMER_T316, /*!< Maximum time between transmitting a RESTART and receiving a RESTART ACK */
++ PRI_TIMER_T317,
++ PRI_TIMER_T318,
++ PRI_TIMER_T319,
++ PRI_TIMER_T320,
++ PRI_TIMER_T321,
++ PRI_TIMER_T322,
+
+-#define PRI_TIMER_T300 8
+-#define PRI_TIMER_T301 9 /* maximum time to respond to an ALERT */
+-#define PRI_TIMER_T302 10
+-#define PRI_TIMER_T303 11 /* maximum time to wait after sending a SETUP without a response */
+-#define PRI_TIMER_T304 12
+-#define PRI_TIMER_T305 13
+-#define PRI_TIMER_T306 14
+-#define PRI_TIMER_T307 15
+-#define PRI_TIMER_T308 16
+-#define PRI_TIMER_T309 17
+-#define PRI_TIMER_T310 18 /* maximum time between receiving a CALLPROCEEDING and receiving a ALERT/CONNECT/DISCONNECT/PROGRESS */
+-#define PRI_TIMER_T313 19
+-#define PRI_TIMER_T314 20
+-#define PRI_TIMER_T316 21 /* maximum time between transmitting a RESTART and receiving a RESTART ACK */
+-#define PRI_TIMER_T317 22
+-#define PRI_TIMER_T318 23
+-#define PRI_TIMER_T319 24
+-#define PRI_TIMER_T320 25
+-#define PRI_TIMER_T321 26
+-#define PRI_TIMER_T322 27
++ PRI_TIMER_TM20, /*!< Maximum time awaiting XID response */
++ PRI_TIMER_NM20, /*!< Number of XID retransmits */
+
+-#define PRI_TIMER_TM20 28 /* maximum time avaiting XID response */
+-#define PRI_TIMER_NM20 29 /* number of XID retransmits */
++ PRI_TIMER_T_HOLD, /*!< Maximum time to wait for HOLD request response. */
++ PRI_TIMER_T_RETRIEVE, /*!< Maximum time to wait for RETRIEVE request response. */
+
++ PRI_TIMER_T_RESPONSE, /*!< Maximum time to wait for a typical APDU response. */
++
++ /* Must be last in the enum list */
++ PRI_MAX_TIMERS
++};
++
+ /* Get PRI version */
+ const char *pri_get_version(void);
+
+Index: asn1_primitive.c
+===================================================================
+--- a/asn1_primitive.c (.../tags/1.4.10.2) (revision 0)
++++ b/asn1_primitive.c (.../branches/1.4) (revision 1357)
+@@ -0,0 +1,1306 @@
++/*
++ * 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 ASN.1 BER encode/decode primitives
++ *
++ * \author Richard Mudgett <rmudgett@digium.com>
++ */
++
++
++#include <stdio.h>
++#include <ctype.h>
++
++#include "compat.h"
++#include "libpri.h"
++#include "pri_internal.h"
++#include "asn1.h"
++
++/* ------------------------------------------------------------------- */
++
++/*!
++ * \internal
++ * \brief Dump the memory contents indicated in printable characters. (Helper function.)
++ *
++ * \param ctrl D channel controller for any diagnostic messages.
++ * \param start Dump memory starting position.
++ * \param end Dump memory ending position. (Not included in dump.)
++ *
++ * \return Nothing
++ */
++static void asn1_dump_mem_helper(struct pri *ctrl, const unsigned char *start,
++ const unsigned char *end)
++{
++ pri_message(ctrl, " - \"");
++ for (; start < end; ++start) {
++ pri_message(ctrl, "%c", (isprint(*start)) ? *start : '~');
++ }
++ pri_message(ctrl, "\"\n");
++}
++
++/*!
++ * \internal
++ * \brief Dump the memory contents indicated.
++ *
++ * \param ctrl D channel controller for any diagnostic messages.
++ * \param indent Number of spaces to indent for each new memory dump line.
++ * \param pos Dump memory starting position.
++ * \param length Number of bytes to dump.
++ *
++ * \return Nothing
++ */
++static void asn1_dump_mem(struct pri *ctrl, unsigned indent, const unsigned char *pos,
++ unsigned length)
++{
++ const unsigned char *seg_start;
++ const unsigned char *end;
++ unsigned delimiter;
++ unsigned count;
++
++ seg_start = pos;
++ end = pos + length;
++ if (pos < end) {
++ delimiter = '<';
++ for (;;) {
++ pri_message(ctrl, "%*s", indent, "");
++ for (count = 0; count++ < 16 && pos < end;) {
++ pri_message(ctrl, "%c%02X", delimiter, *pos++);
++ delimiter = (count == 8) ? '-' : ' ';
++ }
++ if (end <= pos) {
++ break;
++ }
++ asn1_dump_mem_helper(ctrl, seg_start, pos);
++ seg_start = pos;
++ }
++ } else {
++ pri_message(ctrl, "%*s<", indent, "");
++ }
++ pri_message(ctrl, ">");
++ asn1_dump_mem_helper(ctrl, seg_start, end);
++}
++
++/*!
++ * \brief Convert the given tag value to a descriptive string.
++ *
++ * \param tag Component tag value to convert to a string.
++ *
++ * \return Converted tag string.
++ */
++const char *asn1_tag2str(unsigned tag)
++{
++ static const char *primitives[32] = {
++ [ASN1_TYPE_INDEF_TERM] = "Indefinite length terminator",
++ [ASN1_TYPE_BOOLEAN] = "Boolean",
++ [ASN1_TYPE_INTEGER] = "Integer",
++ [ASN1_TYPE_BIT_STRING] = "Bit String",
++ [ASN1_TYPE_OCTET_STRING] = "Octet String",
++ [ASN1_TYPE_NULL] = "NULL",
++ [ASN1_TYPE_OBJECT_IDENTIFIER] = "OID",
++ [ASN1_TYPE_OBJECT_DESCRIPTOR] = "Object Descriptor",
++ [ASN1_TYPE_EXTERN] = "External",
++ [ASN1_TYPE_REAL] = "Real",
++ [ASN1_TYPE_ENUMERATED] = "Enumerated",
++ [ASN1_TYPE_EMBEDDED_PDV] = "Embedded PDV",
++ [ASN1_TYPE_UTF8_STRING] = "UTF8 String",
++ [ASN1_TYPE_RELATIVE_OID] = "Relative OID",
++ [ASN1_TYPE_SEQUENCE] = "Sequence",
++ [ASN1_TYPE_SET] = "Set",
++ [ASN1_TYPE_NUMERIC_STRING] = "Numeric String",
++ [ASN1_TYPE_PRINTABLE_STRING] = "Printable String",
++ [ASN1_TYPE_TELETEX_STRING] = "Teletex String",
++ [ASN1_TYPE_VIDEOTEX_STRING] = "Videotex String",
++ [ASN1_TYPE_IA5_STRING] = "IA5 String",
++ [ASN1_TYPE_UTC_TIME] = "UTC Time",
++ [ASN1_TYPE_GENERALIZED_TIME] = "Generalized Time",
++ [ASN1_TYPE_GRAPHIC_STRING] = "Graphic String",
++ [ASN1_TYPE_VISIBLE_STRING] = "Visible/ISO646 String",
++ [ASN1_TYPE_GENERAL_STRING] = "General String",
++ [ASN1_TYPE_UNIVERSAL_STRING] = "Universal String",
++ [ASN1_TYPE_CHAR_STRING] = "Character String",
++ [ASN1_TYPE_BMP_STRING] = "BMP String",
++ [ASN1_TYPE_EXTENSION] = "Type Extension",
++ };
++ static char buf[64];
++ const char *description;
++ unsigned asn1_constructed; /*! TRUE if the tag is constructed. */
++ unsigned asn1_type;
++
++ asn1_constructed = ((tag & ASN1_PC_MASK) == ASN1_PC_CONSTRUCTED);
++ asn1_type = tag & ASN1_TYPE_MASK;
++
++ switch (tag & ASN1_CLASS_MASK) {
++ case ASN1_CLASS_UNIVERSAL:
++ if (tag == (ASN1_CLASS_UNIVERSAL | ASN1_PC_CONSTRUCTED | ASN1_TYPE_INDEF_TERM)) {
++ description = NULL;
++ } else {
++ description = primitives[asn1_type];
++ }
++ if (!description) {
++ description = "Reserved";
++ }
++ snprintf(buf, sizeof(buf), "%s%s(%u 0x%02X)", description,
++ asn1_constructed ? "/C" : "", tag, tag);
++ return buf;
++ case ASN1_CLASS_APPLICATION:
++ description = "Application";
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC:
++ description = "Context Specific";
++ break;
++ case ASN1_CLASS_PRIVATE:
++ description = "Private";
++ break;
++ default:
++ snprintf(buf, sizeof(buf), "Unknown tag (%u 0x%02X)", tag, tag);
++ return buf;
++ }
++ snprintf(buf, sizeof(buf), "%s%s [%u 0x%02X]", description,
++ asn1_constructed ? "/C" : "", asn1_type, asn1_type);
++ return buf;
++}
++
++/*!
++ * \brief Decode the ASN.1 tag value.
++ *
++ * \param tag_pos ASN.1 tag starting position.
++ * \param end End of ASN.1 encoded data buffer.
++ * \param tag Decoded tag value returned on success.
++ *
++ * \retval Next octet after the tag on success.
++ * \retval NULL on error.
++ */
++const unsigned char *asn1_dec_tag(const unsigned char *tag_pos, const unsigned char *end,
++ unsigned *tag)
++{
++ unsigned extended_tag;
++
++ if (end <= tag_pos) {
++ return NULL;
++ }
++ *tag = *tag_pos++;
++ if ((*tag & ASN1_TYPE_MASK) == ASN1_TYPE_EXTENSION) {
++ /* Extract the extended tag value */
++ extended_tag = 0;
++ do {
++ if (end <= tag_pos) {
++ return NULL;
++ }
++ extended_tag <<= 7;
++ extended_tag |= *tag_pos & ~0x80;
++ } while (*tag_pos++ & 0x80);
++ if (extended_tag && extended_tag < ASN1_TYPE_EXTENSION) {
++ /*
++ * The sender did not need to use the extended format.
++ * This is an encoding error on their part, but we will
++ * accept it anyway.
++ *
++ * Note we cannot return a null tag value from this path.
++ * We would misinterpret the indefinite length
++ * terminator.
++ */
++ *tag &= ~ASN1_TYPE_MASK;
++ *tag |= extended_tag;
++ }
++ }
++
++ return tag_pos;
++}
++
++/*!
++ * \brief Decode the length of an ASN.1 component length.
++ *
++ * \param len_pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param length Decoded length value returned on success. (-1 if indefinite)
++ *
++ * \retval Next octet after the length on success.
++ * \retval NULL on error.
++ *
++ * \note The decoded length is checked to see if there is enough buffer
++ * left for the component body.
++ */
++const unsigned char *asn1_dec_length(const unsigned char *len_pos,
++ const unsigned char *end, int *length)
++{
++ unsigned length_size;
++
++ if (end <= len_pos) {
++ /* Not enough buffer to determine how the length is encoded */
++ return NULL;
++ }
++
++ if (*len_pos < 0x80) {
++ /* Short length encoding */
++ *length = *len_pos++;
++ } else if (*len_pos == 0x80) {
++ /* Indefinite length encoding */
++ *length = -1;
++ ++len_pos;
++ if (end < len_pos + ASN1_INDEF_TERM_LEN) {
++ /* Not enough buffer for the indefinite length terminator */
++ return NULL;
++ }
++ return len_pos;
++ } else {
++ /* Long length encoding */
++ length_size = *len_pos++ & 0x7f;
++ if (length_size == 0x7f) {
++ /* Reserved extension encoding that has not been defined. */
++ return NULL;
++ }
++ if (end < len_pos + length_size) {
++ /* Not enough buffer for the length value */
++ return NULL;
++ }
++ *length = 0;
++ while (length_size--) {
++ *length = (*length << 8) | *len_pos++;
++ }
++ }
++
++ if (end < len_pos + *length) {
++ /* Not enough buffer for the component body. */
++ return NULL;
++ }
++ return len_pos;
++}
++
++/*!
++ * \internal
++ * \brief Skip to the end of an indefinite length constructed component helper.
++ *
++ * \param pos ASN.1 tag starting position.
++ * \param end End of ASN.1 decoding data buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++static const unsigned char *asn1_dec_indef_end_fixup_helper(const unsigned char *pos,
++ const unsigned char *end)
++{
++ unsigned tag;
++ int length;
++
++ while (pos < end && *pos != ASN1_INDEF_TERM) {
++ ASN1_CALL(pos, asn1_dec_tag(pos, end, &tag));
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ if (length < 0) {
++ /* Skip over indefinite length sub-component */
++ if ((tag & ASN1_PC_MASK) == ASN1_PC_CONSTRUCTED
++ || tag == (ASN1_CLASS_UNIVERSAL | ASN1_PC_PRIMITIVE | ASN1_TYPE_SET)
++ || tag ==
++ (ASN1_CLASS_UNIVERSAL | ASN1_PC_PRIMITIVE | ASN1_TYPE_SEQUENCE)) {
++ /* This is an ITU encoded indefinite length component. */
++ ASN1_CALL(pos, asn1_dec_indef_end_fixup_helper(pos, end));
++ } else {
++ /* This is a non-ITU encoded indefinite length component. */
++ while (pos < end && *pos != ASN1_INDEF_TERM) {
++ ++pos;
++ }
++ pos += ASN1_INDEF_TERM_LEN;
++ }
++ } else {
++ /* Skip over defininte length sub-component */
++ pos += length;
++ }
++ }
++ if (end < pos + ASN1_INDEF_TERM_LEN) {
++ return NULL;
++ }
++
++ return pos + ASN1_INDEF_TERM_LEN;
++}
++
++/*!
++ * \brief Skip to the end of an indefinite length constructed component.
++ *
++ * \param ctrl D channel controller for any diagnostic messages.
++ * \param pos ASN.1 tag starting position.
++ * \param end End of ASN.1 decoding data buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *asn1_dec_indef_end_fixup(struct pri *ctrl, const unsigned char *pos,
++ const unsigned char *end)
++{
++ if (pos < end && *pos != ASN1_INDEF_TERM && (ctrl->debug & PRI_DEBUG_APDU)) {
++ pri_message(ctrl,
++ " Skipping unused indefinite length constructed component octets!\n");
++ }
++ return asn1_dec_indef_end_fixup_helper(pos, end);
++}
++
++/*!
++ * \brief Decode the boolean primitive.
++ *
++ * \param ctrl D channel controller for any diagnostic messages.
++ * \param name Field name
++ * \param tag Component tag that identified this primitive.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param value Decoded boolean value.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *asn1_dec_boolean(struct pri *ctrl, const char *name, unsigned tag,
++ const unsigned char *pos, const unsigned char *end, int32_t *value)
++{
++ int length;
++
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ if (length != 1) {
++ /*
++ * The encoding rules say the length can only be one.
++ * It is rediculus to get anything else anyway.
++ */
++ return NULL;
++ }
++
++ *value = *pos++ ? 1 : 0;
++
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " %s %s = %d\n", name, asn1_tag2str(tag), *value);
++ }
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the integer type primitive.
++ *
++ * \param ctrl D channel controller for any diagnostic messages.
++ * \param name Field name
++ * \param tag Component tag that identified this primitive.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param value Decoded integer type value.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *asn1_dec_int(struct pri *ctrl, const char *name, unsigned tag,
++ const unsigned char *pos, const unsigned char *end, int32_t *value)
++{
++ int length;
++
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ if (length <= 0) {
++ /*
++ * The encoding rules say the length can not be indefinite.
++ * It cannot be empty for that matter either.
++ */
++ return NULL;
++ }
++
++#if 1
++ /* Read value as signed */
++ if (*pos & 0x80) {
++ /* The value is negative */
++ *value = -1;
++ } else {
++ *value = 0;
++ }
++#else
++ /* Read value as unsigned */
++ *value = 0;
++#endif
++ while (length--) {
++ *value = (*value << 8) | *pos;
++ pos++;
++ }
++
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " %s %s = %d 0x%04X\n", name, asn1_tag2str(tag), *value,
++ *value);
++ }
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the null primitive.
++ *
++ * \param ctrl D channel controller for any diagnostic messages.
++ * \param name Field name
++ * \param tag Component tag that identified this primitive.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *asn1_dec_null(struct pri *ctrl, const char *name, unsigned tag,
++ const unsigned char *pos, const unsigned char *end)
++{
++ int length;
++
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ if (length != 0) {
++ /*
++ * The encoding rules say the length can only be zero.
++ * It is rediculus to get anything else anyway.
++ */
++ return NULL;
++ }
++
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " %s %s\n", name, asn1_tag2str(tag));
++ }
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the object identifier primitive.
++ *
++ * \param ctrl D channel controller for any diagnostic messages.
++ * \param name Field name
++ * \param tag Component tag that identified this primitive.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param oid Decoded OID type value.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *asn1_dec_oid(struct pri *ctrl, const char *name, unsigned tag,
++ const unsigned char *pos, const unsigned char *end, struct asn1_oid *oid)
++{
++ int length;
++ unsigned num_values;
++ unsigned value;
++ unsigned delimiter;
++
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ if (length < 0) {
++ /*
++ * The encoding rules say the length can not be indefinite.
++ */
++ return NULL;
++ }
++
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " %s %s =", name, asn1_tag2str(tag));
++ }
++ delimiter = ' ';
++ num_values = 0;
++ while (length) {
++ value = 0;
++ for (;;) {
++ --length;
++ value = (value << 7) | (*pos & 0x7F);
++ if (!(*pos++ & 0x80)) {
++ /* Last octet in the OID subidentifier value */
++ if (num_values < ARRAY_LEN(oid->value)) {
++ oid->value[num_values] = value;
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, "%c%u", delimiter, value);
++ }
++ delimiter = '.';
++ } else {
++ /* Too many OID subidentifier values */
++ delimiter = '~';
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, "%c%u", delimiter, value);
++ }
++ }
++ ++num_values;
++ break;
++ }
++ if (!length) {
++ oid->num_values = 0;
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, "\n"
++ " Last OID subidentifier value not terminated!\n");
++ }
++ return NULL;
++ }
++ }
++ }
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, "\n");
++ }
++
++ if (num_values <= ARRAY_LEN(oid->value)) {
++ oid->num_values = num_values;
++ return pos;
++ } else {
++ /* Need to increase the size of the OID subidentifier list. */
++ oid->num_values = 0;
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " Too many OID values!\n");
++ }
++ return NULL;
++ }
++}
++
++/*!
++ * \brief Decode a binary string primitive.
++ *
++ * \param ctrl D channel controller for any diagnostic messages.
++ * \param name Field name
++ * \param tag Component tag that identified this primitive.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param buf_size Size of the supplied string buffer. (Must be nonzero)
++ * \param str Where to put the decoded string.
++ * \param str_len Length of the decoded string.
++ *
++ * \note The string will be null terminated just in case.
++ * The buffer needs to have enough room for a null terminator.
++ * \note The parse will fail if the parsed string is too large for
++ * the supplied buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *asn1_dec_string_bin(struct pri *ctrl, const char *name,
++ unsigned tag, const unsigned char *pos, const unsigned char *end, size_t buf_size,
++ unsigned char *str, size_t *str_len)
++{
++ int length;
++ size_t sub_buf_size;
++ size_t sub_str_len;
++ unsigned char *sub_str;
++
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ if (length < 0) {
++ /* This is an indefinite length string */
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " %s %s = Indefinite length string\n", name,
++ asn1_tag2str(tag));
++ }
++ if ((tag & ASN1_PC_MASK) == ASN1_PC_CONSTRUCTED) {
++ /*
++ * This is an ITU encoded indefinite length string
++ * and could contain null.
++ */
++
++ /* Ensure that an empty string is null terminated. */
++ *str = 0;
++
++ /* Collect all substrings into the original string buffer. */
++ *str_len = 0;
++ sub_str = str;
++ sub_buf_size = buf_size;
++ for (;;) {
++ ASN1_CALL(pos, asn1_dec_tag(pos, end, &tag));
++ if (tag == ASN1_INDEF_TERM) {
++ /* End-of-contents octets */
++ break;
++ }
++
++ /* Append the substring to the accumulated indefinite string. */
++ ASN1_CALL(pos, asn1_dec_string_bin(ctrl, name, tag, pos, end,
++ sub_buf_size, sub_str, &sub_str_len));
++
++ sub_buf_size -= sub_str_len;
++ sub_str += sub_str_len;
++ *str_len += sub_str_len;
++ }
++ } else {
++ /*
++ * This is a non-ITU encoded indefinite length string
++ * and must not contain null's.
++ */
++ for (length = 0;; ++length) {
++ if (end <= pos + length) {
++ /* Not enough buffer left */
++ return NULL;
++ }
++ if (pos[length] == 0) {
++ /* Found End-of-contents octets */
++ break;
++ }
++ }
++
++ if (buf_size - 1 < length) {
++ /* The destination buffer is not large enough for the data */
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " String buffer not large enough!\n");
++ }
++ return NULL;
++ }
++
++ /* Extract the string and null terminate it. */
++ memcpy(str, pos, length);
++ str[length] = 0;
++ *str_len = length;
++
++ pos += length + 1;
++ }
++ if (end <= pos) {
++ /* Not enough buffer left for End-of-contents octets */
++ return NULL;
++ }
++ if (*pos++ != 0) {
++ /* We actually did not find the End-of-contents octets. */
++ return NULL;
++ }
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ /* Dump the collected string buffer contents. */
++ pri_message(ctrl, " Completed string =\n");
++ asn1_dump_mem(ctrl, 6, str, *str_len);
++ }
++ } else {
++ /* This is a definite length string */
++ if (buf_size - 1 < length) {
++ /* The destination buffer is not large enough for the data */
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " %s %s = Buffer not large enough!\n", name,
++ asn1_tag2str(tag));
++ }
++ return NULL;
++ }
++
++ /* Extract the string and null terminate it. */
++ memcpy(str, pos, length);
++ str[length] = 0;
++ *str_len = length;
++
++ pos += length;
++
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ /* Dump the collected string buffer contents. */
++ pri_message(ctrl, " %s %s =\n", name, asn1_tag2str(tag));
++ asn1_dump_mem(ctrl, 4, str, *str_len);
++ }
++ }
++
++ return pos;
++}
++
++/*!
++ * \brief Decode a string that can be truncated to a maximum length primitive.
++ *
++ * \param ctrl D channel controller for any diagnostic messages.
++ * \param name Field name
++ * \param tag Component tag that identified this primitive.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param buf_size Size of the supplied string buffer. (Must be nonzero)
++ * \param str Where to put the decoded null terminated string.
++ * \param str_len Length of the decoded string.
++ * (computed for convenience since you could just do a strlen())
++ *
++ * \note The parsed string will be truncated if the string buffer
++ * cannot contain it.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *asn1_dec_string_max(struct pri *ctrl, const char *name,
++ unsigned tag, const unsigned char *pos, const unsigned char *end, size_t buf_size,
++ unsigned char *str, size_t *str_len)
++{
++ int length;
++ size_t str_length;
++ size_t sub_buf_size;
++ size_t sub_str_len;
++ unsigned char *sub_str;
++
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ if (length < 0) {
++ /* This is an indefinite length string */
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " %s %s = Indefinite length string\n", name,
++ asn1_tag2str(tag));
++ }
++ if ((tag & ASN1_PC_MASK) == ASN1_PC_CONSTRUCTED) {
++ /* This is an ITU encoded indefinite length string. */
++
++ /* Ensure that an empty string is null terminated. */
++ *str = 0;
++
++ /* Collect all substrings into the original string buffer. */
++ *str_len = 0;
++ sub_str = str;
++ sub_buf_size = buf_size;
++ for (;;) {
++ ASN1_CALL(pos, asn1_dec_tag(pos, end, &tag));
++ if (tag == ASN1_INDEF_TERM) {
++ /* End-of-contents octets */
++ break;
++ }
++
++ /* Append the substring to the accumulated indefinite string. */
++ ASN1_CALL(pos, asn1_dec_string_max(ctrl, name, tag, pos, end,
++ sub_buf_size, sub_str, &sub_str_len));
++
++ sub_buf_size -= sub_str_len;
++ sub_str += sub_str_len;
++ *str_len += sub_str_len;
++ }
++ } else {
++ /* This is a non-ITU encoded indefinite length string. */
++ for (length = 0;; ++length) {
++ if (end <= pos + length) {
++ /* Not enough buffer left */
++ return NULL;
++ }
++ if (pos[length] == 0) {
++ /* Found End-of-contents octets */
++ break;
++ }
++ }
++
++ /* Extract the string, truncate if necessary, and terminate it. */
++ str_length = (buf_size - 1 < length) ? buf_size - 1 : length;
++ memcpy(str, pos, str_length);
++ str[str_length] = 0;
++ *str_len = str_length;
++
++ pos += length + 1;
++ }
++ if (end <= pos) {
++ /* Not enough buffer left for End-of-contents octets */
++ return NULL;
++ }
++ if (*pos++ != 0) {
++ /* We actually did not find the End-of-contents octets. */
++ return NULL;
++ }
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " Completed string = \"%s\"\n", str);
++ }
++ } else {
++ /*
++ * This is a definite length string
++ *
++ * Extract the string, truncate if necessary, and terminate it.
++ */
++ str_length = (buf_size - 1 < length) ? buf_size - 1 : length;
++ memcpy(str, pos, str_length);
++ str[str_length] = 0;
++ *str_len = str_length;
++
++ pos += length;
++
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " %s %s = \"%s\"\n", name, asn1_tag2str(tag), str);
++ }
++ }
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Recursive ASN.1 buffer decoding dump helper.
++ *
++ * \param ctrl D channel controller for any diagnostic messages.
++ * \param pos ASN.1 tag starting position.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param level Indentation level to use.
++ * \param indefinite_term TRUE if to stop on an indefinite length terminator.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++static const unsigned char *asn1_dump_helper(struct pri *ctrl, const unsigned char *pos,
++ const unsigned char *end, unsigned level, unsigned indefinite_term)
++{
++ unsigned delimiter;
++ unsigned tag;
++ int length;
++ const unsigned char *len_pos;
++
++ while (pos < end && (!indefinite_term || *pos != ASN1_INDEF_TERM)) {
++ /* Decode the tag */
++ pri_message(ctrl, "%*s", 2 * level, "");
++ len_pos = asn1_dec_tag(pos, end, &tag);
++ if (!len_pos) {
++ pri_message(ctrl, "Invalid tag encoding!\n");
++ return NULL;
++ }
++
++ /* Dump the tag contents. */
++ pri_message(ctrl, "%s ", asn1_tag2str(tag));
++ delimiter = '<';
++ while (pos < len_pos) {
++ pri_message(ctrl, "%c%02X", delimiter, *pos);
++ delimiter = ' ';
++ ++pos;
++ }
++ pri_message(ctrl, "> ");
++
++ /* Decode the length */
++ pos = asn1_dec_length(len_pos, end, &length);
++ if (!pos) {
++ pri_message(ctrl, "Invalid length encoding!\n");
++ return NULL;
++ }
++
++ /* Dump the length contents. */
++ if (length < 0) {
++ pri_message(ctrl, "Indefinite length ");
++ } else {
++ pri_message(ctrl, "Len:%d ", length);
++ }
++ delimiter = '<';
++ while (len_pos < pos) {
++ pri_message(ctrl, "%c%02X", delimiter, *len_pos);
++ delimiter = ' ';
++ ++len_pos;
++ }
++ pri_message(ctrl, ">\n");
++
++ /* Dump the body contents */
++ ++level;
++ if (length < 0) {
++ /* Indefinite length */
++ if ((tag & ASN1_PC_MASK) == ASN1_PC_CONSTRUCTED) {
++ /* This is an ITU encoded indefinite length component. */
++ ASN1_CALL(pos, asn1_dump_helper(ctrl, pos, end, level, 1));
++ } else if (tag == (ASN1_CLASS_UNIVERSAL | ASN1_PC_PRIMITIVE | ASN1_TYPE_SET)
++ || tag ==
++ (ASN1_CLASS_UNIVERSAL | ASN1_PC_PRIMITIVE | ASN1_TYPE_SEQUENCE)) {
++ pri_message(ctrl, "%*sThis tag must always be constructed!\n", 2 * level,
++ "");
++ /* Assume tag was constructed to keep going */
++ ASN1_CALL(pos, asn1_dump_helper(ctrl, pos, end, level, 1));
++ } else {
++ /* This is a non-ITU encoded indefinite length component. */
++ pri_message(ctrl, "%*sNon-ITU indefininte length component.\n",
++ 2 * level, "");
++ length = 0;
++ while (pos + length < end && pos[length] != ASN1_INDEF_TERM) {
++ ++length;
++ }
++ if (length) {
++ asn1_dump_mem(ctrl, 2 * level, pos, length);
++ pos += length;
++ }
++ }
++ --level;
++ if (end < pos + ASN1_INDEF_TERM_LEN) {
++ pri_message(ctrl, "%*sNot enough room for the End-of-contents octets!\n",
++ 2 * level, "");
++ pos = end;
++ } else {
++ pri_message(ctrl, "%*sEnd-of-contents <%02X %02X>%s\n", 2 * level, "",
++ pos[0], pos[1], (pos[1] != 0) ? " Invalid!" : "");
++ pos += ASN1_INDEF_TERM_LEN;
++ }
++ } else {
++ /* Defininte length */
++ if ((tag & ASN1_PC_MASK) == ASN1_PC_CONSTRUCTED) {
++ /* Dump constructed contents */
++ ASN1_CALL(pos, asn1_dump_helper(ctrl, pos, pos + length, level, 0));
++ } else if (tag == (ASN1_CLASS_UNIVERSAL | ASN1_PC_PRIMITIVE | ASN1_TYPE_SET)
++ || tag ==
++ (ASN1_CLASS_UNIVERSAL | ASN1_PC_PRIMITIVE | ASN1_TYPE_SEQUENCE)) {
++ /* Assume tag was constructed to keep going */
++ pri_message(ctrl, "%*sThis tag must always be constructed!\n", 2 * level,
++ "");
++ ASN1_CALL(pos, asn1_dump_helper(ctrl, pos, pos + length, level, 0));
++ } else if (0 < length) {
++ /* Dump primitive contents. */
++ asn1_dump_mem(ctrl, 2 * level, pos, length);
++ pos += length;
++ }
++ --level;
++ }
++
++#if 0
++ pri_message(ctrl, "%*sEnd\n", 2 * level, "");
++#endif
++ }
++
++ return pos;
++}
++
++/*!
++ * \brief Dump the given ASN.1 buffer contents.
++ *
++ * \param ctrl D channel controller for any diagnostic messages.
++ * \param start_asn1 First octet in the ASN.1 buffer. (ASN.1 tag starting position)
++ * \param end One beyond the last octet in the ASN.1 buffer.
++ *
++ * \return Nothing
++ */
++void asn1_dump(struct pri *ctrl, const unsigned char *start_asn1,
++ const unsigned char *end)
++{
++ pri_message(ctrl, "ASN.1 dump\n");
++ if (start_asn1) {
++ asn1_dump_helper(ctrl, start_asn1, end, 1, 0);
++ }
++ pri_message(ctrl, "ASN.1 end\n");
++}
++
++/*!
++ * \brief Encode the length of an ASN.1 component body of predetermined size.
++ *
++ * \param len_pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param length Predetermined component body length.
++ *
++ * \note The encoding buffer does not need to be checked after calling.
++ * It is already checked to have the requested room.
++ *
++ * \retval Next octet after the length on success.
++ * \retval NULL on error.
++ */
++unsigned char *asn1_enc_length(unsigned char *len_pos, unsigned char *end, size_t length)
++{
++ u_int32_t body_length; /* Length of component contents */
++ u_int32_t value;
++ u_int32_t test_mask;
++ unsigned length_size; /* Length of the length encoding */
++
++ body_length = length;
++
++ /* Determine length encoding length */
++ if (body_length < 128) {
++ length_size = 1;
++ } else {
++ /* Find most significant octet of 32 bit integer that carries meaning. */
++ test_mask = 0xFF000000;
++ for (length_size = 4; --length_size;) {
++ if (body_length & test_mask) {
++ /*
++ * Found the first 8 bits of a multiple octet length that
++ * is not all zeroes.
++ */
++ break;
++ }
++ test_mask >>= 8;
++ }
++ length_size += 1 + 1;
++ }
++
++ if (end < len_pos + length_size + body_length) {
++ /* No room for the length and component body in the buffer */
++ return NULL;
++ }
++
++ /* Encode the component body length */
++ if (length_size == 1) {
++ *len_pos++ = body_length;
++ } else {
++ *len_pos++ = 0x80 | --length_size;
++ while (length_size--) {
++ value = body_length;
++ value >>= (8 * length_size);
++ *len_pos++ = value & 0xFF;
++ }
++ }
++
++ return len_pos;
++}
++
++/*!
++ * \brief Encode the length of an already encoded ASN.1 component.
++ *
++ * \param len_pos Starting position of the ASN.1 component length.
++ * \param component_end Next octet after the component body.
++ * \param end End of ASN.1 encoding data buffer.
++ *
++ * \note The total component size could increase or decrease.
++ * \note The component length field must have been initialized with
++ * ASN1_LEN_INIT() or ASN1_CONSTRUCTED_BEGIN().
++ *
++ * \retval Next octet after the component body on success.
++ * \retval NULL on error.
++ */
++unsigned char *asn1_enc_length_fixup(unsigned char *len_pos,
++ unsigned char *component_end, unsigned char *end)
++{
++ u_int32_t body_length; /* Length of component contents */
++ u_int32_t value;
++ u_int32_t test_mask;
++ unsigned length_size; /* Length of the length encoding */
++
++ if (component_end < len_pos + *len_pos) {
++ /* Sanity check */
++ return NULL;
++ }
++
++ body_length = component_end - len_pos - *len_pos;
++
++ /* Determine length encoding length */
++ if (body_length < 128) {
++ length_size = 1;
++ } else {
++ /* Find most significant octet of 32 bit integer that carries meaning. */
++ test_mask = 0xFF000000;
++ for (length_size = 4; --length_size;) {
++ if (body_length & test_mask) {
++ /*
++ * Found the first 8 bits of a multiple octet length that
++ * is not all zeroes.
++ */
++ break;
++ }
++ test_mask >>= 8;
++ }
++ length_size += 1 + 1;
++ }
++
++ component_end = len_pos + length_size + body_length;
++ if (end < component_end) {
++ /* No room for the component in the buffer */
++ return NULL;
++ }
++ if (length_size != *len_pos) {
++ /* Must shift the component body */
++ memmove(len_pos + length_size, len_pos + *len_pos, body_length);
++ }
++
++ /* Encode the component body length */
++ if (length_size == 1) {
++ *len_pos = body_length;
++ } else {
++ *len_pos++ = 0x80 | --length_size;
++ while (length_size--) {
++ value = body_length;
++ value >>= (8 * length_size);
++ *len_pos++ = value & 0xFF;
++ }
++ }
++
++ return component_end;
++}
++
++/*!
++ * \brief Encode the boolean primitive.
++ *
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param tag Component tag to identify the encoded component.
++ * \param value Component value to encode.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *asn1_enc_boolean(unsigned char *pos, unsigned char *end, unsigned tag,
++ int32_t value)
++{
++ if (end < pos + 3) {
++ /* No room for the component in the buffer */
++ return NULL;
++ }
++
++ /* Encode component */
++ *pos++ = tag;
++ *pos++ = 1;
++ *pos++ = value ? 1 : 0;
++
++ return pos;
++}
++
++/*!
++ * \brief Encode the integer type primitive.
++ *
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param tag Component tag to identify the encoded component.
++ * \param value Component value to encode.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *asn1_enc_int(unsigned char *pos, unsigned char *end, unsigned tag,
++ int32_t value)
++{
++ unsigned count;
++ u_int32_t test_mask;
++ u_int32_t val;
++
++ /* Find most significant octet of 32 bit integer that carries meaning. */
++ test_mask = 0xFF800000;
++ val = (u_int32_t) value;
++ for (count = 4; --count;) {
++ if ((val & test_mask) != test_mask && (val & test_mask) != 0) {
++ /*
++ * The first 9 bits of a multiple octet integer is not
++ * all ones or zeroes.
++ */
++ break;
++ }
++ test_mask >>= 8;
++ }
++
++ if (end < pos + 3 + count) {
++ /* No room for the component in the buffer */
++ return NULL;
++ }
++
++ /* Encode component */
++ *pos++ = tag;
++ *pos++ = count + 1;
++ do {
++ val = (u_int32_t) value;
++ val >>= (8 * count);
++ *pos++ = val & 0xFF;
++ } while (count--);
++
++ return pos;
++}
++
++/*!
++ * \brief Encode the null type primitive.
++ *
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param tag Component tag to identify the encoded component.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *asn1_enc_null(unsigned char *pos, unsigned char *end, unsigned tag)
++{
++ if (end < pos + 2) {
++ /* No room for the component in the buffer */
++ return NULL;
++ }
++
++ /* Encode component */
++ *pos++ = tag;
++ *pos++ = 0;
++
++ return pos;
++}
++
++/*!
++ * \brief Encode the object identifier (OID) primitive.
++ *
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param tag Component tag to identify the encoded component.
++ * \param oid Component value to encode.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *asn1_enc_oid(unsigned char *pos, unsigned char *end, unsigned tag,
++ const struct asn1_oid *oid)
++{
++ unsigned char *len_pos;
++ unsigned num_values;
++ unsigned count;
++ u_int32_t value;
++
++ if (end < pos + 2) {
++ /* No room for the component tag and length in the buffer */
++ return NULL;
++ }
++
++ *pos++ = tag;
++ len_pos = pos++;
++
++ /* For all OID subidentifer values */
++ for (num_values = 0; num_values < oid->num_values; ++num_values) {
++ /*
++ * Count the number of 7 bit chunks that are needed
++ * to encode the integer.
++ */
++ value = oid->value[num_values] >> 7;
++ for (count = 0; value; ++count) {
++ /* There are bits still set */
++ value >>= 7;
++ }
++
++ if (end < pos + count + 1) {
++ /* No room for the component body in the buffer */
++ return NULL;
++ }
++
++ /* Store OID subidentifier value */
++ do {
++ value = oid->value[num_values];
++ value >>= (7 * count);
++ *pos++ = (value & 0x7F) | (count ? 0x80 : 0);
++ } while (count--);
++ }
++
++ /* length */
++ *len_pos = pos - len_pos - 1;
++
++ return pos;
++}
++
++/*!
++ * \brief Encode the binary string type primitive.
++ *
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param tag Component tag to identify the encoded component.
++ * \param str Binary string to encode.
++ * \param str_len Length of binary string to encode.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *asn1_enc_string_bin(unsigned char *pos, unsigned char *end, unsigned tag,
++ const unsigned char *str, size_t str_len)
++{
++ if (end < pos + 1) {
++ /* No room for the component tag in the buffer */
++ return NULL;
++ }
++
++ /* Encode component */
++ *pos++ = tag;
++ ASN1_CALL(pos, asn1_enc_length(pos, end, str_len));
++ memcpy(pos, str, str_len);
++
++ return pos + str_len;
++}
++
++/*!
++ * \brief Encode a string that can be truncated to a maximum length primitive.
++ *
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param tag Component tag to identify the encoded component.
++ * \param str Null terminated string to encode.
++ * \param max_len Maximum length of string to encode.
++ *
++ * \note The string will be truncated if it is too long.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *asn1_enc_string_max(unsigned char *pos, unsigned char *end, unsigned tag,
++ const unsigned char *str, size_t max_len)
++{
++ size_t str_len;
++
++ str_len = strlen((char *) str);
++ if (max_len < str_len) {
++ str_len = max_len;
++ }
++ return asn1_enc_string_bin(pos, end, tag, str, str_len);
++}
++
++/* ------------------------------------------------------------------- */
++/* end asn1_primitive.c */
+
+Property changes on: asn1_primitive.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+Added: svn:mime-type
+ + text/plain
+Added: svn:keywords
+ + 'Author Date Id Revision'
+
+Index: pri.c
+===================================================================
+--- a/pri.c (.../tags/1.4.10.2) (revision 1357)
++++ b/pri.c (.../branches/1.4) (revision 1357)
+@@ -42,8 +42,56 @@
+ #include "pri_facility.h"
+ #include "pri_q921.h"
+ #include "pri_q931.h"
+-#include "pri_timers.h"
+
++#define PRI_BIT(a_bit) (1UL << (a_bit))
++#define PRI_ALL_SWITCHES 0xFFFFFFFF
++
++struct pri_timer_table {
++ const char *name;
++ enum PRI_TIMERS_AND_COUNTERS number;
++ unsigned long used_by;
++};
++
++/*!
++ * \note Sort the timer table entries in the order of the timer name so
++ * pri_dump_info_str() can display them in a consitent order.
++ */
++static const struct pri_timer_table pri_timer[] = {
++/* *INDENT-OFF* */
++ /* timer name timer number used by switches */
++ { "N200", PRI_TIMER_N200, PRI_ALL_SWITCHES },
++ { "N201", PRI_TIMER_N201, PRI_ALL_SWITCHES },
++ { "N202", PRI_TIMER_N202, PRI_ALL_SWITCHES },
++ { "K", PRI_TIMER_K, PRI_ALL_SWITCHES },
++ { "T200", PRI_TIMER_T200, PRI_ALL_SWITCHES },
++ { "T202", PRI_TIMER_T202, PRI_ALL_SWITCHES },
++ { "T203", PRI_TIMER_T203, PRI_ALL_SWITCHES },
++ { "T300", PRI_TIMER_T300, PRI_ALL_SWITCHES },
++ { "T301", PRI_TIMER_T301, PRI_ALL_SWITCHES },
++ { "T302", PRI_TIMER_T302, PRI_ALL_SWITCHES },
++ { "T303", PRI_TIMER_T303, PRI_ALL_SWITCHES },
++ { "T304", PRI_TIMER_T304, PRI_ALL_SWITCHES },
++ { "T305", PRI_TIMER_T305, PRI_ALL_SWITCHES },
++ { "T306", PRI_TIMER_T306, PRI_ALL_SWITCHES },
++ { "T307", PRI_TIMER_T307, PRI_ALL_SWITCHES },
++ { "T308", PRI_TIMER_T308, PRI_ALL_SWITCHES },
++ { "T309", PRI_TIMER_T309, PRI_ALL_SWITCHES },
++ { "T310", PRI_TIMER_T310, PRI_ALL_SWITCHES },
++ { "T313", PRI_TIMER_T313, PRI_ALL_SWITCHES },
++ { "T314", PRI_TIMER_T314, PRI_ALL_SWITCHES },
++ { "T316", PRI_TIMER_T316, PRI_ALL_SWITCHES },
++ { "T317", PRI_TIMER_T317, PRI_ALL_SWITCHES },
++ { "T318", PRI_TIMER_T318, PRI_ALL_SWITCHES },
++ { "T319", PRI_TIMER_T319, PRI_ALL_SWITCHES },
++ { "T320", PRI_TIMER_T320, PRI_ALL_SWITCHES },
++ { "T321", PRI_TIMER_T321, PRI_ALL_SWITCHES },
++ { "T322", PRI_TIMER_T322, PRI_ALL_SWITCHES },
++ { "T-HOLD", PRI_TIMER_T_HOLD, PRI_ALL_SWITCHES },
++ { "T-RETRIEVE", PRI_TIMER_T_RETRIEVE, PRI_ALL_SWITCHES },
++ { "T-RESPONSE", PRI_TIMER_T_RESPONSE, PRI_ALL_SWITCHES },
++/* *INDENT-ON* */
++};
++
+ char *pri_node2str(int node)
+ {
+ switch(node) {
+@@ -84,14 +132,39 @@
+ }
+ }
+
+-static void pri_default_timers(struct pri *pri, int switchtype)
++static void pri_default_timers(struct pri *ctrl, int switchtype)
+ {
+- static const int defaulttimers[20][PRI_MAX_TIMERS] = PRI_TIMERS_ALL;
+- int x;
++ unsigned idx;
+
+- for (x = 0; x<PRI_MAX_TIMERS; x++) {
+- pri->timers[x] = defaulttimers[switchtype][x];
++ /* Initialize all timers/counters to unsupported/disabled. */
++ for (idx = 0; idx < PRI_MAX_TIMERS; ++idx) {
++ ctrl->timers[idx] = -1;
+ }
++
++ /* Set timer values to standard defaults. Time is in ms. */
++ ctrl->timers[PRI_TIMER_N200] = 3; /* Max numer of Q.921 retransmissions */
++ ctrl->timers[PRI_TIMER_N202] = 3; /* Max numer of transmissions of the TEI identity request message */
++ ctrl->timers[PRI_TIMER_K] = 7; /* Max number of outstanding I-frames */
++ ctrl->timers[PRI_TIMER_T200] = 1000; /* Time between SABME's */
++ ctrl->timers[PRI_TIMER_T202] = 10 * 1000; /* Min time between transmission of TEI Identity request messages */
++ ctrl->timers[PRI_TIMER_T203] = 10 * 1000; /* Max time without exchanging packets */
++ ctrl->timers[PRI_TIMER_T305] = 30 * 1000; /* Wait for DISCONNECT acknowledge */
++ ctrl->timers[PRI_TIMER_T308] = 4 * 1000; /* Wait for RELEASE acknowledge */
++ ctrl->timers[PRI_TIMER_T313] = 4 * 1000; /* Wait for CONNECT acknowledge, CPE side only */
++ ctrl->timers[PRI_TIMER_TM20] = 2500; /* Max time awaiting XID response - Q.921 Appendix IV */
++ ctrl->timers[PRI_TIMER_NM20] = 3; /* Number of XID retransmits - Q.921 Appendix IV */
++ ctrl->timers[PRI_TIMER_T303] = 4 * 1000; /* Length between SETUP retransmissions and timeout */
++
++ ctrl->timers[PRI_TIMER_T_HOLD] = 4 * 1000; /* Wait for HOLD request response. */
++ ctrl->timers[PRI_TIMER_T_RETRIEVE] = 4 * 1000;/* Wait for RETRIEVE request response. */
++
++ ctrl->timers[PRI_TIMER_T_RESPONSE] = 4 * 1000; /* Maximum time to wait for a typical APDU response. */
++
++ /* Set any switch specific override default values */
++ switch (switchtype) {
++ default:
++ break;
++ }
+ }
+
+ int pri_set_timer(struct pri *pri, int timer, int value)
+@@ -110,66 +183,30 @@
+ return pri->timers[timer];
+ }
+
+-int pri_timer2idx(char *timer)
++int pri_set_service_message_support(struct pri *pri, int supportflag)
+ {
+- if (!strcasecmp(timer, "N200"))
+- return PRI_TIMER_N200;
+- else if (!strcasecmp(timer, "N201"))
+- return PRI_TIMER_N201;
+- else if (!strcasecmp(timer, "N202"))
+- return PRI_TIMER_N202;
+- else if (!strcasecmp(timer, "K"))
+- return PRI_TIMER_K;
+- else if (!strcasecmp(timer, "T200"))
+- return PRI_TIMER_T200;
+- else if (!strcasecmp(timer, "T202"))
+- return PRI_TIMER_T202;
+- else if (!strcasecmp(timer, "T203"))
+- return PRI_TIMER_T203;
+- else if (!strcasecmp(timer, "T300"))
+- return PRI_TIMER_T300;
+- else if (!strcasecmp(timer, "T301"))
+- return PRI_TIMER_T301;
+- else if (!strcasecmp(timer, "T302"))
+- return PRI_TIMER_T302;
+- else if (!strcasecmp(timer, "T303"))
+- return PRI_TIMER_T303;
+- else if (!strcasecmp(timer, "T304"))
+- return PRI_TIMER_T304;
+- else if (!strcasecmp(timer, "T305"))
+- return PRI_TIMER_T305;
+- else if (!strcasecmp(timer, "T306"))
+- return PRI_TIMER_T306;
+- else if (!strcasecmp(timer, "T307"))
+- return PRI_TIMER_T307;
+- else if (!strcasecmp(timer, "T308"))
+- return PRI_TIMER_T308;
+- else if (!strcasecmp(timer, "T309"))
+- return PRI_TIMER_T309;
+- else if (!strcasecmp(timer, "T310"))
+- return PRI_TIMER_T310;
+- else if (!strcasecmp(timer, "T313"))
+- return PRI_TIMER_T313;
+- else if (!strcasecmp(timer, "T314"))
+- return PRI_TIMER_T314;
+- else if (!strcasecmp(timer, "T316"))
+- return PRI_TIMER_T316;
+- else if (!strcasecmp(timer, "T317"))
+- return PRI_TIMER_T317;
+- else if (!strcasecmp(timer, "T318"))
+- return PRI_TIMER_T318;
+- else if (!strcasecmp(timer, "T319"))
+- return PRI_TIMER_T319;
+- else if (!strcasecmp(timer, "T320"))
+- return PRI_TIMER_T320;
+- else if (!strcasecmp(timer, "T321"))
+- return PRI_TIMER_T321;
+- else if (!strcasecmp(timer, "T322"))
+- return PRI_TIMER_T322;
+- else
++ if (!pri) {
+ return -1;
++ }
++ pri->service_message_support = supportflag;
++ return 0;
+ }
+
++int pri_timer2idx(const char *timer_name)
++{
++ unsigned idx;
++ enum PRI_TIMERS_AND_COUNTERS timer_number;
++
++ timer_number = -1;
++ for (idx = 0; idx < ARRAY_LEN(pri_timer); ++idx) {
++ if (!strcasecmp(timer_name, pri_timer[idx].name)) {
++ timer_number = pri_timer[idx].number;
++ break;
++ }
++ }
++ return timer_number;
++}
++
+ static int __pri_read(struct pri *pri, void *buf, int buflen)
+ {
+ int res = read(pri->fd, buf, buflen);
+@@ -192,18 +229,53 @@
+ return res;
+ }
+
+-/* Pass in the master for this function */
+ void __pri_free_tei(struct pri * p)
+ {
+- free (p);
++ if (p) {
++ struct q931_call *call;
++
++ call = p->dummy_call;
++ if (call) {
++ pri_schedule_del(call->pri, call->retranstimer);
++ pri_call_apdu_queue_cleanup(call);
++ }
++ free(p->msg_line);
++ free(p);
++ }
+ }
+
+ struct pri *__pri_new_tei(int fd, int node, int switchtype, struct pri *master, pri_io_cb rd, pri_io_cb wr, void *userdata, int tei, int bri)
+ {
++ struct d_ctrl_dummy *dummy_ctrl;
+ struct pri *p;
+
+- if (!(p = calloc(1, sizeof(*p))))
+- return NULL;
++ switch (switchtype) {
++ case PRI_SWITCH_GR303_EOC:
++ case PRI_SWITCH_GR303_TMC:
++ case PRI_SWITCH_GR303_TMC_SWITCHING:
++ case PRI_SWITCH_GR303_EOC_PATH:
++ p = calloc(1, sizeof(*p));
++ if (!p) {
++ return NULL;
++ }
++ dummy_ctrl = NULL;
++ break;
++ default:
++ dummy_ctrl = calloc(1, sizeof(*dummy_ctrl));
++ if (!dummy_ctrl) {
++ return NULL;
++ }
++ p = &dummy_ctrl->ctrl;
++ break;
++ }
++ if (!master) {
++ /* This is the master record. */
++ p->msg_line = calloc(1, sizeof(*p->msg_line));
++ if (!p->msg_line) {
++ free(p);
++ return NULL;
++ }
++ }
+
+ p->bri = bri;
+ p->fd = fd;
+@@ -231,7 +303,14 @@
+ p->q931_rxcount = 0;
+ p->q931_txcount = 0;
+ #endif
+- if (switchtype == PRI_SWITCH_GR303_EOC) {
++ if (dummy_ctrl) {
++ /* Initialize the dummy call reference call record. */
++ dummy_ctrl->ctrl.dummy_call = &dummy_ctrl->dummy_call;
++ q931_init_call_record(&dummy_ctrl->ctrl, dummy_ctrl->ctrl.dummy_call,
++ Q931_DUMMY_CALL_REFERENCE);
++ }
++ switch (switchtype) {
++ case PRI_SWITCH_GR303_EOC:
+ p->protodisc = GR303_PROTOCOL_DISCRIMINATOR;
+ p->sapi = Q921_SAPI_GR303_EOC;
+ p->tei = Q921_TEI_GR303_EOC_OPS;
+@@ -240,7 +319,8 @@
+ free(p);
+ p = NULL;
+ }
+- } else if (switchtype == PRI_SWITCH_GR303_TMC) {
++ break;
++ case PRI_SWITCH_GR303_TMC:
+ p->protodisc = GR303_PROTOCOL_DISCRIMINATOR;
+ p->sapi = Q921_SAPI_GR303_TMC_CALLPROC;
+ p->tei = Q921_TEI_GR303_TMC_CALLPROC;
+@@ -249,14 +329,19 @@
+ free(p);
+ p = NULL;
+ }
+- } else if (switchtype == PRI_SWITCH_GR303_TMC_SWITCHING) {
++ break;
++ case PRI_SWITCH_GR303_TMC_SWITCHING:
+ p->protodisc = GR303_PROTOCOL_DISCRIMINATOR;
+ p->sapi = Q921_SAPI_GR303_TMC_SWITCHING;
+ p->tei = Q921_TEI_GR303_TMC_SWITCHING;
+- } else if (switchtype == PRI_SWITCH_GR303_EOC_PATH) {
++ break;
++ case PRI_SWITCH_GR303_EOC_PATH:
+ p->protodisc = GR303_PROTOCOL_DISCRIMINATOR;
+ p->sapi = Q921_SAPI_GR303_EOC;
+ p->tei = Q921_TEI_GR303_EOC_PATH;
++ break;
++ default:
++ break;
+ }
+ /* Start Q.921 layer, Wait if we're the network */
+ if (p)
+@@ -327,44 +412,47 @@
+
+ char *pri_event2str(int id)
+ {
+- switch(id) {
+- case PRI_EVENT_DCHAN_UP:
+- return "D-Channel Up";
+- case PRI_EVENT_DCHAN_DOWN:
+- return "D-channel Down";
+- case PRI_EVENT_RESTART:
+- return "Restart channel";
+- case PRI_EVENT_RING:
+- return "Ring";
+- case PRI_EVENT_HANGUP:
+- return "Hangup";
+- case PRI_EVENT_RINGING:
+- return "Ringing";
+- case PRI_EVENT_ANSWER:
+- return "Answer";
+- case PRI_EVENT_HANGUP_ACK:
+- return "Hangup ACK";
+- case PRI_EVENT_RESTART_ACK:
+- return "Restart ACK";
+- case PRI_EVENT_FACNAME:
+- return "FacName";
+- case PRI_EVENT_INFO_RECEIVED:
+- return "Info Received";
+- case PRI_EVENT_PROCEEDING:
+- return "Proceeding";
+- case PRI_EVENT_SETUP_ACK:
+- return "Setup ACK";
+- case PRI_EVENT_HANGUP_REQ:
+- return "Hangup Req";
+- case PRI_EVENT_NOTIFY:
+- return "Notify";
+- case PRI_EVENT_PROGRESS:
+- return "Progress";
+- case PRI_EVENT_CONFIG_ERR:
+- return "Configuration Error";
+- default:
+- return "Unknown Event";
++ unsigned idx;
++ struct {
++ int id;
++ char *name;
++ } events[] = {
++/* *INDENT-OFF* */
++ { PRI_EVENT_DCHAN_UP, "D-Channel Up" },
++ { PRI_EVENT_DCHAN_DOWN, "D-channel Down" },
++ { PRI_EVENT_RESTART, "Restart channel" },
++ { PRI_EVENT_CONFIG_ERR, "Configuration Error" },
++ { PRI_EVENT_RING, "Ring" },
++ { PRI_EVENT_HANGUP, "Hangup" },
++ { PRI_EVENT_RINGING, "Ringing" },
++ { PRI_EVENT_ANSWER, "Answer" },
++ { PRI_EVENT_HANGUP_ACK, "Hangup ACK" },
++ { PRI_EVENT_RESTART_ACK, "Restart ACK" },
++ { PRI_EVENT_FACILITY, "Facility" },
++ { PRI_EVENT_INFO_RECEIVED, "Info Received" },
++ { PRI_EVENT_PROCEEDING, "Proceeding" },
++ { PRI_EVENT_SETUP_ACK, "Setup ACK" },
++ { PRI_EVENT_HANGUP_REQ, "Hangup Req" },
++ { PRI_EVENT_NOTIFY, "Notify" },
++ { PRI_EVENT_PROGRESS, "Progress" },
++ { PRI_EVENT_KEYPAD_DIGIT, "Keypad Digit" },
++ { PRI_EVENT_SERVICE, "Service" },
++ { PRI_EVENT_SERVICE_ACK, "Service ACK" },
++ { PRI_EVENT_HOLD, "Hold" },
++ { PRI_EVENT_HOLD_ACK, "Hold Ack" },
++ { PRI_EVENT_HOLD_REJ, "Hold Rej" },
++ { PRI_EVENT_RETRIEVE, "Retrieve" },
++ { PRI_EVENT_RETRIEVE_ACK, "Retrieve ACK" },
++ { PRI_EVENT_RETRIEVE_REJ, "Retrieve Rej" },
++/* *INDENT-ON* */
++ };
++
++ for (idx = 0; idx < ARRAY_LEN(events); ++idx) {
++ if (events[idx].id == id) {
++ return events[idx].name;
++ }
+ }
++ return "Unknown Event";
+ }
+
+ pri_event *pri_check_event(struct pri *pri)
+@@ -506,7 +594,7 @@
+ return q931_information(pri, call, digit);
+ }
+
+-int pri_keypad_facility(struct pri *pri, q931_call *call, char *digits)
++int pri_keypad_facility(struct pri *pri, q931_call *call, const char *digits)
+ {
+ if (!pri || !call || !digits || !digits[0])
+ return -1;
+@@ -514,15 +602,6 @@
+ return q931_keypad_facility(pri, call, digits);
+ }
+
+-
+-int pri_callrerouting_facility(struct pri *pri, q931_call *call, const char *dest, const char* original, const char* reason)
+-{
+- if (!pri || !call)
+- return -1;
+-
+- return qsig_cf_callrerouting(pri, call, dest, original, reason);
+-}
+-
+ int pri_notify(struct pri *pri, q931_call *call, int channel, int info)
+ {
+ if (!pri || !call)
+@@ -533,7 +612,7 @@
+ void pri_destroycall(struct pri *pri, q931_call *call)
+ {
+ if (pri && call)
+- __q931_destroycall(pri, call);
++ q931_destroycall(pri, call);
+ return;
+ }
+
+@@ -551,6 +630,268 @@
+ return q931_connect(pri, call, channel, nonisdn);
+ }
+
++/*!
++ * \internal
++ * \brief Copy the PRI party name to the Q.931 party name structure.
++ *
++ * \param q931_name Q.931 party name structure
++ * \param pri_name PRI party name structure
++ *
++ * \return Nothing
++ */
++static void pri_copy_party_name_to_q931(struct q931_party_name *q931_name, const struct pri_party_name *pri_name)
++{
++ q931_party_name_init(q931_name);
++ if (pri_name->valid) {
++ q931_name->valid = 1;
++ q931_name->presentation = pri_name->presentation;
++ q931_name->char_set = pri_name->char_set;
++ libpri_copy_string(q931_name->str, pri_name->str, sizeof(q931_name->str));
++ }
++}
++
++/*!
++ * \internal
++ * \brief Copy the PRI party number to the Q.931 party number structure.
++ *
++ * \param q931_number Q.931 party number structure
++ * \param pri_number PRI party number structure
++ *
++ * \return Nothing
++ */
++static void pri_copy_party_number_to_q931(struct q931_party_number *q931_number, const struct pri_party_number *pri_number)
++{
++ q931_party_number_init(q931_number);
++ if (pri_number->valid) {
++ q931_number->valid = 1;
++ q931_number->presentation = pri_number->presentation;
++ q931_number->plan = pri_number->plan;
++ libpri_copy_string(q931_number->str, pri_number->str, sizeof(q931_number->str));
++ }
++}
++
++/*!
++ * \internal
++ * \brief Copy the PRI party subaddress to the Q.931 party subaddress structure.
++ *
++ * \param q931_subaddress Q.931 party subaddress structure
++ * \param pri_subaddress PRI party subaddress structure
++ *
++ * \return Nothing
++ */
++static void pri_copy_party_subaddress_to_q931(struct q931_party_subaddress *q931_subaddress, const struct pri_party_subaddress *pri_subaddress)
++{
++ int length;
++ int maxlen = sizeof(q931_subaddress->data) - 1;
++
++ q931_party_subaddress_init(q931_subaddress);
++
++ if (!pri_subaddress->valid) {
++ return;
++ }
++
++ q931_subaddress->valid = 1;
++ q931_subaddress->type = pri_subaddress->type;
++
++ length = pri_subaddress->length;
++ if (length > maxlen){
++ length = maxlen;
++ } else {
++ q931_subaddress->odd_even_indicator = pri_subaddress->odd_even_indicator;
++ }
++ q931_subaddress->length = length;
++ memcpy(q931_subaddress->data, pri_subaddress->data, length);
++ q931_subaddress->data[length] = '\0';
++}
++
++/*!
++ * \internal
++ * \brief Copy the PRI party id to the Q.931 party id structure.
++ *
++ * \param q931_id Q.931 party id structure
++ * \param pri_id PRI party id structure
++ *
++ * \return Nothing
++ */
++static void pri_copy_party_id_to_q931(struct q931_party_id *q931_id, const struct pri_party_id *pri_id)
++{
++ pri_copy_party_name_to_q931(&q931_id->name, &pri_id->name);
++ pri_copy_party_number_to_q931(&q931_id->number, &pri_id->number);
++ pri_copy_party_subaddress_to_q931(&q931_id->subaddress, &pri_id->subaddress);
++}
++
++int pri_connected_line_update(struct pri *ctrl, q931_call *call, const struct pri_party_connected_line *connected)
++{
++ struct q931_party_id party_id;
++ unsigned idx;
++ struct q931_call *subcall;
++
++ if (!ctrl || !call) {
++ return -1;
++ }
++
++ pri_copy_party_id_to_q931(&party_id, &connected->id);
++ q931_party_id_fixup(ctrl, &party_id);
++ if (!q931_party_id_cmp(&party_id, &call->local_id)) {
++ /* The local party information did not change so do nothing. */
++ return 0;
++ }
++ call->local_id = party_id;
++
++ /* Update all subcalls with new local_id. */
++ if (call->outboundbroadcast && call->master_call == call) {
++ for (idx = 0; idx < Q931_MAX_TEI; ++idx) {
++ subcall = call->subcalls[idx];
++ if (subcall) {
++ subcall->local_id = party_id;
++ }
++ }
++ }
++
++ switch (call->ourcallstate) {
++ case Q931_CALL_STATE_CALL_INITIATED:
++ case Q931_CALL_STATE_OVERLAP_SENDING:
++ case Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING:
++ case Q931_CALL_STATE_CALL_DELIVERED:
++ /*
++ * The local party transferred to someone else before
++ * the remote end answered.
++ */
++ case Q931_CALL_STATE_ACTIVE:
++ switch (ctrl->switchtype) {
++ case PRI_SWITCH_EUROISDN_E1:
++ case PRI_SWITCH_EUROISDN_T1:
++ if (q931_is_ptmp(ctrl)) {
++ /* PTMP mode */
++ q931_notify_redirection(ctrl, call, PRI_NOTIFY_TRANSFER_ACTIVE,
++ &call->local_id.number);
++ } else {
++ /* PTP mode */
++ /* Immediately send EctInform APDU, callStatus=answered(0) */
++ send_call_transfer_complete(ctrl, call, 0);
++ }
++ break;
++ case PRI_SWITCH_QSIG:
++ /* Immediately send CallTransferComplete APDU, callStatus=answered(0) */
++ send_call_transfer_complete(ctrl, call, 0);
++ break;
++ default:
++ break;
++ }
++ break;
++ default:
++ /* Just save the data for further developments. */
++ break;
++ }
++
++ return 0;
++}
++
++int pri_redirecting_update(struct pri *ctrl, q931_call *call, const struct pri_party_redirecting *redirecting)
++{
++ unsigned idx;
++ struct q931_call *subcall;
++
++ if (!ctrl || !call) {
++ return -1;
++ }
++
++ /* Save redirecting.to information and reason. */
++ pri_copy_party_id_to_q931(&call->redirecting.to, &redirecting->to);
++ q931_party_id_fixup(ctrl, &call->redirecting.to);
++ call->redirecting.reason = redirecting->reason;
++
++ /*
++ * Update all subcalls with new redirecting.to information and reason.
++ * I do not think we will ever have any subcalls when this data is relevant,
++ * but update it just in case.
++ */
++ if (call->outboundbroadcast && call->master_call == call) {
++ for (idx = 0; idx < Q931_MAX_TEI; ++idx) {
++ subcall = call->subcalls[idx];
++ if (subcall) {
++ subcall->redirecting.to = call->redirecting.to;
++ subcall->redirecting.reason = redirecting->reason;
++ }
++ }
++ }
++
++ switch (call->ourcallstate) {
++ case Q931_CALL_STATE_NULL:
++ /* Save the remaining redirecting information before we place a call. */
++ pri_copy_party_id_to_q931(&call->redirecting.from, &redirecting->from);
++ q931_party_id_fixup(ctrl, &call->redirecting.from);
++ pri_copy_party_id_to_q931(&call->redirecting.orig_called, &redirecting->orig_called);
++ q931_party_id_fixup(ctrl, &call->redirecting.orig_called);
++ call->redirecting.orig_reason = redirecting->orig_reason;
++ if (redirecting->count <= 0) {
++ if (call->redirecting.from.number.valid) {
++ /*
++ * We are redirecting with an unknown count
++ * so assume the count is one.
++ */
++ call->redirecting.count = 1;
++ } else {
++ call->redirecting.count = 0;
++ }
++ } else if (redirecting->count < PRI_MAX_REDIRECTS) {
++ call->redirecting.count = redirecting->count;
++ } else {
++ call->redirecting.count = PRI_MAX_REDIRECTS;
++ }
++ break;
++ case Q931_CALL_STATE_OVERLAP_RECEIVING:
++ case Q931_CALL_STATE_INCOMING_CALL_PROCEEDING:
++ case Q931_CALL_STATE_CALL_RECEIVED:
++ /* This is an incoming call that has not connected yet. */
++ if (!call->redirecting.to.number.valid) {
++ /* Not being redirected toward valid number data. Ignore. */
++ break;
++ }
++
++ switch (ctrl->switchtype) {
++ case PRI_SWITCH_EUROISDN_E1:
++ case PRI_SWITCH_EUROISDN_T1:
++ if (q931_is_ptmp(ctrl)) {
++ /* PTMP mode */
++ q931_notify_redirection(ctrl, call, PRI_NOTIFY_CALL_DIVERTING,
++ &call->redirecting.to.number);
++ break;
++ }
++ /* PTP mode - same behaviour as Q.SIG */
++ /* fall through */
++ case PRI_SWITCH_QSIG:
++ if (call->redirecting.state != Q931_REDIRECTING_STATE_PENDING_TX_DIV_LEG_3
++ || strcmp(call->redirecting.to.number.str, call->called.number.str) != 0) {
++ /* immediately send divertingLegInformation1 APDU */
++ if (rose_diverting_leg_information1_encode(ctrl, call)
++ || q931_facility(ctrl, call)) {
++ pri_message(ctrl,
++ "Could not schedule facility message for divertingLegInfo1\n");
++ }
++ }
++ call->redirecting.state = Q931_REDIRECTING_STATE_IDLE;
++
++ /* immediately send divertingLegInformation3 APDU */
++ if (rose_diverting_leg_information3_encode(ctrl, call, Q931_FACILITY)
++ || q931_facility(ctrl, call)) {
++ pri_message(ctrl,
++ "Could not schedule facility message for divertingLegInfo3\n");
++ }
++ break;
++ default:
++ break;
++ }
++ break;
++ default:
++ pri_message(ctrl, "Ignored redirecting update because call in state %s(%d).\n",
++ q931_call_state_str(call->ourcallstate), call->ourcallstate);
++ break;
++ }
++
++ return 0;
++}
++
+ #if 0
+ /* deprecated routines, use pri_hangup */
+ int pri_release(struct pri *pri, q931_call *call, int cause)
+@@ -619,7 +960,7 @@
+ return -1;
+ if (cause == -1)
+ /* normal clear cause */
+- cause = 16;
++ cause = PRI_CAUSE_NORMAL_CLEARING;
+ return q931_hangup(pri, call, cause);
+ }
+
+@@ -630,6 +971,14 @@
+ return q931_restart(pri, channel);
+ }
+
++int pri_maintenance_service(struct pri *pri, int span, int channel, int changestatus)
++{
++ if (!pri) {
++ return -1;
++ }
++ return maintenance_service(pri, span, channel, changestatus);
++}
++
+ q931_call *pri_new_call(struct pri *pri)
+ {
+ if (!pri)
+@@ -637,6 +986,14 @@
+ return q931_new_call(pri);
+ }
+
++int pri_is_dummy_call(q931_call *call)
++{
++ if (!call) {
++ return 0;
++ }
++ return q931_is_dummy_call(call);
++}
++
+ void pri_dump_event(struct pri *pri, pri_event *e)
+ {
+ if (!pri || !e)
+@@ -667,7 +1024,10 @@
+ static void pri_sr_init(struct pri_sr *req)
+ {
+ memset(req, 0, sizeof(struct pri_sr));
+-
++ q931_party_redirecting_init(&req->redirecting);
++ q931_party_id_init(&req->caller);
++ q931_party_address_init(&req->called);
++ req->reversecharge = PRI_REVERSECHARGE_NONE;
+ }
+
+ int pri_sr_set_connection_call_independent(struct pri_sr *req)
+@@ -675,10 +1035,21 @@
+ if (!req)
+ return -1;
+
+- req->justsignalling = 1; /* have to set justsignalling for all those pesky IEs we need to setup */
++ req->cis_call = 1; /* have to set cis_call for all those pesky IEs we need to setup */
++ req->cis_auto_disconnect = 1;
+ return 0;
+ }
+
++int pri_sr_set_no_channel_call(struct pri_sr *req)
++{
++ if (!req) {
++ return -1;
++ }
++
++ req->cis_call = 1;
++ return 0;
++}
++
+ /* Don't call any other pri functions on this */
+ int pri_mwi_activate(struct pri *pri, q931_call *c, char *caller, int callerplan, char *callername, int callerpres, char *called,
+ int calledplan)
+@@ -689,14 +1060,9 @@
+
+ pri_sr_init(&req);
+ pri_sr_set_connection_call_independent(&req);
++ pri_sr_set_caller(&req, caller, callername, callerplan, callerpres);
++ pri_sr_set_called(&req, called, calledplan, 0);
+
+- req.caller = caller;
+- req.callerplan = callerplan;
+- req.callername = callername;
+- req.callerpres = callerpres;
+- req.called = called;
+- req.calledplan = calledplan;
+-
+ if (mwi_message_send(pri, c, &req, 1) < 0) {
+ pri_message(pri, "Unable to send MWI activate message\n");
+ return -1;
+@@ -714,14 +1080,9 @@
+
+ pri_sr_init(&req);
+ pri_sr_set_connection_call_independent(&req);
++ pri_sr_set_caller(&req, caller, callername, callerplan, callerpres);
++ pri_sr_set_called(&req, called, calledplan, 0);
+
+- req.caller = caller;
+- req.callerplan = callerplan;
+- req.callername = callername;
+- req.callerpres = callerpres;
+- req.called = called;
+- req.calledplan = calledplan;
+-
+ if(mwi_message_send(pri, c, &req, 0) < 0) {
+ pri_message(pri, "Unable to send MWI deactivate message\n");
+ return -1;
+@@ -740,22 +1101,18 @@
+
+ int pri_call(struct pri *pri, q931_call *c, int transmode, int channel, int exclusive,
+ int nonisdn, char *caller, int callerplan, char *callername, int callerpres, char *called,
+- int calledplan,int ulayer1)
++ int calledplan, int ulayer1)
+ {
+ struct pri_sr req;
+ if (!pri || !c)
+ return -1;
+ pri_sr_init(&req);
++ pri_sr_set_caller(&req, caller, callername, callerplan, callerpres);
++ pri_sr_set_called(&req, called, calledplan, 0);
+ req.transmode = transmode;
+ req.channel = channel;
+ req.exclusive = exclusive;
+ req.nonisdn = nonisdn;
+- req.caller = caller;
+- req.callerplan = callerplan;
+- req.callername = callername;
+- req.callerpres = callerpres;
+- req.called = called;
+- req.calledplan = calledplan;
+ req.userl1 = ulayer1;
+ return q931_setup(pri, c, &req);
+ }
+@@ -773,28 +1130,85 @@
+ __pri_error = func;
+ }
+
+-void pri_message(struct pri *pri, char *fmt, ...)
++static void pri_old_message(struct pri *ctrl, const char *fmt, va_list *ap)
+ {
+ char tmp[1024];
+- va_list ap;
+- va_start(ap, fmt);
+- vsnprintf(tmp, sizeof(tmp), fmt, ap);
+- va_end(ap);
++
++ vsnprintf(tmp, sizeof(tmp), fmt, *ap);
+ if (__pri_message)
+- __pri_message(pri, tmp);
++ __pri_message(ctrl, tmp);
+ else
+ fputs(tmp, stdout);
+ }
+
+-void pri_error(struct pri *pri, char *fmt, ...)
++void pri_message(struct pri *ctrl, const char *fmt, ...)
+ {
++ int added_length;
++ va_list ap;
++
++ ctrl = PRI_MASTER(ctrl);
++ if (!ctrl || !ctrl->msg_line) {
++ /* Just have to do it the old way. */
++ va_start(ap, fmt);
++ pri_old_message(ctrl, fmt, &ap);
++ va_end(ap);
++ return;
++ }
++
++ va_start(ap, fmt);
++ added_length = vsnprintf(ctrl->msg_line->str + ctrl->msg_line->length,
++ sizeof(ctrl->msg_line->str) - ctrl->msg_line->length, fmt, ap);
++ va_end(ap);
++ if (added_length < 0
++ || sizeof(ctrl->msg_line->str) <= ctrl->msg_line->length + added_length) {
++ static char truncated_output[] =
++ "v-- Error building output or output was truncated. (Next line) --v\n";
++
++ /*
++ * This clause should never need to run because the
++ * output line accumulation buffer is quite large.
++ */
++
++ /* vsnprintf() error or output string was truncated. */
++ if (__pri_message) {
++ __pri_message(ctrl, truncated_output);
++ } else {
++ fputs(truncated_output, stdout);
++ }
++
++ /* Add a terminating '\n' to force a flush of the line. */
++ ctrl->msg_line->length = strlen(ctrl->msg_line->str);
++ if (ctrl->msg_line->length) {
++ ctrl->msg_line->str[ctrl->msg_line->length - 1] = '\n';
++ } else {
++ ctrl->msg_line->str[0] = '\n';
++ ctrl->msg_line->str[1] = '\0';
++ }
++ } else {
++ ctrl->msg_line->length += added_length;
++ }
++
++ if (ctrl->msg_line->length
++ && ctrl->msg_line->str[ctrl->msg_line->length - 1] == '\n') {
++ /* The accumulated output line was terminated so send it out. */
++ ctrl->msg_line->length = 0;
++ if (__pri_message) {
++ __pri_message(ctrl, ctrl->msg_line->str);
++ } else {
++ fputs(ctrl->msg_line->str, stdout);
++ }
++ }
++}
++
++void pri_error(struct pri *pri, const char *fmt, ...)
++{
+ char tmp[1024];
+ va_list ap;
+ va_start(ap, fmt);
+ vsnprintf(tmp, sizeof(tmp), fmt, ap);
+ va_end(ap);
+ if (__pri_error)
+- __pri_error(pri, tmp);
++ __pri_error(PRI_MASTER(pri), tmp);
+ else
+ fputs(tmp, stderr);
+ }
+@@ -821,49 +1235,102 @@
+ return pri->fd;
+ }
+
+-char *pri_dump_info_str(struct pri *pri)
++/*!
++ * \internal
++ * \brief Append snprintf output to the given buffer.
++ *
++ * \param buf Buffer currently filling.
++ * \param buf_used Offset into buffer where to put new stuff.
++ * \param buf_size Actual buffer size of buf.
++ * \param format printf format string.
++ *
++ * \return Total buffer space used.
++ */
++static size_t pri_snprintf(char *buf, size_t buf_used, size_t buf_size, const char *format, ...) __attribute__((format(printf, 4, 5)));
++static size_t pri_snprintf(char *buf, size_t buf_used, size_t buf_size, const char *format, ...)
+ {
+- char buf[4096];
+- int len = 0;
++ va_list args;
++
++ if (buf_used < buf_size) {
++ va_start(args, format);
++ buf_used += vsnprintf(buf + buf_used, buf_size - buf_used, format, args);
++ va_end(args);
++ }
++ if (buf_size < buf_used) {
++ buf_used = buf_size + 1;
++ }
++ return buf_used;
++}
++
++char *pri_dump_info_str(struct pri *ctrl)
++{
++ char *buf;
++ size_t buf_size;
++ size_t used;
+ #ifdef LIBPRI_COUNTERS
+ struct q921_frame *f;
+- int q921outstanding = 0;
++ unsigned q921outstanding;
+ #endif
+- if (!pri)
++ unsigned idx;
++ unsigned long switch_bit;
++
++ if (!ctrl) {
+ return NULL;
++ }
+
++ buf_size = 4096; /* This should be bigger than we will ever need. */
++ buf = malloc(buf_size);
++ if (!buf) {
++ return NULL;
++ }
++
+ /* Might be nice to format these a little better */
+- len += sprintf(buf + len, "Switchtype: %s\n", pri_switch2str(pri->switchtype));
+- len += sprintf(buf + len, "Type: %s\n", pri_node2str(pri->localtype));
++ used = 0;
++ used = pri_snprintf(buf, used, buf_size, "Switchtype: %s\n",
++ pri_switch2str(ctrl->switchtype));
++ used = pri_snprintf(buf, used, buf_size, "Type: %s\n", pri_node2str(ctrl->localtype));
+ #ifdef LIBPRI_COUNTERS
+ /* Remember that Q921 Counters include Q931 packets (and any retransmissions) */
+- len += sprintf(buf + len, "Q931 RX: %d\n", pri->q931_rxcount);
+- len += sprintf(buf + len, "Q931 TX: %d\n", pri->q931_txcount);
+- len += sprintf(buf + len, "Q921 RX: %d\n", pri->q921_rxcount);
+- len += sprintf(buf + len, "Q921 TX: %d\n", pri->q921_txcount);
+- f = pri->txqueue;
++ used = pri_snprintf(buf, used, buf_size, "Q931 RX: %d\n", ctrl->q931_rxcount);
++ used = pri_snprintf(buf, used, buf_size, "Q931 TX: %d\n", ctrl->q931_txcount);
++ used = pri_snprintf(buf, used, buf_size, "Q921 RX: %d\n", ctrl->q921_rxcount);
++ used = pri_snprintf(buf, used, buf_size, "Q921 TX: %d\n", ctrl->q921_txcount);
++ q921outstanding = 0;
++ f = ctrl->txqueue;
+ while (f) {
+ q921outstanding++;
+ f = f->next;
+ }
+- len += sprintf(buf + len, "Q921 Outstanding: %d\n", q921outstanding);
++ used = pri_snprintf(buf, used, buf_size, "Q921 Outstanding: %u\n", q921outstanding);
+ #endif
+- len += sprintf(buf + len, "Window Length: %d/%d\n", pri->windowlen, pri->window);
+- len += sprintf(buf + len, "Sentrej: %d\n", pri->sentrej);
+- len += sprintf(buf + len, "SolicitFbit: %d\n", pri->solicitfbit);
+- len += sprintf(buf + len, "Retrans: %d\n", pri->retrans);
+- len += sprintf(buf + len, "Busy: %d\n", pri->busy);
+- len += sprintf(buf + len, "Overlap Dial: %d\n", pri->overlapdial);
+- len += sprintf(buf + len, "Logical Channel Mapping: %d\n", pri->chan_mapping_logical);
+- len += sprintf(buf + len, "T200 Timer: %d\n", pri->timers[PRI_TIMER_T200]);
+- len += sprintf(buf + len, "T203 Timer: %d\n", pri->timers[PRI_TIMER_T203]);
+- len += sprintf(buf + len, "T305 Timer: %d\n", pri->timers[PRI_TIMER_T305]);
+- len += sprintf(buf + len, "T308 Timer: %d\n", pri->timers[PRI_TIMER_T308]);
+- len += sprintf(buf + len, "T309 Timer: %d\n", pri->timers[PRI_TIMER_T309]);
+- len += sprintf(buf + len, "T313 Timer: %d\n", pri->timers[PRI_TIMER_T313]);
+- len += sprintf(buf + len, "N200 Counter: %d\n", pri->timers[PRI_TIMER_N200]);
++ used = pri_snprintf(buf, used, buf_size, "Window Length: %d/%d\n", ctrl->windowlen,
++ ctrl->window);
++ used = pri_snprintf(buf, used, buf_size, "Sentrej: %d\n", ctrl->sentrej);
++ used = pri_snprintf(buf, used, buf_size, "SolicitFbit: %d\n", ctrl->solicitfbit);
++ used = pri_snprintf(buf, used, buf_size, "Retrans: %d\n", ctrl->retrans);
++ used = pri_snprintf(buf, used, buf_size, "Busy: %d\n", ctrl->busy);
++ used = pri_snprintf(buf, used, buf_size, "Overlap Dial: %d\n", ctrl->overlapdial);
++ used = pri_snprintf(buf, used, buf_size, "Logical Channel Mapping: %d\n",
++ ctrl->chan_mapping_logical);
++ used = pri_snprintf(buf, used, buf_size, "Timer and counter settings:\n");
++ switch_bit = PRI_BIT(ctrl->switchtype);
++ for (idx = 0; idx < ARRAY_LEN(pri_timer); ++idx) {
++ if (pri_timer[idx].used_by & switch_bit) {
++ enum PRI_TIMERS_AND_COUNTERS tmr;
+
+- return strdup(buf);
++ tmr = pri_timer[idx].number;
++ if (0 <= ctrl->timers[tmr] || tmr == PRI_TIMER_T309) {
++ used = pri_snprintf(buf, used, buf_size, " %s: %d\n",
++ pri_timer[idx].name, ctrl->timers[tmr]);
++ }
++ }
++ }
++
++ if (buf_size < used) {
++ pri_message(ctrl,
++ "pri_dump_info_str(): Produced output exceeded buffer capacity. (Truncated)\n");
++ }
++ return buf;
+ }
+
+ int pri_get_crv(struct pri *pri, q931_call *call, int *callmode)
+@@ -913,26 +1380,213 @@
+
+ int pri_sr_set_called(struct pri_sr *sr, char *called, int calledplan, int numcomplete)
+ {
+- sr->called = called;
+- sr->calledplan = calledplan;
++ q931_party_address_init(&sr->called);
++ if (called) {
++ sr->called.number.valid = 1;
++ sr->called.number.plan = calledplan;
++ libpri_copy_string(sr->called.number.str, called, sizeof(sr->called.number.str));
++ }
+ sr->numcomplete = numcomplete;
+ return 0;
+ }
+
++void pri_sr_set_called_subaddress(struct pri_sr *sr, const struct pri_party_subaddress *subaddress)
++{
++ pri_copy_party_subaddress_to_q931(&sr->called.subaddress, subaddress);
++}
++
+ int pri_sr_set_caller(struct pri_sr *sr, char *caller, char *callername, int callerplan, int callerpres)
+ {
+- sr->caller = caller;
+- sr->callername = callername;
+- sr->callerplan = callerplan;
+- sr->callerpres = callerpres;
++ q931_party_id_init(&sr->caller);
++ if (caller) {
++ sr->caller.number.valid = 1;
++ sr->caller.number.presentation = callerpres;
++ sr->caller.number.plan = callerplan;
++ libpri_copy_string(sr->caller.number.str, caller, sizeof(sr->caller.number.str));
++
++ if (callername) {
++ sr->caller.name.valid = 1;
++ sr->caller.name.presentation = callerpres;
++ sr->caller.name.char_set = PRI_CHAR_SET_ISO8859_1;
++ libpri_copy_string(sr->caller.name.str, callername,
++ sizeof(sr->caller.name.str));
++ }
++ }
+ return 0;
+ }
+
++void pri_sr_set_caller_subaddress(struct pri_sr *sr, const struct pri_party_subaddress *subaddress)
++{
++ pri_copy_party_subaddress_to_q931(&sr->caller.subaddress, subaddress);
++}
++
++void pri_sr_set_caller_party(struct pri_sr *sr, const struct pri_party_id *caller)
++{
++ pri_copy_party_id_to_q931(&sr->caller, caller);
++}
++
+ int pri_sr_set_redirecting(struct pri_sr *sr, char *num, int plan, int pres, int reason)
+ {
+- sr->redirectingnum = num;
+- sr->redirectingplan = plan;
+- sr->redirectingpres = pres;
+- sr->redirectingreason = reason;
++ q931_party_redirecting_init(&sr->redirecting);
++ if (num && num[0]) {
++ sr->redirecting.from.number.valid = 1;
++ sr->redirecting.from.number.presentation = pres;
++ sr->redirecting.from.number.plan = plan;
++ libpri_copy_string(sr->redirecting.from.number.str, num,
++ sizeof(sr->redirecting.from.number.str));
++
++ sr->redirecting.count = 1;
++ sr->redirecting.reason = reason;
++ }
+ return 0;
+ }
++
++void pri_sr_set_redirecting_parties(struct pri_sr *sr, const struct pri_party_redirecting *redirecting)
++{
++ pri_copy_party_id_to_q931(&sr->redirecting.from, &redirecting->from);
++ pri_copy_party_id_to_q931(&sr->redirecting.to, &redirecting->to);
++ pri_copy_party_id_to_q931(&sr->redirecting.orig_called, &redirecting->orig_called);
++ sr->redirecting.orig_reason = redirecting->orig_reason;
++ sr->redirecting.reason = redirecting->reason;
++ if (redirecting->count <= 0) {
++ if (sr->redirecting.from.number.valid) {
++ /*
++ * We are redirecting with an unknown count
++ * so assume the count is one.
++ */
++ sr->redirecting.count = 1;
++ } else {
++ sr->redirecting.count = 0;
++ }
++ } else if (redirecting->count < PRI_MAX_REDIRECTS) {
++ sr->redirecting.count = redirecting->count;
++ } else {
++ sr->redirecting.count = PRI_MAX_REDIRECTS;
++ }
++}
++
++void pri_sr_set_reversecharge(struct pri_sr *sr, int requested)
++{
++ sr->reversecharge = requested;
++}
++
++void pri_sr_set_keypad_digits(struct pri_sr *sr, const char *keypad_digits)
++{
++ sr->keypad_digits = keypad_digits;
++}
++
++void pri_hold_enable(struct pri *ctrl, int enable)
++{
++ ctrl = PRI_MASTER(ctrl);
++ if (ctrl) {
++ ctrl->hold_support = enable ? 1 : 0;
++ }
++}
++
++int pri_hold(struct pri *ctrl, q931_call *call)
++{
++ if (!ctrl || !call) {
++ return -1;
++ }
++ return q931_send_hold(ctrl, call);
++}
++
++int pri_hold_ack(struct pri *ctrl, q931_call *call)
++{
++ if (!ctrl || !call) {
++ return -1;
++ }
++ return q931_send_hold_ack(ctrl, call);
++}
++
++int pri_hold_rej(struct pri *ctrl, q931_call *call, int cause)
++{
++ if (!ctrl || !call) {
++ return -1;
++ }
++ return q931_send_hold_rej(ctrl, call, cause);
++}
++
++int pri_retrieve(struct pri *ctrl, q931_call *call, int channel)
++{
++ if (!ctrl || !call) {
++ return -1;
++ }
++ return q931_send_retrieve(ctrl, call, channel);
++}
++
++int pri_retrieve_ack(struct pri *ctrl, q931_call *call, int channel)
++{
++ if (!ctrl || !call) {
++ return -1;
++ }
++ return q931_send_retrieve_ack(ctrl, call, channel);
++}
++
++int pri_retrieve_rej(struct pri *ctrl, q931_call *call, int cause)
++{
++ if (!ctrl || !call) {
++ return -1;
++ }
++ return q931_send_retrieve_rej(ctrl, call, cause);
++}
++
++int pri_callrerouting_facility(struct pri *pri, q931_call *call, const char *dest, const char* original, const char* reason)
++{
++ if (!pri || !call || !dest)
++ return -1;
++
++ return qsig_cf_callrerouting(pri, call, dest, original, reason);
++}
++
++void pri_reroute_enable(struct pri *ctrl, int enable)
++{
++ ctrl = PRI_MASTER(ctrl);
++ if (ctrl) {
++ ctrl->deflection_support = enable ? 1 : 0;
++ }
++}
++
++int pri_reroute_call(struct pri *ctrl, q931_call *call, const struct pri_party_id *caller, const struct pri_party_redirecting *deflection, int subscription_option)
++{
++ const struct q931_party_id *caller_id;
++ struct q931_party_id local_caller;
++ struct q931_party_redirecting reroute;
++
++ if (!ctrl || !call || !deflection) {
++ return -1;
++ }
++
++ if (caller) {
++ /* Convert the caller update information. */
++ pri_copy_party_id_to_q931(&local_caller, caller);
++ q931_party_id_fixup(ctrl, &local_caller);
++ caller_id = &local_caller;
++ } else {
++ caller_id = NULL;
++ }
++
++ /* Convert the deflection information. */
++ q931_party_redirecting_init(&reroute);
++ pri_copy_party_id_to_q931(&reroute.from, &deflection->from);
++ q931_party_id_fixup(ctrl, &reroute.from);
++ pri_copy_party_id_to_q931(&reroute.to, &deflection->to);
++ q931_party_id_fixup(ctrl, &reroute.to);
++ pri_copy_party_id_to_q931(&reroute.orig_called, &deflection->orig_called);
++ q931_party_id_fixup(ctrl, &reroute.orig_called);
++ reroute.reason = deflection->reason;
++ reroute.orig_reason = deflection->orig_reason;
++ if (deflection->count <= 0) {
++ /*
++ * We are deflecting with an unknown count
++ * so assume the count is one.
++ */
++ reroute.count = 1;
++ } else if (deflection->count < PRI_MAX_REDIRECTS) {
++ reroute.count = deflection->count;
++ } else {
++ reroute.count = PRI_MAX_REDIRECTS;
++ }
++
++ return send_reroute_request(ctrl, call, caller_id, &reroute, subscription_option);
++}
+Index: Makefile
+===================================================================
+--- a/Makefile (.../tags/1.4.10.2) (revision 1357)
++++ b/Makefile (.../branches/1.4) (revision 1357)
+@@ -41,15 +41,55 @@
+
+ STATIC_LIBRARY=libpri.a
+ DYNAMIC_LIBRARY:=libpri.so.$(SONAME)
+-STATIC_OBJS=copy_string.o pri.o q921.o prisched.o q931.o pri_facility.o version.o
+-DYNAMIC_OBJS=copy_string.lo pri.lo q921.lo prisched.lo q931.lo pri_facility.lo version.lo
+-CFLAGS=-Wall -Werror -Wstrict-prototypes -Wmissing-prototypes -g -fPIC $(ALERTING) $(LIBPRI_COUNTERS)
++STATIC_OBJS= \
++ copy_string.o \
++ pri.o \
++ q921.o \
++ prisched.o \
++ q931.o \
++ pri_facility.o \
++ asn1_primitive.o \
++ rose.o \
++ rose_address.o \
++ rose_etsi_aoc.o \
++ rose_etsi_diversion.o \
++ rose_etsi_ect.o \
++ rose_other.o \
++ rose_q931.o \
++ rose_qsig_aoc.o \
++ rose_qsig_ct.o \
++ rose_qsig_diversion.o \
++ rose_qsig_mwi.o \
++ rose_qsig_name.o \
++ version.o
++DYNAMIC_OBJS= \
++ copy_string.lo \
++ pri.lo \
++ q921.lo \
++ prisched.lo \
++ q931.lo \
++ pri_facility.lo \
++ asn1_primitive.lo \
++ rose.lo \
++ rose_address.lo \
++ rose_etsi_aoc.lo \
++ rose_etsi_diversion.lo \
++ rose_etsi_ect.lo \
++ rose_other.lo \
++ rose_q931.lo \
++ rose_qsig_aoc.lo \
++ rose_qsig_ct.lo \
++ rose_qsig_diversion.lo \
++ rose_qsig_mwi.lo \
++ rose_qsig_name.lo \
++ version.lo
++CFLAGS+=-Wall -Werror -Wstrict-prototypes -Wmissing-prototypes -g -fPIC $(ALERTING) $(LIBPRI_COUNTERS) $(LIBPRI_OPT)
+ INSTALL_PREFIX=$(DESTDIR)
+ INSTALL_BASE=/usr
+ libdir?=$(INSTALL_BASE)/lib
+ SOFLAGS:=-Wl,-h$(DYNAMIC_LIBRARY)
+ LDCONFIG = /sbin/ldconfig
+-ifneq (,$(findstring X$(OSARCH)X, XLinuxX XGNU/kFreeBSDX))
++ifneq (,$(findstring X$(OSARCH)X, XLinuxX XGNU/kFreeBSDX XGNUX))
+ LDCONFIG_FLAGS=-n
+ else
+ ifeq (${OSARCH},FreeBSD)
+@@ -74,7 +114,9 @@
+ #A ultrasparc cpu is really v9 but the stock debian stable 3.0 gcc doesnt support it.
+ ifeq ($(PROC),sparc64)
+ PROC=ultrasparc
+-CFLAGS += -mtune=$(PROC) -O3 -pipe -fomit-frame-pointer -mcpu=v8
++LIBPRI_OPT = -mtune=$(PROC) -O3 -pipe -fomit-frame-pointer -mcpu=v8
++else
++LIBPRI_OPT = -O2
+ endif
+
+ all: $(STATIC_LIBRARY) $(DYNAMIC_LIBRARY)
+@@ -132,6 +174,9 @@
+ pridump: pridump.o
+ $(CC) -o pridump pridump.o -L. -lpri $(CFLAGS)
+
++rosetest: rosetest.o
++ $(CC) -o rosetest rosetest.o -L. -lpri $(CFLAGS)
++
+ MAKE_DEPS= -MD -MT $@ -MF .$(subst /,_,$@).d -MP
+
+ %.o: %.c
+Index: q931.c
+===================================================================
+--- a/q931.c (.../tags/1.4.10.2) (revision 1357)
++++ b/q931.c (.../branches/1.4) (revision 1357)
+@@ -33,6 +33,7 @@
+ #include "pri_q921.h"
+ #include "pri_q931.h"
+ #include "pri_facility.h"
++#include "rose.h"
+
+ #include <unistd.h>
+ #include <stdlib.h>
+@@ -67,7 +68,7 @@
+ { Q931_RESTART_ACKNOWLEDGE, "RESTART ACKNOWLEDGE", { Q931_RESTART_INDICATOR } },
+
+ /* Miscellaneous */
+- { Q931_STATUS, "STATUS", { Q931_CAUSE, Q931_CALL_STATE } },
++ { Q931_STATUS, "STATUS", { Q931_CAUSE, Q931_IE_CALL_STATE } },
+ { Q931_STATUS_ENQUIRY, "STATUS ENQUIRY" },
+ { Q931_USER_INFORMATION, "USER_INFORMATION" },
+ { Q931_SEGMENT, "SEGMENT" },
+@@ -79,22 +80,32 @@
+ /* Call Management */
+ { Q931_HOLD, "HOLD" },
+ { Q931_HOLD_ACKNOWLEDGE, "HOLD ACKNOWLEDGE" },
+- { Q931_HOLD_REJECT, "HOLD REJECT" },
++ { Q931_HOLD_REJECT, "HOLD REJECT", { Q931_CAUSE } },
+ { Q931_RETRIEVE, "RETRIEVE" },
+ { Q931_RETRIEVE_ACKNOWLEDGE, "RETRIEVE ACKNOWLEDGE" },
+- { Q931_RETRIEVE_REJECT, "RETRIEVE REJECT" },
++ { Q931_RETRIEVE_REJECT, "RETRIEVE REJECT", { Q931_CAUSE } },
+ { Q931_RESUME, "RESUME" },
+ { Q931_RESUME_ACKNOWLEDGE, "RESUME ACKNOWLEDGE", { Q931_CHANNEL_IDENT } },
+ { Q931_RESUME_REJECT, "RESUME REJECT", { Q931_CAUSE } },
+ { Q931_SUSPEND, "SUSPEND" },
+ { Q931_SUSPEND_ACKNOWLEDGE, "SUSPEND ACKNOWLEDGE" },
+ { Q931_SUSPEND_REJECT, "SUSPEND REJECT" },
++};
+
+- /* Maintenance */
+- { NATIONAL_SERVICE, "SERVICE" },
+- { NATIONAL_SERVICE_ACKNOWLEDGE, "SERVICE ACKNOWLEDGE" },
++static int post_handle_q931_message(struct pri *ctrl, struct q931_mh *mh, struct q931_call *c, int missingmand);
++static void nt_ptmp_handle_q931_message(struct pri *ctrl, struct q931_mh *mh, struct q931_call *c, int *allow_event, int *allow_posthandle);
++
++struct msgtype att_maintenance_msgs[] = {
++ { ATT_SERVICE, "SERVICE", { Q931_CHANNEL_IDENT } },
++ { ATT_SERVICE_ACKNOWLEDGE, "SERVICE ACKNOWLEDGE", { Q931_CHANNEL_IDENT } },
+ };
+
++struct msgtype national_maintenance_msgs[] = {
++ { NATIONAL_SERVICE, "SERVICE", { Q931_CHANNEL_IDENT } },
++ { NATIONAL_SERVICE_ACKNOWLEDGE, "SERVICE ACKNOWLEDGE", { Q931_CHANNEL_IDENT } },
++};
++static int post_handle_maintenance_message(struct pri *ctrl, int protodisc, struct q931_mh *mh, struct q931_call *c);
++
+ static struct msgtype causes[] = {
+ { PRI_CAUSE_UNALLOCATED, "Unallocated (unassigned) number" },
+ { PRI_CAUSE_NO_ROUTE_TRANSIT_NET, "No route to specified transmit network" },
+@@ -107,6 +118,7 @@
+ { PRI_CAUSE_NO_ANSWER, "User alerting, no answer" },
+ { PRI_CAUSE_CALL_REJECTED, "Call Rejected" },
+ { PRI_CAUSE_NUMBER_CHANGED, "Number changed" },
++ { PRI_CAUSE_NONSELECTED_USER_CLEARING, "Non-selected user clearing" },
+ { PRI_CAUSE_DESTINATION_OUT_OF_ORDER, "Destination out of order" },
+ { PRI_CAUSE_INVALID_NUMBER_FORMAT, "Invalid number format" },
+ { PRI_CAUSE_FACILITY_REJECTED, "Facility rejected" },
+@@ -119,13 +131,14 @@
+ { PRI_CAUSE_ACCESS_INFO_DISCARDED, "Access information discarded" },
+ { PRI_CAUSE_REQUESTED_CHAN_UNAVAIL, "Requested channel not available" },
+ { PRI_CAUSE_PRE_EMPTED, "Pre-empted" },
++ { PRI_CAUSE_RESOURCE_UNAVAIL_UNSPECIFIED, "Resource unavailable, unspecified" },
+ { PRI_CAUSE_FACILITY_NOT_SUBSCRIBED, "Facility not subscribed" },
+ { PRI_CAUSE_OUTGOING_CALL_BARRED, "Outgoing call barred" },
+ { PRI_CAUSE_INCOMING_CALL_BARRED, "Incoming call barred" },
+ { PRI_CAUSE_BEARERCAPABILITY_NOTAUTH, "Bearer capability not authorized" },
+ { PRI_CAUSE_BEARERCAPABILITY_NOTAVAIL, "Bearer capability not available" },
++ { PRI_CAUSE_SERVICEOROPTION_NOTAVAIL, "Service or option not available, unspecified" },
+ { PRI_CAUSE_BEARERCAPABILITY_NOTIMPL, "Bearer capability not implemented" },
+- { PRI_CAUSE_SERVICEOROPTION_NOTAVAIL, "Service or option not available, unspecified" },
+ { PRI_CAUSE_CHAN_NOT_IMPLEMENTED, "Channel not implemented" },
+ { PRI_CAUSE_FACILITY_NOT_IMPLEMENTED, "Facility not implemented" },
+ { PRI_CAUSE_INVALID_CALL_REFERENCE, "Invalid call reference value" },
+@@ -163,8 +176,9 @@
+ { PRI_NSF_CALL_REDIRECTION_SERVICE, "Call Redirection Service" }
+ };
+
+-#define FLAG_PREFERRED 2
+-#define FLAG_EXCLUSIVE 4
++#define FLAG_WHOLE_INTERFACE 0x01
++#define FLAG_PREFERRED 0x02
++#define FLAG_EXCLUSIVE 0x04
+
+ #define RESET_INDICATOR_CHANNEL 0
+ #define RESET_INDICATOR_DS1 6
+@@ -214,26 +228,49 @@
+ #define LOC_NETWORK_BEYOND_INTERWORKING 0xa
+
+ static char *ie2str(int ie);
+-static char *msg2str(int msg);
+
+
+-#define FUNC_DUMP(name) void ((name))(int full_ie, struct pri *pri, q931_ie *ie, int len, char prefix)
+-#define FUNC_RECV(name) int ((name))(int full_ie, struct pri *pri, q931_call *call, int msgtype, q931_ie *ie, int len)
+-#define FUNC_SEND(name) int ((name))(int full_ie, struct pri *pri, q931_call *call, int msgtype, q931_ie *ie, int len, int order)
++#define FUNC_DUMP(name) void (name)(int full_ie, struct pri *pri, q931_ie *ie, int len, char prefix)
++#define FUNC_RECV(name) int (name)(int full_ie, struct pri *pri, q931_call *call, int msgtype, q931_ie *ie, int len)
++#define FUNC_SEND(name) int (name)(int full_ie, struct pri *pri, q931_call *call, int msgtype, q931_ie *ie, int len, int order)
+
+ #if 1
+ /* Update call state with transition trace. */
+-#define UPDATE_OURCALLSTATE(pri,c,newstate) do {\
+- if (pri->debug & (PRI_DEBUG_Q931_STATE) && c->ourcallstate != newstate) \
+- pri_message(pri, DBGHEAD "call %d on channel %d enters state %d (%s)\n", DBGINFO, \
+- c->cr, c->channelno, newstate, callstate2str(newstate)); \
+- c->ourcallstate = newstate; \
++#define UPDATE_OURCALLSTATE(ctrl, call, newstate) \
++ do { \
++ if (((ctrl)->debug & PRI_DEBUG_Q931_STATE) && (call)->ourcallstate != (newstate)) { \
++ pri_message((ctrl), \
++ DBGHEAD "%s %d enters state %d (%s). Hold state: %s\n", \
++ DBGINFO, ((call) == (call)->master_call) ? "Call" : "Subcall", \
++ (call)->cr, (newstate), q931_call_state_str(newstate), \
++ q931_hold_state_str((call)->master_call->hold_state)); \
++ } \
++ (call)->ourcallstate = (newstate); \
+ } while (0)
+ #else
+ /* Update call state with no trace. */
+-#define UPDATE_OURCALLSTATE(pri,c,newstate) c->ourcallstate = newstate
++#define UPDATE_OURCALLSTATE(ctrl, call, newstate) (call)->ourcallstate = (newstate)
+ #endif
+
++#if 1
++/* Update hold state with transition trace. */
++#define UPDATE_HOLD_STATE(ctrl, master_call, newstate) \
++ do { \
++ if (((ctrl)->debug & PRI_DEBUG_Q931_STATE) \
++ && (master_call)->hold_state != (newstate)) { \
++ pri_message((ctrl), \
++ DBGHEAD "Call %d in state %d (%s) enters Hold state: %s\n", \
++ DBGINFO, (master_call)->cr, (master_call)->ourcallstate, \
++ q931_call_state_str((master_call)->ourcallstate), \
++ q931_hold_state_str(newstate)); \
++ } \
++ (master_call)->hold_state = (newstate); \
++ } while (0)
++#else
++/* Update hold state with no trace. */
++#define UPDATE_HOLD_STATE(ctrl, master_call, newstate) (master_call)->hold_state = (newstate)
++#endif
++
+ struct ie {
+ /* Maximal count of same IEs at the message (0 - any, 1..n - limited) */
+ int max_count;
+@@ -249,6 +286,506 @@
+ FUNC_SEND(*transmit);
+ };
+
++/*!
++ * \internal
++ * \brief Encode the channel id information to pass to upper level.
++ *
++ * \param call Q.931 call leg
++ *
++ * \return Encoded channel value.
++ */
++static int q931_encode_channel(const q931_call *call)
++{
++ int held_call;
++ int channelno;
++ int ds1no;
++
++ switch (call->master_call->hold_state) {
++ case Q931_HOLD_STATE_CALL_HELD:
++ case Q931_HOLD_STATE_RETRIEVE_REQ:
++ case Q931_HOLD_STATE_RETRIEVE_IND:
++ held_call = 1 << 18;
++
++ /* So a -1 does not wipe out the held_call flag. */
++ channelno = call->channelno & 0xFF;
++ ds1no = call->ds1no & 0xFF;
++ break;
++ default:
++ held_call = 0;
++ channelno = call->channelno;
++ ds1no = call->ds1no;
++ break;
++ }
++ return channelno | (ds1no << 8) | (call->ds1explicit << 16) | (call->cis_call << 17)
++ | held_call;
++}
++
++/*!
++ * \brief Determine if layer 2 is in PTMP mode.
++ *
++ * \param ctrl D channel controller.
++ *
++ * \retval TRUE if in PTMP mode.
++ * \retval FALSE otherwise.
++ */
++int q931_is_ptmp(const struct pri *ctrl)
++{
++ /* Check master control structure */
++ for (; ctrl->master; ctrl = ctrl->master) {
++ }
++ return ctrl->tei == Q921_TEI_GROUP;
++}
++
++/*!
++ * \brief Initialize the given struct q931_party_name
++ *
++ * \param name Structure to initialize
++ *
++ * \return Nothing
++ */
++void q931_party_name_init(struct q931_party_name *name)
++{
++ name->valid = 0;
++ name->presentation = PRI_PRES_UNAVAILABLE;
++ name->char_set = PRI_CHAR_SET_ISO8859_1;
++ name->str[0] = '\0';
++}
++
++/*!
++ * \brief Initialize the given struct q931_party_number
++ *
++ * \param number Structure to initialize
++ *
++ * \return Nothing
++ */
++void q931_party_number_init(struct q931_party_number *number)
++{
++ number->valid = 0;
++ number->presentation = PRI_PRES_UNAVAILABLE | PRI_PRES_USER_NUMBER_UNSCREENED;
++ number->plan = (PRI_TON_UNKNOWN << 4) | PRI_NPI_E163_E164;
++ number->str[0] = '\0';
++}
++
++/*!
++ * \brief Initialize the given struct q931_party_subaddress
++ *
++ * \param subaddress Structure to initialize
++ *
++ * \return Nothing
++ */
++void q931_party_subaddress_init(struct q931_party_subaddress *subaddress)
++{
++ subaddress->valid = 0;
++ subaddress->type = 0;
++ subaddress->odd_even_indicator = 0;
++ subaddress->length = 0;
++ subaddress->data[0] = '\0';
++}
++
++/*!
++ * \brief Initialize the given struct q931_party_address
++ *
++ * \param address Structure to initialize
++ *
++ * \return Nothing
++ */
++void q931_party_address_init(struct q931_party_address *address)
++{
++ q931_party_number_init(&address->number);
++ q931_party_subaddress_init(&address->subaddress);
++}
++
++/*!
++ * \brief Initialize the given struct q931_party_id
++ *
++ * \param id Structure to initialize
++ *
++ * \return Nothing
++ */
++void q931_party_id_init(struct q931_party_id *id)
++{
++ q931_party_name_init(&id->name);
++ q931_party_number_init(&id->number);
++ q931_party_subaddress_init(&id->subaddress);
++}
++
++/*!
++ * \brief Initialize the given struct q931_party_redirecting
++ *
++ * \param redirecting Structure to initialize
++ *
++ * \return Nothing
++ */
++void q931_party_redirecting_init(struct q931_party_redirecting *redirecting)
++{
++ q931_party_id_init(&redirecting->from);
++ q931_party_id_init(&redirecting->to);
++ q931_party_id_init(&redirecting->orig_called);
++ redirecting->state = Q931_REDIRECTING_STATE_IDLE;
++ redirecting->count = 0;
++ redirecting->orig_reason = PRI_REDIR_UNKNOWN;
++ redirecting->reason = PRI_REDIR_UNKNOWN;
++}
++
++/*!
++ * \brief Compare the left and right party name.
++ *
++ * \param left Left parameter party name.
++ * \param right Right parameter party name.
++ *
++ * \retval < 0 when left < right.
++ * \retval == 0 when left == right.
++ * \retval > 0 when left > right.
++ */
++int q931_party_name_cmp(const struct q931_party_name *left, const struct q931_party_name *right)
++{
++ int cmp;
++
++ if (!left->valid) {
++ if (!right->valid) {
++ return 0;
++ }
++ return -1;
++ } else if (!right->valid) {
++ return 1;
++ }
++ cmp = left->char_set - right->char_set;
++ if (cmp) {
++ return cmp;
++ }
++ cmp = strcmp(left->str, right->str);
++ if (cmp) {
++ return cmp;
++ }
++ cmp = left->presentation - right->presentation;
++ return cmp;
++}
++
++/*!
++ * \brief Compare the left and right party number.
++ *
++ * \param left Left parameter party number.
++ * \param right Right parameter party number.
++ *
++ * \retval < 0 when left < right.
++ * \retval == 0 when left == right.
++ * \retval > 0 when left > right.
++ */
++int q931_party_number_cmp(const struct q931_party_number *left, const struct q931_party_number *right)
++{
++ int cmp;
++
++ if (!left->valid) {
++ if (!right->valid) {
++ return 0;
++ }
++ return -1;
++ } else if (!right->valid) {
++ return 1;
++ }
++ cmp = left->plan - right->plan;
++ if (cmp) {
++ return cmp;
++ }
++ cmp = strcmp(left->str, right->str);
++ if (cmp) {
++ return cmp;
++ }
++ cmp = left->presentation - right->presentation;
++ return cmp;
++}
++
++/*!
++ * \brief Compare the left and right party subaddress.
++ *
++ * \param left Left parameter party subaddress.
++ * \param right Right parameter party subaddress.
++ *
++ * \retval < 0 when left < right.
++ * \retval == 0 when left == right.
++ * \retval > 0 when left > right.
++ */
++int q931_party_subaddress_cmp(const struct q931_party_subaddress *left, const struct q931_party_subaddress *right)
++{
++ int cmp;
++
++ if (!left->valid) {
++ if (!right->valid) {
++ return 0;
++ }
++ return -1;
++ } else if (!right->valid) {
++ return 1;
++ }
++ cmp = left->type - right->type;
++ if (cmp) {
++ return cmp;
++ }
++ cmp = memcmp(left->data, right->data,
++ (left->length < right->length) ? left->length : right->length);
++ if (cmp) {
++ return cmp;
++ }
++ cmp = left->length - right->length;
++ if (cmp) {
++ return cmp;
++ }
++ cmp = left->odd_even_indicator - right->odd_even_indicator;
++ return cmp;
++}
++
++/*!
++ * \brief Compare the left and right party id.
++ *
++ * \param left Left parameter party id.
++ * \param right Right parameter party id.
++ *
++ * \retval < 0 when left < right.
++ * \retval == 0 when left == right.
++ * \retval > 0 when left > right.
++ */
++int q931_party_id_cmp(const struct q931_party_id *left, const struct q931_party_id *right)
++{
++ int cmp;
++
++ cmp = q931_party_number_cmp(&left->number, &right->number);
++ if (cmp) {
++ return cmp;
++ }
++ cmp = q931_party_subaddress_cmp(&left->subaddress, &right->subaddress);
++ if (cmp) {
++ return cmp;
++ }
++ cmp = q931_party_name_cmp(&left->name, &right->name);
++ return cmp;
++}
++
++/*!
++ * \brief Copy the Q.931 party name to the PRI party name structure.
++ *
++ * \param pri_name PRI party name structure
++ * \param q931_name Q.931 party name structure
++ *
++ * \return Nothing
++ */
++void q931_party_name_copy_to_pri(struct pri_party_name *pri_name, const struct q931_party_name *q931_name)
++{
++ if (q931_name->valid) {
++ pri_name->valid = 1;
++ pri_name->presentation = q931_name->presentation;
++ pri_name->char_set = q931_name->char_set;
++ libpri_copy_string(pri_name->str, q931_name->str, sizeof(pri_name->str));
++ } else {
++ pri_name->valid = 0;
++ pri_name->presentation = PRI_PRES_UNAVAILABLE;
++ pri_name->char_set = PRI_CHAR_SET_ISO8859_1;
++ pri_name->str[0] = 0;
++ }
++}
++
++/*!
++ * \brief Copy the Q.931 party number to the PRI party number structure.
++ *
++ * \param pri_number PRI party number structure
++ * \param q931_number Q.931 party number structure
++ *
++ * \return Nothing
++ */
++void q931_party_number_copy_to_pri(struct pri_party_number *pri_number, const struct q931_party_number *q931_number)
++{
++ if (q931_number->valid) {
++ pri_number->valid = 1;
++ pri_number->presentation = q931_number->presentation;
++ pri_number->plan = q931_number->plan;
++ libpri_copy_string(pri_number->str, q931_number->str, sizeof(pri_number->str));
++ } else {
++ pri_number->valid = 0;
++ pri_number->presentation = PRI_PRES_UNAVAILABLE | PRI_PRES_USER_NUMBER_UNSCREENED;
++ pri_number->plan = (PRI_TON_UNKNOWN << 4) | PRI_NPI_E163_E164;
++ pri_number->str[0] = 0;
++ }
++}
++
++/*!
++ * \brief Copy the Q.931 party subaddress to the PRI party subaddress structure.
++ *
++ * \param pri_subaddress PRI party subaddress structure
++ * \param q931_subaddress Q.931 party subaddress structure
++ *
++ * \return Nothing
++ */
++void q931_party_subaddress_copy_to_pri(struct pri_party_subaddress *pri_subaddress, const struct q931_party_subaddress *q931_subaddress)
++{
++ int length;
++
++ /*
++ * The size of pri_subaddress->data[] is not the same as the size of
++ * q931_subaddress->data[].
++ */
++
++ if (!q931_subaddress->valid) {
++ pri_subaddress->valid = 0;
++ pri_subaddress->type = 0;
++ pri_subaddress->odd_even_indicator = 0;
++ pri_subaddress->length = 0;
++ pri_subaddress->data[0] = '\0';
++ return;
++ }
++
++ pri_subaddress->valid = 1;
++ pri_subaddress->type = q931_subaddress->type;
++ pri_subaddress->odd_even_indicator = q931_subaddress->odd_even_indicator;
++
++ length = q931_subaddress->length;
++ pri_subaddress->length = length;
++ memcpy(pri_subaddress->data, q931_subaddress->data, length);
++ pri_subaddress->data[length] = '\0';
++}
++
++/*!
++ * \brief Copy the Q.931 party id to the PRI party id structure.
++ *
++ * \param pri_id PRI party id structure
++ * \param q931_id Q.931 party id structure
++ *
++ * \return Nothing
++ */
++void q931_party_id_copy_to_pri(struct pri_party_id *pri_id, const struct q931_party_id *q931_id)
++{
++ q931_party_name_copy_to_pri(&pri_id->name, &q931_id->name);
++ q931_party_number_copy_to_pri(&pri_id->number, &q931_id->number);
++ q931_party_subaddress_copy_to_pri(&pri_id->subaddress, &q931_id->subaddress);
++}
++
++/*!
++ * \brief Copy the Q.931 redirecting data to the PRI redirecting structure.
++ *
++ * \param pri_redirecting PRI redirecting structure
++ * \param q931_redirecting Q.931 redirecting structure
++ *
++ * \return Nothing
++ */
++void q931_party_redirecting_copy_to_pri(struct pri_party_redirecting *pri_redirecting, const struct q931_party_redirecting *q931_redirecting)
++{
++ q931_party_id_copy_to_pri(&pri_redirecting->from, &q931_redirecting->from);
++ q931_party_id_copy_to_pri(&pri_redirecting->to, &q931_redirecting->to);
++ q931_party_id_copy_to_pri(&pri_redirecting->orig_called,
++ &q931_redirecting->orig_called);
++ pri_redirecting->count = q931_redirecting->count;
++ pri_redirecting->orig_reason = q931_redirecting->orig_reason;
++ pri_redirecting->reason = q931_redirecting->reason;
++}
++
++/*!
++ * \brief Fixup some values in the q931_party_id that may be objectionable by switches.
++ *
++ * \param ctrl D channel controller.
++ * \param id Party ID to tweak.
++ *
++ * \return Nothing
++ */
++void q931_party_id_fixup(const struct pri *ctrl, struct q931_party_id *id)
++{
++ switch (ctrl->switchtype) {
++ case PRI_SWITCH_DMS100:
++ case PRI_SWITCH_ATT4ESS:
++ /* Doesn't like certain presentation types */
++ if (id->number.valid && !(id->number.presentation & 0x7c)) {
++ /* i.e., If presentation is allowed it must be a network number */
++ id->number.presentation = PRES_ALLOWED_NETWORK_NUMBER;
++ }
++ break;
++ default:
++ break;
++ }
++}
++
++/*!
++ * \brief Determine the overall presentation value for the given party.
++ *
++ * \param id Party to determine the overall presentation value.
++ *
++ * \return Overall presentation value for the given party.
++ */
++int q931_party_id_presentation(const struct q931_party_id *id)
++{
++ int number_priority;
++ int number_value;
++ int number_screening;
++ int name_priority;
++ int name_value;
++
++ /* Determine name presentation priority. */
++ if (!id->name.valid) {
++ name_value = PRI_PRES_UNAVAILABLE;
++ name_priority = 3;
++ } else {
++ name_value = id->name.presentation & PRI_PRES_RESTRICTION;
++ switch (name_value) {
++ case PRI_PRES_RESTRICTED:
++ name_priority = 0;
++ break;
++ case PRI_PRES_ALLOWED:
++ name_priority = 1;
++ break;
++ case PRI_PRES_UNAVAILABLE:
++ name_priority = 2;
++ break;
++ default:
++ name_value = PRI_PRES_UNAVAILABLE;
++ name_priority = 3;
++ break;
++ }
++ }
++
++ /* Determine number presentation priority. */
++ if (!id->number.valid) {
++ number_screening = PRI_PRES_USER_NUMBER_UNSCREENED;
++ number_value = PRI_PRES_UNAVAILABLE;
++ number_priority = 3;
++ } else {
++ number_screening = id->number.presentation & PRI_PRES_NUMBER_TYPE;
++ number_value = id->number.presentation & PRI_PRES_RESTRICTION;
++ switch (number_value) {
++ case PRI_PRES_RESTRICTED:
++ number_priority = 0;
++ break;
++ case PRI_PRES_ALLOWED:
++ number_priority = 1;
++ break;
++ case PRI_PRES_UNAVAILABLE:
++ number_priority = 2;
++ break;
++ default:
++ number_screening = PRI_PRES_USER_NUMBER_UNSCREENED;
++ number_value = PRI_PRES_UNAVAILABLE;
++ number_priority = 3;
++ break;
++ }
++ }
++
++ /* Select the wining presentation value. */
++ if (name_priority < number_priority) {
++ number_value = name_value;
++ }
++
++ return number_value | number_screening;
++}
++
++static void q931_clr_subcommands(struct pri *ctrl)
++{
++ ctrl->subcmds.counter_subcmd = 0;
++}
++
++struct pri_subcommand *q931_alloc_subcommand(struct pri *ctrl)
++{
++ if (ctrl->subcmds.counter_subcmd < PRI_MAX_SUBCOMMANDS) {
++ return &ctrl->subcmds.subcmd[ctrl->subcmds.counter_subcmd++];
++ }
++
++ return NULL;
++}
++
+ static char *code2str(int code, struct msgtype *codes, int max)
+ {
+ int x;
+@@ -258,15 +795,18 @@
+ return "Unknown";
+ }
+
+-static void call_init(struct q931_call *c)
++static char *pritype(int type)
+ {
+- c->forceinvert = -1;
+- c->cr = -1;
+- c->slotmap = -1;
+- c->channelno = -1;
+- c->newcall = 1;
+- c->ourcallstate = Q931_CALL_STATE_NULL;
+- c->peercallstate = Q931_CALL_STATE_NULL;
++ switch (type) {
++ case PRI_CPE:
++ return "CPE";
++ break;
++ case PRI_NETWORK:
++ return "NET";
++ break;
++ default:
++ return "UNKNOWN";
++ }
+ }
+
+ static char *binary(int b, int len) {
+@@ -280,56 +820,85 @@
+ return res;
+ }
+
+-static FUNC_RECV(receive_channel_id)
++static int receive_channel_id(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len)
+ {
+ int x;
+- int pos=0;
+-#ifdef NO_BRI_SUPPORT
+- if (!ie->data[0] & 0x20) {
+- pri_error(pri, "!! Not PRI type!?\n");
+- return -1;
+- }
+-#endif
+-#ifndef NOAUTO_CHANNEL_SELECTION_SUPPORT
+- if (pri->bri) {
+- if (!(ie->data[0] & 3))
+- call->justsignalling = 1;
+- else
+- call->channelno = ie->data[0] & 3;
++ int pos = 0;
++ int need_extended_channel_octets;/*!< TRUE if octets 3.2 and 3.3 need to be present. */
++
++ if (ie->data[0] & 0x08) {
++ call->chanflags = FLAG_EXCLUSIVE;
+ } else {
+- switch (ie->data[0] & 3) {
+- case 0:
+- call->justsignalling = 1;
+- break;
+- case 1:
+- break;
+- default:
+- pri_error(pri, "!! Unexpected Channel selection %d\n", ie->data[0] & 3);
+- return -1;
++ call->chanflags = FLAG_PREFERRED;
++ }
++
++ need_extended_channel_octets = 0;
++ if (ie->data[0] & 0x20) {
++ /* PRI encoded interface type */
++ switch (ie->data[0] & 0x03) {
++ case 0x00:
++ /* No channel */
++ call->channelno = 0;
++ call->chanflags = FLAG_PREFERRED;
++ break;
++ case 0x01:
++ /* As indicated in following octets */
++ need_extended_channel_octets = 1;
++ break;
++ case 0x03:
++ /* Any channel */
++ call->chanflags = FLAG_PREFERRED;
++ break;
++ default:
++ pri_error(ctrl, "!! Unexpected Channel selection %d\n", ie->data[0] & 0x03);
++ return -1;
+ }
++ } else {
++ /* BRI encoded interface type */
++ switch (ie->data[0] & 0x03) {
++ case 0x00:
++ /* No channel */
++ call->channelno = 0;
++ call->chanflags = FLAG_PREFERRED;
++ break;
++ case 0x03:
++ /* Any channel */
++ call->chanflags = FLAG_PREFERRED;
++ break;
++ default:
++ /* Specified B channel (B1 or B2) */
++ call->channelno = ie->data[0] & 0x03;
++ break;
++ }
+ }
+-#endif
+- if (ie->data[0] & 0x08)
+- call->chanflags = FLAG_EXCLUSIVE;
+- else
+- call->chanflags = FLAG_PREFERRED;
++
+ pos++;
+ if (ie->data[0] & 0x40) {
+ /* DS1 specified -- stop here */
+ call->ds1no = ie->data[1] & 0x7f;
+ call->ds1explicit = 1;
+ pos++;
+- } else
++ } else {
+ call->ds1explicit = 0;
++ }
+
+- if (pos+2 < len) {
++ if (ie->data[0] & 0x04) {
++ /* D channel call. Signaling only. */
++ call->cis_call = 1;
++ call->chanflags = FLAG_EXCLUSIVE;/* For safety mark this channel as exclusive. */
++ call->channelno = 0;
++ return 0;
++ }
++
++ if (need_extended_channel_octets && pos + 2 < len) {
+ /* More coming */
+ if ((ie->data[pos] & 0x0f) != 3) {
+- pri_error(pri, "!! Unexpected Channel Type %d\n", ie->data[1] & 0x0f);
++ /* Channel type/mapping is not for B channel units. */
++ pri_error(ctrl, "!! Unexpected Channel Type %d\n", ie->data[1] & 0x0f);
+ return -1;
+ }
+ if ((ie->data[pos] & 0x60) != 0) {
+- pri_error(pri, "!! Invalid CCITT coding %d\n", (ie->data[1] & 0x60) >> 5);
++ pri_error(ctrl, "!! Invalid CCITT coding %d\n", (ie->data[1] & 0x60) >> 5);
+ return -1;
+ }
+ if (ie->data[pos] & 0x10) {
+@@ -340,136 +909,167 @@
+ call->slotmap <<= 8;
+ call->slotmap |= ie->data[x + pos];
+ }
+- return 0;
+ } else {
+ pos++;
+ /* Only expect a particular channel */
+ call->channelno = ie->data[pos] & 0x7f;
+- if (pri->chan_mapping_logical && call->channelno > 15)
++ if (ctrl->chan_mapping_logical && call->channelno > 15)
+ call->channelno++;
+- return 0;
+ }
+- } else
+- return 0;
+- return -1;
++ }
++ return 0;
+ }
+
+-static FUNC_SEND(transmit_channel_id)
++static int transmit_channel_id(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order)
+ {
+- int pos=0;
++ int pos = 0;
+
+-
+ /* We are ready to transmit single IE only */
+ if (order > 1)
+ return 0;
+-
+- if (call->justsignalling) {
+- ie->data[pos++] = 0xac; /* Read the standards docs to figure this out
+- ECMA-165 section 7.3 */
++
++ if (call->cis_call) {
++ /*
++ * Read the standards docs to figure this out.
++ * Q.SIG ECMA-165 section 7.3
++ * ITU Q.931 section 4.5.13
++ */
++ ie->data[pos++] = ctrl->bri ? 0x8c : 0xac;
+ return pos + 2;
+ }
+-
++
+ /* Start with standard stuff */
+- if (pri->switchtype == PRI_SWITCH_GR303_TMC)
++ if (ctrl->switchtype == PRI_SWITCH_GR303_TMC)
+ ie->data[pos] = 0x69;
+- else if (pri->bri) {
++ else if (ctrl->bri) {
+ ie->data[pos] = 0x80;
+- if (call->channelno > -1)
+- ie->data[pos] |= (call->channelno & 0x3);
+- } else
+- ie->data[pos] = 0xa1;
+- /* Add exclusive flag if necessary */
+- if (call->chanflags & FLAG_EXCLUSIVE)
++ ie->data[pos] |= (call->channelno & 0x3);
++ } else {
++ /* PRI */
++ if (call->slotmap != -1 || (call->chanflags & FLAG_WHOLE_INTERFACE)) {
++ /* Specified channel */
++ ie->data[pos] = 0xa1;
++ } else if (call->channelno < 0 || call->channelno == 0xff) {
++ /* Any channel */
++ ie->data[pos] = 0xa3;
++ } else if (!call->channelno) {
++ /* No channel */
++ ie->data[pos] = 0xa0;
++ } else {
++ /* Specified channel */
++ ie->data[pos] = 0xa1;
++ }
++ }
++ if (call->chanflags & FLAG_EXCLUSIVE) {
++ /* Channel is exclusive */
+ ie->data[pos] |= 0x08;
+- else if (!(call->chanflags & FLAG_PREFERRED)) {
++ } else if (!call->chanflags) {
+ /* Don't need this IE */
+ return 0;
+ }
+
+- if (((pri->switchtype != PRI_SWITCH_QSIG) && (call->ds1no > 0)) || call->ds1explicit) {
+- /* Note that we are specifying the identifier */
++ if (!ctrl->bri && (((ctrl->switchtype != PRI_SWITCH_QSIG) && (call->ds1no > 0)) || call->ds1explicit)) {
++ /* We are specifying the interface. Octet 3.1 */
+ ie->data[pos++] |= 0x40;
+- /* We need to use the Channel Identifier Present thingy. Just specify it and we're done */
+ ie->data[pos++] = 0x80 | call->ds1no;
+- } else
+- pos++;
++ } else {
++ ++pos;
++ }
+
+- if (pri->bri)
+- return pos + 2;
++ if (!ctrl->bri && (ie->data[0] & 0x03) == 0x01 /* Specified channel */
++ && !(call->chanflags & FLAG_WHOLE_INTERFACE)) {
++ /* The 3.2 and 3.3 octets need to be present */
++ ie->data[pos] = 0x83;
++ if (call->slotmap != -1) {
++ int octet;
+
+- if ((call->channelno > -1) || (call->slotmap != -1)) {
+- /* We'll have the octet 8.2 and 8.3's present */
+- ie->data[pos++] = 0x83;
+- if (call->channelno > -1) {
++ /* We have to send a channel map */
++ ie->data[pos++] |= 0x10;
++ for (octet = 3; octet--;) {
++ ie->data[pos++] = (call->slotmap >> (8 * octet)) & 0xff;
++ }
++ } else {
+ /* Channel number specified */
+- if (pri->chan_mapping_logical && call->channelno > 16)
++ ++pos;
++ if (ctrl->chan_mapping_logical && call->channelno > 16) {
+ ie->data[pos++] = 0x80 | (call->channelno - 1);
+- else
++ } else {
+ ie->data[pos++] = 0x80 | call->channelno;
+- return pos + 2;
++ }
+ }
+- /* We have to send a channel map */
+- if (call->slotmap != -1) {
+- ie->data[pos-1] |= 0x10;
+- ie->data[pos++] = (call->slotmap & 0xff0000) >> 16;
+- ie->data[pos++] = (call->slotmap & 0xff00) >> 8;
+- ie->data[pos++] = (call->slotmap & 0xff);
+- return pos + 2;
+- }
+ }
+- if (call->ds1no > 0) {
+- /* We're done */
+- return pos + 2;
+- }
+- pri_error(pri, "!! No channel map, no channel, and no ds1? What am I supposed to identify?\n");
+- return -1;
++
++ return pos + 2;
+ }
+
+-static FUNC_DUMP(dump_channel_id)
++static void dump_channel_id(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix)
+ {
+- int pos=0;
++ int pos;
+ int x;
+- int res = 0;
+- static const char* msg_chan_sel[] = {
+- "No channel selected", "B1 channel", "B2 channel","Any channel selected",
+- "No channel selected", "As indicated in following octets", "Reserved","Any channel selected"
++ int res;
++
++ static const char *msg_chan_sel[] = {
++ "No channel selected", "B1 channel", "B2 channel", "Any channel selected",
++ "No channel selected", "As indicated in following octets", "Reserved", "Any channel selected"
+ };
+
+- pri_message(pri, "%c Channel ID (len=%2d) [ Ext: %d IntID: %s %s Spare: %d %s Dchan: %d\n",
+- prefix, len, (ie->data[0] & 0x80) ? 1 : 0, (ie->data[0] & 0x40) ? "Explicit" : "Implicit",
+- (ie->data[0] & 0x20) ? "PRI" : "Other", (ie->data[0] & 0x10) ? 1 : 0,
+- (ie->data[0] & 0x08) ? "Exclusive" : "Preferred", (ie->data[0] & 0x04) ? 1 : 0);
+- pri_message(pri, "%c ChanSel: %s\n",
+- prefix, msg_chan_sel[(ie->data[0] & 0x3) + ((ie->data[0]>>3) & 0x4)]);
+- pos++;
+- len--;
+- if (ie->data[0] & 0x40) {
++ pri_message(ctrl,
++ "%c Channel ID (len=%2d) [ Ext: %d IntID: %s %s Spare: %d %s Dchan: %d\n",
++ prefix, len,
++ (ie->data[0] & 0x80) ? 1 : 0,
++ (ie->data[0] & 0x40) ? "Explicit" : "Implicit",
++ (ie->data[0] & 0x20) ? "Other(PRI)" : "BRI",
++ (ie->data[0] & 0x10) ? 1 : 0,
++ (ie->data[0] & 0x08) ? "Exclusive" : "Preferred",
++ (ie->data[0] & 0x04) ? 1 : 0);
++ pri_message(ctrl, "%c ChanSel: %s\n",
++ prefix, msg_chan_sel[(ie->data[0] & 0x03) | ((ie->data[0] >> 3) & 0x04)]);
++ pos = 1;
++ len -= 2;
++ if (ie->data[0] & 0x40) {
+ /* Explicitly defined DS1 */
+- pri_message(pri, "%c Ext: %d DS1 Identifier: %d \n", prefix, (ie->data[pos] & 0x80) >> 7, ie->data[pos] & 0x7f);
+- pos++;
++ do {
++ pri_message(ctrl, "%c Ext: %d DS1 Identifier: %d \n",
++ prefix, (ie->data[pos] & 0x80) >> 7, ie->data[pos] & 0x7f);
++ ++pos;
++ } while (!(ie->data[pos - 1] & 0x80) && pos < len);
+ } else {
+ /* Implicitly defined DS1 */
+ }
+- if (pos+2 < len) {
++ if (pos < len) {
+ /* Still more information here */
+- pri_message(pri, "%c Ext: %d Coding: %d %s Specified Channel Type: %d\n",
+- prefix, (ie->data[pos] & 0x80) >> 7, (ie->data[pos] & 60) >> 5,
+- (ie->data[pos] & 0x10) ? "Slot Map" : "Number", ie->data[pos] & 0x0f);
+- if (!(ie->data[pos] & 0x10)) {
++ pri_message(ctrl,
++ "%c Ext: %d Coding: %d %s Specified Channel Type: %d\n",
++ prefix, (ie->data[pos] & 0x80) >> 7, (ie->data[pos] & 60) >> 5,
++ (ie->data[pos] & 0x10) ? "Slot Map" : "Number", ie->data[pos] & 0x0f);
++ ++pos;
++ }
++ if (pos < len) {
++ if (!(ie->data[pos - 1] & 0x10)) {
+ /* Number specified */
+- pos++;
+- pri_message(pri, "%c Ext: %d Channel: %d ]\n", prefix, (ie->data[pos] & 0x80) >> 7,
+- (ie->data[pos]) & 0x7f);
++ do {
++ pri_message(ctrl,
++ "%c Ext: %d Channel: %d Type: %s%c\n",
++ prefix, (ie->data[pos] & 0x80) >> 7,
++ (ie->data[pos]) & 0x7f, pritype(ctrl->localtype),
++ (pos + 1 < len) ? ' ' : ']');
++ ++pos;
++ } while (pos < len);
+ } else {
+- pos++;
+ /* Map specified */
+- for (x=0;x<3;x++) {
++ res = 0;
++ x = 0;
++ do {
+ res <<= 8;
+ res |= ie->data[pos++];
+- }
+- pri_message(pri, "%c Map: %s ]\n", prefix, binary(res, 24));
++ ++x;
++ } while (pos < len);
++ pri_message(ctrl, "%c Map len: %d Map: %s ]\n", prefix,
++ x, binary(res, x << 3));
+ }
+- } else pri_message(pri, " ]\n");
++ } else {
++ pri_message(ctrl, " ]\n");
++ }
+ }
+
+ static char *ri2str(int ri)
+@@ -482,20 +1082,20 @@
+ return code2str(ri, ris, sizeof(ris) / sizeof(ris[0]));
+ }
+
+-static FUNC_DUMP(dump_restart_indicator)
++static void dump_restart_indicator(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix)
+ {
+- pri_message(pri, "%c Restart Indentifier (len=%2d) [ Ext: %d Spare: %d Resetting %s (%d) ]\n",
++ pri_message(ctrl, "%c Restart Indentifier (len=%2d) [ Ext: %d Spare: %d Resetting %s (%d) ]\n",
+ prefix, len, (ie->data[0] & 0x80) >> 7, (ie->data[0] & 0x78) >> 3, ri2str(ie->data[0] & 0x7), ie->data[0] & 0x7);
+ }
+
+-static FUNC_RECV(receive_restart_indicator)
++static int receive_restart_indicator(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len)
+ {
+ /* Pretty simple */
+ call->ri = ie->data[0] & 0x7;
+ return 0;
+ }
+
+-static FUNC_SEND(transmit_restart_indicator)
++static int transmit_restart_indicator(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order)
+ {
+ /* Pretty simple */
+ switch(call->ri) {
+@@ -509,7 +1109,7 @@
+ ie->data[0] = 0xA0 | (call->ri & 0x7);
+ break;
+ default:
+- pri_error(pri, "!! Invalid restart indicator value %d\n", call->ri);
++ pri_error(ctrl, "!! Invalid restart indicator value %d\n", call->ri);
+ return-1;
+ }
+ return 3;
+@@ -607,16 +1207,16 @@
+ return code2str(proto, protos, sizeof(protos) / sizeof(protos[0]));
+ }
+
+-static FUNC_DUMP(dump_bearer_capability)
++static void dump_bearer_capability(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix)
+ {
+ int pos=2;
+- pri_message(pri, "%c Bearer Capability (len=%2d) [ Ext: %d Q.931 Std: %d Info transfer capability: %s (%d)\n",
++ pri_message(ctrl, "%c Bearer Capability (len=%2d) [ Ext: %d Q.931 Std: %d Info transfer capability: %s (%d)\n",
+ prefix, len, (ie->data[0] & 0x80 ) >> 7, (ie->data[0] & 0x60) >> 5, cap2str(ie->data[0] & 0x1f), (ie->data[0] & 0x1f));
+- pri_message(pri, "%c Ext: %d Trans mode/rate: %s (%d)\n", prefix, (ie->data[1] & 0x80) >> 7, mode2str(ie->data[1] & 0x7f), ie->data[1] & 0x7f);
++ pri_message(ctrl, "%c Ext: %d Trans mode/rate: %s (%d)\n", prefix, (ie->data[1] & 0x80) >> 7, mode2str(ie->data[1] & 0x7f), ie->data[1] & 0x7f);
+
+ /* octet 4.1 exists iff mode/rate is multirate */
+ if ((ie->data[1] & 0x7f) == 0x18) {
+- pri_message(pri, "%c Ext: %d Transfer rate multiplier: %d x 64\n", prefix, (ie->data[2] & 0x80) >> 7, ie->data[2] & 0x7f);
++ pri_message(ctrl, "%c Ext: %d Transfer rate multiplier: %d x 64\n", prefix, (ie->data[2] & 0x80) >> 7, ie->data[2] & 0x7f);
+ pos++;
+ }
+
+@@ -632,7 +1232,7 @@
+ too, so we have to do the same for binary compatability */
+ u_int8_t layer1 = ie->data[pos] & 0x7f;
+
+- pri_message(pri, "%c User information layer 1: %s (%d)\n",
++ pri_message(ctrl, "%c User information layer 1: %s (%d)\n",
+ prefix, l12str(layer1), layer1);
+ pos++;
+
+@@ -640,7 +1240,7 @@
+ if (pos < len && !(ie->data[pos-1] & 0x80)) {
+ int ra = ie->data[pos] & 0x7f;
+
+- pri_message(pri, "%c Async: %d, Negotiation: %d, "
++ pri_message(ctrl, "%c Async: %d, Negotiation: %d, "
+ "User rate: %s (%#x)\n",
+ prefix,
+ ra & PRI_RATE_ADAPT_ASYNC ? 1 : 0,
+@@ -654,7 +1254,7 @@
+ if (pos < len && !(ie->data[pos-1] & 0x80)) {
+ u_int8_t data = ie->data[pos];
+ if (layer1 == PRI_LAYER_1_ITU_RATE_ADAPT) {
+- pri_message(pri, "%c Intermediate rate: %s (%d), "
++ pri_message(ctrl, "%c Intermediate rate: %s (%d), "
+ "NIC on Tx: %d, NIC on Rx: %d, "
+ "Flow control on Tx: %d, "
+ "Flow control on Rx: %d\n",
+@@ -665,7 +1265,7 @@
+ (data & 0x04)?1:0,
+ (data & 0x02)?1:0);
+ } else if (layer1 == PRI_LAYER_1_V120_RATE_ADAPT) {
+- pri_message(pri, "%c Hdr: %d, Multiframe: %d, Mode: %d, "
++ pri_message(ctrl, "%c Hdr: %d, Multiframe: %d, Mode: %d, "
+ "LLI negot: %d, Assignor: %d, "
+ "In-band neg: %d\n", prefix,
+ (data & 0x40)?1:0,
+@@ -675,7 +1275,8 @@
+ (data & 0x04)?1:0,
+ (data & 0x02)?1:0);
+ } else {
+- pri_message(pri, "%c Unknown octet 5b: 0x%x\n", data );
++ pri_message(ctrl, "%c Unknown octet 5b: 0x%x\n",
++ prefix, data);
+ }
+ pos++;
+ }
+@@ -688,7 +1289,7 @@
+ const char *parity[] = {"Odd","?","Even","None",
+ "zero","one","?","?"};
+
+- pri_message(pri, "%c Stop bits: %s, data bits: %s, "
++ pri_message(ctrl, "%c Stop bits: %s, data bits: %s, "
+ "parity: %s\n", prefix,
+ stop_bits[(data & 0x60) >> 5],
+ data_bits[(data & 0x18) >> 3],
+@@ -700,7 +1301,7 @@
+ /* octet 5d? */
+ if (pos < len && !(ie->data[pos-1] & 0x80)) {
+ u_int8_t data = ie->data[pos];
+- pri_message(pri, "%c Duplex mode: %d, modem type: %d\n",
++ pri_message(ctrl, "%c Duplex mode: %d, modem type: %d\n",
+ prefix, (data & 0x40) ? 1 : 0,data & 0x3F);
+ pos++;
+ }
+@@ -710,7 +1311,7 @@
+ /* Look for octet 6; this is identified by bits 5,6 == 10 */
+ if (pos < len &&
+ (ie->data[pos] & 0x60) == 0x40) {
+- pri_message(pri, "%c User information layer 2: %s (%d)\n",
++ pri_message(ctrl, "%c User information layer 2: %s (%d)\n",
+ prefix, l22str(ie->data[pos] & 0x1f),
+ ie->data[pos] & 0x1f);
+ pos++;
+@@ -718,7 +1319,7 @@
+
+ /* Look for octet 7; this is identified by bits 5,6 == 11 */
+ if (pos < len && (ie->data[pos] & 0x60) == 0x60) {
+- pri_message(pri, "%c User information layer 3: %s (%d)\n",
++ pri_message(ctrl, "%c User information layer 3: %s (%d)\n",
+ prefix, l32str(ie->data[pos] & 0x1f),
+ ie->data[pos] & 0x1f);
+ pos++;
+@@ -730,18 +1331,18 @@
+ proto = ((ie->data[pos] & 0xF) << 4 ) |
+ (ie->data[pos+1] & 0xF);
+
+- pri_message(pri, "%c Network layer: 0x%x\n", prefix,
++ pri_message(ctrl, "%c Network layer: 0x%x\n", prefix,
+ proto );
+ pos += 2;
+ }
+ }
+ }
+
+-static FUNC_RECV(receive_bearer_capability)
++static int receive_bearer_capability(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len)
+ {
+ int pos=2;
+ if (ie->data[0] & 0x60) {
+- pri_error(pri, "!! non-standard Q.931 standard field\n");
++ pri_error(ctrl, "!! non-standard Q.931 standard field\n");
+ return -1;
+ }
+ call->transcapability = ie->data[0] & 0x1f;
+@@ -788,7 +1389,7 @@
+ return 0;
+ }
+
+-static FUNC_SEND(transmit_bearer_capability)
++static int transmit_bearer_capability(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order)
+ {
+ int tc;
+ int pos;
+@@ -797,20 +1398,20 @@
+ if(order > 1)
+ return 0;
+
+- tc = call->transcapability;
+- if (pri->subchannel && !pri->bri) {
++ if (ctrl->subchannel && !ctrl->bri) {
+ /* Bearer capability is *hard coded* in GR-303 */
+ ie->data[0] = 0x88;
+ ie->data[1] = 0x90;
+ return 4;
+ }
+-
+- if (call->justsignalling) {
++
++ if (call->cis_call) {
+ ie->data[0] = 0xa8;
+ ie->data[1] = 0x80;
+ return 4;
+ }
+-
++
++ tc = call->transcapability;
+ ie->data[0] = 0x80 | tc;
+ ie->data[1] = call->transmoderate | 0x80;
+
+@@ -820,7 +1421,7 @@
+ ie->data[pos++] = call->transmultiple | 0x80;
+ }
+
+- if ((tc & PRI_TRANS_CAP_DIGITAL) && (pri->switchtype == PRI_SWITCH_EUROISDN_E1) &&
++ if ((tc & PRI_TRANS_CAP_DIGITAL) && (ctrl->switchtype == PRI_SWITCH_EUROISDN_E1) &&
+ (call->transmoderate == TRANS_MODE_PACKET)) {
+ /* Apparently EuroISDN switches don't seem to like user layer 2/3 */
+ return 4;
+@@ -833,7 +1434,7 @@
+
+ if (call->transmoderate != TRANS_MODE_PACKET) {
+ /* If you have an AT&T 4ESS, you don't send any more info */
+- if ((pri->switchtype != PRI_SWITCH_ATT4ESS) && (call->userl1 > -1)) {
++ if ((ctrl->switchtype != PRI_SWITCH_ATT4ESS) && (call->userl1 > -1)) {
+ ie->data[pos++] = call->userl1 | 0x80; /* XXX Ext bit? XXX */
+ if (call->userl1 == PRI_LAYER_1_ITU_RATE_ADAPT) {
+ ie->data[pos++] = call->rateadaption | 0x80;
+@@ -908,6 +1509,30 @@
+ return code2str(plan, plans, sizeof(plans) / sizeof(plans[0]));
+ }
+
++/* Calling Party Category (Definitions from Q.763) */
++static char *cpc2str(int plan)
++{
++ static struct msgtype plans[] = {
++ { 0, "Unknown Source" },
++ { 1, "Operator French" },
++ { 2, "Operator English" },
++ { 3, "Operator German" },
++ { 4, "Operator Russian" },
++ { 5, "Operator Spanish" },
++ { 6, "Mut Agree Chinese" },
++ { 7, "Mut Agreement" },
++ { 8, "Mut Agree Japanese" },
++ { 9, "National Operator" },
++ { 10, "Ordinary Toll Caller" },
++ { 11, "Priority Toll Caller" },
++ { 12, "Data Call" },
++ { 13, "Test Call" },
++ { 14, "Spare" },
++ { 15, "Pay Phone" },
++ };
++ return code2str(plan, plans, ARRAY_LEN(plans));
++}
++
+ char *pri_pres2str(int pres)
+ {
+ static struct msgtype press[] = {
+@@ -934,51 +1559,134 @@
+ num[len] = 0;
+ }
+
+-static FUNC_DUMP(dump_called_party_number)
++static void q931_get_subaddr_specific(unsigned char *num, int maxlen, unsigned char *src, int len, char oddflag)
+ {
+- unsigned char cnum[256];
++ /* User Specified */
++ int x;
++ char *ptr = (char *) num;
+
+- q931_get_number(cnum, sizeof(cnum), ie->data + 1, len - 3);
+- pri_message(pri, "%c Called Number (len=%2d) [ Ext: %d TON: %s (%d) NPI: %s (%d) '%s' ]\n",
+- prefix, len, ie->data[0] >> 7, ton2str((ie->data[0] >> 4) & 0x07), (ie->data[0] >> 4) & 0x07, npi2str(ie->data[0] & 0x0f), ie->data[0] & 0x0f, cnum);
++ if (len <= 0) {
++ num[0] = '\0';
++ return;
++ }
++
++ if (((len * 2) + 1) > maxlen) {
++ len = (maxlen / 2) - 1;
++ }
++
++ for (x = 0; x < (len - 1); ++x) {
++ ptr += sprintf(ptr, "%02x", src[x]);
++ }
++
++ if (oddflag) {
++ /* ODD */
++ sprintf(ptr, "%01x", (src[len - 1]) >> 4);
++ } else {
++ /* EVEN */
++ sprintf(ptr, "%02x", src[len - 1]);
++ }
+ }
+
+-static FUNC_DUMP(dump_called_party_subaddr)
++static int transmit_subaddr_helper(int full_ie, struct pri *ctrl, struct q931_party_subaddress *q931_subaddress, int msgtype, q931_ie *ie, int offset, int len, int order)
+ {
++ size_t datalen;
++
++ if (!q931_subaddress->valid) {
++ return 0;
++ }
++
++ datalen = q931_subaddress->length;
++ if (!q931_subaddress->type) {
++ /* 0 = NSAP */
++ /* 0 = Odd/Even indicator */
++ ie->data[0] = 0x80;
++ } else {
++ /* 2 = User Specified */
++ ie->data[0] = q931_subaddress->odd_even_indicator ? 0xA8 : 0xA0;
++ }
++ memcpy(ie->data + offset, q931_subaddress->data, datalen);
++
++ return datalen + (offset + 2);
++}
++
++static int receive_subaddr_helper(int full_ie, struct pri *ctrl, struct q931_party_subaddress *q931_subaddress, int msgtype, q931_ie *ie, int offset, int len)
++{
++ if (len <= 0) {
++ return -1;
++ }
++
++ q931_subaddress->valid = 1;
++ q931_subaddress->length = len;
++ /* type: 0 = NSAP, 2 = User Specified */
++ q931_subaddress->type = ((ie->data[0] & 0x70) >> 4);
++ q931_subaddress->odd_even_indicator = (ie->data[0] & 0x08) ? 1 : 0;
++ q931_get_number(q931_subaddress->data, sizeof(q931_subaddress->data),
++ ie->data + offset, len);
++
++ return 0;
++}
++
++static void dump_subaddr_helper(int full_ie, struct pri *ctrl, q931_ie *ie, int offset, int len, int datalen, char prefix, const char *named)
++{
+ unsigned char cnum[256];
+- q931_get_number(cnum, sizeof(cnum), ie->data + 1, len - 3);
+- pri_message(pri, "%c Called Sub-Address (len=%2d) [ Ext: %d Type: %s (%d) O: %d '%s' ]\n",
+- prefix, len, ie->data[0] >> 7,
++
++ if (!(ie->data[0] & 0x70)) {
++ /* NSAP */
++ q931_get_number(cnum, sizeof(cnum), ie->data + offset, datalen);
++ } else {
++ /* User Specified */
++ q931_get_subaddr_specific(cnum, sizeof(cnum), ie->data + offset, datalen,
++ ie->data[0] & 0x08);
++ }
++
++ pri_message(ctrl,
++ "%c %s Sub-Address (len=%2d) [ Ext: %d Type: %s (%d) O: %d '%s' ]\n",
++ prefix, named, len, ie->data[0] >> 7,
+ subaddrtype2str((ie->data[0] & 0x70) >> 4), (ie->data[0] & 0x70) >> 4,
+ (ie->data[0] & 0x08) >> 3, cnum);
+ }
+
+-static FUNC_DUMP(dump_calling_party_number)
++static void dump_called_party_number(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix)
+ {
+ unsigned char cnum[256];
++
++ q931_get_number(cnum, sizeof(cnum), ie->data + 1, len - 3);
++ pri_message(ctrl, "%c Called Number (len=%2d) [ Ext: %d TON: %s (%d) NPI: %s (%d) '%s' ]\n",
++ prefix, len, ie->data[0] >> 7, ton2str((ie->data[0] >> 4) & 0x07), (ie->data[0] >> 4) & 0x07, npi2str(ie->data[0] & 0x0f), ie->data[0] & 0x0f, cnum);
++}
++
++static void dump_called_party_subaddr(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix)
++{
++ dump_subaddr_helper(full_ie, ctrl, ie, 1 , len, len - 3, prefix, "Called");
++}
++
++static void dump_calling_party_number(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix)
++{
++ unsigned char cnum[256];
+ if (ie->data[0] & 0x80)
+ q931_get_number(cnum, sizeof(cnum), ie->data + 1, len - 3);
+ else
+ q931_get_number(cnum, sizeof(cnum), ie->data + 2, len - 4);
+- pri_message(pri, "%c Calling Number (len=%2d) [ Ext: %d TON: %s (%d) NPI: %s (%d)\n", prefix, len, ie->data[0] >> 7, ton2str((ie->data[0] >> 4) & 0x07), (ie->data[0] >> 4) & 0x07, npi2str(ie->data[0] & 0x0f), ie->data[0] & 0x0f);
++ pri_message(ctrl, "%c Calling Number (len=%2d) [ Ext: %d TON: %s (%d) NPI: %s (%d)\n", prefix, len, ie->data[0] >> 7, ton2str((ie->data[0] >> 4) & 0x07), (ie->data[0] >> 4) & 0x07, npi2str(ie->data[0] & 0x0f), ie->data[0] & 0x0f);
+ if (ie->data[0] & 0x80)
+- pri_message(pri, "%c Presentation: %s (%d) '%s' ]\n", prefix, pri_pres2str(0), 0, cnum);
++ pri_message(ctrl, "%c Presentation: %s (%d) '%s' ]\n", prefix, pri_pres2str(0), 0, cnum);
+ else
+- pri_message(pri, "%c Presentation: %s (%d) '%s' ]\n", prefix, pri_pres2str(ie->data[1] & 0x7f), ie->data[1] & 0x7f, cnum);
++ pri_message(ctrl, "%c Presentation: %s (%d) '%s' ]\n", prefix, pri_pres2str(ie->data[1] & 0x7f), ie->data[1] & 0x7f, cnum);
+ }
+
+-static FUNC_DUMP(dump_calling_party_subaddr)
++static void dump_calling_party_subaddr(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix)
+ {
+- unsigned char cnum[256];
+- q931_get_number(cnum, sizeof(cnum), ie->data + 1, len - 3);
+- pri_message(pri, "%c Calling Sub-Address (len=%2d) [ Ext: %d Type: %s (%d) O: %d '%s' ]\n",
+- prefix, len, ie->data[0] >> 7,
+- subaddrtype2str((ie->data[0] & 0x70) >> 4), (ie->data[0] & 0x70) >> 4,
+- (ie->data[0] & 0x08) >> 3, cnum);
++ dump_subaddr_helper(full_ie, ctrl, ie, 1 , len, len - 3, prefix, "Calling");
+ }
+
+-static FUNC_DUMP(dump_redirecting_number)
++static void dump_calling_party_category(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix)
+ {
++ pri_message(ctrl, "%c Calling Party Category (len=%2d) [ Ext: %d Cat: %s (%d) ]\n",
++ prefix, len, ie->data[0] >> 7, cpc2str(ie->data[0] & 0x0F), ie->data[0] & 0x0F);
++}
++
++static void dump_redirecting_number(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix)
++{
+ unsigned char cnum[256];
+ int i = 0;
+ /* To follow Q.931 (4.5.1), we must search for start of octet 4 by
+@@ -986,172 +1694,369 @@
+ do {
+ switch(i) {
+ case 0: /* Octet 3 */
+- pri_message(pri, "%c Redirecting Number (len=%2d) [ Ext: %d TON: %s (%d) NPI: %s (%d)",
++ pri_message(ctrl, "%c Redirecting Number (len=%2d) [ Ext: %d TON: %s (%d) NPI: %s (%d)",
+ prefix, len, ie->data[0] >> 7, ton2str((ie->data[0] >> 4) & 0x07), (ie->data[0] >> 4) & 0x07, npi2str(ie->data[0] & 0x0f), ie->data[0] & 0x0f);
+ break;
+ case 1: /* Octet 3a */
+- pri_message(pri, "\n%c Ext: %d Presentation: %s (%d)",
++ pri_message(ctrl, "\n%c Ext: %d Presentation: %s (%d)",
+ prefix, ie->data[1] >> 7, pri_pres2str(ie->data[1] & 0x7f), ie->data[1] & 0x7f);
+ break;
+ case 2: /* Octet 3b */
+- pri_message(pri, "\n%c Ext: %d Reason: %s (%d)",
++ pri_message(ctrl, "\n%c Ext: %d Reason: %s (%d)",
+ prefix, ie->data[2] >> 7, redirection_reason2str(ie->data[2] & 0x7f), ie->data[2] & 0x7f);
+ break;
+ }
+- }
+- while(!(ie->data[i++]& 0x80));
++ } while(!(ie->data[i++]& 0x80));
+ q931_get_number(cnum, sizeof(cnum), ie->data + i, ie->len - i);
+- pri_message(pri, " '%s' ]\n", cnum);
++ pri_message(ctrl, " '%s' ]\n", cnum);
+ }
+
+-static FUNC_DUMP(dump_connected_number)
++static void dump_redirection_number(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix)
+ {
+ unsigned char cnum[256];
+ int i = 0;
+ /* To follow Q.931 (4.5.1), we must search for start of octet 4 by
+ walking through all bytes until one with ext bit (8) set to 1 */
+ do {
++ switch (i) {
++ case 0: /* Octet 3 */
++ pri_message(ctrl,
++ "%c Redirection Number (len=%2d) [ Ext: %d TON: %s (%d) NPI: %s (%d)",
++ prefix, len, ie->data[0] >> 7,
++ ton2str((ie->data[0] >> 4) & 0x07), (ie->data[0] >> 4) & 0x07,
++ npi2str(ie->data[0] & 0x0f), ie->data[0] & 0x0f);
++ break;
++ case 1: /* Octet 3a */
++ pri_message(ctrl, "\n%c Ext: %d Presentation: %s (%d)",
++ prefix, ie->data[1] >> 7, pri_pres2str(ie->data[1] & 0x7f), ie->data[1] & 0x7f);
++ break;
++ }
++ } while (!(ie->data[i++] & 0x80));
++ q931_get_number(cnum, sizeof(cnum), ie->data + i, ie->len - i);
++ pri_message(ctrl, " '%s' ]\n", cnum);
++}
++
++static int receive_connected_number(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len)
++{
++ int i = 0;
++
++ call->connected_number_in_message = 1;
++ call->remote_id.number.valid = 1;
++ call->remote_id.number.presentation =
++ PRI_PRES_ALLOWED | PRI_PRES_USER_NUMBER_UNSCREENED;
++ /* To follow Q.931 (4.5.1), we must search for start of octet 4 by
++ walking through all bytes until one with ext bit (8) set to 1 */
++ do {
++ switch (i) {
++ case 0:
++ call->remote_id.number.plan = ie->data[i] & 0x7f;
++ break;
++ case 1:
++ /* Keep only the presentation and screening fields */
++ call->remote_id.number.presentation =
++ ie->data[i] & (PRI_PRES_RESTRICTION | PRI_PRES_NUMBER_TYPE);
++ break;
++ }
++ } while (!(ie->data[i++] & 0x80));
++ q931_get_number((unsigned char *) call->remote_id.number.str, sizeof(call->remote_id.number.str), ie->data + i, ie->len - i);
++
++ return 0;
++}
++
++static int transmit_connected_number(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order)
++{
++ size_t datalen;
++
++ if (!call->local_id.number.valid) {
++ return 0;
++ }
++
++ datalen = strlen(call->local_id.number.str);
++ ie->data[0] = call->local_id.number.plan;
++ ie->data[1] = 0x80 | call->local_id.number.presentation;
++ memcpy(ie->data + 2, call->local_id.number.str, datalen);
++ return datalen + (2 + 2);
++}
++
++static void dump_connected_number(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix)
++{
++ unsigned char cnum[256];
++ int i = 0;
++ /* To follow Q.931 (4.5.1), we must search for start of octet 4 by
++ walking through all bytes until one with ext bit (8) set to 1 */
++ do {
+ switch(i) {
+ case 0: /* Octet 3 */
+- pri_message(pri, "%c Connected Number (len=%2d) [ Ext: %d TON: %s (%d) NPI: %s (%d)",
++ pri_message(ctrl, "%c Connected Number (len=%2d) [ Ext: %d TON: %s (%d) NPI: %s (%d)",
+ prefix, len, ie->data[0] >> 7, ton2str((ie->data[0] >> 4) & 0x07), (ie->data[0] >> 4) & 0x07, npi2str(ie->data[0] & 0x0f), ie->data[0] & 0x0f);
+ break;
+ case 1: /* Octet 3a */
+- pri_message(pri, "\n%c Ext: %d Presentation: %s (%d)",
++ pri_message(ctrl, "\n%c Ext: %d Presentation: %s (%d)",
+ prefix, ie->data[1] >> 7, pri_pres2str(ie->data[1] & 0x7f), ie->data[1] & 0x7f);
+ break;
+ }
+- }
+- while(!(ie->data[i++]& 0x80));
++ } while(!(ie->data[i++]& 0x80));
+ q931_get_number(cnum, sizeof(cnum), ie->data + i, ie->len - i);
+- pri_message(pri, " '%s' ]\n", cnum);
++ pri_message(ctrl, " '%s' ]\n", cnum);
+ }
+
++static int receive_connected_subaddr(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len)
++{
++ if (len < 3) {
++ return -1;
++ }
+
+-static FUNC_RECV(receive_redirecting_number)
++ return receive_subaddr_helper(full_ie, ctrl, &call->remote_id.subaddress, msgtype, ie,
++ 1, len - 3);
++}
++
++static int transmit_connected_subaddr(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order)
+ {
++ return transmit_subaddr_helper(full_ie, ctrl, &call->local_id.subaddress, msgtype, ie,
++ 1, len, order);
++}
++
++static void dump_connected_subaddr(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix)
++{
++ dump_subaddr_helper(full_ie, ctrl, ie, 1 , len, len - 3, prefix, "Connected");
++}
++
++static int receive_redirecting_number(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len)
++{
+ int i = 0;
+
++ call->redirecting_number_in_message = 1;
++ call->redirecting.from.number.valid = 1;
++ call->redirecting.from.number.presentation =
++ PRI_PRES_ALLOWED | PRI_PRES_USER_NUMBER_UNSCREENED;
++ call->redirecting.reason = PRI_REDIR_UNKNOWN;
+ /* To follow Q.931 (4.5.1), we must search for start of octet 4 by
+ walking through all bytes until one with ext bit (8) set to 1 */
+ do {
+- switch(i) {
++ switch (i) {
+ case 0:
+- call->redirectingplan = ie->data[i] & 0x7f;
++ call->redirecting.from.number.plan = ie->data[i] & 0x7f;
+ break;
+ case 1:
+- call->redirectingpres = ie->data[i] & 0x7f;
++ /* Keep only the presentation and screening fields */
++ call->redirecting.from.number.presentation =
++ ie->data[i] & (PRI_PRES_RESTRICTION | PRI_PRES_NUMBER_TYPE);
+ break;
+ case 2:
+- call->redirectingreason = ie->data[i] & 0x0f;
++ call->redirecting.reason = ie->data[i] & 0x0f;
+ break;
+ }
+- }
+- while(!(ie->data[i++] & 0x80));
+- q931_get_number((unsigned char *) call->redirectingnum, sizeof(call->redirectingnum), ie->data + i, ie->len - i);
++ } while (!(ie->data[i++] & 0x80));
++ q931_get_number((unsigned char *) call->redirecting.from.number.str, sizeof(call->redirecting.from.number.str), ie->data + i, ie->len - i);
+ return 0;
+ }
+
+-static FUNC_SEND(transmit_redirecting_number)
++static int transmit_redirecting_number(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order)
+ {
++ size_t datalen;
++
+ if (order > 1)
+ return 0;
+- if (call->redirectingnum && *call->redirectingnum) {
+- ie->data[0] = call->redirectingplan;
+- ie->data[1] = call->redirectingpres;
+- ie->data[2] = (call->redirectingreason & 0x0f) | 0x80;
+- memcpy(ie->data + 3, call->redirectingnum, strlen(call->redirectingnum));
+- return strlen(call->redirectingnum) + 3 + 2;
++ if (!call->redirecting.from.number.valid) {
++ return 0;
+ }
+- return 0;
++
++ datalen = strlen(call->redirecting.from.number.str);
++ ie->data[0] = call->redirecting.from.number.plan;
++#if 1
++ /* ETSI and Q.952 do not define the screening field */
++ ie->data[1] = call->redirecting.from.number.presentation & PRI_PRES_RESTRICTION;
++#else
++ /* Q.931 defines the screening field */
++ ie->data[1] = call->redirecting.from.number.presentation;
++#endif
++ ie->data[2] = (call->redirecting.reason & 0x0f) | 0x80;
++ memcpy(ie->data + 3, call->redirecting.from.number.str, datalen);
++ return datalen + (3 + 2);
+ }
+
+-static FUNC_DUMP(dump_redirecting_subaddr)
++static void dump_redirecting_subaddr(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix)
+ {
+- unsigned char cnum[256];
+- q931_get_number(cnum, sizeof(cnum), ie->data + 2, len - 4);
+- pri_message(pri, "%c Redirecting Sub-Address (len=%2d) [ Ext: %d Type: %s (%d) O: %d '%s' ]\n",
+- prefix, len, ie->data[0] >> 7,
+- subaddrtype2str((ie->data[0] & 0x70) >> 4), (ie->data[0] & 0x70) >> 4,
+- (ie->data[0] & 0x08) >> 3, cnum);
++ dump_subaddr_helper(full_ie, ctrl, ie, 2, len, len - 4, prefix, "Redirecting");
+ }
+
+-static FUNC_RECV(receive_calling_party_subaddr)
++static int receive_redirection_number(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len)
+ {
+- /* copy digits to call->callingsubaddr */
+- q931_get_number((unsigned char *) call->callingsubaddr, sizeof(call->callingsubaddr), ie->data + 1, len - 3);
++ int i = 0;
++
++ call->redirection_number.valid = 1;
++ call->redirection_number.presentation =
++ PRI_PRES_ALLOWED | PRI_PRES_USER_NUMBER_UNSCREENED;
++ /* To follow Q.931 (4.5.1), we must search for start of octet 4 by
++ walking through all bytes until one with ext bit (8) set to 1 */
++ do {
++ switch (i) {
++ case 0:
++ call->redirection_number.plan = ie->data[i] & 0x7f;
++ break;
++ case 1:
++ /* Keep only the presentation and screening fields */
++ call->redirection_number.presentation =
++ ie->data[i] & (PRI_PRES_RESTRICTION | PRI_PRES_NUMBER_TYPE);
++ break;
++ }
++ } while (!(ie->data[i++] & 0x80));
++ q931_get_number((unsigned char *) call->redirection_number.str, sizeof(call->redirection_number.str), ie->data + i, ie->len - i);
+ return 0;
+ }
+
+-static FUNC_RECV(receive_called_party_number)
++static int transmit_redirection_number(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order)
+ {
+- /* copy digits to call->callednum */
+- q931_get_number((unsigned char *) call->callednum, sizeof(call->callednum), ie->data + 1, len - 3);
+- call->calledplan = ie->data[0] & 0x7f;
+- return 0;
++ size_t datalen;
++
++ if (order > 1) {
++ return 0;
++ }
++ if (!call->redirection_number.valid) {
++ return 0;
++ }
++
++ datalen = strlen(call->redirection_number.str);
++ ie->data[0] = call->redirection_number.plan;
++ ie->data[1] = (call->redirection_number.presentation & PRI_PRES_RESTRICTION) | 0x80;
++ memcpy(ie->data + 2, call->redirection_number.str, datalen);
++ return datalen + (2 + 2);
+ }
+
+-static FUNC_SEND(transmit_called_party_number)
++static int receive_calling_party_subaddr(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len)
+ {
+- ie->data[0] = 0x80 | call->calledplan;
+- if (*call->callednum)
+- memcpy(ie->data + 1, call->callednum, strlen(call->callednum));
+- return strlen(call->callednum) + 3;
++ if (len < 3) {
++ return -1;
++ }
++
++ return receive_subaddr_helper(full_ie, ctrl, &call->remote_id.subaddress, msgtype, ie,
++ 1, len - 3);
+ }
+
+-static FUNC_RECV(receive_calling_party_number)
++static int transmit_calling_party_subaddr(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order)
+ {
+- u_int8_t *data;
+- size_t length;
+-
+- if (ie->data[0] & 0x80) {
+- data = ie->data + 1;
+- length = len - 3;
+- call->callerpres = 0; /* PI presentation allowed SI user-provided, not screened */
+- } else {
+- data = ie->data + 2;
+- length = len - 4;
+- call->callerpres = ie->data[1] & 0x7f;
++ return transmit_subaddr_helper(full_ie, ctrl, &call->local_id.subaddress, msgtype, ie,
++ 1, len, order);
++}
++
++static int receive_called_party_subaddr(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len)
++{
++ if (len < 3) {
++ return -1;
+ }
++ return receive_subaddr_helper(full_ie, ctrl, &call->called.subaddress, msgtype, ie, 1,
++ len - 3);
++}
+
+- if (call->callerpres == PRES_ALLOWED_NETWORK_NUMBER ||
+- call->callerpres == PRES_PROHIB_NETWORK_NUMBER) {
+- q931_get_number((u_int8_t *)call->callerani, sizeof(call->callerani), data, length);
+- call->callerplanani = ie->data[0] & 0x7f;
++static int transmit_called_party_subaddr(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order)
++{
++ return transmit_subaddr_helper(full_ie, ctrl, &call->called.subaddress, msgtype, ie,
++ 1, len, order);
++}
+
+- if (!*call->callernum) { /*Copy ANI to CallerID if CallerID is not already set */
+- libpri_copy_string(call->callernum, call->callerani, sizeof(call->callernum));
+- call->callerplan = call->callerplanani;
++static int receive_called_party_number(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len)
++{
++ size_t called_len;
++ size_t max_len;
++ char *called_end;
++
++ if (len < 3) {
++ return -1;
++ }
++
++ call->called.number.valid = 1;
++ call->called.number.plan = ie->data[0] & 0x7f;
++ if (msgtype == Q931_SETUP) {
++ q931_get_number((unsigned char *) call->called.number.str,
++ sizeof(call->called.number.str), ie->data + 1, len - 3);
++ } else if (call->ourcallstate == Q931_CALL_STATE_OVERLAP_RECEIVING) {
++ /*
++ * Since we are receiving overlap digits now, we need to append
++ * them to any previously received digits in call->called.number.str.
++ */
++ called_len = strlen(call->called.number.str);
++ called_end = call->called.number.str + called_len;
++ max_len = (sizeof(call->called.number.str) - 1) - called_len;
++ if (max_len < len - 3) {
++ called_len = max_len;
++ } else {
++ called_len = len - 3;
+ }
+-
+- } else {
+- q931_get_number((u_int8_t *)call->callernum, sizeof(call->callernum), data, length);
+- call->callerplan = ie->data[0] & 0x7f;
++ strncat(called_end, (char *) ie->data + 1, called_len);
+ }
+
++ q931_get_number((unsigned char *) call->overlap_digits, sizeof(call->overlap_digits),
++ ie->data + 1, len - 3);
+ return 0;
+ }
+
+-static FUNC_SEND(transmit_calling_party_number)
++static int transmit_called_party_number(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order)
+ {
+- ie->data[0] = call->callerplan;
+- ie->data[1] = 0x80 | call->callerpres;
+- if (*call->callernum)
+- memcpy(ie->data + 2, call->callernum, strlen(call->callernum));
+- return strlen(call->callernum) + 4;
++ size_t datalen;
++
++ if (!call->called.number.valid) {
++ return 0;
++ }
++
++ datalen = strlen(call->overlap_digits);
++ ie->data[0] = 0x80 | call->called.number.plan;
++ memcpy(ie->data + 1, call->overlap_digits, datalen);
++ return datalen + (1 + 2);
+ }
+
+-static FUNC_DUMP(dump_user_user)
++static int receive_calling_party_number(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len)
+ {
++ int i = 0;
++
++ call->remote_id.number.valid = 1;
++ call->remote_id.number.presentation =
++ PRI_PRES_ALLOWED | PRI_PRES_USER_NUMBER_UNSCREENED;
++ /* To follow Q.931 (4.5.1), we must search for start of octet 4 by
++ walking through all bytes until one with ext bit (8) set to 1 */
++ do {
++ switch (i) {
++ case 0:
++ call->remote_id.number.plan = ie->data[i] & 0x7f;
++ break;
++ case 1:
++ /* Keep only the presentation and screening fields */
++ call->remote_id.number.presentation =
++ ie->data[i] & (PRI_PRES_RESTRICTION | PRI_PRES_NUMBER_TYPE);
++ break;
++ }
++ } while (!(ie->data[i++] & 0x80));
++ q931_get_number((unsigned char *) call->remote_id.number.str,
++ sizeof(call->remote_id.number.str), ie->data + i, ie->len - i);
++
++ return 0;
++}
++
++static int transmit_calling_party_number(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order)
++{
++ size_t datalen;
++
++ if (!call->local_id.number.valid) {
++ return 0;
++ }
++
++ datalen = strlen(call->local_id.number.str);
++ ie->data[0] = call->local_id.number.plan;
++ ie->data[1] = 0x80 | call->local_id.number.presentation;
++ memcpy(ie->data + 2, call->local_id.number.str, datalen);
++ return datalen + (2 + 2);
++}
++
++static void dump_user_user(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix)
++{
+ int x;
+- pri_message(pri, "%c User-User Information (len=%2d) [", prefix, len);
++ pri_message(ctrl, "%c User-User Information (len=%2d) [", prefix, len);
+ for (x=0;x<ie->len;x++)
+- pri_message(pri, " %02x", ie->data[x] & 0x7f);
+- pri_message(pri, " ]\n");
++ pri_message(ctrl, " %02x", ie->data[x] & 0x7f);
++ pri_message(ctrl, " ]\n");
+ }
+
+
+-static FUNC_RECV(receive_user_user)
++static int receive_user_user(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len)
+ {
+ call->useruserprotocoldisc = ie->data[0] & 0xff;
+ if (call->useruserprotocoldisc == 4) /* IA5 */
+@@ -1159,7 +2064,7 @@
+ return 0;
+ }
+
+-static FUNC_SEND(transmit_user_user)
++static int transmit_user_user(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order)
+ {
+ int datalen = strlen(call->useruserinfo);
+ if (datalen > 0) {
+@@ -1180,6 +2085,29 @@
+ return 0;
+ }
+
++static void dump_change_status(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix)
++{
++ int x;
++
++ pri_message(ctrl, "%c Change Status Information (len=%2d) [", prefix, len);
++ for (x=0; x<ie->len; x++) {
++ pri_message(ctrl, " %02x", ie->data[x] & 0x7f);
++ }
++ pri_message(ctrl, " ]\n");
++}
++
++static int receive_change_status(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len)
++{
++ call->changestatus = ie->data[0] & 0x0f;
++ return 0;
++}
++
++static int transmit_change_status(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order)
++{
++ ie->data[0] = 0xc0 | call->changestatus;
++ return 3;
++}
++
+ static char *prog2str(int prog)
+ {
+ static struct msgtype progs[] = {
+@@ -1222,47 +2150,83 @@
+ return code2str(loc, locs, sizeof(locs) / sizeof(locs[0]));
+ }
+
+-static FUNC_DUMP(dump_progress_indicator)
++static void dump_progress_indicator(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix)
+ {
+- pri_message(pri, "%c Progress Indicator (len=%2d) [ Ext: %d Coding: %s (%d) 0: %d Location: %s (%d)\n",
++ pri_message(ctrl, "%c Progress Indicator (len=%2d) [ Ext: %d Coding: %s (%d) 0: %d Location: %s (%d)\n",
+ prefix, len, ie->data[0] >> 7, coding2str((ie->data[0] & 0x60) >> 5), (ie->data[0] & 0x60) >> 5,
+ (ie->data[0] & 0x10) >> 4, loc2str(ie->data[0] & 0xf), ie->data[0] & 0xf);
+- pri_message(pri, "%c Ext: %d Progress Description: %s (%d) ]\n",
++ pri_message(ctrl, "%c Ext: %d Progress Description: %s (%d) ]\n",
+ prefix, ie->data[1] >> 7, prog2str(ie->data[1] & 0x7f), ie->data[1] & 0x7f);
+ }
+
+-static FUNC_RECV(receive_display)
++static int receive_display(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len)
+ {
+ unsigned char *data;
++
++ switch (msgtype) {
++ case Q931_SETUP:
++ case Q931_CONNECT:
++ /*
++ * Only keep the display message on SETUP and CONNECT messages
++ * as the remote name.
++ */
++ break;
++ default:
++ return 0;
++ }
++
++ call->remote_id.name.valid = 1;
++
+ data = ie->data;
+ if (data[0] & 0x80) {
+ /* Skip over character set */
+ data++;
+ len--;
+ }
+- q931_get_number((unsigned char *) call->callername, sizeof(call->callername), data, len - 2);
++ call->remote_id.name.char_set = PRI_CHAR_SET_ISO8859_1;
++
++ q931_get_number((unsigned char *) call->remote_id.name.str, sizeof(call->remote_id.name.str), data, len - 2);
++ if (call->remote_id.name.str[0]) {
++ call->remote_id.name.presentation = PRI_PRES_ALLOWED;
++ } else {
++ call->remote_id.name.presentation = PRI_PRES_RESTRICTED;
++ }
+ return 0;
+ }
+
+-static FUNC_SEND(transmit_display)
++static int transmit_display(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order)
+ {
++ size_t datalen;
+ int i;
+-
+- if ((pri->switchtype == PRI_SWITCH_QSIG) ||
+- ((pri->switchtype == PRI_SWITCH_EUROISDN_E1) && (pri->localtype == PRI_CPE)) ||
+- !call->callername[0])
+- return 0;
+
+ i = 0;
+- if(pri->switchtype != PRI_SWITCH_EUROISDN_E1) {
++
++ if (!call->local_id.name.valid || !call->local_id.name.str[0]) {
++ return 0;
++ }
++ switch (ctrl->switchtype) {
++ case PRI_SWITCH_QSIG:
++ /* Q.SIG supports names */
++ return 0;
++ case PRI_SWITCH_EUROISDN_E1:
++ case PRI_SWITCH_EUROISDN_T1:
++ if (ctrl->localtype == PRI_CPE) {
++ return 0;
++ }
++ break;
++ default:
++ /* Prefix name with character set indicator. */
+ ie->data[0] = 0xb1;
+ ++i;
++ break;
+ }
+- memcpy(ie->data + i, call->callername, strlen(call->callername));
+- return 2 + i + strlen(call->callername);
++
++ datalen = strlen(call->local_id.name.str);
++ memcpy(ie->data + i, call->local_id.name.str, datalen);
++ return 2 + i + datalen;
+ }
+
+-static FUNC_RECV(receive_progress_indicator)
++static int receive_progress_indicator(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len)
+ {
+ call->progloc = ie->data[0] & 0xf;
+ call->progcode = (ie->data[0] & 0x60) >> 5;
+@@ -1298,153 +2262,204 @@
+ call->progressmask |= PRI_PROG_INTERWORKING_NO_RELEASE_POST_ANSWER;
+ break;
+ default:
+- pri_error(pri, "XXX Invalid Progress indicator value received: %02x\n",(ie->data[1] & 0x7f));
++ pri_error(ctrl, "XXX Invalid Progress indicator value received: %02x\n",(ie->data[1] & 0x7f));
+ break;
+ }
+ return 0;
+ }
+
+-static FUNC_SEND(transmit_facility)
++static void q931_apdu_timeout(void *data);
++
++static int transmit_facility(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order)
+ {
+- struct apdu_event *tmp;
+- int i = 0;
++ struct apdu_event **prev;
++ struct apdu_event *cur;
++ int apdu_len;
+
+- for (tmp = call->apdus; tmp; tmp = tmp->next) {
+- if ((tmp->message == msgtype) && !tmp->sent)
++ for (prev = &call->apdus, cur = call->apdus;
++ cur;
++ prev = &cur->next, cur = cur->next) {
++ if (!cur->sent && cur->message == msgtype) {
+ break;
++ }
+ }
+-
+- if (!tmp) /* No APDU found */
++ if (!cur) {
++ /* No APDU found */
+ return 0;
++ }
+
+- if (tmp->apdu_len > 235) { /* TODO: find out how much space we can use */
+- pri_message(pri, "Requested APDU (%d bytes) is too long\n", tmp->apdu_len);
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, "Adding facility ie contents to send in %s message:\n",
++ msg2str(msgtype));
++ facility_decode_dump(ctrl, cur->apdu, cur->apdu_len);
++ }
++
++ if (len < cur->apdu_len) {
++ pri_error(ctrl,
++ "Could not fit facility ie in message. Size needed:%d Available space:%d\n",
++ cur->apdu_len + 2, len);
++
++ /* Remove APDU from list. */
++ *prev = cur->next;
++
++ if (cur->response.callback) {
++ /* Indicate to callback that the APDU had a problem getting sent. */
++ cur->response.callback(APDU_CALLBACK_REASON_ERROR, ctrl, call, cur, NULL);
++ }
++
++ free(cur);
+ return 0;
+ }
+-
+- memcpy(&ie->data[i], tmp->apdu, tmp->apdu_len);
+- i += tmp->apdu_len;
+- tmp->sent = 1;
+
+- return i + 2;
++ memcpy(ie->data, cur->apdu, cur->apdu_len);
++ apdu_len = cur->apdu_len;
++ cur->sent = 1;
++
++ if (cur->response.callback && cur->response.timeout_time) {
++ int duration;
++
++ if (0 < cur->response.timeout_time) {
++ /* Sender specified timeout duration. */
++ duration = cur->response.timeout_time;
++ } else {
++ /* Sender wants to use the typical timeout duration. */
++ duration = ctrl->timers[PRI_TIMER_T_RESPONSE];
++ }
++ cur->timer = pri_schedule_event(ctrl, duration, q931_apdu_timeout, cur);
++ if (!cur->timer) {
++ /* Remove APDU from list. */
++ *prev = cur->next;
++
++ /* Indicate to callback that the APDU had a problem getting sent. */
++ cur->response.callback(APDU_CALLBACK_REASON_ERROR, ctrl, call, cur, NULL);
++
++ free(cur);
++ }
++ } else if (!cur->timer) {
++ /* Remove APDU from list. */
++ *prev = cur->next;
++ free(cur);
++ }
++
++ return apdu_len + 2;
+ }
+
+-static FUNC_RECV(receive_facility)
++static int receive_facility(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len)
+ {
+- int i = 0;
+- int protocol, next_protocol;
+- struct rose_component *comp = NULL;
+- enum {
+- Q932_STATE_NFE, /* Network facility extension */
+- Q932_STATE_NPP, /* Network protocol profile */
+- Q932_STATE_INTERPRETATION, /* Interpretation component */
+- Q932_STATE_SERVICE /* Service component(s) */
+- } state = Q932_STATE_SERVICE;
+-#define Q932_HANDLE_PROC(component, my_state, name, handler) \
+- case component: \
+- if(state > my_state) { \
+- pri_error(pri, "!! %s component received in wrong place\n"); \
+- break; \
+- } \
+- state = my_state; \
+- if (pri->debug) \
+- pri_message(pri, "Handle Q.932 %s component\n", name); \
+- (handler)(pri, call, ie, comp->data, comp->len); \
+- break;
+-#define Q932_HANDLE_NULL(component, my_state, name, handle) \
+- case component: \
+- if(state > my_state) { \
+- pri_error(pri, "!! %s component received in wrong place\n"); \
+- break; \
+- } \
+- state = my_state; \
+- if (pri->debug & PRI_DEBUG_APDU) \
+- pri_message(pri, "Q.932 %s component is not handled\n", name); \
+- break;
+-
+- if (ie->len < 1)
++ /* Delay processing facility ie's till after all other ie's are processed. */
++ if (MAX_FACILITY_IES <= ctrl->facility.count) {
++ pri_message(ctrl, "!! Too many facility ie's to delay.\n");
+ return -1;
++ }
++ /* Make sure we have enough room for the protocol profile ie octet(s) */
++ if (ie->data + ie->len < ie->data + 2) {
++ return -1;
++ }
+
+- switch(next_protocol = protocol = (ie->data[i] & 0x1f)) {
+- case Q932_PROTOCOL_CMIP:
+- case Q932_PROTOCOL_ACSE:
+- if (pri->debug & PRI_DEBUG_APDU)
+- pri_message(pri, "!! Don't know how to handle Q.932 Protocol Profile of type 0x%X\n", protocol);
++ /* Save the facility ie location for delayed decode. */
++ ctrl->facility.ie[ctrl->facility.count] = ie;
++ ctrl->facility.codeset[ctrl->facility.count] = Q931_IE_CODESET((unsigned) full_ie);
++ ++ctrl->facility.count;
++ return 0;
++}
++
++static int process_facility(struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie)
++{
++ struct fac_extension_header header;
++ struct rose_message rose;
++ const unsigned char *pos;
++ const unsigned char *end;
++
++ pos = ie->data;
++ end = ie->data + ie->len;
++
++ /* Make sure we have enough room for the protocol profile ie octet(s) */
++ if (end < pos + 2) {
+ return -1;
++ }
++ switch (*pos & Q932_PROTOCOL_MASK) {
++ case Q932_PROTOCOL_ROSE:
+ case Q932_PROTOCOL_EXTENSIONS:
+- state = Q932_STATE_NFE;
+- next_protocol = Q932_PROTOCOL_ROSE;
+ break;
+- case Q932_PROTOCOL_ROSE:
+- break;
+ default:
+- pri_error(pri, "!! Invalid Q.932 Protocol Profile of type 0x%X received\n", protocol);
++ case Q932_PROTOCOL_CMIP:
++ case Q932_PROTOCOL_ACSE:
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl,
++ "!! Don't know how to handle Q.932 Protocol Profile type 0x%X\n",
++ *pos & Q932_PROTOCOL_MASK);
++ }
+ return -1;
+ }
+- /* Service indicator octet - Just ignore for now */
+- if (!(ie->data[i] & 0x80))
+- i++;
+- i++;
++ if (!(*pos & 0x80)) {
++ /* DMS-100 Service indicator octet - Just ignore for now */
++ ++pos;
++ }
++ ++pos;
+
+- if (ie->len < 3)
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ asn1_dump(ctrl, pos, end);
++ }
++
++ pos = fac_dec_extension_header(ctrl, pos, end, &header);
++ if (!pos) {
+ return -1;
+-
+- while ((i+1 < ie->len) && (&ie->data[i])) {
+- comp = (struct rose_component*)&ie->data[i];
+- if (comp->type) {
+- if (protocol == Q932_PROTOCOL_EXTENSIONS) {
+- switch (comp->type) {
+- Q932_HANDLE_NULL(COMP_TYPE_INTERPRETATION, Q932_STATE_INTERPRETATION, "Interpretation", NULL);
+- Q932_HANDLE_NULL(COMP_TYPE_NFE, Q932_STATE_NFE, "Network facility extensions", NULL);
+- Q932_HANDLE_NULL(COMP_TYPE_NETWORK_PROTOCOL_PROFILE, Q932_STATE_NPP, "Network protocol profile", NULL);
+- default:
+- protocol = next_protocol;
+- break;
+- }
+- }
+- switch (protocol) {
+- case Q932_PROTOCOL_ROSE:
+- switch (comp->type) {
+- Q932_HANDLE_PROC(COMP_TYPE_INVOKE, Q932_STATE_SERVICE, "ROSE Invoke", rose_invoke_decode);
+- Q932_HANDLE_PROC(COMP_TYPE_RETURN_RESULT, Q932_STATE_SERVICE, "ROSE return result", rose_return_result_decode);
+- Q932_HANDLE_PROC(COMP_TYPE_RETURN_ERROR, Q932_STATE_SERVICE, "ROSE return error", rose_return_error_decode);
+- Q932_HANDLE_PROC(COMP_TYPE_REJECT, Q932_STATE_SERVICE, "ROSE reject", rose_reject_decode);
+- default:
+- if (pri->debug & PRI_DEBUG_APDU)
+- pri_message(pri, "Don't know how to handle ROSE component of type 0x%X\n", comp->type);
+- break;
+- }
+- break;
+- case Q932_PROTOCOL_CMIP:
+- switch (comp->type) {
+- default:
+- if (pri->debug & PRI_DEBUG_APDU)
+- pri_message(pri, "Don't know how to handle CMIP component of type 0x%X\n", comp->type);
+- break;
+- }
+- break;
+- case Q932_PROTOCOL_ACSE:
+- switch (comp->type) {
+- default:
+- if (pri->debug & PRI_DEBUG_APDU)
+- pri_message(pri, "Don't know how to handle ACSE component of type 0x%X\n", comp->type);
+- break;
+- }
+- break;
+- }
++ }
++ if (header.npp_present) {
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl,
++ "!! Don't know how to handle Network Protocol Profile type 0x%X\n",
++ header.npp);
+ }
+- i += (comp->len + 2);
++ return -1;
+ }
+-#undef Q932_HANDLE
+
++ pos = rose_decode(ctrl, pos, end, &rose);
++ if (!pos) {
++ return -1;
++ }
++ switch (rose.type) {
++ case ROSE_COMP_TYPE_INVOKE:
++ rose_handle_invoke(ctrl, call, msgtype, ie, &header, &rose.component.invoke);
++ break;
++ case ROSE_COMP_TYPE_RESULT:
++ rose_handle_result(ctrl, call, msgtype, ie, &header, &rose.component.result);
++ break;
++ case ROSE_COMP_TYPE_ERROR:
++ rose_handle_error(ctrl, call, msgtype, ie, &header, &rose.component.error);
++ break;
++ case ROSE_COMP_TYPE_REJECT:
++ rose_handle_reject(ctrl, call, msgtype, ie, &header, &rose.component.reject);
++ break;
++ default:
++ return -1;
++ }
+ return 0;
+ }
+
+-static FUNC_SEND(transmit_progress_indicator)
++static void q931_handle_facilities(struct pri *ctrl, q931_call *call, int msgtype)
+ {
++ unsigned idx;
++ unsigned codeset;
++ unsigned full_ie;
++ q931_ie *ie;
++
++ for (idx = 0; idx < ctrl->facility.count; ++idx) {
++ ie = ctrl->facility.ie[idx];
++ if (ctrl->debug & PRI_DEBUG_Q931_STATE) {
++ codeset = ctrl->facility.codeset[idx];
++ full_ie = Q931_FULL_IE(codeset, ie->ie);
++ pri_message(ctrl, "-- Delayed processing IE %d (cs%d, %s)\n", ie->ie, codeset, ie2str(full_ie));
++ }
++ process_facility(ctrl, call, msgtype, ie);
++ }
++}
++
++static int transmit_progress_indicator(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order)
++{
+ int code, mask;
+ /* Can't send progress indicator on GR-303 -- EVER! */
+- if (pri->subchannel && !pri->bri)
++ if (ctrl->subchannel && !ctrl->bri)
+ return 0;
+ if (call->progressmask > 0) {
+ if (call->progressmask & (mask = PRI_PROG_CALL_NOT_E2E_ISDN))
+@@ -1467,7 +2482,7 @@
+ code = Q931_PROG_INTERWORKING_NO_RELEASE_POST_ANSWER;
+ else {
+ code = 0;
+- pri_error(pri, "XXX Undefined progress bit: %x\n", call->progressmask);
++ pri_error(ctrl, "XXX Undefined progress bit: %x\n", call->progressmask);
+ }
+ if (code) {
+ ie->data[0] = 0x80 | (call->progcode << 5) | (call->progloc);
+@@ -1479,82 +2494,139 @@
+ /* Leave off */
+ return 0;
+ }
+-static FUNC_SEND(transmit_call_state)
++static int transmit_call_state(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order)
+ {
+- if (call->ourcallstate > -1 ) {
++ ie->data[0] = Q931_CALL_STATE_NULL;
++ switch (call->ourcallstate) {
++ case Q931_CALL_STATE_NULL:
++ case Q931_CALL_STATE_CALL_INITIATED:
++ case Q931_CALL_STATE_OVERLAP_SENDING:
++ case Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING:
++ case Q931_CALL_STATE_CALL_DELIVERED:
++ case Q931_CALL_STATE_CALL_PRESENT:
++ case Q931_CALL_STATE_CALL_RECEIVED:
++ case Q931_CALL_STATE_CONNECT_REQUEST:
++ case Q931_CALL_STATE_INCOMING_CALL_PROCEEDING:
++ case Q931_CALL_STATE_ACTIVE:
++ case Q931_CALL_STATE_DISCONNECT_REQUEST:
++ case Q931_CALL_STATE_DISCONNECT_INDICATION:
++ case Q931_CALL_STATE_SUSPEND_REQUEST:
++ case Q931_CALL_STATE_RESUME_REQUEST:
++ case Q931_CALL_STATE_RELEASE_REQUEST:
++ case Q931_CALL_STATE_CALL_ABORT:
++ case Q931_CALL_STATE_OVERLAP_RECEIVING:
++ case Q931_CALL_STATE_CALL_INDEPENDENT_SERVICE:
++ case Q931_CALL_STATE_RESTART_REQUEST:
++ case Q931_CALL_STATE_RESTART:
+ ie->data[0] = call->ourcallstate;
+- return 3;
++ break;
++ case Q931_CALL_STATE_NOT_SET:
++ break;
+ }
+- return 0;
++ return 3;
+ }
+
+-static FUNC_RECV(receive_call_state)
++static int receive_call_state(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len)
+ {
+ call->sugcallstate = ie->data[0] & 0x3f;
+ return 0;
+ }
+
+-static char *callstate2str(int callstate)
++/*!
++ * \brief Convert the internal Q.931 call state to a string.
++ *
++ * \param callstate Internal Q.931 call state.
++ *
++ * \return String equivalent of the given Q.931 call state.
++ */
++const char *q931_call_state_str(enum Q931_CALL_STATE callstate)
+ {
+ static struct msgtype callstates[] = {
+- { 0, "Null" },
+- { 1, "Call Initiated" },
+- { 2, "Overlap sending" },
+- { 3, "Outgoing call Proceeding" },
+- { 4, "Call Delivered" },
+- { 6, "Call Present" },
+- { 7, "Call Received" },
+- { 8, "Connect Request" },
+- { 9, "Incoming Call Proceeding" },
+- { 10, "Active" },
+- { 11, "Disconnect Request" },
+- { 12, "Disconnect Indication" },
+- { 15, "Suspend Request" },
+- { 17, "Resume Request" },
+- { 19, "Release Request" },
+- { 22, "Call Abort" },
+- { 25, "Overlap Receiving" },
+- { 61, "Restart Request" },
+- { 62, "Restart" },
++/* *INDENT-OFF* */
++ { Q931_CALL_STATE_NULL, "Null" },
++ { Q931_CALL_STATE_CALL_INITIATED, "Call Initiated" },
++ { Q931_CALL_STATE_OVERLAP_SENDING, "Overlap Sending" },
++ { Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING, "Outgoing Call Proceeding" },
++ { Q931_CALL_STATE_CALL_DELIVERED, "Call Delivered" },
++ { Q931_CALL_STATE_CALL_PRESENT, "Call Present" },
++ { Q931_CALL_STATE_CALL_RECEIVED, "Call Received" },
++ { Q931_CALL_STATE_CONNECT_REQUEST, "Connect Request" },
++ { Q931_CALL_STATE_INCOMING_CALL_PROCEEDING, "Incoming Call Proceeding" },
++ { Q931_CALL_STATE_ACTIVE, "Active" },
++ { Q931_CALL_STATE_DISCONNECT_REQUEST, "Disconnect Request" },
++ { Q931_CALL_STATE_DISCONNECT_INDICATION, "Disconnect Indication" },
++ { Q931_CALL_STATE_SUSPEND_REQUEST, "Suspend Request" },
++ { Q931_CALL_STATE_RESUME_REQUEST, "Resume Request" },
++ { Q931_CALL_STATE_RELEASE_REQUEST, "Release Request" },
++ { Q931_CALL_STATE_CALL_ABORT, "Call Abort" },
++ { Q931_CALL_STATE_OVERLAP_RECEIVING, "Overlap Receiving" },
++ { Q931_CALL_STATE_CALL_INDEPENDENT_SERVICE, "Call Independent Service" },
++ { Q931_CALL_STATE_RESTART_REQUEST, "Restart Request" },
++ { Q931_CALL_STATE_RESTART, "Restart" },
++ { Q931_CALL_STATE_NOT_SET, "Not set. Internal use only." },
++/* *INDENT-ON* */
+ };
+- return code2str(callstate, callstates, sizeof(callstates) / sizeof(callstates[0]));
++ return code2str(callstate, callstates, ARRAY_LEN(callstates));
+ }
+
+-static FUNC_DUMP(dump_call_state)
++/*!
++ * \internal
++ * \brief Convert the Q.932 supplementary hold state to a string.
++ *
++ * \param state Q.932 supplementary hold state.
++ *
++ * \return String equivalent of the given hold state.
++ */
++static const char *q931_hold_state_str(enum Q931_HOLD_STATE state)
+ {
+- pri_message(pri, "%c Call State (len=%2d) [ Ext: %d Coding: %s (%d) Call state: %s (%d)\n",
++ static struct msgtype hold_states[] = {
++/* *INDENT-OFF* */
++ { Q931_HOLD_STATE_IDLE, "Idle" },
++ { Q931_HOLD_STATE_HOLD_REQ, "Hold Request" },
++ { Q931_HOLD_STATE_HOLD_IND, "Hold Indication" },
++ { Q931_HOLD_STATE_CALL_HELD, "Call Held" },
++ { Q931_HOLD_STATE_RETRIEVE_REQ, "Retrieve Request" },
++ { Q931_HOLD_STATE_RETRIEVE_IND, "Retrieve Indication" },
++/* *INDENT-ON* */
++ };
++ return code2str(state, hold_states, ARRAY_LEN(hold_states));
++}
++
++static void dump_call_state(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix)
++{
++ pri_message(ctrl, "%c Call State (len=%2d) [ Ext: %d Coding: %s (%d) Call state: %s (%d)\n",
+ prefix, len, ie->data[0] >> 7, coding2str((ie->data[0] & 0xC0) >> 6), (ie->data[0] & 0xC0) >> 6,
+- callstate2str(ie->data[0] & 0x3f), ie->data[0] & 0x3f);
++ q931_call_state_str(ie->data[0] & 0x3f), ie->data[0] & 0x3f);
+ }
+
+-static FUNC_DUMP(dump_call_identity)
++static void dump_call_identity(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix)
+ {
+ int x;
+- pri_message(pri, "%c Call Identity (len=%2d) [ ", prefix, len);
++ pri_message(ctrl, "%c Call Identity (len=%2d) [ ", prefix, len);
+ for (x=0;x<ie->len;x++)
+- pri_message(pri, "0x%02X ", ie->data[x]);
+- pri_message(pri, " ]\n");
++ pri_message(ctrl, "0x%02X ", ie->data[x]);
++ pri_message(ctrl, " ]\n");
+ }
+
+-static FUNC_DUMP(dump_time_date)
++static void dump_time_date(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix)
+ {
+- pri_message(pri, "%c Time Date (len=%2d) [ ", prefix, len);
++ pri_message(ctrl, "%c Time Date (len=%2d) [ ", prefix, len);
+ if (ie->len > 0)
+- pri_message(pri, "%02d", ie->data[0]);
++ pri_message(ctrl, "%02d", ie->data[0]);
+ if (ie->len > 1)
+- pri_message(pri, "-%02d", ie->data[1]);
++ pri_message(ctrl, "-%02d", ie->data[1]);
+ if (ie->len > 2)
+- pri_message(pri, "-%02d", ie->data[2]);
++ pri_message(ctrl, "-%02d", ie->data[2]);
+ if (ie->len > 3)
+- pri_message(pri, " %02d", ie->data[3]);
++ pri_message(ctrl, " %02d", ie->data[3]);
+ if (ie->len > 4)
+- pri_message(pri, ":%02d", ie->data[4]);
++ pri_message(ctrl, ":%02d", ie->data[4]);
+ if (ie->len > 5)
+- pri_message(pri, ":%02d", ie->data[5]);
+- pri_message(pri, " ]\n");
++ pri_message(ctrl, ":%02d", ie->data[5]);
++ pri_message(ctrl, " ]\n");
+ }
+
+-static FUNC_DUMP(dump_keypad_facility)
++static void dump_keypad_facility(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix)
+ {
+ char tmp[64];
+
+@@ -1563,10 +2635,10 @@
+
+ memcpy(tmp, ie->data, ie->len);
+ tmp[ie->len] = '\0';
+- pri_message(pri, "%c Keypad Facility (len=%2d) [ %s ]\n", prefix, ie->len, tmp );
++ pri_message(ctrl, "%c Keypad Facility (len=%2d) [ %s ]\n", prefix, ie->len, tmp );
+ }
+
+-static FUNC_RECV(receive_keypad_facility)
++static int receive_keypad_facility(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len)
+ {
+ int mylen;
+
+@@ -1584,27 +2656,19 @@
+ return 0;
+ }
+
+-static FUNC_SEND(transmit_keypad_facility)
++static int transmit_keypad_facility(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order)
+ {
+ int sublen;
+
+ sublen = strlen(call->keypad_digits);
+-
+- if (sublen > 32) {
+- sublen = 32;
+- call->keypad_digits[32] = '\0';
+- }
+-
+ if (sublen) {
+- libpri_copy_string((char *)ie->data, (char *)call->keypad_digits, sizeof(call->keypad_digits));
+- /* Make sure we clear the field */
+- call->keypad_digits[0] = '\0';
++ libpri_copy_string((char *) ie->data, call->keypad_digits, sizeof(call->keypad_digits));
+ return sublen + 2;
+ } else
+ return 0;
+ }
+
+-static FUNC_DUMP(dump_display)
++static void dump_display(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix)
+ {
+ int x, y;
+ char *buf = malloc(len + 1);
+@@ -1618,7 +2682,7 @@
+ for (y=x; x<ie->len; x++)
+ buf[x] = ie->data[x] & 0x7f;
+ buf[x] = '\0';
+- pri_message(pri, "%c Display (len=%2d) %s[ %s ]\n", prefix, ie->len, tmp, &buf[y]);
++ pri_message(ctrl, "%c Display (len=%2d) %s[ %s ]\n", prefix, ie->len, tmp, &buf[y]);
+ free(buf);
+ }
+ }
+@@ -1626,10 +2690,10 @@
+ #define CHECK_OVERFLOW(limit) \
+ if (tmpptr - tmp + limit >= sizeof(tmp)) { \
+ *tmpptr = '\0'; \
+- pri_message(pri, "%s", tmpptr = tmp); \
++ pri_message(ctrl, "%s", tmpptr = tmp); \
+ }
+
+-static void dump_ie_data(struct pri *pri, unsigned char *c, int len)
++static void dump_ie_data(struct pri *ctrl, unsigned char *c, int len)
+ {
+ static char hexs[16] = "0123456789ABCDEF";
+ char tmp[1024], *tmpptr;
+@@ -1665,47 +2729,54 @@
+ if (lastascii)
+ *tmpptr++ = '\'';
+ *tmpptr = '\0';
+- pri_message(pri, "%s", tmp);
++ pri_message(ctrl, "%s", tmp);
+ }
+
+-static FUNC_DUMP(dump_facility)
++static void dump_facility(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix)
+ {
+- int dataat = (ie->data[0] & 0x80) ? 1 : 2;
+- pri_message(pri, "%c Facility (len=%2d, codeset=%d) [ ", prefix, len, Q931_IE_CODESET(full_ie));
+- dump_ie_data(pri, ie->data, ie->len);
+- pri_message(NULL, " ]\n");
++ pri_message(ctrl, "%c Facility (len=%2d, codeset=%d) [ ", prefix, len, Q931_IE_CODESET(full_ie));
++ dump_ie_data(ctrl, ie->data, ie->len);
++ pri_message(ctrl, " ]\n");
++#if 0 /* Lets not dump parse of facility contents here anymore. */
++ /*
++ * The ASN.1 decode dump has already been done when the facility ie was added to the outgoing
++ * message or the ASN.1 decode dump will be done when the facility ie is processed on incoming
++ * messages. This dump is redundant and very noisy.
++ */
+ if (ie->len > 1) {
+- pri_message(pri, "PROTOCOL %02X\n", ie->data[0] & ASN1_TYPE_MASK);
+- asn1_dump(pri, &ie->data[dataat], ie->len - dataat);
++ int dataat = (ie->data[0] & 0x80) ? 1 : 2;
++
++ pri_message(ctrl, "PROTOCOL %02X\n", ie->data[0] & Q932_PROTOCOL_MASK);
++ asn1_dump(ctrl, ie->data + dataat, ie->data + ie->len);
+ }
+-
++#endif /* Lets not dump parse of facility contents here anymore. */
+ }
+
+-static FUNC_DUMP(dump_network_spec_fac)
++static void dump_network_spec_fac(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix)
+ {
+- pri_message(pri, "%c Network-Specific Facilities (len=%2d) [ ", prefix, ie->len);
++ pri_message(ctrl, "%c Network-Specific Facilities (len=%2d) [ ", prefix, ie->len);
+ if (ie->data[0] == 0x00) {
+- pri_message(pri, "%s", code2str(ie->data[1], facilities, sizeof(facilities) / sizeof(facilities[0])));
++ pri_message(ctrl, "%s", code2str(ie->data[1], facilities, ARRAY_LEN(facilities)));
+ }
+ else
+- dump_ie_data(pri, ie->data, ie->len);
+- pri_message(pri, " ]\n");
++ dump_ie_data(ctrl, ie->data, ie->len);
++ pri_message(ctrl, " ]\n");
+ }
+
+-static FUNC_RECV(receive_network_spec_fac)
++static int receive_network_spec_fac(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len)
+ {
+ return 0;
+ }
+
+-static FUNC_SEND(transmit_network_spec_fac)
++static int transmit_network_spec_fac(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order)
+ {
+ /* We are ready to transmit single IE only */
+ if (order > 1)
+ return 0;
+
+- if (pri->nsf != PRI_NSF_NONE) {
++ if (ctrl->nsf != PRI_NSF_NONE) {
+ ie->data[0] = 0x00;
+- ie->data[1] = pri->nsf;
++ ie->data[1] = ctrl->nsf;
+ return 4;
+ }
+ /* Leave off */
+@@ -1732,13 +2803,13 @@
+ return code2str(cause, causeclasses, sizeof(causeclasses) / sizeof(causeclasses[0]));
+ }
+
+-static FUNC_DUMP(dump_cause)
++static void dump_cause(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix)
+ {
+ int x;
+- pri_message(pri, "%c Cause (len=%2d) [ Ext: %d Coding: %s (%d) Spare: %d Location: %s (%d)\n",
++ pri_message(ctrl, "%c Cause (len=%2d) [ Ext: %d Coding: %s (%d) Spare: %d Location: %s (%d)\n",
+ prefix, len, ie->data[0] >> 7, coding2str((ie->data[0] & 0x60) >> 5), (ie->data[0] & 0x60) >> 5,
+ (ie->data[0] & 0x10) >> 4, loc2str(ie->data[0] & 0xf), ie->data[0] & 0xf);
+- pri_message(pri, "%c Ext: %d Cause: %s (%d), class = %s (%d) ]\n",
++ pri_message(ctrl, "%c Ext: %d Cause: %s (%d), class = %s (%d) ]\n",
+ prefix, (ie->data[1] >> 7), pri_cause2str(ie->data[1] & 0x7f), ie->data[1] & 0x7f,
+ pri_causeclass2str((ie->data[1] & 0x7f) >> 4), (ie->data[1] & 0x7f) >> 4);
+ if (ie->len < 3)
+@@ -1747,29 +2818,29 @@
+ switch(ie->data[1] & 0x7f) {
+ case PRI_CAUSE_IE_NONEXIST:
+ for (x=2;x<ie->len;x++)
+- pri_message(pri, "%c Cause data %d: %02x (%d, %s IE)\n", prefix, x-1, ie->data[x], ie->data[x], ie2str(ie->data[x]));
++ pri_message(ctrl, "%c Cause data %d: %02x (%d, %s IE)\n", prefix, x-1, ie->data[x], ie->data[x], ie2str(ie->data[x]));
+ break;
+ case PRI_CAUSE_WRONG_CALL_STATE:
+ for (x=2;x<ie->len;x++)
+- pri_message(pri, "%c Cause data %d: %02x (%d, %s message)\n", prefix, x-1, ie->data[x], ie->data[x], msg2str(ie->data[x]));
++ pri_message(ctrl, "%c Cause data %d: %02x (%d, %s message)\n", prefix, x-1, ie->data[x], ie->data[x], msg2str(ie->data[x]));
+ break;
+ case PRI_CAUSE_RECOVERY_ON_TIMER_EXPIRE:
+- pri_message(pri, "%c Cause data:", prefix);
++ pri_message(ctrl, "%c Cause data:", prefix);
+ for (x=2;x<ie->len;x++)
+- pri_message(pri, " %02x", ie->data[x]);
+- pri_message(pri, " (Timer T");
++ pri_message(ctrl, " %02x", ie->data[x]);
++ pri_message(ctrl, " (Timer T");
+ for (x=2;x<ie->len;x++)
+- pri_message(pri, "%c", ((ie->data[x] >= ' ') && (ie->data[x] < 0x7f)) ? ie->data[x] : '.');
+- pri_message(pri, ")\n");
++ pri_message(ctrl, "%c", ((ie->data[x] >= ' ') && (ie->data[x] < 0x7f)) ? ie->data[x] : '.');
++ pri_message(ctrl, ")\n");
+ break;
+ default:
+ for (x=2;x<ie->len;x++)
+- pri_message(pri, "%c Cause data %d: %02x (%d)\n", prefix, x-1, ie->data[x], ie->data[x]);
++ pri_message(ctrl, "%c Cause data %d: %02x (%d)\n", prefix, x-1, ie->data[x], ie->data[x]);
+ break;
+ }
+ }
+
+-static FUNC_RECV(receive_cause)
++static int receive_cause(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len)
+ {
+ call->causeloc = ie->data[0] & 0xf;
+ call->causecode = (ie->data[0] & 0x60) >> 5;
+@@ -1777,7 +2848,7 @@
+ return 0;
+ }
+
+-static FUNC_SEND(transmit_cause)
++static int transmit_cause(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order)
+ {
+ /* We are ready to transmit single IE only */
+ if (order > 1)
+@@ -1793,23 +2864,23 @@
+ }
+ }
+
+-static FUNC_DUMP(dump_sending_complete)
++static void dump_sending_complete(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix)
+ {
+- pri_message(pri, "%c Sending Complete (len=%2d)\n", prefix, len);
++ pri_message(ctrl, "%c Sending Complete (len=%2d)\n", prefix, len);
+ }
+
+-static FUNC_RECV(receive_sending_complete)
++static int receive_sending_complete(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len)
+ {
+ /* We've got a "Complete" message: Exect no further digits. */
+ call->complete = 1;
+ return 0;
+ }
+
+-static FUNC_SEND(transmit_sending_complete)
++static int transmit_sending_complete(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order)
+ {
+- if ((pri->overlapdial && call->complete) || /* Explicit */
+- (!pri->overlapdial && ((pri->switchtype == PRI_SWITCH_EUROISDN_E1) ||
+- /* Implicit */ (pri->switchtype == PRI_SWITCH_EUROISDN_T1)))) {
++ if ((ctrl->overlapdial && call->complete) || /* Explicit */
++ (!ctrl->overlapdial && ((ctrl->switchtype == PRI_SWITCH_EUROISDN_E1) ||
++ /* Implicit */ (ctrl->switchtype == PRI_SWITCH_EUROISDN_T1)))) {
+ /* Include this single-byte IE */
+ return 1;
+ }
+@@ -1846,18 +2917,18 @@
+ return code2str(info, notifies, sizeof(notifies) / sizeof(notifies[0]));
+ }
+
+-static FUNC_DUMP(dump_notify)
++static void dump_notify(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix)
+ {
+- pri_message(pri, "%c Notification indicator (len=%2d): Ext: %d %s (%d)\n", prefix, len, ie->data[0] >> 7, notify2str(ie->data[0] & 0x7f), ie->data[0] & 0x7f);
++ pri_message(ctrl, "%c Notification indicator (len=%2d): Ext: %d %s (%d)\n", prefix, len, ie->data[0] >> 7, notify2str(ie->data[0] & 0x7f), ie->data[0] & 0x7f);
+ }
+
+-static FUNC_RECV(receive_notify)
++static int receive_notify(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len)
+ {
+ call->notify = ie->data[0] & 0x7F;
+ return 0;
+ }
+
+-static FUNC_SEND(transmit_notify)
++static int transmit_notify(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order)
+ {
+ if (call->notify >= 0) {
+ ie->data[0] = 0x80 | call->notify;
+@@ -1866,9 +2937,9 @@
+ return 0;
+ }
+
+-static FUNC_DUMP(dump_shift)
++static void dump_shift(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix)
+ {
+- pri_message(pri, "%c %sLocking Shift (len=%02d): Requested codeset %d\n", prefix, (full_ie & 8) ? "Non-" : "", len, full_ie & 7);
++ pri_message(ctrl, "%c %sLocking Shift (len=%02d): Requested codeset %d\n", prefix, (full_ie & 8) ? "Non-" : "", len, full_ie & 7);
+ }
+
+ static char *lineinfo2str(int info)
+@@ -1903,21 +2974,21 @@
+ return code2str(info, lineinfo, sizeof(lineinfo) / sizeof(lineinfo[0]));
+ }
+
+-static FUNC_DUMP(dump_line_information)
++static void dump_line_information(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix)
+ {
+- pri_message(pri, "%c Originating Line Information (len=%02d): %s (%d)\n", prefix, len, lineinfo2str(ie->data[0]), ie->data[0]);
++ pri_message(ctrl, "%c Originating Line Information (len=%02d): %s (%d)\n", prefix, len, lineinfo2str(ie->data[0]), ie->data[0]);
+ }
+
+-static FUNC_RECV(receive_line_information)
++static int receive_line_information(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len)
+ {
+ call->ani2 = ie->data[0];
+ return 0;
+ }
+
+-static FUNC_SEND(transmit_line_information)
++static int transmit_line_information(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order)
+ {
+ #if 0 /* XXX Is this IE possible for 4ESS only? XXX */
+- if(pri->switchtype == PRI_SWITCH_ATT4ESS) {
++ if(ctrl->switchtype == PRI_SWITCH_ATT4ESS) {
+ ie->data[0] = 0;
+ return 3;
+ }
+@@ -1953,53 +3024,54 @@
+ return code2str(type, gdtype, sizeof(gdtype) / sizeof(gdtype[0]));
+ }
+
+-static FUNC_DUMP(dump_generic_digits)
++static void dump_generic_digits(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix)
+ {
+ int encoding;
+ int type;
+ int idx;
+ int value;
+ if (len < 3) {
+- pri_message(pri, "%c Generic Digits (len=%02d): Invalid length\n", prefix, len);
++ pri_message(ctrl, "%c Generic Digits (len=%02d): Invalid length\n", prefix, len);
+ return;
+ }
+ encoding = (ie->data[0] >> 5) & 7;
+ type = ie->data[0] & 0x1F;
+- pri_message(pri, "%c Generic Digits (len=%02d): Encoding %s Type %s\n", prefix, len, gdencoding2str(encoding), gdtype2str(type));
++ pri_message(ctrl, "%c Generic Digits (len=%02d): Encoding %s Type %s\n", prefix, len, gdencoding2str(encoding), gdtype2str(type));
+ if (encoding == 3) { /* Binary */
+- pri_message(pri, "%c Don't know how to handle binary encoding\n");
++ pri_message(ctrl, "%c Don't know how to handle binary encoding\n",
++ prefix);
+ return;
+ }
+ if (len == 3) /* No number information */
+ return;
+- pri_message(pri, "%c Digits: ");
++ pri_message(ctrl, "%c Digits: ", prefix);
+ value = 0;
+ for(idx = 3; idx < len; ++idx) {
+ switch(encoding) {
+ case 0: /* BCD even */
+ case 1: /* BCD odd */
+- pri_message(pri, "%d", ie->data[idx-2] & 0x0f);
++ pri_message(ctrl, "%d", ie->data[idx-2] & 0x0f);
+ value = value * 10 + (ie->data[idx-2] & 0x0f);
+ if(!encoding || (idx+1 < len)) { /* Special handling for BCD odd */
+- pri_message(pri, "%d", (ie->data[idx-2] >> 4) & 0x0f);
++ pri_message(ctrl, "%d", (ie->data[idx-2] >> 4) & 0x0f);
+ value = value * 10 + ((ie->data[idx-2] >> 4) & 0x0f);
+ }
+ break;
+ case 2: /* IA5 */
+- pri_message(pri, "%c", ie->data[idx-2]);
++ pri_message(ctrl, "%c", ie->data[idx-2]);
+ value = value * 10 + ie->data[idx-2] - '0';
+ break;
+ }
+ }
+ switch(type) {
+ case 4: /* Info Digits */
+- pri_message(pri, " - %s", lineinfo2str(value));
++ pri_message(ctrl, " - %s", lineinfo2str(value));
+ break;
+ }
+- pri_message(pri, "\n");
++ pri_message(ctrl, "\n");
+ }
+
+-static FUNC_RECV(receive_generic_digits)
++static int receive_generic_digits(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len)
+ {
+ int encoding;
+ int type;
+@@ -2009,13 +3081,13 @@
+ char number[260];
+
+ if (len < 3) {
+- pri_error(pri, "Invalid length of Generic Digits IE\n");
++ pri_error(ctrl, "Invalid length of Generic Digits IE\n");