Some more ISUP decoding and encoding routines, mostly for phone numbers
diff --git a/src/isup.hrl b/src/isup.hrl
index fc6bd32..b00eee3 100644
--- a/src/isup.hrl
+++ b/src/isup.hrl
@@ -1,53 +1,102 @@
 % Table 1 / Q.762 - ISDN user part message acronyms
+% Table C-3 / Q.762
+-define(ISUP_MSGT_ACM, 2#00000110).	%  Address complete
+-define(ISUP_MSGT_ANM, 2#00001001).	%  Answer
+%-define(ISUP_MSGT_APM).	%  Application transport
+-define(ISUP_MSGT_BLA, 2#00010101).	%  Blocking acknowledgement
+-define(ISUP_MSGT_BLO, 2#00010011).	%  Blocking
+-define(ISUP_MSGT_CCR, 2#00010001).	%  Continuity check request
+-define(ISUP_MSGT_CFN, 2#00101111).	%  Confusion
+-define(ISUP_MSGT_CGB, 2#00011000).	%  Circuit group blocking
+-define(ISUP_MSGT_CGBA,2#00011010).%  Circuit group blocking acknowledgement
+-define(ISUP_MSGT_CGU, 2#00011001).	%  Circuit group unblocking
+-define(ISUP_MSGT_CGUA,2#00011011).%  Circuit group unblocking acknowledgement
+-define(ISUP_MSGT_CON, 2#00000111).	%  Connect
+-define(ISUP_MSGT_COT, 2#00000101).	%  Continuity
+-define(ISUP_MSGT_CPG, 2#00101100).	%  Call progress
+-define(ISUP_MSGT_CRG, 2#00110001).	%  Charge information
+-define(ISUP_MSGT_CQM, 2#00101010).	%  Circuit group query
+-define(ISUP_MSGT_CQR, 2#00101011).	%  Circuit group query response
+-define(ISUP_MSGT_DRS, 2#00100111).	%  Delayed release (reserved – used in 1988 version)
+-define(ISUP_MSGT_FAA, 2#00100000).	%  Facility accepted
+%-define(ISUP_MSGT_FAC).	%  Facility
+-define(ISUP_MSGT_FAR, 2#00011111).	%  Facility request
+-define(ISUP_MSGT_FOT, 2#00001000).	%  Forward transfer
+-define(ISUP_MSGT_FRJ, 2#00100001).	%  Facility reject
+-define(ISUP_MSGT_GRA, 2#00101001).	%  Circuit group reset acknowledgement
+-define(ISUP_MSGT_GRS, 2#00010111).	%  Circuit group reset
+-define(ISUP_MSGT_IAM, 2#00000001).	%  Initial address
+%-define(ISUP_MSGT_IDR).	%  Identification request
+%-define(ISUP_MSGT_IRS).	%  Identification response
+-define(ISUP_MSGT_INF, 2#00000100).	%  Information
+-define(ISUP_MSGT_INR, 2#00000011).	%  Information request
+-define(ISUP_MSGT_LPA, 2#00100100).	%  Loop back acknowledgement
+%-define(ISUP_MSGT_LOP).	%  Loop prevention
+%-define(ISUP_MSGT_NRM).	%  Network resource management
+-define(ISUP_MSGT_OLM, 2#00110000).	%  Overload
+-define(ISUP_MSGT_PAM, 2#00101000).	%  Pass-along
+%-define(ISUP_MSGT_PRI).	%  Pre-release information
+-define(ISUP_MSGT_REL, 2#00001100).	%  Release
+-define(ISUP_MSGT_RES, 2#00001110).	%  Resume
+-define(ISUP_MSGT_RLC, 2#00010000).	%  Release complete
+-define(ISUP_MSGT_RSC, 2#00010010).	%  Reset circuit
+-define(ISUP_MSGT_SAM, 2#00000010).	%  Subsequent address
+%-define(ISUP_MSGT_SDM).	%  Subsequent directory number
+%-define(ISUP_MSGT_SGM).	%  Segmentation
+-define(ISUP_MSGT_SUS, 2#00001101).	%  Suspend
+-define(ISUP_MSGT_UBL, 2#00010100).	%  Unblocking
+-define(ISUP_MSGT_UBA, 2#00010110).	%  Unblocking acknowledgement
+-define(ISUP_MSGT_UCIC,2#00101110).%  Unequipped circuit identification code
+%-define(ISUP_MSGT_UPA).	%  User part available
+%-define(ISUP_MSGT_UPT).	%  User part test
+-define(ISUP_MSGT_USR, 2#00101101).	%  User-to-user information
 
--define(ISUP_MSGT_ACM).	%  Address complete
--define(ISUP_MSGT_ANM).	%  Answer
--define(ISUP_MSGT_APM).	%  Application transport
--define(ISUP_MSGT_BLA).	%  Blocking acknowledgement
--define(ISUP_MSGT_BLO).	%  Blocking
--define(ISUP_MSGT_CCR).	%  Continuity check request
--define(ISUP_MSGT_CFN).	%  Confusion
--define(ISUP_MSGT_CGB).	%  Circuit group blocking
--define(ISUP_MSGT_CGBA).%  Circuit group blocking acknowledgement
--define(ISUP_MSGT_CGU).	%  Circuit group unblocking
--define(ISUP_MSGT_CGUA).%  Circuit group unblocking acknowledgement
--define(ISUP_MSGT_CON).	%  Connect
--define(ISUP_MSGT_COT).	%  Continuity
--define(ISUP_MSGT_CPG).	%  Call progress
--define(ISUP_MSGT_CRG).	%  Charge information
--define(ISUP_MSGT_CQM).	%  Circuit group query
--define(ISUP_MSGT_CQR).	%  Circuit group query response
--define(ISUP_MSGT_DRS).	%  Delayed release (reserved – used in 1988 version)
--define(ISUP_MSGT_FAA).	%  Facility accepted
--define(ISUP_MSGT_FAC).	%  Facility
--define(ISUP_MSGT_FAR).	%  Facility request
--define(ISUP_MSGT_FOT).	%  Forward transfer
--define(ISUP_MSGT_FRJ).	%  Facility reject
--define(ISUP_MSGT_GRA).	%  Circuit group reset acknowledgement
--define(ISUP_MSGT_GRS).	%  Circuit group reset
--define(ISUP_MSGT_IAM).	%  Initial address
--define(ISUP_MSGT_IDR).	%  Identification request
--define(ISUP_MSGT_IRS).	%  Identification response
--define(ISUP_MSGT_INF).	%  Information
--define(ISUP_MSGT_INR).	%  Information request
--define(ISUP_MSGT_LPA).	%  Loop back acknowledgement
--define(ISUP_MSGT_LOP).	%  Loop prevention
--define(ISUP_MSGT_NRM).	%  Network resource management
--define(ISUP_MSGT_OLM).	%  Overload
--define(ISUP_MSGT_PAM).	%  Pass-along
--define(ISUP_MSGT_PRI).	%  Pre-release information
--define(ISUP_MSGT_REL).	%  Release
--define(ISUP_MSGT_RES).	%  Resume
--define(ISUP_MSGT_RLC).	%  Release complete
--define(ISUP_MSGT_RSC).	%  Reset circuit
--define(ISUP_MSGT_SAM).	%  Subsequent address
--define(ISUP_MSGT_SDM).	%  Subsequent directory number
--define(ISUP_MSGT_SGM).	%  Segmentation
--define(ISUP_MSGT_SUS).	%  Suspend
--define(ISUP_MSGT_UBL).	%  Unblocking
--define(ISUP_MSGT_UBA).	%  Unblocking acknowledgement
--define(ISUP_MSGT_UCIC).%  Unequipped circuit identification code
--define(ISUP_MSGT_UPA).	%  User part available
--define(ISUP_MSGT_UPT).	%  User part test
--define(ISUP_MSGT_USR).	%  User-to-user information
 
+% TABLE C-4/Q.767
+-define(ISUP_PAR_ACC_TRANSP,		2#00000011).	% Access transport
+-define(ISUP_PAR_AUT_CONG_LVL,		2#00100111).	% Automatic congestion level
+-define(ISUP_PAR_BACKW_CALL_IND,	2#00010001).	% Backward call indicators
+-define(ISUP_PAR_CALL_MOD_IND,		2#00010111).	% Call modification indicators
+-define(ISUP_PAR_CALL_REF,		2#00000001).	% Call reference
+-define(ISUP_PAR_CALLED_P_NUM,		2#00000100).	% Called party number
+-define(ISUP_PAR_CALLING_P_NUM,		2#00001010).	% Calling party number
+-define(ISUP_PAR_CALLING_P_CAT,		2#00001001).	% Calling party category
+-define(ISUP_PAR_CAUSE_IND,		2#00010010).	% Cause indicators
+-define(ISUP_PAR_CG_SUB_MSGT_IND,	2#00010101).	% Circuit group supervision message type indicator
+-define(ISUP_PAR_CIRC_STATE_IND,	2#00100110).	% Circuit state indicator
+-define(ISUP_PAR_CLSD_U_INTERL_CODE,	2#00011010).	% Closed user interlock code
+-define(ISUP_PAR_CONNECTED_NUM,		2#00100001).	% Connected number
+-define(ISUP_PAR_CONN_REQ,		2#00001101).	% Connection request
+-define(ISUP_PAR_CONTINUITY_IND,	2#00010000).	% Continuity idnicators
+-define(ISUP_PAR_END_OF_OPT,		2#00000000).	% End of optional parameters
+-define(ISUP_PAR_EVENT_INFO,		2#00100100).	% Event information
+-define(ISUP_PAR_FACILITY_IND,		2#00011000).	% Facility indicators
+-define(ISUP_PAR_FW_CALL_IND,		2#00000111).	% Forward call indicators
+-define(ISUP_PAR_INFO_IND,		2#00001111).	% Information indicators
+-define(ISUP_PAR_INFO_REQ_IND,		2#00001110).	% Information request indicatos
+-define(ISUP_PAR_NAT_OF_CONN_IND,	2#00000110).	% Nature of connection indicators
+-define(ISUP_PAR_OPT_BW_CALL_IND,	2#00101001).	% Optional backward call indicators
+-define(ISUP_PAR_OPT_FW_CALL_IND,	2#00001000).	% Optional forward call indicators
+-define(ISUP_PAR_ORIG_CALLED_NUM,	2#00101000).	% Original called number
+-define(ISUP_PAR_RANGE_AND_STATUS,	2#00010110).	% Range and status
+-define(ISUP_PAR_REDIR_NUM,		2#00001011).	% Redirecting number
+-define(ISUP_PAR_REDIR_INFO,		2#00010011).	% Redirection information
+-define(ISUP_PAR_REDIRECTION_NUM,	2#00001100).	% Redirection number
+-define(ISUP_PAR_SIGN_POINT_CODE,	2#00011110).	% Signalling point code
+-define(ISUP_PAR_SUBSEQ_NUM,		2#00000101).	% Subsequent number
+-define(ISUP_PAR_SUSP_RES_IND,		2#00100010).	% Suspend/resume indicators
+-define(ISUP_PAR_XMIT_NET_SEL,		2#00100011).	% Transmit network selection
+-define(ISUP_PAR_TRANSM_MED_REQ,	2#00000010).	% Transmission medium requirement
+-define(ISUP_PAR_USER_SERV_INFO,	2#00011101).	% User service information
+-define(ISUP_PAR_USER_USER_IND,		2#00101010).	% User-to-user indicators
+-define(ISUP_PAR_USER_USER_INFO,	2#00100000).	% User-to-user information
+
+-record(party_number, {
+	nature_of_addr_ind,
+	internal_net_num,	% only in called party
+	number_incompl_ind,	% only in calling party
+	numbering_plan,
+	present_restrict,	% only in calling party
+	screening_ind,		% only in calling party
+	phone_number}
+	).
diff --git a/src/isup_codec.erl b/src/isup_codec.erl
index 025808f..a98da31 100644
--- a/src/isup_codec.erl
+++ b/src/isup_codec.erl
@@ -23,6 +23,71 @@
 
 -export([parse_isup_msg/1, encode_isup_msg/1]).
 
+parse_isup_party(<<>>, OddEven, DigitList) ->
+	% in case of odd number of digits, we need to cut the last
+	case OddEven of
+		1 ->
+			lists:sublist(DigitList, lists:length(DigitList)-1);
+		0 ->
+			DigitList
+	end;
+parse_isup_party(BcdBin, OddEven, DigitList) ->
+	<<Second:4, First:4, Remain/binary>> = BcdBin,
+	NewDigits = [First, Second],
+	parse_isup_party(Remain, OddEven, DigitList ++ NewDigits).
+
+parse_isup_party(BinBcd, OddEven) when is_binary(BinBcd) ->
+	parse_isup_party(BinBcd, OddEven, []).
+
+
+% parse a single option
+parse_isup_opt(?ISUP_PAR_CALLED_P_NUM, OptLen, Content) ->
+	% C.3.7 Called Party Number
+	<<OddEven:1, Nature:7, Inn:1, NumPlan:3, 0:4, Remain/binary>> = Content,
+	PhoneNum = parse_isup_party(Remain, OddEven),
+	{OptType, #party_number{nature_of_addr_ind = Nature,
+				internal_net_num = Inn,
+				numbering_plan = NumPlan,
+				phone_number = PhoneNum}};
+parse_isup_opt(?ISUP_PAR_CALLING_P_NUM, OptLen, Content) ->
+	% C.3.8 Calling Party Number
+	<<OddEven:1, Nature:7, Ni:1, NumPlan:3, PresRestr:2, Screen:2, Remain/binary>> = Content,
+	PhoneNum = parse_isup_party(Remain, OddEven),
+	{OptType, #party_number{nature_of_addr_ind = Nature,
+				number_incompl_ind = Ni,
+				numbering_plan = NumPlan,
+				present_restrict = PresRestr,
+				screening_ind = Screen,
+				phone_number = PhoneNum}};
+parse_isup_opt(?ISUP_PAR_CONNECTED_NUM, OptLen, Content) ->
+	% C.3.14 Connected Number
+	<<OddEven:1, Nature:7, 0:1, NumPlan:3, PresRestr:2, Screen:2, Remain/binary>> = Content,
+	PhoneNum = parse_isup_party(Remain, OddEven),
+	{OptType, #party_number{nature_of_addr_ind = Nature,
+				numbering_plan = NumPlan,
+				present_restrict = PresRestr,
+				screening_ind = Screen,
+				phone_number = PhoneNum}};
+parse_isup_opt(?ISUP_PAR_SUBSEQ_NUM, OptLen, Content) ->
+	% C.3.32 Subsequent Number
+	<<OddEven:1, Spare:7, Remain/binary>> = Content,
+	PhoneNum = parse_isup_party(Remain, OddEven),
+	{OptType, #party_number{phone_number = PhoneNum}};
+parse_isup_opt(OptType, OptLen, Content) ->
+	{OptType, {OptLen, Content}}.
+
+% parse a Binary into a list of options
+parse_isup_opts(<<>>, OptList) ->
+	% empty list
+	OptList;
+parse_isup_opts(<<0>>, OptList) ->
+	% end of options
+	OptList;
+parse_isup_opts(OptBin, OptList) when is_binary(OptBin) ->
+	<<OptType:8, OptLen:8, Content:OptLen/binary, Remain/binary>> = OptBin,
+	NewOpt = parse_isup_opt(OptType, OptLen, Content),
+	parse_isup_opts(Remain, [NewOpt|OptList]).
+
 % References to 'Tabe C-xxx' are to Annex C of Q.767
 
 % Default case: no fixed and no variable parts, only options
@@ -30,29 +95,29 @@
 parse_isup_msgt(M, Bin) when
 	M == ?ISUP_MSGT_ANM;
 	M == ?ISUP_MSGT_RLC;
-	M == ?ISUP_MSGT_FOT;
+	M == ?ISUP_MSGT_FOT ->
 		parse_isup_opts(Bin);
 % Table C-5	Address complete
 parse_isup_msgt(?ISUP_MSGT_ACM, Bin) ->
 	<<BackCallInd:16, Remain/binary>> = Bin,
 	BciOpt = {backward_call_ind, BackCallInd},
-	Opts = parse_isup_opts(Remain)
+	Opts = parse_isup_opts(Remain),
 	[BciOpt|Opts];
 % Table C-7	Call progress
 parse_isup_msgt(?ISUP_MSGT_CPG, Bin) ->
 	<<EventInf:8, Remain/binary>> = Bin,
 	BciOpt = {event_info, EventInf},
-	Opts = parse_isup_opts(Remain)
+	Opts = parse_isup_opts(Remain),
 	[BciOpt|Opts];
 % Table C-9	Circuit group reset acknowledgement
 parse_isup_msgt(?ISUP_MSGT_GRA, Bin) ->
 	% V: Range and status
-
+	0;
 % Table C-11	Connect
 parse_isup_msgt(?ISUP_MSGT_CON, Bin) ->
 	<<BackCallInd:16, Remain/binary>> = Bin,
 	BciOpt = {backward_call_ind, BackCallInd},
-	Opts = parse_isup_opts(Remain)
+	Opts = parse_isup_opts(Remain),
 	[BciOpt|Opts];
 % Table C-12	Continuity
 parse_isup_msgt(?ISUP_MSGT_COT, Bin) ->
@@ -64,23 +129,23 @@
 	FixedOpts = [{conn_ind_nature, CINat}, {fw_call_ind, FwCallInd}, {calling_cat, CallingCat},
 		     {transm_medium_req, TransmReq}],
 	% V: Called Party Number
-	VarOpts = FIXME;
+	VarOpts = FIXME,
 	Opts = parse_isup_opts(Remain),
 	[FixedOpts,VarOpts,Opts];
 % Table C-17	Release
 parse_isup_msgt(?ISUP_MSGT_REL, Bin) ->
 	% V: Cause indicators
-	VarOpts = FIXME;
+	VarOpts = FIXME,
 	Opts = parse_isup_opts(Remain),
 	[VarOpts,Opts];
 % Table C-19	Subsequent address
 parse_isup_msgt(?ISUP_MSGT_SAM, Bin) ->
 	% V: Subsequent number
-	VarOpts = FIXME;
+	VarOpts = FIXME,
 	Opts = parse_isup_opts(Remain),
 	[VarOpts,Opts];
 % Table C-21	Suspend, Resume
-parse_isup_msgt(Msgt, Bin) when Msgt == ?ISUP_MSGT_RES or Msgt == ?ISUP_MSGT_SUS ->
+parse_isup_msgt(Msgt, Bin) when Msgt == ?ISUP_MSGT_RES; Msgt == ?ISUP_MSGT_SUS ->
 	<<SuspResInd:8, Remain/binary>> = Bin,
 	FixedOpts = [{susp_res_ind, SuspResInd}],
 	Opts = parse_isup_opts(Remain),
@@ -116,3 +181,48 @@
 	<<0:4, Cic:12/big, MsgType:8, Remain/binary>> = DataBin,
 	Opts = parse_isup_msgt(MsgType, Remain),
 	#isup_msg{cic = Cic, msg_type = MsgType, parameters = Opts}.
+
+
+encode_isup_party(BcdList) ->
+	encode_isup_party(BcdList, <<>>, list:length(BcdList)).
+encode_isup_party([], Bin, NumDigits) ->
+	case NumDigits rem 2 of
+		1 ->
+			{Bin, 1};
+		0 ->
+			{Bin, 0}
+	end;
+encode_isup_party([First,Second|BcdList], Bin, NumDigits) ->
+	encode_isup_party(BcdList, <<Bin/binary, Second:4, First:4>>).
+	
+% encode a single option
+encode_isup_opt(?ISUP_PAR_CALLED_P_NUM,
+		#party_number{nature_of_addr_ind = Nature,
+			      internal_net_num = Inn,
+			      numbering_plan = NumPlan,
+			      phone_number=  PhoneNum}) ->
+	% C.3.7 Called Party Number
+	{PhoneBin, OddEven} = encode_isup_party(PhoneNum),
+	<<OddEven:1, Nature:7, Inn:1, NumPlan:3, 0:4, PhoneBin/binary>>.
+encode_isup_opt(?ISUP_PAR_CALLING_P_NUM,
+		#party_number{nature_of_addr_ind = Nature,
+			      number_incompl_ind = Ni,
+			      numbering_plan = NumPlan,
+			      present_restrict = PresRestr,
+			      screening_ind = Screen,
+			      phone_number=  PhoneNum}) ->
+	% C.3.8 Calling Party Number
+	{PhoneBin, OddEven} = encode_isup_party(PhoneNum),
+	<<OddEven:1, Nature:7, Ni:1, NumPlan:3, PresRestr:2, Screen:2, PhoneBin/binary>>;
+encode_isup_opt(?ISUP_PAR_CONNECTED_NUM,
+		#party_number{nature_of_addr_ind = Nature,
+			      numbering_plan = NumPlan,
+			      present_restrict = PresRestr,
+			      screening_ind = Screen,
+			      phone_number = PhoneNum}) ->
+	% C.3.14 Connected Number
+	{PhoneBin, OddEven} = encode_isup_party(PhoneNum),
+	<<OddEven:1, Nature:7, 0:1, NumPlan:3, PresRestr:2, Screen:2, PhoneBin/binary>>;
+encode_isup_opt(OptNum, {OptLen, Binary}) when is_binary(Binary) ->
+	Binary.
+