[svn-commits] rmudgett: branch 1.4 r1714 - in /branches/1.4: ./ doc/

SVN commits to the Digium repositories svn-commits at lists.digium.com
Wed May 26 11:01:16 CDT 2010


Author: rmudgett
Date: Wed May 26 11:01:10 2010
New Revision: 1714

URL: http://svnview.digium.com/svn/libpri?view=rev&rev=1714
Log:
Add Call Completion Suppplementary Service

Call Completion Supplementary Service (CCSS) added for the following 
switch types: ETSI PTMP, ETSI PTP, Q.SIG.  

Specifications:
ETS 300 359 CCBS for PTMP and PTP
ETS 301 065 CCNR for PTMP and PTP
ECMA-186 Call Completion for Q.SIG

Several support services were added to support CC:
Dummy Call Reference.
Q.931 REGISTER message.
Dynamic expansion of the number of available timers (up to 8192).
Enhanced facility message handling.

Current implementation limitations preclude the following:
CC service retention is not supported.
Q.SIG path reservation is not supported.

(closes issue #14292)
Reported by: tomaso
Tested by: rmudgett

JIRA SWP-1493

Review:	https://reviewboard.asterisk.org/r/522/

Added:
    branches/1.4/doc/
      - copied from r1704, team/group/ccss/doc/
    branches/1.4/doc/cc_ptmp_agent.fsm
      - copied unchanged from r1704, team/group/ccss/doc/cc_ptmp_agent.fsm
    branches/1.4/doc/cc_ptmp_agent_flattened.fsm
      - copied unchanged from r1704, team/group/ccss/doc/cc_ptmp_agent_flattened.fsm
    branches/1.4/doc/cc_ptmp_monitor.fsm
      - copied unchanged from r1704, team/group/ccss/doc/cc_ptmp_monitor.fsm
    branches/1.4/doc/cc_ptmp_monitor_flattened.fsm
      - copied unchanged from r1704, team/group/ccss/doc/cc_ptmp_monitor_flattened.fsm
    branches/1.4/doc/cc_ptp_agent.fsm
      - copied unchanged from r1704, team/group/ccss/doc/cc_ptp_agent.fsm
    branches/1.4/doc/cc_ptp_agent_flattened.fsm
      - copied unchanged from r1704, team/group/ccss/doc/cc_ptp_agent_flattened.fsm
    branches/1.4/doc/cc_ptp_monitor.fsm
      - copied unchanged from r1704, team/group/ccss/doc/cc_ptp_monitor.fsm
    branches/1.4/doc/cc_ptp_monitor_flattened.fsm
      - copied unchanged from r1704, team/group/ccss/doc/cc_ptp_monitor_flattened.fsm
    branches/1.4/doc/cc_qsig_agent.fsm
      - copied unchanged from r1704, team/group/ccss/doc/cc_qsig_agent.fsm
    branches/1.4/doc/cc_qsig_agent_flattened.fsm
      - copied unchanged from r1704, team/group/ccss/doc/cc_qsig_agent_flattened.fsm
    branches/1.4/doc/cc_qsig_monitor.fsm
      - copied unchanged from r1704, team/group/ccss/doc/cc_qsig_monitor.fsm
    branches/1.4/doc/cc_qsig_monitor_flattened.fsm
      - copied unchanged from r1704, team/group/ccss/doc/cc_qsig_monitor_flattened.fsm
    branches/1.4/pri_cc.c
      - copied unchanged from r1704, team/group/ccss/pri_cc.c
    branches/1.4/rose_etsi_cc.c
      - copied unchanged from r1704, team/group/ccss/rose_etsi_cc.c
    branches/1.4/rose_qsig_cc.c
      - copied unchanged from r1704, team/group/ccss/rose_qsig_cc.c
Modified:
    branches/1.4/Makefile
    branches/1.4/libpri.h
    branches/1.4/pri.c
    branches/1.4/pri_facility.c
    branches/1.4/pri_facility.h
    branches/1.4/pri_internal.h
    branches/1.4/pri_q931.h
    branches/1.4/prisched.c
    branches/1.4/q931.c
    branches/1.4/rose.c
    branches/1.4/rose.h
    branches/1.4/rose_internal.h
    branches/1.4/rosetest.c

Modified: branches/1.4/Makefile
URL: http://svnview.digium.com/svn/libpri/branches/1.4/Makefile?view=diff&rev=1714&r1=1713&r2=1714
==============================================================================
--- branches/1.4/Makefile (original)
+++ branches/1.4/Makefile Wed May 26 11:01:10 2010
@@ -47,16 +47,19 @@
 	q921.o \
 	prisched.o \
 	q931.o \
+	pri_cc.o \
 	pri_facility.o \
 	asn1_primitive.o \
 	rose.o \
 	rose_address.o \
 	rose_etsi_aoc.o \
+	rose_etsi_cc.o \
 	rose_etsi_diversion.o \
 	rose_etsi_ect.o \
 	rose_other.o \
 	rose_q931.o \
 	rose_qsig_aoc.o \
+	rose_qsig_cc.o \
 	rose_qsig_ct.o \
 	rose_qsig_diversion.o \
 	rose_qsig_mwi.o \
@@ -68,16 +71,19 @@
 	q921.lo \
 	prisched.lo \
 	q931.lo \
+	pri_cc.lo \
 	pri_facility.lo \
 	asn1_primitive.lo \
 	rose.lo \
 	rose_address.lo \
 	rose_etsi_aoc.lo \
+	rose_etsi_cc.lo \
 	rose_etsi_diversion.lo \
 	rose_etsi_ect.lo \
 	rose_other.lo \
 	rose_q931.lo \
 	rose_qsig_aoc.lo \
+	rose_qsig_cc.lo \
 	rose_qsig_ct.lo \
 	rose_qsig_diversion.lo \
 	rose_qsig_mwi.lo \

Modified: branches/1.4/libpri.h
URL: http://svnview.digium.com/svn/libpri/branches/1.4/libpri.h?view=diff&rev=1714&r1=1713&r2=1714
==============================================================================
--- branches/1.4/libpri.h (original)
+++ branches/1.4/libpri.h Wed May 26 11:01:10 2010
@@ -51,6 +51,7 @@
 #define	PRI_DEBUG_Q931_ANOMALY 	(1 << 7)	/* Show unexpected events */
 #define PRI_DEBUG_APDU			(1 << 8)	/* Debug of APDU components such as ROSE */
 #define PRI_DEBUG_AOC			(1 << 9)	/* Debug of Advice of Charge ROSE Messages */
+#define PRI_DEBUG_CC			(1 << 10)	/* Debug call-completion. */
 
 #define PRI_DEBUG_ALL			(0xffff)	/* Everything */
 
@@ -439,6 +440,14 @@
 	unsigned char data[32];
 };
 
+/*! \brief Addressing information needed to identify an endpoint in a call. */
+struct pri_party_address {
+	/*! \brief Subscriber phone number */
+	struct pri_party_number number;
+	/*! \brief Subscriber subaddress */
+	struct pri_party_subaddress subaddress;
+};
+
 /*! \brief Information needed to identify an endpoint in a call. */
 struct pri_party_id {
 	/*! \brief Subscriber name */
@@ -503,11 +512,127 @@
 	int invoke_id;
 };
 
+/*
+ * NOTE:
+ * The code surrounded by STATUS_REQUEST_PLACE_HOLDER is not implemented.
+ * The STATUS_REQUEST_PLACE_HOLDER code will be made unconditional if support
+ * for the messages is ever needed (and gets written).
+ */
+
 /* Subcommands derived from supplementary services. */
-#define PRI_SUBCMD_REDIRECTING		1
-#define PRI_SUBCMD_CONNECTED_LINE	2
-#define PRI_SUBCMD_REROUTING		3
-
+#define PRI_SUBCMD_REDIRECTING				1	/*!< Redirecting information update */
+#define PRI_SUBCMD_CONNECTED_LINE			2	/*!< Connected line information update */
+#define PRI_SUBCMD_REROUTING				3	/*!< CallRerouting/CallDeflection received. */
+#if defined(STATUS_REQUEST_PLACE_HOLDER)
+#define PRI_SUBCMD_STATUS_REQ				4	/*!< Determine the status of the given party. */
+#define PRI_SUBCMD_STATUS_REQ_RSP			5	/*!< Status request response */
+#endif	/* defined(STATUS_REQUEST_PLACE_HOLDER) */
+#define PRI_SUBCMD_CC_AVAILABLE				6	/*!< Indicate that CC is available */
+#define PRI_SUBCMD_CC_REQ					7	/*!< CC activation request */
+#define PRI_SUBCMD_CC_REQ_RSP				8	/*!< CC activation request response */
+#define PRI_SUBCMD_CC_REMOTE_USER_FREE		9	/*!< Indicate that CC party B is available, party A is considered free. */
+#define PRI_SUBCMD_CC_B_FREE				10	/*!< Indicate that CC party B is available, party A is considered busy. */
+#define PRI_SUBCMD_CC_STATUS_REQ			11	/*!< Request/prod to receive updates of CC party A status */
+#define PRI_SUBCMD_CC_STATUS_REQ_RSP		12	/*!< Requested update of CC party A status */
+#define PRI_SUBCMD_CC_STATUS				13	/*!< Unsolicited update of CC party A status */
+#define PRI_SUBCMD_CC_CALL					14	/*!< Indicate that this call is a CC callback */
+#define PRI_SUBCMD_CC_CANCEL				15	/*!< Unsolicited indication that CC is canceled */
+#define PRI_SUBCMD_CC_STOP_ALERTING			16	/*!< Indicate that someone else has responed to remote user free */
+
+#if defined(STATUS_REQUEST_PLACE_HOLDER)
+struct pri_subcmd_status_request {
+	/*!
+	 * \brief Invoke id in case there are multiple outstanding requests.
+	 * \note Used to match any responses with the original invoke in case
+	 * there are several requests active.
+	 */
+	int invoke_id;
+	/*! \brief Party address requesting status about. */
+	struct pri_party_address party;
+};
+#endif	/* defined(STATUS_REQUEST_PLACE_HOLDER) */
+
+#if defined(STATUS_REQUEST_PLACE_HOLDER)
+struct pri_subcmd_status_request_rsp {
+	/*!
+	 * \brief Request id in case there are multiple outstanding requests.
+	 * \note Used to match any responses with the request in case there
+	 * are several requests active.
+	 */
+	int request_id;
+	/*!
+	 * \brief Response status to the status request.
+	 * \details
+	 * free(0),
+	 * busy(1),
+	 * incompatible(2)
+	 * timeout(3),
+	 */
+	int status;
+};
+#endif	/* defined(STATUS_REQUEST_PLACE_HOLDER) */
+
+struct pri_subcmd_cc_id {
+	/*! \brief Call-Completion record id */
+	long cc_id;
+};
+
+struct pri_subcmd_cc_request {
+	/*! \brief Call-Completion record id */
+	long cc_id;
+	/*!
+	 * \brief Mode of call-completion requested.
+	 * \details
+	 * ccbs(0),
+	 * ccnr(1)
+	 */
+	int mode;
+};
+
+struct pri_subcmd_cc_request_rsp {
+	/*! \brief Call-Completion record id */
+	long cc_id;
+	/*!
+	 * \brief Status of the requested call-completion activation.
+	 * \details
+	 * success(0),
+	 * timeout(1),
+	 * error(2),
+	 * reject(3)
+	 */
+	int status;
+	/*!
+	 * \brief Failure code that can be converted to a string to further
+	 * explain the non-timeout failure.
+	 * \note Valid when status is error or reject.
+	 * \note Use pri_facility_error2str() to convert the error_code.
+	 * \note Use pri_facility_reject2str() to convert the reject_code.
+	 */
+	int fail_code;
+};
+
+struct pri_subcmd_cc_status {
+	/*! \brief Call-Completion record id */
+	long cc_id;
+	/*!
+	 * \brief Party A status.
+	 * \details
+	 * free(0),
+	 * busy(1)
+	 */
+	int status;
+};
+
+struct pri_subcmd_cc_cancel {
+	/*! \brief Call-Completion record id */
+	long cc_id;
+	/*!
+	 * \brief TRUE if the cc_id is for an agent.
+	 * \note This is a convenience value so the upper layer can know which
+	 * list it should search for the cc_id.
+	 */
+	int is_agent;
+};
 
 struct pri_subcommand {
 	/*! PRI_SUBCMD_xxx defined values */
@@ -518,6 +643,21 @@
 		struct pri_party_connected_line connected_line;
 		struct pri_party_redirecting redirecting;
 		struct pri_rerouting_data rerouting;
+#if defined(STATUS_REQUEST_PLACE_HOLDER)
+		struct pri_subcmd_status_request status_request;
+		struct pri_subcmd_status_request_rsp status_request_rsp;
+#endif	/* defined(STATUS_REQUEST_PLACE_HOLDER) */
+		struct pri_subcmd_cc_id cc_available;
+		struct pri_subcmd_cc_request cc_request;
+		struct pri_subcmd_cc_request_rsp cc_request_rsp;
+		struct pri_subcmd_cc_id cc_remote_user_free;
+		struct pri_subcmd_cc_id cc_b_free;
+		struct pri_subcmd_cc_id cc_stop_alerting;
+		struct pri_subcmd_cc_id cc_status_req;
+		struct pri_subcmd_cc_status cc_status_req_rsp;
+		struct pri_subcmd_cc_status cc_status;
+		struct pri_subcmd_cc_id cc_call;
+		struct pri_subcmd_cc_cancel cc_cancel;
 	} u;
 };
 
@@ -867,6 +1007,24 @@
 /* Turn cause into a string */
 char *pri_cause2str(int cause);
 
+/*!
+ * \brief Convert the given facility error code to a descriptive string.
+ *
+ * \param facility_error_code Error code to convert to a string.
+ *
+ * \return Descriptive error string.
+ */
+const char *pri_facility_error2str(int facility_error_code);
+
+/*!
+ * \brief Convert the given facility reject code to a descriptive string.
+ *
+ * \param facility_reject_code Error code to convert to a string.
+ *
+ * \return Descriptive reject string.
+ */
+const char *pri_facility_reject2str(int facility_reject_code);
+
 /* Acknowledge a call and place it on the given channel.  Set info to non-zero if there
    is in-band data available on the channel */
 int pri_acknowledge(struct pri *pri, q931_call *call, int channel, int info);
@@ -1261,6 +1419,65 @@
  * \retval -1 on error.
  */
 int pri_retrieve_rej(struct pri *ctrl, q931_call *call, int cause);
+
+#if defined(STATUS_REQUEST_PLACE_HOLDER)
+int pri_status_req(struct pri *ctrl, int request_id, const struct pri_sr *req);
+void pri_status_req_rsp(struct pri *ctrl, int invoke_id, int status);
+#endif	/* defined(STATUS_REQUEST_PLACE_HOLDER) */
+
+/*!
+ * \brief Set the call completion feature enable flag.
+ *
+ * \param ctrl D channel controller.
+ * \param enable TRUE to enable call completion feature.
+ *
+ * \return Nothing
+ */
+void pri_cc_enable(struct pri *ctrl, int enable);
+
+/*!
+ * \brief Set the PTMP NT call completion recall mode.
+ *
+ * \param ctrl D channel controller.
+ * \param mode globalRecall(0), specificRecall(1)
+ *
+ * \return Nothing
+ */
+void pri_cc_recall_mode(struct pri *ctrl, int mode);
+
+/*!
+ * \brief Set the Q.SIG call completion signaling link retention mode.
+ * (Requestor/Initiator/Originator/Party-A)
+ *
+ * \param ctrl D channel controller.
+ * \param signaling_retention release(0), retain(1), do-not-care(2).
+ *
+ * \return Nothing
+ */
+void pri_cc_retain_signaling_req(struct pri *ctrl, int signaling_retention);
+
+/*!
+ * \brief Set the Q.SIG call completion signaling link retention mode.
+ * (Responder/Answerer/Party-B)
+ *
+ * \param ctrl D channel controller.
+ * \param signaling_retention release(0), retain(1).
+ *
+ * \return Nothing
+ */
+void pri_cc_retain_signaling_rsp(struct pri *ctrl, int signaling_retention);
+
+long pri_cc_available(struct pri *ctrl, q931_call *call);
+int pri_cc_req(struct pri *ctrl, long cc_id, int mode);
+int pri_cc_req_rsp(struct pri *ctrl, long cc_id, int status);
+void pri_cc_remote_user_free(struct pri *ctrl, long cc_id);
+void pri_cc_b_free(struct pri *ctrl, long cc_id);
+void pri_cc_stop_alerting(struct pri *ctrl, long cc_id);
+void pri_cc_status_req(struct pri *ctrl, long cc_id);
+void pri_cc_status_req_rsp(struct pri *ctrl, long cc_id, int status);
+void pri_cc_status(struct pri *ctrl, long cc_id, int status);
+int pri_cc_call(struct pri *ctrl, long cc_id, q931_call *call, struct pri_sr *req);
+void pri_cc_cancel(struct pri *ctrl, long cc_id);
 
 /* Get/Set PRI Timers  */
 #define PRI_GETSET_TIMERS
@@ -1309,6 +1526,31 @@
 
 	PRI_TIMER_T_RESPONSE,	/*!< Maximum time to wait for a typical APDU response. */
 
+	PRI_TIMER_T_STATUS,		/*!< Max time to wait for all replies to check for compatible terminals */
+
+	PRI_TIMER_T_ACTIVATE,	/*!< Request supervision timeout. */
+	PRI_TIMER_T_DEACTIVATE,	/*!< Deactivate supervision timeout. */
+	PRI_TIMER_T_INTERROGATE,/*!< Interrogation supervision timeout. */
+
+	/* ETSI call-completion timers */
+	PRI_TIMER_T_RETENTION,	/*!< Max time to wait for user A to activate call-completion. */
+	PRI_TIMER_T_CCBS1,		/*!< T-STATUS timer equivalent for CC user A status. */
+	PRI_TIMER_T_CCBS2,		/*!< Max time the CCBS service will be active */
+	PRI_TIMER_T_CCBS3,		/*!< Max time to wait for user A to respond to user B availability. */
+	PRI_TIMER_T_CCBS4,		/*!< CC user B guard time before sending CC recall indication. */
+	PRI_TIMER_T_CCBS5,		/*!< Network B CCBS supervision timeout. */
+	PRI_TIMER_T_CCBS6,		/*!< Network A CCBS supervision timeout. */
+	PRI_TIMER_T_CCNR2,		/*!< Max time the CCNR service will be active */
+	PRI_TIMER_T_CCNR5,		/*!< Network B CCNR supervision timeout. */
+	PRI_TIMER_T_CCNR6,		/*!< Network A CCNR supervision timeout. */
+
+	/* Q.SIG call-completion timers */
+	PRI_TIMER_QSIG_CC_T1,	/*!< CC request supervision timeout. */
+	PRI_TIMER_QSIG_CCBS_T2,	/*!< CCBS supervision timeout. */
+	PRI_TIMER_QSIG_CCNR_T2,	/*!< CCNR supervision timeout. */
+	PRI_TIMER_QSIG_CC_T3,	/*!< Max time to wait for user A to respond to user B availability. */
+	PRI_TIMER_QSIG_CC_T4,	/*!< Path reservation supervision timeout. */
+
 	/* Must be last in the enum list */
 	PRI_MAX_TIMERS
 };

Modified: branches/1.4/pri.c
URL: http://svnview.digium.com/svn/libpri/branches/1.4/pri.c?view=diff&rev=1714&r1=1713&r2=1714
==============================================================================
--- branches/1.4/pri.c (original)
+++ branches/1.4/pri.c Wed May 26 11:01:10 2010
@@ -40,11 +40,10 @@
 #include "libpri.h"
 #include "pri_internal.h"
 #include "pri_facility.h"
-#include "pri_q921.h"
-#include "pri_q931.h"
 
 #define PRI_BIT(a_bit)		(1UL << (a_bit))
 #define PRI_ALL_SWITCHES	0xFFFFFFFF
+#define PRI_ETSI_SWITCHES	(PRI_BIT(PRI_SWITCH_EUROISDN_E1) | PRI_BIT(PRI_SWITCH_EUROISDN_T1))
 
 struct pri_timer_table {
 	const char *name;
@@ -89,6 +88,27 @@
 	{ "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 },
+	{ "T-STATUS",       PRI_TIMER_T_STATUS,         PRI_ETSI_SWITCHES },
+	{ "T-ACTIVATE",     PRI_TIMER_T_ACTIVATE,       PRI_ETSI_SWITCHES },
+	{ "T-DEACTIVATE",   PRI_TIMER_T_DEACTIVATE,     PRI_ETSI_SWITCHES },
+	{ "T-INTERROGATE",  PRI_TIMER_T_INTERROGATE,    PRI_ETSI_SWITCHES },
+	{ "T-RETENTION",    PRI_TIMER_T_RETENTION,      PRI_ETSI_SWITCHES | PRI_BIT(PRI_SWITCH_QSIG) },
+	{ "T-CCBS1",        PRI_TIMER_T_CCBS1,          PRI_ETSI_SWITCHES },
+	{ "T-CCBS2",        PRI_TIMER_T_CCBS2,          PRI_ETSI_SWITCHES },
+	{ "T-CCBS3",        PRI_TIMER_T_CCBS3,          PRI_ETSI_SWITCHES },
+	{ "T-CCBS4",        PRI_TIMER_T_CCBS4,          PRI_ETSI_SWITCHES },
+	{ "T-CCBS5",        PRI_TIMER_T_CCBS5,          PRI_ETSI_SWITCHES },
+	{ "T-CCBS6",        PRI_TIMER_T_CCBS6,          PRI_ETSI_SWITCHES },
+	{ "T-CCNR2",        PRI_TIMER_T_CCNR2,          PRI_ETSI_SWITCHES },
+	{ "T-CCNR5",        PRI_TIMER_T_CCNR5,          PRI_ETSI_SWITCHES },
+	{ "T-CCNR6",        PRI_TIMER_T_CCNR6,          PRI_ETSI_SWITCHES },
+	{ "CC-T1",          PRI_TIMER_QSIG_CC_T1,       PRI_BIT(PRI_SWITCH_QSIG) },
+	{ "CCBS-T2",        PRI_TIMER_QSIG_CCBS_T2,     PRI_BIT(PRI_SWITCH_QSIG) },
+	{ "CCNR-T2",        PRI_TIMER_QSIG_CCNR_T2,     PRI_BIT(PRI_SWITCH_QSIG) },
+	{ "CC-T3",          PRI_TIMER_QSIG_CC_T3,       PRI_BIT(PRI_SWITCH_QSIG) },
+#if defined(QSIG_PATH_RESERVATION_SUPPORT)
+	{ "CC-T4",          PRI_TIMER_QSIG_CC_T4,       PRI_BIT(PRI_SWITCH_QSIG) },
+#endif	/* defined(QSIG_PATH_RESERVATION_SUPPORT) */
 /* *INDENT-ON* */
 };
 
@@ -166,6 +186,33 @@
 
 	ctrl->timers[PRI_TIMER_T_RESPONSE] = 4 * 1000;	/* Maximum time to wait for a typical APDU response. */
 
+	/* ETSI timers */
+	ctrl->timers[PRI_TIMER_T_STATUS] = 4 * 1000;	/* Max time to wait for all replies to check for compatible terminals */
+	ctrl->timers[PRI_TIMER_T_ACTIVATE] = 10 * 1000;	/* Request supervision timeout. */
+	ctrl->timers[PRI_TIMER_T_DEACTIVATE] = 4 * 1000;/* Deactivate supervision timeout. */
+	ctrl->timers[PRI_TIMER_T_INTERROGATE] = 4 * 1000;/* Interrogation supervision timeout. */
+
+	/* ETSI call-completion timers */
+	ctrl->timers[PRI_TIMER_T_RETENTION] = 30 * 1000;/* Max time to wait for user A to activate call-completion. */
+	ctrl->timers[PRI_TIMER_T_CCBS1] = 4 * 1000;		/* T-STATUS timer equivalent for CC user A status. */
+	ctrl->timers[PRI_TIMER_T_CCBS2] = 45 * 60 * 1000;/* Max time the CCBS service will be active */
+	ctrl->timers[PRI_TIMER_T_CCBS3] = 20 * 1000;	/* Max time to wait for user A to respond to user B availability. */
+	ctrl->timers[PRI_TIMER_T_CCBS4] = 5 * 1000;		/* CC user B guard time before sending CC recall indication. */
+	ctrl->timers[PRI_TIMER_T_CCBS5] = 60 * 60 * 1000;/* Network B CCBS supervision timeout. */
+	ctrl->timers[PRI_TIMER_T_CCBS6] = 60 * 60 * 1000;/* Network A CCBS supervision timeout. */
+	ctrl->timers[PRI_TIMER_T_CCNR2] = 180 * 60 * 1000;/* Max time the CCNR service will be active */
+	ctrl->timers[PRI_TIMER_T_CCNR5] = 195 * 60 * 1000;/* Network B CCNR supervision timeout. */
+	ctrl->timers[PRI_TIMER_T_CCNR6] = 195 * 60 * 1000;/* Network A CCNR supervision timeout. */
+
+	/* Q.SIG call-completion timers */
+	ctrl->timers[PRI_TIMER_QSIG_CC_T1] = 30 * 1000;/* CC request supervision timeout. */
+	ctrl->timers[PRI_TIMER_QSIG_CCBS_T2] = 60 * 60 * 1000;/* CCBS supervision timeout. */
+	ctrl->timers[PRI_TIMER_QSIG_CCNR_T2] = 195 * 60 * 1000;/* CCNR supervision timeout. */
+	ctrl->timers[PRI_TIMER_QSIG_CC_T3] = 30 * 1000;/* Max time to wait for user A to respond to user B availability. */
+#if defined(QSIG_PATH_RESERVATION_SUPPORT)
+	ctrl->timers[PRI_TIMER_QSIG_CC_T4] = 40 * 1000;/* Path reservation supervision timeout. */
+#endif	/* defined(QSIG_PATH_RESERVATION_SUPPORT) */
+
 	/* Set any switch specific override default values */
 	switch (switchtype) {
 	default:
@@ -246,6 +293,7 @@
 			pri_call_apdu_queue_cleanup(call);
 		}
 		free(p->msg_line);
+		free(p->sched.timer);
 		free(p);
 	}
 }
@@ -903,6 +951,52 @@
 	return 0;
 }
 
+#if defined(STATUS_REQUEST_PLACE_HOLDER)
+/*!
+ * \brief Poll/ping for the status of any "called" party.
+ *
+ * \param ctrl D channel controller.
+ * \param request_id The upper layer's ID number to match with the response in case
+ *		there are several requests at the same time.
+ * \param req Setup request for "called" party to determine the status.
+ *
+ * \note
+ * There could be one or more PRI_SUBCMD_STATUS_REQ_RSP to the status request
+ * depending upon how many endpoints respond to the request.
+ * (This includes the timeout termination response.)
+ * \note
+ * Could be used to poll for the status of call-completion party B.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+int pri_status_req(struct pri *ctrl, int request_id, const struct pri_sr *req)
+{
+	return -1;
+}
+#endif	/* defined(STATUS_REQUEST_PLACE_HOLDER) */
+
+#if defined(STATUS_REQUEST_PLACE_HOLDER)
+/*!
+ * \brief Response to a poll/ping request for status of any "called" party by libpri.
+ *
+ * \param ctrl D channel controller.
+ * \param invoke_id ID given by libpri when it requested the party status.
+ * \param status free(0)/busy(1)/incompatible(2)
+ *
+ * \note
+ * There could be zero, one, or more responses to the original
+ * status request depending upon how many endpoints respond to the request.
+ * \note
+ * Could be used to poll for the status of call-completion party B.
+ *
+ * \return Nothing
+ */
+void pri_status_req_rsp(struct pri *ctrl, int invoke_id, int status)
+{
+}
+#endif	/* defined(STATUS_REQUEST_PLACE_HOLDER) */
+
 #if 0
 /* deprecated routines, use pri_hangup */
 int pri_release(struct pri *pri, q931_call *call, int cause)
@@ -930,7 +1024,7 @@
 		return -1;
 
 	/* Check for bearer capability */
-	if (call1->transcapability != call2->transcapability)
+	if (call1->bc.transcapability != call2->bc.transcapability)
 		return -1;
 
 	/* Check to see if we're on the same PRI */
@@ -1040,7 +1134,7 @@
 	}
 }
 
-static void pri_sr_init(struct pri_sr *req)
+void pri_sr_init(struct pri_sr *req)
 {
 	memset(req, 0, sizeof(struct pri_sr));
 	q931_party_redirecting_init(&req->redirecting);
@@ -1618,3 +1712,35 @@
 
 	return send_reroute_request(ctrl, call, caller_id, &reroute, subscription_option);
 }
+
+void pri_cc_enable(struct pri *ctrl, int enable)
+{
+	if (ctrl) {
+		ctrl = PRI_MASTER(ctrl);
+		ctrl->cc_support = enable ? 1 : 0;
+	}
+}
+
+void pri_cc_recall_mode(struct pri *ctrl, int mode)
+{
+	if (ctrl) {
+		ctrl = PRI_MASTER(ctrl);
+		ctrl->cc.option.recall_mode = mode ? 1 : 0;
+	}
+}
+
+void pri_cc_retain_signaling_req(struct pri *ctrl, int signaling_retention)
+{
+	if (ctrl && 0 <= signaling_retention && signaling_retention < 3) {
+		ctrl = PRI_MASTER(ctrl);
+		ctrl->cc.option.signaling_retention_req = signaling_retention;
+	}
+}
+
+void pri_cc_retain_signaling_rsp(struct pri *ctrl, int signaling_retention)
+{
+	if (ctrl) {
+		ctrl = PRI_MASTER(ctrl);
+		ctrl->cc.option.signaling_retention_rsp = signaling_retention ? 1 : 0;
+	}
+}

Modified: branches/1.4/pri_facility.c
URL: http://svnview.digium.com/svn/libpri/branches/1.4/pri_facility.c?view=diff&rev=1714&r1=1713&r2=1714
==============================================================================
--- branches/1.4/pri_facility.c (original)
+++ branches/1.4/pri_facility.c Wed May 26 11:01:10 2010
@@ -30,20 +30,21 @@
 #include "compat.h"
 #include "libpri.h"
 #include "pri_internal.h"
-#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 short get_invokeid(struct pri *ctrl)
-{
-	ctrl = PRI_MASTER(ctrl);
-	return ++ctrl->last_invoke;
+const char *pri_facility_error2str(int facility_error_code)
+{
+	return rose_error2str(facility_error_code);
+}
+
+const char *pri_facility_reject2str(int facility_reject_code)
+{
+	return rose_reject2str(facility_reject_code);
 }
 
 static int redirectingreason_from_q931(struct pri *ctrl, int redirectingreason)
@@ -171,6 +172,7 @@
 }
 
 /*!
+ * \internal
  * \brief Convert the Q.931 type-of-number field to facility.
  *
  * \param ctrl D channel controller for diagnostic messages or global options.
@@ -497,7 +499,6 @@
 }
 
 /*!
- * \internal
  * \brief Copy the given rose party number to the q931_party_number
  *
  * \param ctrl D channel controller for diagnostic messages or global options.
@@ -508,8 +509,8 @@
  *
  * \return Nothing
  */
-static void rose_copy_number_to_q931(struct pri *ctrl,
-	struct q931_party_number *q931_number, const struct rosePartyNumber *rose_number)
+void rose_copy_number_to_q931(struct pri *ctrl, struct q931_party_number *q931_number,
+	const struct rosePartyNumber *rose_number)
 {
 	//q931_party_number_init(q931_number);
 	libpri_copy_string(q931_number->str, (char *) rose_number->str,
@@ -520,7 +521,6 @@
 }
 
 /*!
- * \internal
  * \brief Copy the given rose subaddress to the q931_party_subaddress.
  *
  * \param ctrl D channel controller for diagnostic messages or global options.
@@ -531,7 +531,7 @@
  *
  * \return Nothing
  */
-static void rose_copy_subaddress_to_q931(struct pri *ctrl,
+void rose_copy_subaddress_to_q931(struct pri *ctrl,
 	struct q931_party_subaddress *q931_subaddress,
 	const struct rosePartySubaddress *rose_subaddress)
 {
@@ -571,19 +571,18 @@
 }
 
 /*!
- * \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
+ * \brief Copy the given rose address to the q931_party_address.
+ *
+ * \param ctrl D channel controller for diagnostic messages or global options.
+ * \param q931_address Q.931 party address structure
  * \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)
+void rose_copy_address_to_q931(struct pri *ctrl, struct q931_party_address *q931_address,
+	const struct roseAddress *rose_address)
 {
 	rose_copy_number_to_q931(ctrl, &q931_address->number, &rose_address->number);
 	rose_copy_subaddress_to_q931(ctrl, &q931_address->subaddress,
@@ -591,7 +590,25 @@
 }
 
 /*!
- * \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
+ */
+void rose_copy_address_to_id_q931(struct pri *ctrl, struct q931_party_id *q931_address,
+	const struct roseAddress *rose_address)
+{
+	rose_copy_number_to_q931(ctrl, &q931_address->number, &rose_address->number);
+	rose_copy_subaddress_to_q931(ctrl, &q931_address->subaddress,
+		&rose_address->subaddress);
+}
+
+/*!
  * \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.
@@ -600,7 +617,7 @@
  *
  * \return Nothing
  */
-static void rose_copy_presented_number_screened_to_q931(struct pri *ctrl,
+void rose_copy_presented_number_screened_to_q931(struct pri *ctrl,
 	struct q931_party_number *q931_number,
 	const struct rosePresentedNumberScreened *rose_presented)
 {
@@ -622,7 +639,6 @@
 }
 
 /*!
- * \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.
@@ -631,7 +647,7 @@
  *
  * \return Nothing
  */
-static void rose_copy_presented_number_unscreened_to_q931(struct pri *ctrl,
+void rose_copy_presented_number_unscreened_to_q931(struct pri *ctrl,
 	struct q931_party_number *q931_number,
 	const struct rosePresentedNumberUnscreened *rose_presented)
 {
@@ -650,7 +666,6 @@
 }
 
 /*!
- * \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.
@@ -659,7 +674,7 @@
  *
  * \return Nothing
  */
-static void rose_copy_presented_address_screened_to_q931(struct pri *ctrl,
+void rose_copy_presented_address_screened_to_id_q931(struct pri *ctrl,
 	struct q931_party_id *q931_address,
 	const struct rosePresentedAddressScreened *rose_presented)
 {
@@ -685,7 +700,6 @@
 }
 
 /*!
- * \internal
  * \brief Copy the given rose party name to the q931_party_name
  *
  * \param ctrl D channel controller for diagnostic messages or global options.
@@ -694,8 +708,8 @@
  *
  * \return Nothing
  */
-static void rose_copy_name_to_q931(struct pri *ctrl,
-	struct q931_party_name *qsig_name, const struct roseQsigName *rose_name)
+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;
@@ -706,7 +720,6 @@
 }
 
 /*!
- * \internal
  * \brief Copy the given q931_party_number to the rose party number
  *
  * \param ctrl D channel controller for diagnostic messages or global options.
@@ -715,8 +728,8 @@
  *
  * \return Nothing
  */
-static void q931_copy_number_to_rose(struct pri *ctrl,
-	struct rosePartyNumber *rose_number, const struct q931_party_number *q931_number)
+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);
@@ -727,7 +740,6 @@
 }
 
 /*!
- * \internal
  * \brief Copy the given q931_party_subaddress to the rose subaddress.
  *
  * \param ctrl D channel controller for diagnostic messages or global options.
@@ -736,7 +748,7 @@
  *
  * \return Nothing
  */
-static void q931_copy_subaddress_to_rose(struct pri *ctrl,
+void q931_copy_subaddress_to_rose(struct pri *ctrl,
 	struct rosePartySubaddress *rose_subaddress,
 	const struct q931_party_subaddress *q931_subaddress)
 {
@@ -778,17 +790,16 @@
 }
 
 /*!
- * \internal
- * \brief Copy the given q931_party_id address to the rose address.
+ * \brief Copy the given q931_party_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
+ * \param q931_address Q.931 party address structure
  *
  * \return Nothing
  */
-static void q931_copy_address_to_rose(struct pri *ctrl, struct roseAddress *rose_address,
-	const struct q931_party_id *q931_address)
+void q931_copy_address_to_rose(struct pri *ctrl, struct roseAddress *rose_address,
+	const struct q931_party_address *q931_address)
 {
 	q931_copy_number_to_rose(ctrl, &rose_address->number, &q931_address->number);
 	q931_copy_subaddress_to_rose(ctrl, &rose_address->subaddress,
@@ -796,7 +807,23 @@
 }
 
 /*!
- * \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
+ */
+void q931_copy_id_address_to_rose(struct pri *ctrl, struct roseAddress *rose_address,
+	const struct q931_party_id *q931_address)
+{
+	q931_copy_number_to_rose(ctrl, &rose_address->number, &q931_address->number);
+	q931_copy_subaddress_to_rose(ctrl, &rose_address->subaddress,
+		&q931_address->subaddress);
+}
+
+/*!
  * \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.
@@ -805,7 +832,7 @@
  *
  * \return Nothing
  */
-static void q931_copy_presented_number_screened_to_rose(struct pri *ctrl,
+void q931_copy_presented_number_screened_to_rose(struct pri *ctrl,
 	struct rosePresentedNumberScreened *rose_presented,
 	const struct q931_party_number *q931_number)
 {
@@ -821,7 +848,6 @@
 }
 
 /*!
- * \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.
@@ -830,7 +856,7 @@
  *
  * \return Nothing
  */
-static void q931_copy_presented_number_unscreened_to_rose(struct pri *ctrl,
+void q931_copy_presented_number_unscreened_to_rose(struct pri *ctrl,
 	struct rosePresentedNumberUnscreened *rose_presented,
 	const struct q931_party_number *q931_number)
 {
@@ -843,9 +869,7 @@
 	}
 }
 
-#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.
@@ -854,7 +878,7 @@
  *
  * \return Nothing
  */
-static void q931_copy_presented_address_screened_to_rose(struct pri *ctrl,
+void q931_copy_presented_id_address_screened_to_rose(struct pri *ctrl,
 	struct rosePresentedAddressScreened *rose_presented,
 	const struct q931_party_id *q931_address)
 {
@@ -872,10 +896,8 @@
 		rose_presented->presentation = 2;/* numberNotAvailableDueToInterworking */
 	}
 }
-#endif	/* In case it is needed in the future */
-
-/*!
- * \internal
+
+/*!
  * \brief Copy the given q931_party_name to the rose party name
  *
  * \param ctrl D channel controller for diagnostic messages or global options.
@@ -884,8 +906,8 @@
  *
  * \return Nothing
  */
-static void q931_copy_name_to_rose(struct pri *ctrl,
-	struct roseQsigName *rose_name, const struct q931_party_name *qsig_name)
+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,
@@ -1841,7 +1863,7 @@
 		redirectingreason_from_q931(ctrl, deflection->reason);
 
 	/* calledAddress is the passed in deflection->to address */
-	q931_copy_address_to_rose(ctrl, &msg.args.qsig.CallRerouting.called, &deflection->to);
+	q931_copy_id_address_to_rose(ctrl, &msg.args.qsig.CallRerouting.called, &deflection->to);
 
 	msg.args.qsig.CallRerouting.diversion_counter = deflection->count;
 
@@ -1849,7 +1871,7 @@
 	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++ = 0x80 | call->bc.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) */
@@ -1953,7 +1975,7 @@
 		redirectingreason_from_q931(ctrl, deflection->reason);
 
 	/* calledAddress is the passed in deflection->to address */
-	q931_copy_address_to_rose(ctrl, &msg.args.etsi.CallRerouting.called_address,
+	q931_copy_id_address_to_rose(ctrl, &msg.args.etsi.CallRerouting.called_address,
 		&deflection->to);
 
 	msg.args.etsi.CallRerouting.rerouting_counter = deflection->count;
@@ -1962,7 +1984,7 @@
 	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++ = 0x80 | call->bc.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
@@ -2014,7 +2036,7 @@
 	msg.invoke_id = get_invokeid(ctrl);
 
 	/* deflectionAddress is the passed in deflection->to address */
-	q931_copy_address_to_rose(ctrl, &msg.args.etsi.CallDeflection.deflection,
+	q931_copy_id_address_to_rose(ctrl, &msg.args.etsi.CallDeflection.deflection,
 		deflection);
 
 	msg.args.etsi.CallDeflection.presentation_allowed_to_diverted_to_user_present = 1;
@@ -2766,13 +2788,15 @@
 		call->apdus = NULL;
 		while (cur_event) {
 			if (cur_event->response.callback) {
+				/* Stop any response timeout. */
+				pri_schedule_del(call->pri, cur_event->timer);
+				cur_event->timer = 0;
+
 				/* Indicate to callback that the APDU is being cleaned up. */
 				cur_event->response.callback(APDU_CALLBACK_REASON_CLEANUP, call->pri,
 					call, cur_event, NULL);
-
-				/* Stop any response timeout. */
-				pri_schedule_del(call->pri, cur_event->timer);
 			}
+
 			free_event = cur_event;
 			cur_event = cur_event->next;
 			free(free_event);
@@ -2781,7 +2805,6 @@
 }
 
 /*!
- * \internal
  * \brief Find an outstanding APDU with the given invoke id.
  *
  * \param call Call to find APDU.
@@ -2790,10 +2813,14 @@
  * \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 *pri_call_apdu_find(struct q931_call *call, int invoke_id)
 {
 	struct apdu_event *apdu;
 
+	if (invoke_id == APDU_INVALID_INVOKE_ID) {
+		/* No need to search the list since it cannot be in there. */
+		return NULL;
+	}
 	for (apdu = call->apdus; apdu; apdu = apdu->next) {
 		/*
 		 * Note: The APDU cannot be sent and still in the queue without a
@@ -2808,14 +2835,15 @@
 }
 
 /*!
- * \brief Delete the given APDU event from the given call.
+ * \brief Extract 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)
+ * \param extract APDU event to extract.
+ *
+ * \retval TRUE on success.
+ * \retval FALSE on error.
+ */
+int pri_call_apdu_extract(struct q931_call *call, struct apdu_event *extract)
 {
 	struct apdu_event **prev;
 	struct apdu_event *cur;
@@ -2824,15 +2852,35 @@
 	for (prev = &call->apdus, cur = call->apdus;
 		cur;
 		prev = &cur->next, cur = cur->next) {
-		if (cur == doomed) {
+		if (cur == extract) {
 			/* Stop any response timeout. */
 			pri_schedule_del(call->pri, cur->timer);
+			cur->timer = 0;
 
 			/* Remove APDU from list. */
 			*prev = cur->next;
-			free(cur);
-			break;
-		}
+
+			/* Found and extracted APDU from list. */
+			return 1;
+		}
+	}
+
+	/* Did not find the APDU in the list. */
+	return 0;
+}
+
+/*!
+ * \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)
+{
+	if (pri_call_apdu_extract(call, doomed)) {
+		free(doomed);
 	}
 }
 
@@ -2985,18 +3033,18 @@
 }
 
 /*!
- * \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 msgtype Q.931 message type to put facility ie in.
  * \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,
+int rose_error_msg_encode(struct pri *ctrl, q931_call *call, int msgtype, int invoke_id,
 	enum rose_error_code code)
 {
 	unsigned char buffer[256];
@@ -3019,7 +3067,7 @@
 		return -1;
 	}
 
-	return pri_call_apdu_queue(call, Q931_FACILITY, buffer, end - buffer, NULL);
+	return pri_call_apdu_queue(call, msgtype, buffer, end - buffer, NULL);
 }
 
 /*!
@@ -3033,10 +3081,10 @@
  * \retval 0 on success.
  * \retval -1 on error.
  */

[... 4564 lines stripped ...]



More information about the svn-commits mailing list