Index: libpri.h
===================================================================
RCS file: /usr/cvsroot/libpri/libpri.h,v
retrieving revision 1.37
diff -u -r1.37 libpri.h
--- libpri.h	30 Oct 2004 20:19:18 -0000	1.37
+++ libpri.h	17 Nov 2004 18:27:21 -0000
@@ -49,35 +49,48 @@
 #define PRI_SWITCH_EUROISDN_E1	5	/* Standard EuroISDN (CTR4, ETSI 300-102) */
 #define PRI_SWITCH_EUROISDN_T1	6	/* T1 EuroISDN variant (ETSI 300-102) */
 #define PRI_SWITCH_NI1			7	/* National ISDN 1 */
-#define PRI_SWITCH_GR303_EOC		8	/* GR-303 Embedded Operations Channel */
-#define PRI_SWITCH_GR303_TMC		9	/* GR-303 Timeslot Management Channel */
+#define PRI_SWITCH_GR303_EOC	8	/* GR-303 Embedded Operations Channel */
+#define PRI_SWITCH_GR303_TMC	9	/* GR-303 Timeslot Management Channel */
 #define PRI_SWITCH_QSIG			10	/* QSIG Switch */
 /* Switchtypes 10 - 20 are reserved for internal use */
 
 
 /* PRI D-Channel Events */
-#define PRI_EVENT_DCHAN_UP	 	1	/* D-channel is up */
-#define PRI_EVENT_DCHAN_DOWN 	2	/* D-channel is down */
-#define PRI_EVENT_RESTART	 	3	/* B-channel is restarted */
-#define PRI_EVENT_CONFIG_ERR 	4	/* Configuration Error Detected */
-#define PRI_EVENT_RING		 	5	/* Incoming call */
-#define PRI_EVENT_HANGUP	 	6	/* Call got hung up */
-#define PRI_EVENT_RINGING	 	7	/* Call is ringing (alerting) */
-#define PRI_EVENT_ANSWER	 	8	/* Call has been answered */
-#define PRI_EVENT_HANGUP_ACK	9	/* Call hangup has been acknowledged */
+#define PRI_EVENT_DCHAN_UP		 1	/* D-channel is up */
+#define PRI_EVENT_DCHAN_DOWN 	 2	/* D-channel is down */
+#define PRI_EVENT_RESTART		 3	/* B-channel is restarted */
+#define PRI_EVENT_CONFIG_ERR 	 4	/* Configuration Error Detected */
+#define PRI_EVENT_RING			 5	/* Incoming call */
+#define PRI_EVENT_HANGUP		 6	/* Call got hung up */
+#define PRI_EVENT_RINGING		 7	/* Call is ringing (alerting) */
+#define PRI_EVENT_ANSWER		 8	/* Call has been answered */
+#define PRI_EVENT_HANGUP_ACK	 9	/* Call hangup has been acknowledged */
 #define PRI_EVENT_RESTART_ACK	10	/* Restart complete on a given channel */
-#define PRI_EVENT_FACNAME	11	/* Caller*ID Name received on Facility */
+#define PRI_EVENT_FACNAME		11	/* Caller*ID Name received on Facility */
 #define PRI_EVENT_INFO_RECEIVED 12	/* Additional info (keypad) received */
 #define PRI_EVENT_PROCEEDING	13	/* When we get CALL_PROCEEDING or PROGRESS */
-#define PRI_EVENT_SETUP_ACK	14	/* When we get SETUP_ACKNOWLEDGE */
+#define PRI_EVENT_SETUP_ACK		14	/* When we get SETUP_ACKNOWLEDGE */
 #define PRI_EVENT_HANGUP_REQ	15	/* Requesting the higher layer to hangup */
-#define PRI_EVENT_NOTIFY	16	/* Notification received */
-#define PRI_EVENT_PROGRESS	17	/* When we get CALL_PROCEEDING or PROGRESS */
+#define PRI_EVENT_NOTIFY		16	/* Notification received */
+#define PRI_EVENT_PROGRESS		17	/* When we get CALL_PROCEEDING or PROGRESS */
 
 /* Simple states */
 #define PRI_STATE_DOWN		0
 #define PRI_STATE_UP		1
 
+#define PRI_PROGRESS_MASK
+
+/* Progress indicator values */
+#define PRI_PROG_CALL_NOT_E2E_ISDN						(1 << 0)
+#define PRI_PROG_CALLED_NOT_ISDN						(1 << 1)
+#define PRI_PROG_CALLER_NOT_ISDN						(1 << 2)
+#define PRI_PROG_INBAND_AVAILABLE						(1 << 3)
+#define PRI_PROG_DELAY_AT_INTERF						(1 << 4)
+#define PRI_PROG_INTERWORKING_WITH_PUBLIC				(1 << 5)
+#define PRI_PROG_INTERWORKING_NO_RELEASE				(1 << 6)
+#define PRI_PROG_INTERWORKING_NO_RELEASE_PRE_ANSWER		(1 << 7)
+#define PRI_PROG_INTERWORKING_NO_RELEASE_POST_ANSWER	(1 << 8)
+
 /* Numbering plan identifier */
 #define PRI_NPI_UNKNOWN					0x0
 #define PRI_NPI_E163_E164				0x1
@@ -254,6 +267,7 @@
 	int channel;
 	int cref;
 	int progress;
+	int progressmask;
 	q931_call *call;
 } pri_event_ringing;
 
@@ -262,6 +276,7 @@
 	int channel;
 	int cref;
 	int progress;
+	int progressmask;
 	q931_call *call;
 } pri_event_answer;
 
@@ -293,6 +308,8 @@
 	int complete;				/* Have we seen "Complete" i.e. no more number? */
 	q931_call *call;			/* Opaque call pointer */
 	char callingsubaddr[256];		/* Calling parties subaddress */
+	int progress;
+	int progressmask;
 } pri_event_ring;
 
 typedef struct pri_event_hangup {
@@ -313,6 +330,7 @@
 	int channel;
 	int cref;
 	int progress;
+	int progressmask;
 	q931_call *call;
 } pri_event_proceeding;
  
Index: pri_internal.h
===================================================================
RCS file: /usr/cvsroot/libpri/pri_internal.h,v
retrieving revision 1.14
diff -u -r1.14 pri_internal.h
--- pri_internal.h	30 Oct 2004 20:13:19 -0000	1.14
+++ pri_internal.h	17 Nov 2004 18:27:21 -0000
@@ -132,7 +132,7 @@
 
 struct q931_call {
 	struct pri *pri;	/* PRI */
-	int cr;		/* Call Reference */
+	int cr;				/* Call Reference */
 	int forceinvert;	/* Force inversion of call number even if 0 */
 	q931_call *next;
 	/* Slotmap specified (bitmap of channels 31/24-1) (Channel Identifier IE) (-1 means not specified) */
@@ -146,10 +146,10 @@
 	
 	int alive;			/* Whether or not the call is alive */
 	int acked;			/* Whether setup has been acked or not */
-	int sendhangupack;		/* Whether or not to send a hangup ack */
+	int sendhangupack;	/* Whether or not to send a hangup ack */
 	int proc;			/* Whether we've sent a call proceeding / alerting */
 	
-	int ri;			/* Restart Indicator (Restart Indicator IE) */
+	int ri;				/* Restart Indicator (Restart Indicator IE) */
 
 	/* Bearer Capability */
 	int transcapability;
@@ -165,14 +165,15 @@
 	int progcode;			/* Progress coding */
 	int progloc;			/* Progress Location */	
 	int progress;			/* Progress indicator */
+	int progressmask;		/* Progress Indicator bitmask */
 	
-	int notify;			/* Notification */
+	int notify;				/* Notification */
 	
 	int causecode;			/* Cause Coding */
 	int causeloc;			/* Cause Location */
 	int cause;				/* Cause of clearing */
 	
-	int peercallstate;			/* Call state of peer as reported */
+	int peercallstate;		/* Call state of peer as reported */
 	int ourcallstate;		/* Our call state */
 	int sugcallstate;		/* Status call state */
 	
@@ -187,7 +188,7 @@
 	int nonisdn;
 	char callednum[256];	/* Called Number */
 	int complete;			/* no more digits coming */
-	int newcall;		/* if the received message has a new call reference value */
+	int newcall;			/* if the received message has a new call reference value */
 
 	int retranstimer;		/* Timer for retransmitting DISC */
 	int t308_timedout;		/* Whether t308 timed out once */
Index: q931.c
===================================================================
RCS file: /usr/cvsroot/libpri/q931.c,v
retrieving revision 1.98
diff -u -r1.98 q931.c
--- q931.c	7 Nov 2004 18:58:05 -0000	1.98
+++ q931.c	17 Nov 2004 18:27:21 -0000
@@ -32,6 +32,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <stdio.h>
+#include <limits.h>
 
 #define MAX_MAND_IES 10
 
@@ -177,7 +178,7 @@
 /* The 4ESS uses a different audio field */
 #define PRI_TRANS_CAP_AUDIO_4ESS	0x08
 
-
+/* Don't forget to update PRI_PROG_xxx at libpri.h */
 #define Q931_PROG_CALL_NOT_E2E_ISDN						0x01
 #define Q931_PROG_CALLED_NOT_ISDN						0x02
 #define Q931_PROG_CALLER_NOT_ISDN						0x03
@@ -205,11 +206,15 @@
 
 #define FUNC_DUMP(name) void ((name))(int full_ie, 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)
+#define FUNC_SEND(name) int ((name))(int full_ie, struct pri *pri, q931_call *call, int msgtype, q931_ie *ie, int len, int order)
 
 
 struct ie {
+	/* Maximal count of same IEs at the message (0 - any, 1..n - limited) */
+	int max_count;
+	/* IE code */
 	int ie;
+	/* IE friendly name */
 	char *name;
 	/* Dump an IE for debugging (preceed all lines by prefix) */
 	FUNC_DUMP(*dump);
@@ -316,6 +321,11 @@
 static FUNC_SEND(transmit_channel_id)
 {
 	int pos=0;
+
+	/* We are ready to transmit single IE only */
+	if (order > 1)
+		return 0;
+
 	/* Start with standard stuff */
 	if (pri->switchtype == PRI_SWITCH_GR303_TMC)
 		ie->data[pos] = 0x69;
@@ -589,6 +599,11 @@
 static FUNC_SEND(transmit_bearer_capability)
 {
 	int tc;
+
+	/* We are ready to transmit single IE only */	
+	if(order > 1)
+		return 0;
+
 	tc = call->transcapability;
 	if (pri->subchannel) {
 		/* Bearer capability is *hard coded* in GR-303 */
@@ -820,6 +835,8 @@
 
 static FUNC_SEND(transmit_redirecting_number)
 {
+	if (order > 1)
+		return 0;
 	if (call->redirectingnum && strlen(call->redirectingnum)) {
 		ie->data[0] = call->redirectingplan;
 		ie->data[1] = call->redirectingpres;
@@ -991,7 +1008,38 @@
 {
 	call->progloc = ie->data[0] & 0xf;
 	call->progcode = (ie->data[0] & 0x60) >> 5;
-	call->progress = (ie->data[1] & 0x7f);
+	switch (call->progress = (ie->data[1] & 0x7f)) {
+	case Q931_PROG_CALL_NOT_E2E_ISDN:
+		call->progressmask |= PRI_PROG_CALL_NOT_E2E_ISDN;
+		break;
+	case Q931_PROG_CALLED_NOT_ISDN:
+		call->progressmask |= PRI_PROG_CALLED_NOT_ISDN;
+		break;
+	case Q931_PROG_CALLER_NOT_ISDN:
+		call->progressmask |= PRI_PROG_CALLER_NOT_ISDN;
+		break;
+	case Q931_PROG_INBAND_AVAILABLE:
+		call->progressmask |= PRI_PROG_INBAND_AVAILABLE;
+		break;
+	case Q931_PROG_DELAY_AT_INTERF:
+		call->progressmask |= PRI_PROG_DELAY_AT_INTERF;
+		break;
+	case Q931_PROG_INTERWORKING_WITH_PUBLIC:
+		call->progressmask |= PRI_PROG_INTERWORKING_WITH_PUBLIC;
+		break;
+	case Q931_PROG_INTERWORKING_NO_RELEASE:
+		call->progressmask |= PRI_PROG_INTERWORKING_NO_RELEASE;
+		break;
+	case Q931_PROG_INTERWORKING_NO_RELEASE_PRE_ANSWER:
+		call->progressmask |= PRI_PROG_INTERWORKING_NO_RELEASE_PRE_ANSWER;
+		break;
+	case Q931_PROG_INTERWORKING_NO_RELEASE_POST_ANSWER:
+		call->progressmask |= PRI_PROG_INTERWORKING_NO_RELEASE_POST_ANSWER;
+		break;
+	default:
+		pri_error("XXX Invalid Progress indicator value received: %02x\n",(ie->data[1] & 0x7f));
+		break;
+	}
 	return 0;
 }
 
@@ -1086,15 +1134,42 @@
 
 static FUNC_SEND(transmit_progress_indicator)
 {
+	int code, mask;
 	/* Can't send progress indicator on GR-303 -- EVER! */
-	if (!pri->subchannel && (call->progress > 0)) {
-		ie->data[0] = 0x80 | (call->progcode << 5)  | (call->progloc);
-		ie->data[1] = 0x80 | (call->progress);
-		return 4;
-	} else {
-		/* Leave off */
+	if (pri->subchannel)
 		return 0;
+	if (call->progressmask > 0) {
+		if (call->progressmask & (mask = PRI_PROG_CALL_NOT_E2E_ISDN))
+			code = Q931_PROG_CALL_NOT_E2E_ISDN;
+		else if (call->progressmask & (mask = PRI_PROG_CALLED_NOT_ISDN))
+			code = Q931_PROG_CALLED_NOT_ISDN;
+		else if (call->progressmask & (mask = PRI_PROG_CALLER_NOT_ISDN))
+			code = Q931_PROG_CALLER_NOT_ISDN;
+		else if (call->progressmask & (mask = PRI_PROG_INBAND_AVAILABLE))
+			code = Q931_PROG_INBAND_AVAILABLE;
+		else if (call->progressmask & (mask = PRI_PROG_DELAY_AT_INTERF))
+			code = Q931_PROG_DELAY_AT_INTERF;
+		else if (call->progressmask & (mask = PRI_PROG_INTERWORKING_WITH_PUBLIC))
+			code = Q931_PROG_INTERWORKING_WITH_PUBLIC;
+		else if (call->progressmask & (mask = PRI_PROG_INTERWORKING_NO_RELEASE))
+			code = Q931_PROG_INTERWORKING_NO_RELEASE;
+		else if (call->progressmask & (mask = PRI_PROG_INTERWORKING_NO_RELEASE_PRE_ANSWER))
+			code = Q931_PROG_INTERWORKING_NO_RELEASE_PRE_ANSWER;
+		else if (call->progressmask & (mask = PRI_PROG_INTERWORKING_NO_RELEASE_POST_ANSWER))
+			code = Q931_PROG_INTERWORKING_NO_RELEASE_POST_ANSWER;
+		else {
+			code = 0;
+			pri_error("XXX Undefined progress bit: %x\n", call->progressmask);
+		}
+		if (code) {
+			ie->data[0] = 0x80 | (call->progcode << 5)  | (call->progloc);
+			ie->data[1] = 0x80 | code;
+			call->progressmask &= ~mask;
+			return 4;
+		}
 	}
+	/* Leave off */
+	return 0;
 }
 static FUNC_SEND(transmit_call_state)
 {
@@ -1237,30 +1312,33 @@
 
 static FUNC_DUMP(dump_network_spec_fac)
 {
-       pri_message("%c Network-Specific Facilities (len=%2d) [ ", prefix, ie->len);
-       if (ie->data[0] == 0x00) {
-               pri_message (code2str(ie->data[1], facilities, sizeof(facilities) / sizeof(facilities[0])));
-       }
-       else
-               dump_ie_data(ie->data, ie->len);
-       pri_message(" ]\n");
+	pri_message("%c Network-Specific Facilities (len=%2d) [ ", prefix, ie->len);
+	if (ie->data[0] == 0x00) {
+		pri_message (code2str(ie->data[1], facilities, sizeof(facilities) / sizeof(facilities[0])));
+	}
+	else
+		dump_ie_data(ie->data, ie->len);
+	pri_message(" ]\n");
 }
 
 static FUNC_RECV(receive_network_spec_fac)
 {
-       return 0;
+	return 0;
 }
 
 static FUNC_SEND(transmit_network_spec_fac)
 {
-       if (pri->nsf != PRI_NSF_NONE) {
-               ie->data[0] = 0x00;
-               ie->data[1] = pri->nsf;
-               return 4;
-       } else {
-               /* Leave off */
-               return 0;
-       }
+	/* We are ready to transmit single IE only */
+	if (order > 1)
+		return 0;
+
+	if (pri->nsf != PRI_NSF_NONE) {
+		ie->data[0] = 0x00;
+		ie->data[1] = pri->nsf;
+		return 4;
+	}
+	/* Leave off */
+	return 0;
 }
 
 char *pri_cause2str(int cause)
@@ -1306,6 +1384,10 @@
 
 static FUNC_SEND(transmit_cause)
 {
+	/* We are ready to transmit single IE only */
+	if (order > 1)
+		return 0;
+
 	if (call->cause > 0) {
 		ie->data[0] = 0x80 | (call->causecode << 5)  | (call->causeloc);
 		ie->data[1] = 0x80 | (call->cause);
@@ -1439,7 +1521,7 @@
 
 static FUNC_SEND(transmit_line_information)
 {
-#if 0	/* XXX Is this IE possible for 4ESS? XXX */
+#if 0	/* XXX Is this IE possible for 4ESS only? XXX */
 	if(pri->switchtype == PRI_SWITCH_ATT4ESS) {
 		ie->data[0] = 0;
 		return 3;
@@ -1600,6 +1682,9 @@
 static FUNC_SEND(transmit_generic_digits)
 {
 #if 0	/* XXX Is this IE possible for other switches? XXX */
+	if (order > 1)
+		return 0;
+
 	if(pri->switchtype == PRI_SWITCH_NI1) {
 		ie->data[0] = 0x04;	/* BCD even, Info Digits */
 		ie->data[1] = 0x00;	/* POTS */
@@ -1610,63 +1695,103 @@
 }
 
 
+static char *signal2str(int signal)
+{
+	/* From Q.931 4.5.8 Table 4-24 */
+	static struct msgtype mtsignal[] = {
+		{  0, "Dial tone" },
+		{  1, "Ring back tone" },
+		{  2, "Intercept tone" },
+		{  3, "Network congestion tone" },
+		{  4, "Busy tone" },
+		{  5, "Confirm tone" },
+		{  6, "Answer tone" },
+		{  7, "Call waiting tone" },
+		{  8, "Off-hook warning tone" },
+		{  9, "Pre-emption tone" },
+		{ 63, "Tones off" },
+		{ 64, "Alerting on - pattern 0" },
+		{ 65, "Alerting on - pattern 1" },
+		{ 66, "Alerting on - pattern 2" },
+		{ 67, "Alerting on - pattern 3" },
+		{ 68, "Alerting on - pattern 4" },
+		{ 69, "Alerting on - pattern 5" },
+		{ 70, "Alerting on - pattern 6" },
+		{ 71, "Alerting on - pattern 7" },
+		{ 79, "Alerting off" },
+	};
+	return code2str(signal, mtsignal, sizeof(mtsignal) / sizeof(mtsignal[0]));
+}
+
+
+static FUNC_DUMP(dump_signal)
+{
+	pri_message("%c Signal (len=%02d): ", prefix, len);
+	if (len < 3) {
+		pri_message("Invalid length\n");
+		return;
+	}
+	pri_message("Signal %s (%d)\n", signal2str(ie->data[0]), ie->data[0]);
+}
+
+
 struct ie ies[] = {
 	/* Codeset 0 - Common */
-	{ NATIONAL_CHANGE_STATUS, "Change Status" },
-	{ Q931_LOCKING_SHIFT, "Locking Shift", dump_shift },
-	{ Q931_BEARER_CAPABILITY, "Bearer Capability", dump_bearer_capability, receive_bearer_capability, transmit_bearer_capability },
-	{ Q931_CAUSE, "Cause", dump_cause, receive_cause, transmit_cause },
-	{ Q931_CALL_STATE, "Call State", dump_call_state, receive_call_state, transmit_call_state },
-	{ Q931_CHANNEL_IDENT, "Channel Identification", dump_channel_id, receive_channel_id, transmit_channel_id },
-	{ Q931_PROGRESS_INDICATOR, "Progress Indicator", dump_progress_indicator, receive_progress_indicator, transmit_progress_indicator },
-	{ Q931_NETWORK_SPEC_FAC, "Network-Specific Facilities", dump_network_spec_fac, receive_network_spec_fac, transmit_network_spec_fac },
-	{ Q931_INFORMATION_RATE, "Information Rate" },
-	{ Q931_TRANSIT_DELAY, "End-to-End Transit Delay" },
-	{ Q931_TRANS_DELAY_SELECT, "Transmit Delay Selection and Indication" },
-	{ Q931_BINARY_PARAMETERS, "Packet-layer Binary Parameters" },
-	{ Q931_WINDOW_SIZE, "Packet-layer Window Size" },
-	{ Q931_CLOSED_USER_GROUP, "Closed User Group" },
-	{ Q931_REVERSE_CHARGE_INDIC, "Reverse Charging Indication" },
-	{ Q931_CALLING_PARTY_NUMBER, "Calling Party Number", dump_calling_party_number, receive_calling_party_number, transmit_calling_party_number },
-	{ Q931_CALLING_PARTY_SUBADDR, "Calling Party Subaddress", dump_calling_party_subaddr, receive_calling_party_subaddr },
-	{ Q931_CALLED_PARTY_NUMBER, "Called Party Number", dump_called_party_number, receive_called_party_number, transmit_called_party_number },
-	{ Q931_CALLED_PARTY_SUBADDR, "Called Party Subaddress", dump_called_party_subaddr },
-	{ Q931_REDIRECTING_NUMBER, "Redirecting Number", dump_redirecting_number, receive_redirecting_number, transmit_redirecting_number },
-	{ Q931_REDIRECTING_SUBADDR, "Redirecting Subaddress", dump_redirecting_subaddr },
-	{ Q931_TRANSIT_NET_SELECT, "Transit Network Selection" },
-	{ Q931_RESTART_INDICATOR, "Restart Indicator", dump_restart_indicator, receive_restart_indicator, transmit_restart_indicator },
-	{ Q931_LOW_LAYER_COMPAT, "Low-layer Compatibility" },
-	{ Q931_HIGH_LAYER_COMPAT, "High-layer Compatibility" },
-	{ Q931_PACKET_SIZE, "Packet Size" },
-	{ Q931_IE_FACILITY, "Facility" , dump_facility, receive_facility, transmit_facility },
-	{ Q931_IE_REDIRECTION_NUMBER, "Redirection Number" },
-	{ Q931_IE_REDIRECTION_SUBADDR, "Redirection Subaddress" },
-	{ Q931_IE_FEATURE_ACTIVATE, "Feature Activation" },
-	{ Q931_IE_INFO_REQUEST, "Feature Request" },
-	{ Q931_IE_FEATURE_IND, "Feature Indication" },
-	{ Q931_IE_SEGMENTED_MSG, "Segmented Message" },
-	{ Q931_IE_CALL_IDENTITY, "Call Identity", dump_call_identity },
-	{ Q931_IE_ENDPOINT_ID, "Endpoint Identification" },
-	{ Q931_IE_NOTIFY_IND, "Notification Indicator", dump_notify, receive_notify, transmit_notify },
-	{ Q931_DISPLAY, "Display", dump_display, receive_display, transmit_display },
-	{ Q931_IE_TIME_DATE, "Date/Time", dump_time_date },
-	{ Q931_IE_KEYPAD_FACILITY, "Keypad Facility" },
-	{ Q931_IE_SIGNAL, "Signal" },
-	{ Q931_IE_SWITCHHOOK, "Switch-hook" },
-	{ Q931_IE_USER_USER, "User-User", dump_user_user, receive_user_user },
-	{ Q931_IE_ESCAPE_FOR_EXT, "Escape for Extension" },
-	{ Q931_IE_CALL_STATUS, "Call Status" },
-	{ Q931_IE_CHANGE_STATUS, "Change Status" },
-	{ Q931_IE_CONNECTED_ADDR, "Connected Number", dump_connected_number },
-	{ Q931_IE_CONNECTED_NUM, "Connected Number", dump_connected_number },
-	{ Q931_IE_ORIGINAL_CALLED_NUMBER, "Original Called Number" },
-	{ Q931_IE_USER_USER_FACILITY, "User-User Facility" },
-	{ Q931_IE_UPDATE, "Update" },
-	{ Q931_SENDING_COMPLETE, "Sending Complete", dump_sending_complete, receive_sending_complete, transmit_sending_complete },
+	{ 1, NATIONAL_CHANGE_STATUS, "Change Status" },
+	{ 0, Q931_LOCKING_SHIFT, "Locking Shift", dump_shift },
+	{ 0, Q931_BEARER_CAPABILITY, "Bearer Capability", dump_bearer_capability, receive_bearer_capability, transmit_bearer_capability },
+	{ 0, Q931_CAUSE, "Cause", dump_cause, receive_cause, transmit_cause },
+	{ 1, Q931_CALL_STATE, "Call State", dump_call_state, receive_call_state, transmit_call_state },
+	{ 0, Q931_CHANNEL_IDENT, "Channel Identification", dump_channel_id, receive_channel_id, transmit_channel_id },
+	{ 0, Q931_PROGRESS_INDICATOR, "Progress Indicator", dump_progress_indicator, receive_progress_indicator, transmit_progress_indicator },
+	{ 0, Q931_NETWORK_SPEC_FAC, "Network-Specific Facilities", dump_network_spec_fac, receive_network_spec_fac, transmit_network_spec_fac },
+	{ 1, Q931_INFORMATION_RATE, "Information Rate" },
+	{ 1, Q931_TRANSIT_DELAY, "End-to-End Transit Delay" },
+	{ 1, Q931_TRANS_DELAY_SELECT, "Transmit Delay Selection and Indication" },
+	{ 1, Q931_BINARY_PARAMETERS, "Packet-layer Binary Parameters" },
+	{ 1, Q931_WINDOW_SIZE, "Packet-layer Window Size" },
+	{ 1, Q931_CLOSED_USER_GROUP, "Closed User Group" },
+	{ 1, Q931_REVERSE_CHARGE_INDIC, "Reverse Charging Indication" },
+	{ 1, Q931_CALLING_PARTY_NUMBER, "Calling Party Number", dump_calling_party_number, receive_calling_party_number, transmit_calling_party_number },
+	{ 1, Q931_CALLING_PARTY_SUBADDR, "Calling Party Subaddress", dump_calling_party_subaddr, receive_calling_party_subaddr },
+	{ 1, Q931_CALLED_PARTY_NUMBER, "Called Party Number", dump_called_party_number, receive_called_party_number, transmit_called_party_number },
+	{ 1, Q931_CALLED_PARTY_SUBADDR, "Called Party Subaddress", dump_called_party_subaddr },
+	{ 0, Q931_REDIRECTING_NUMBER, "Redirecting Number", dump_redirecting_number, receive_redirecting_number, transmit_redirecting_number },
+	{ 1, Q931_REDIRECTING_SUBADDR, "Redirecting Subaddress", dump_redirecting_subaddr },
+	{ 0, Q931_TRANSIT_NET_SELECT, "Transit Network Selection" },
+	{ 1, Q931_RESTART_INDICATOR, "Restart Indicator", dump_restart_indicator, receive_restart_indicator, transmit_restart_indicator },
+	{ 0, Q931_LOW_LAYER_COMPAT, "Low-layer Compatibility" },
+	{ 0, Q931_HIGH_LAYER_COMPAT, "High-layer Compatibility" },
+	{ 1, Q931_PACKET_SIZE, "Packet Size" },
+	{ 1, Q931_IE_FACILITY, "Facility" , dump_facility, receive_facility, transmit_facility },
+	{ 1, Q931_IE_REDIRECTION_NUMBER, "Redirection Number" },
+	{ 1, Q931_IE_REDIRECTION_SUBADDR, "Redirection Subaddress" },
+	{ 1, Q931_IE_FEATURE_ACTIVATE, "Feature Activation" },
+	{ 1, Q931_IE_INFO_REQUEST, "Feature Request" },
+	{ 1, Q931_IE_FEATURE_IND, "Feature Indication" },
+	{ 1, Q931_IE_SEGMENTED_MSG, "Segmented Message" },
+	{ 1, Q931_IE_CALL_IDENTITY, "Call Identity", dump_call_identity },
+	{ 1, Q931_IE_ENDPOINT_ID, "Endpoint Identification" },
+	{ 1, Q931_IE_NOTIFY_IND, "Notification Indicator", dump_notify, receive_notify, transmit_notify },
+	{ 1, Q931_DISPLAY, "Display", dump_display, receive_display, transmit_display },
+	{ 1, Q931_IE_TIME_DATE, "Date/Time", dump_time_date },
+	{ 1, Q931_IE_KEYPAD_FACILITY, "Keypad Facility" },
+	{ 0, Q931_IE_SIGNAL, "Signal", dump_signal },
+	{ 1, Q931_IE_SWITCHHOOK, "Switch-hook" },
+	{ 1, Q931_IE_USER_USER, "User-User", dump_user_user, receive_user_user },
+	{ 1, Q931_IE_ESCAPE_FOR_EXT, "Escape for Extension" },
+	{ 1, Q931_IE_CALL_STATUS, "Call Status" },
+	{ 1, Q931_IE_CHANGE_STATUS, "Change Status" },
+	{ 1, Q931_IE_CONNECTED_ADDR, "Connected Number", dump_connected_number },
+	{ 1, Q931_IE_CONNECTED_NUM, "Connected Number", dump_connected_number },
+	{ 1, Q931_IE_ORIGINAL_CALLED_NUMBER, "Original Called Number" },
+	{ 1, Q931_IE_USER_USER_FACILITY, "User-User Facility" },
+	{ 1, Q931_IE_UPDATE, "Update" },
+	{ 1, Q931_SENDING_COMPLETE, "Sending Complete", dump_sending_complete, receive_sending_complete, transmit_sending_complete },
 	/* Codeset 6 - Network specific */
-	{ Q931_IE_ORIGINATING_LINE_INFO, "Originating Line Information", dump_line_information, receive_line_information, transmit_line_information },
-	{ Q931_IE_FACILITY | Q931_CODESET(6), "Facility", dump_facility, receive_facility, transmit_facility },
-	{ Q931_IE_GENERIC_DIGITS, "Generic Digits", dump_generic_digits, receive_generic_digits, transmit_generic_digits },
+	{ 1, Q931_IE_ORIGINATING_LINE_INFO, "Originating Line Information", dump_line_information, receive_line_information, transmit_line_information },
+	{ 1, Q931_IE_FACILITY | Q931_CODESET(6), "Facility", dump_facility, receive_facility, transmit_facility },
+	{ 0, Q931_IE_GENERIC_DIGITS, "Generic Digits", dump_generic_digits, receive_generic_digits, transmit_generic_digits },
 	/* Codeset 7 */
 };
 
@@ -1886,8 +2011,9 @@
 static int add_ie(struct pri *pri, q931_call *call, int msgtype, int ie, q931_ie *iet, int maxlen, int *codeset)
 {
 	unsigned int x;
-	int res;
+	int res, total_res;
 	int have_shift;
+	int ies_count, order;
 	for (x=0;x<sizeof(ies) / sizeof(ies[0]);x++) {
 		if (ies[x].ie == ie) {
 			/* This is our baby */
@@ -1902,19 +2028,32 @@
 				}
 				else
 					have_shift = 0;
-				iet->ie = ie;
-				res = ies[x].transmit(ie, pri, call, msgtype, iet, maxlen);
-				/* Error if res < 0 or ignored if res == 0 */
-				if (res <= 0)
-					return res;
-				if ((iet->ie & 0x80) == 0) /* Multibyte IE */
-					iet->len = res - 2;
-				if (have_shift) {
+				ies_count = ies[x].max_count;
+				if (ies_count == 0)
+					ies_count = INT_MAX;
+				order = 0;
+				total_res = 0;
+				do {
+					iet->ie = ie;
+					res = ies[x].transmit(ie, pri, call, msgtype, iet, maxlen, ++order);
+					/* Error if res < 0 or ignored if res == 0 */
+					if (res < 0)
+						return res;
+					if (res > 0) {
+						if ((iet->ie & 0x80) == 0) /* Multibyte IE */
+							iet->len = res - 2;
+						total_res += res;
+						maxlen -= res;
+						iet = (q931_ie *)((char *)iet + res);
+					}
+				}
+				while (res > 0 && order < ies_count);
+				if (have_shift && total_res) {
 					if (Q931_IE_CODESET(ies[x].ie))
 						*codeset = Q931_IE_CODESET(ies[x].ie);
-					return res + 1; /* Shift is single-byte IE */
+					return total_res + 1; /* Shift is single-byte IE */
 				}
-				return res;
+				return total_res;
 			} else {
 				pri_error("!! Don't know how to add an IE %s (%d)\n", ie2str(ie), ie);
 				return -1;
@@ -2141,9 +2280,12 @@
 	if (info) {
 		c->progloc = LOC_PRIV_NET_LOCAL_USER;
 		c->progcode = CODE_CCITT;
-		c->progress = Q931_PROG_INBAND_AVAILABLE;
-	} else
-		c->progress = -1;
+		c->progressmask = PRI_PROG_INBAND_AVAILABLE;
+	} else {
+		/* PI is mandatory IE for PROGRESS message - Q.931 3.1.8 */
+		pri_error("XXX Progress message requested but no information is provided\n");
+		c->progressmask = 0;
+	}
 	c->alive = 1;
 	return send_message(pri, c, Q931_PROGRESS, call_progress_ies);
 }
@@ -2168,9 +2310,9 @@
 	if (info) {
 		c->progloc = LOC_PRIV_NET_LOCAL_USER;
 		c->progcode = CODE_CCITT;
-		c->progress = Q931_PROG_INBAND_AVAILABLE;
+		c->progressmask = PRI_PROG_INBAND_AVAILABLE;
 	} else
-		c->progress = -1;
+		c->progressmask = 0;
 	c->proc = 1;
 	c->alive = 1;
 	return send_message(pri, c, Q931_CALL_PROCEEDING, call_proceeding_ies);
@@ -2188,9 +2330,9 @@
 	if (info) {
 		c->progloc = LOC_PRIV_NET_LOCAL_USER;
 		c->progcode = CODE_CCITT;
-		c->progress = Q931_PROG_INBAND_AVAILABLE;
+		c->progressmask = PRI_PROG_INBAND_AVAILABLE;
 	} else
-		c->progress = -1;
+		c->progressmask = 0;
 	c->ourcallstate = Q931_CALL_STATE_CALL_RECEIVED;
 	c->peercallstate = Q931_CALL_STATE_CALL_DELIVERED;
 	c->alive = 1;
@@ -2211,9 +2353,9 @@
 	if (nonisdn && (pri->switchtype != PRI_SWITCH_DMS100)) {
 		c->progloc  = LOC_PRIV_NET_LOCAL_USER;
 		c->progcode = CODE_CCITT;
-		c->progress = Q931_PROG_CALLED_NOT_ISDN;
+		c->progressmask = PRI_PROG_CALLED_NOT_ISDN;
 	} else
-		c->progress = -1;
+		c->progressmask = 0;
 	c->ourcallstate = Q931_CALL_STATE_OVERLAP_RECEIVING;
 	c->peercallstate = Q931_CALL_STATE_OVERLAP_SENDING;
 	c->alive = 1;
@@ -2282,9 +2424,9 @@
 	if (nonisdn && (pri->switchtype != PRI_SWITCH_DMS100)) {
 		c->progloc  = LOC_PRIV_NET_LOCAL_USER;
 		c->progcode = CODE_CCITT;
-		c->progress = Q931_PROG_CALLED_NOT_ISDN;
+		c->progressmask = PRI_PROG_CALLED_NOT_ISDN;
 	} else
-		c->progress = -1;
+		c->progressmask = 0;
 	c->ourcallstate = Q931_CALL_STATE_CONNECT_REQUEST;
 	c->peercallstate = Q931_CALL_STATE_ACTIVE;
 	c->alive = 1;
@@ -2439,9 +2581,9 @@
 		return -1;
 
 	if (req->nonisdn && (pri->switchtype == PRI_SWITCH_NI2))
-		c->progress = Q931_PROG_CALLER_NOT_ISDN;
+		c->progressmask = PRI_PROG_CALLER_NOT_ISDN;
 	else
-		c->progress = -1;
+		c->progressmask = 0;
 	if (pri->subchannel)
 		res = send_message(pri, c, Q931_SETUP, gr303_setup_ies);
 	else
@@ -2659,19 +2801,19 @@
                 c->useruserprotocoldisc = -1; 
 		strcpy(c->useruserinfo, "");
 		c->complete = 0;
-		break;
+		c->nonisdn = 0;
+		/* Fall through */
 	case Q931_CONNECT:
 	case Q931_ALERTING:
 	case Q931_PROGRESS:
+	case Q931_CALL_PROCEEDING:
 		c->progress = -1;
+		c->progressmask = 0;
 		break;
 	case Q931_CONNECT_ACKNOWLEDGE:
 		if (c->retranstimer)
 			pri_schedule_del(pri, c->retranstimer);
 		c->retranstimer = 0;
-		/* Fall through */
-	case Q931_CALL_PROCEEDING:
-		/* Do nothing */
 		break;
 	case Q931_RELEASE:
 	case Q931_DISCONNECT:
@@ -2838,6 +2980,12 @@
 		if (!c->newcall) {
 			break;
 		}
+		if (c->transmoderate != TRANS_MODE_64_CIRCUIT) {
+			q931_release_complete(pri, c, PRI_CAUSE_BEARERCAPABILITY_NOTIMPL);
+			break;
+		}
+		if (c->progressmask & PRI_PROG_CALLER_NOT_ISDN)
+			c->nonisdn = 1;
 		c->newcall = 0;
 		c->ourcallstate = Q931_CALL_STATE_CALL_PRESENT;
 		c->peercallstate = Q931_CALL_STATE_CALL_INITIATED;
@@ -2861,10 +3009,8 @@
 		pri->ev.ring.layer1 = c->userl1;
 		pri->ev.ring.complete = c->complete; 
 		pri->ev.ring.ctype = c->transcapability;
-		if (c->transmoderate != TRANS_MODE_64_CIRCUIT) {
-			q931_release_complete(pri, c, PRI_CAUSE_BEARERCAPABILITY_NOTIMPL);
-			break;
-		}
+		pri->ev.ring.progress = c->progress;
+		pri->ev.ring.progressmask = c->progressmask;
 		return Q931_RES_HAVEEVENT;
 	case Q931_ALERTING:
 		if (c->newcall) {
@@ -2878,6 +3024,7 @@
 		pri->ev.ringing.cref = c->cr;
 		pri->ev.ringing.call = c;
 		pri->ev.ringing.progress = c->progress;
+		pri->ev.ringing.progressmask = c->progressmask;
 		return Q931_RES_HAVEEVENT;
 	case Q931_CONNECT:
 		if (c->newcall) {
@@ -2895,6 +3042,7 @@
 		pri->ev.answer.cref = c->cr;
 		pri->ev.answer.call = c;
 		pri->ev.answer.progress = c->progress;
+		pri->ev.answer.progressmask = c->progressmask;
 		q931_connect_acknowledge(pri, c);
 		return Q931_RES_HAVEEVENT;
 	case Q931_FACILITY:
@@ -2939,6 +3087,7 @@
 			c->peercallstate = Q931_CALL_STATE_INCOMING_CALL_PROCEEDING;
 		}
 		pri->ev.proceeding.progress = c->progress;
+		pri->ev.proceeding.progressmask = c->progressmask;
 		pri->ev.proceeding.cref = c->cr;
 		pri->ev.proceeding.call = c;
 		return Q931_RES_HAVEEVENT;
