[libpri-commits] rmudgett: branch group/ccss r1248 - /team/group/ccss/

SVN commits to the libpri project libpri-commits at lists.digium.com
Fri Oct 23 16:10:41 CDT 2009


Author: rmudgett
Date: Fri Oct 23 16:10:37 2009
New Revision: 1248

URL: http://svnview.digium.com/svn/libpri?view=rev&rev=1248
Log:
Merged revisions 1242 via svnmerge from 
https://origsvn.digium.com/svn/libpri/branches/1.4

........
  r1242 | rmudgett | 2009-10-23 14:50:45 -0500 (Fri, 23 Oct 2009) | 16 lines
  
  Add BRI PTMP NT mode, HOLD/RETRIEVE, Call rerouting/deflection, and keypad facility support.
  
  * Added support for BRI PTMP NT mode.  (Overlap dialing NT -> TE not supported.)
  * Added handling of received HOLD/RETRIEVE messages and the optional ability
    to transfer a held call on disconnect similar to an analog phone.
  * Added CallRerouting/CallDeflection support for Q.SIG, ETSI PTP, ETSI PTMP.
    Will reroute/deflect an outgoing call when receive the message.
    Can use the DAHDISendCallreroutingFacility to send the message for the
    supported switches.
  * Added ability to send/receive keypad digits in the SETUP message.
    Send keypad digits in SETUP message: Dial(DAHDI/g1[/K<keypad_digits>][/extension])
    Access any received keypad digits in SETUP message by: ${CHANNEL(keypad_digits)}
  
  (closes issue #15048)
  Tested by: rmudgett, mattf
........

Modified:
    team/group/ccss/   (props changed)
    team/group/ccss/libpri.h
    team/group/ccss/pri.c
    team/group/ccss/pri_facility.c
    team/group/ccss/pri_facility.h
    team/group/ccss/pri_internal.h
    team/group/ccss/pri_q921.h
    team/group/ccss/pri_q931.h
    team/group/ccss/q921.c
    team/group/ccss/q931.c

Propchange: team/group/ccss/
------------------------------------------------------------------------------
    automerge = *

Propchange: team/group/ccss/
------------------------------------------------------------------------------
--- svnmerge-integrated (original)
+++ svnmerge-integrated Fri Oct 23 16:10:37 2009
@@ -1,1 +1,1 @@
-/branches/1.4:1-1237
+/branches/1.4:1-1242

Modified: team/group/ccss/libpri.h
URL: http://svnview.digium.com/svn/libpri/team/group/ccss/libpri.h?view=diff&rev=1248&r1=1247&r2=1248
==============================================================================
--- team/group/ccss/libpri.h (original)
+++ team/group/ccss/libpri.h Fri Oct 23 16:10:37 2009
@@ -91,6 +91,12 @@
 #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
@@ -200,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 */
@@ -212,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 */
@@ -482,6 +490,33 @@
 	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;
+};
+
 /* BUGBUG eliminate this struct definition. */
 /* Structures for qsig_cc_facilities */
 struct pri_qsig_cc_extension {
@@ -507,19 +542,20 @@
 /* Subcommands derived from supplementary services. */
 #define PRI_SUBCMD_REDIRECTING				1	/*!< Redirecting information update */
 #define PRI_SUBCMD_CONNECTED_LINE			2	/*!< Connected line information update */
-#define PRI_SUBCMD_STATUS_REQ				3	/*!< Determine the status of the given party. */
-#define PRI_SUBCMD_STATUS_REQ_RSP			4	/*!< Status request response */
-#define PRI_SUBCMD_CC_RECORD_RETENTION		5	/*!< Give cc_id to upper layer */
-#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 */
-#define PRI_SUBCMD_CC_STATUS_REQ			10	/*!< Request/prod to receive updates of CC party A status */
-#define PRI_SUBCMD_CC_STATUS				11	/*!< Unsolicited update of CC party A status */
-#define PRI_SUBCMD_CC_CALL					12	/*!< Indicate that this call is a CC callback */
-#define PRI_SUBCMD_CC_CANCEL				13	/*!< Unsolicited indication that CC is canceled */
-#define PRI_SUBCMD_CC_DEACTIVATE_REQ		14	/*!< CC deactivation request */
-#define PRI_SUBCMD_CC_DEACTIVATE_RSP		15	/*!< CC deactivation request response */
+#define PRI_SUBCMD_REROUTING				3	/*!< CallRerouting/CallDeflection received. */
+#define PRI_SUBCMD_STATUS_REQ				4	/*!< Determine the status of the given party. */
+#define PRI_SUBCMD_STATUS_REQ_RSP			5	/*!< Status request response */
+#define PRI_SUBCMD_CC_RECORD_RETENTION		6	/*!< Give cc_id to upper layer */
+#define PRI_SUBCMD_CC_AVAILABLE				7	/*!< Indicate that CC is available */
+#define PRI_SUBCMD_CC_REQ					8	/*!< CC activation request */
+#define PRI_SUBCMD_CC_REQ_RSP				9	/*!< CC activation request response */
+#define PRI_SUBCMD_CC_REMOTE_USER_FREE		10	/*!< Indicate that CC party B is available */
+#define PRI_SUBCMD_CC_STATUS_REQ			11	/*!< Request/prod to receive updates of CC party A status */
+#define PRI_SUBCMD_CC_STATUS				12	/*!< Unsolicited update of CC party A status */
+#define PRI_SUBCMD_CC_CALL					13	/*!< Indicate that this call is a CC callback */
+#define PRI_SUBCMD_CC_CANCEL				14	/*!< Unsolicited indication that CC is canceled */
+#define PRI_SUBCMD_CC_DEACTIVATE_REQ		15	/*!< CC deactivation request */
+#define PRI_SUBCMD_CC_DEACTIVATE_RSP		16	/*!< CC deactivation request response */
 
 struct pri_subcmd_status_request {
 	/*!
@@ -679,6 +715,7 @@
 		char reserve_space[512];
 		struct pri_party_connected_line connected_line;
 		struct pri_party_redirecting redirecting;
+		struct pri_rerouting_data rerouting;
 		struct pri_subcmd_status_request status_request;
 		struct pri_subcmd_status_request_rsp status_request_rsp;
 		struct pri_subcmd_cc_id cc_available;
@@ -716,13 +753,14 @@
  * Event channel parameter encoding:
  * 3322 2222 2222 1111 1111 1100 0000 0000
  * 1098 7654 3210 9876 5432 1098 7654 3210
- * xxxx xxxx xxxx xxDC BBBBBBBBB AAAAAAAAA
+ * 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)
@@ -786,10 +824,16 @@
 	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
@@ -828,6 +872,7 @@
 	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 {
@@ -835,10 +880,22 @@
 	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 */
 	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 {
@@ -870,6 +927,7 @@
 	int channel;
 	int info;
 	struct pri_subcommands *subcmds;
+	q931_call *call;
 } pri_event_notify;
 
 typedef struct pri_event_keypad_digit {
@@ -891,6 +949,51 @@
 	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;
@@ -910,6 +1013,12 @@
 	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;
@@ -1124,6 +1233,16 @@
 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);
 
 /* BUGBUG eliminate this prototype. */
 int pri_sr_set_ccringout(struct pri_sr *sr, int ccringout);
@@ -1214,6 +1333,157 @@
 int pri_notify(struct pri *pri, q931_call *c, int channel, int info);
 
 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);
 
 int pri_status_request(struct pri *ctrl, int request_id, const struct pri_sr *req);
 void pri_status_request_response(struct pri *ctrl, int invoke_id, int status);
@@ -1271,6 +1541,9 @@
 	PRI_TIMER_TM20,	/*!< Maximum time awaiting XID response */
 	PRI_TIMER_NM20,	/*!< 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_STATUS,		/*!< Max time to wait for all replies to check for compatible terminals */
 
 	PRI_TIMER_T_ACTIVATE,	/*!< Request supervision timeout. */

Modified: team/group/ccss/pri.c
URL: http://svnview.digium.com/svn/libpri/team/group/ccss/pri.c?view=diff&rev=1248&r1=1247&r2=1248
==============================================================================
--- team/group/ccss/pri.c (original)
+++ team/group/ccss/pri.c Fri Oct 23 16:10:37 2009
@@ -87,6 +87,8 @@
 	{ "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-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 },
@@ -169,6 +171,10 @@
 	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. */
 
 	/* ETSI timers */
 	ctrl->timers[PRI_TIMER_T_STATUS] = 4 * 1000;	/* Max time to wait for all replies to check for compatible terminals */
@@ -424,6 +430,12 @@
 		{ 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* */
 	};
 
@@ -582,26 +594,17 @@
 	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)
+int pri_notify(struct pri *pri, q931_call *call, int channel, int info)
 {
 	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)
-		return -1;
 	return q931_notify(pri, call, channel, info);
 }
 
 void pri_destroycall(struct pri *pri, q931_call *call)
 {
 	if (pri && call)
-		__q931_destroycall(pri, call);
+		q931_destroycall(pri, call);
 	return;
 }
 
@@ -712,6 +715,8 @@
 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;
@@ -724,6 +729,16 @@
 		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:
@@ -766,6 +781,9 @@
 
 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;
 	}
@@ -774,6 +792,21 @@
 	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:
@@ -1147,7 +1180,7 @@
 	vsnprintf(tmp, sizeof(tmp), fmt, ap);
 	va_end(ap);
 	if (__pri_message)
-		__pri_message(pri, tmp);
+		__pri_message(PRI_MASTER(pri), tmp);
 	else
 		fputs(tmp, stdout);
 }
@@ -1160,7 +1193,7 @@
 	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);
 }
@@ -1479,6 +1512,127 @@
 	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);
+}
+
 int pri_sr_set_ccringout(struct pri_sr *sr, int ccringout)
 {
 	sr->ccringout = ccringout;

Modified: team/group/ccss/pri_facility.c
URL: http://svnview.digium.com/svn/libpri/team/group/ccss/pri_facility.c?view=diff&rev=1248&r1=1247&r2=1248
==============================================================================
--- team/group/ccss/pri_facility.c (original)
+++ team/group/ccss/pri_facility.c Fri Oct 23 16:10:37 2009
@@ -525,6 +525,24 @@
 
 /*!
  * \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)
+{
+	rose_copy_number_to_q931(ctrl, &q931_address->number, &rose_address->number);
+}
+
+/*!
+ * \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.
@@ -658,6 +676,22 @@
 
 /*!
  * \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)
+{
+	q931_copy_number_to_rose(ctrl, &rose_address->number, &q931_address->number);
+}
+
+/*!
+ * \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.
@@ -1664,17 +1698,24 @@
  * \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 Calling party info.
- * \param dest Destination number.
- * \param original Original called number.
- * \param reason Rerouting reason: cfu, cfb, cfnr
+ * \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 char *dest, const char *original, const char *reason)
+	const struct q931_party_redirecting *deflection, int subscription_option)
 {
 	struct fac_extension_header header;
 	struct rose_msg_invoke msg;
@@ -1695,26 +1736,13 @@
 	msg.operation = ROSE_QSIG_CallRerouting;
 	msg.invoke_id = get_invokeid(ctrl);
 
-	/* The rerouting_reason defaults to unknown */
-	if (reason) {
-		if (!strcasecmp(reason, "cfu")) {
-			msg.args.qsig.CallRerouting.rerouting_reason = 1;	/* cfu */
-		} else if (!strcasecmp(reason, "cfb")) {
-			msg.args.qsig.CallRerouting.rerouting_reason = 2;	/* cfb */
-		} else if (!strcasecmp(reason, "cfnr")) {
-			msg.args.qsig.CallRerouting.rerouting_reason = 3;	/* cfnr */
-		}
-	}
-
-	/* calledAddress is the passed in dest number */
-	msg.args.qsig.CallRerouting.called.number.plan = 1;	/* public */
-	msg.args.qsig.CallRerouting.called.number.ton = 0;	/* unknown */
-	libpri_copy_string((char *) msg.args.qsig.CallRerouting.called.number.str, dest,
-		sizeof(msg.args.qsig.CallRerouting.called.number.str));
-	msg.args.qsig.CallRerouting.called.number.length = strlen((char *)
-		msg.args.qsig.CallRerouting.called.number.str);
-
-	msg.args.qsig.CallRerouting.diversion_counter = call->redirecting.count + 1;
+	msg.args.qsig.CallRerouting.rerouting_reason =
+		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);
+
+	msg.args.qsig.CallRerouting.diversion_counter = deflection->count;
 
 	/* pSS1InfoElement */
 	q931ie_pos = msg.args.qsig.CallRerouting.q931ie_contents;
@@ -1730,30 +1758,276 @@
 	msg.args.qsig.CallRerouting.q931ie.length = q931ie_pos
 		- msg.args.qsig.CallRerouting.q931ie_contents;
 
-	/* lastReroutingNr is the passed in original number */
-	msg.args.qsig.CallRerouting.last_rerouting.presentation = 0;	/* presentationAllowedNumber */
-	msg.args.qsig.CallRerouting.last_rerouting.number.plan = 1;	/* public */
-	msg.args.qsig.CallRerouting.last_rerouting.number.ton = 0;	/* unknown */
-	libpri_copy_string((char *) msg.args.qsig.CallRerouting.last_rerouting.number.str,
-		original, sizeof(msg.args.qsig.CallRerouting.last_rerouting.number.str));
-	msg.args.qsig.CallRerouting.last_rerouting.number.length = strlen((char *)
-		msg.args.qsig.CallRerouting.last_rerouting.number.str);
-
-	msg.args.qsig.CallRerouting.subscription_option = 0;	/* noNotification */
+	/* 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);
+
+	msg.args.qsig.CallRerouting.subscription_option = subscription_option;
 
 	/* callingNumber is the passed in calling->number */
 	q931_copy_presented_number_screened_to_rose(ctrl,
 		&msg.args.qsig.CallRerouting.calling, &calling->number);
 
+	/* callingPartySubaddress is the passed in calling->subaddress if valid */
+
 	/* 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);
+		q931_copy_name_to_rose(ctrl, &msg.args.qsig.CallRerouting.calling_name,
+			&calling->name);
+	}
+
+	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);
+
+		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);
 
 	return pos;
+}
+
+/*!
+ * \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;
+
+	pos = facility_encode_header(ctrl, pos, end, NULL);
+	if (!pos) {
+		return NULL;
+	}
+
+	memset(&msg, 0, sizeof(msg));
+	msg.operation = ROSE_ETSI_CallRerouting;
+	msg.invoke_id = get_invokeid(ctrl);
+
+	msg.args.etsi.CallRerouting.rerouting_reason =
+		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,
+		&deflection->to);
+
+	msg.args.etsi.CallRerouting.rerouting_counter = deflection->count;
+
+	/* 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;
+
+	/* 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);
+
+	msg.args.etsi.CallRerouting.subscription_option = subscription_option;
+
+	/* callingPartySubaddress is the passed in calling->subaddress if valid */
+
+	pos = rose_encode_invoke(ctrl, pos, end, &msg);
+
+	return pos;
+}
+
+/*!
+ * \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;
+
+	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);
+
+	/* deflectionAddress is the passed in deflection->to address */
+	q931_copy_address_to_rose(ctrl, &msg.args.etsi.CallDeflection.deflection,
+		deflection);
+
+	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;
+	}
+
+	return pri_call_apdu_queue(call, Q931_FACILITY, buffer, end - buffer, NULL, NULL);
+}
+
+/*!
+ * \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;
 }
 

[... 3710 lines stripped ...]



More information about the libpri-commits mailing list