From 84adefa331c4159d432d22840663c38f155cd4c1 Mon Sep 17 00:00:00 2001 From: Erlang/OTP Date: Fri, 20 Nov 2009 14:54:40 +0000 Subject: The R13B03 release. --- lib/megaco/src/text/megaco_text_gen_v2.hrl | 2794 ++++++++++++++++++++++++++++ 1 file changed, 2794 insertions(+) create mode 100644 lib/megaco/src/text/megaco_text_gen_v2.hrl (limited to 'lib/megaco/src/text/megaco_text_gen_v2.hrl') diff --git a/lib/megaco/src/text/megaco_text_gen_v2.hrl b/lib/megaco/src/text/megaco_text_gen_v2.hrl new file mode 100644 index 0000000000..6cfcac8664 --- /dev/null +++ b/lib/megaco/src/text/megaco_text_gen_v2.hrl @@ -0,0 +1,2794 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2003-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%%---------------------------------------------------------------------- +%% Purpose: Encode V2 Megaco/H.248 text messages from internal form +%% The following was changed: +%% - MuxType (Nx64kToken) +%% - auditItem (terminationAudit) +%% - serviceChangeParm (auditItem) +%% +%% The following was added: +%% - All IndAud stuff +%%---------------------------------------------------------------------- + +%% -define(d(F,A), io:format("~w:" ++ F ++ "~n", [?MODULE|A])). + +-define(META_ENC(Type, Item), Item) . +%% -define(META_ENC(Type, Item), megaco_meta_package:encode(text, Type, Item)). +%% -define(META_DEC(Type, Item), megaco_meta_package:decode(text, Type, Item)). + +enc_MegacoMessage(Val) -> + State = ?INIT_INDENT, + enc_MegacoMessage(Val, State). + +enc_MegacoMessage(#'MegacoMessage'{authHeader = asn1_NOVALUE, + mess = Mess}, State) -> + [ + ?LWSP, + enc_Message(Mess, State) + ]; +enc_MegacoMessage(#'MegacoMessage'{authHeader = Auth, + mess = Mess}, State) -> + [ + ?LWSP, + enc_AuthenticationHeader(Auth, State), + enc_Message(Mess, State) + ]. + +%% Note that encoding the transaction this way +%% make the message look a bit strange. +enc_Transaction(Val) -> + State = ?INIT_INDENT, + enc_Transaction(Val, State). + +%% Note that encoding the action request's this way +%% make the message look a bit strange. +enc_ActionRequests(Val) -> + State = ?INIT_INDENT, + enc_TransactionRequest_actions(Val, State). + +%% Note that encoding the action request this way +%% make the message look a bit strange. +enc_ActionRequest(Val) -> + State = ?INIT_INDENT, + enc_ActionRequest(Val, State). + +enc_CommandRequest(Val) -> + State = ?INIT_INDENT, + enc_CommandRequest(Val, State). + +enc_ActionReply(Val) -> + State = ?INIT_INDENT, + enc_ActionReply(Val, State). + +enc_AuthenticationHeader(asn1_NOVALUE, _State) -> + []; +enc_AuthenticationHeader(Val, State) + when is_record(Val, 'AuthenticationHeader') -> + [ + ?AuthToken, + ?EQUAL, + enc_SecurityParmIndex(Val#'AuthenticationHeader'.secParmIndex, State), + ?COLON, + enc_SequenceNum(Val#'AuthenticationHeader'.seqNum, State), + ?COLON, + enc_AuthData(Val#'AuthenticationHeader'.ad, State), + ?SEP_INDENT(State) + ]. + +enc_SecurityParmIndex({'SecurityParmIndex',Val}, State) -> + enc_SecurityParmIndex(Val, State); +enc_SecurityParmIndex(Val, State) -> + [ + "0x", + enc_HEXDIG(Val, State, 8, 8) + ]. + +enc_SequenceNum({'SequenceNum',Val}, State) -> + enc_SequenceNum(Val, State); +enc_SequenceNum(Val, State) -> + [ + "0x", + enc_HEXDIG(Val, State, 8, 8) + ]. + +enc_AuthData({'AuthData',Val}, State) -> + enc_AuthData(Val, State); +enc_AuthData(Val, State) -> + [ + "0x", + enc_HEXDIG(Val, State, 24, 64) %% OTP-4710 + ]. + +enc_Message(Val, State) + when is_record(Val, 'Message') -> + [ + ?MegacopToken, + ?SLASH, + enc_version(Val#'Message'.version, State), + ?SEP, + enc_MId(Val#'Message'.mId, State), + ?SEP_INDENT(State), + enc_Message_messageBody(Val#'Message'.messageBody, State) + ]. + +enc_version(Val, State) when is_integer(Val) andalso (Val >= 0) -> + enc_DIGIT(Val, State, 0, 99). + +enc_Message_messageBody({'Message_messageBody',Val}, State) -> + enc_Message_messageBody(Val, State); +enc_Message_messageBody({Tag, Val}, State) -> + case Tag of + messageError -> + enc_ErrorDescriptor(Val, State); + transactions -> + enc_Message_messageBody_transactions(Val, State); + _ -> + error({invalid_messageBody_tag, Tag}) + end. + +enc_Message_messageBody_transactions({'Message_messageBody_transactions',Val}, + State) -> + enc_Message_messageBody_transactions(Val, State); +enc_Message_messageBody_transactions(Val, State) + when is_list(Val) andalso (Val =/= []) -> + [enc_Transaction(T, State) || T <- Val]. + +enc_MId({'MId',Val}, State) -> + enc_MId(Val, State); +enc_MId({Tag, Val}, State) -> + case Tag of + ip4Address -> + enc_IP4Address(Val, State); + ip6Address -> + enc_IP6Address(Val, State); + domainName -> + enc_DomainName(Val, State); + deviceName -> + enc_PathName(Val, State); + mtpAddress -> + enc_mtpAddress(Val, State); + _ -> + error({invalid_MId_tag, Tag}) + end. + +enc_mtpAddress(Val, State) -> + [ + ?MtpToken, + ?LBRKT, + enc_OCTET_STRING(Val, State, 2, 4), + ?RBRKT + ]. + +enc_DomainName(#'DomainName'{portNumber = asn1_NOVALUE, + name = Name}, State) -> + [ + $<, + %% BUGBUG: (ALPHA / DIGIT) *63(ALPHA / DIGIT / "-" / ".") + enc_STRING(Name, State, 1, 64), + $> + ]; +enc_DomainName(#'DomainName'{portNumber = PortNumber, + name = Name}, State) -> + [ + $<, + %% BUGBUG: (ALPHA / DIGIT) *63(ALPHA / DIGIT / "-" / ".") + enc_STRING(Name, State, 1, 64), + $>, + $:, + enc_portNumber(PortNumber, State) + ]. + +enc_IP4Address(#'IP4Address'{portNumber = asn1_NOVALUE, + address = [A1, A2, A3, A4]}, State) -> + [ + $[, + enc_V4hex(A1, State), + ?DOT, + enc_V4hex(A2, State), + ?DOT, + enc_V4hex(A3, State), + ?DOT, + enc_V4hex(A4, State), + $] + ]; +enc_IP4Address(#'IP4Address'{portNumber = PortNumber, + address = [A1, A2, A3, A4]}, State) -> + [ + $[, + enc_V4hex(A1, State), + ?DOT, + enc_V4hex(A2, State), + ?DOT, + enc_V4hex(A3, State), + ?DOT, + enc_V4hex(A4, State), + $], + $:, + enc_portNumber(PortNumber, State) + ]. + +enc_V4hex(Val, State) -> + enc_DIGIT(Val, State, 0, 255). + +enc_IP6Address(#'IP6Address'{portNumber = asn1_NOVALUE, + address = Addr}, State) + when is_list(Addr) andalso (length(Addr) == 16) -> + [ + $[, + enc_IP6Address_address(Addr, State), + $] + ]; +enc_IP6Address(#'IP6Address'{portNumber = PortNumber, + address = Addr}, State) + when is_list(Addr) andalso (length(Addr) =:= 16) -> + [ + $[, + enc_IP6Address_address(Addr, State), + $], + $:, + enc_portNumber(PortNumber, State) + ]. + +enc_IP6Address_address([0, 0|Addr], State) -> + enc_IP6Address_address2(Addr, 1, false, true, State); +enc_IP6Address_address(Addr, State) -> + enc_IP6Address_address2(Addr, 0, false, false, State). + +enc_IP6Address_address2([0,0], 0, _Padding, _First, _State) -> + [$0]; +enc_IP6Address_address2([0,0], PadN, false, true, _State) when PadN > 0 -> + [$:, $:]; % Padding from the beginning (all zero's) +enc_IP6Address_address2([0,0], PadN, false, false, _State) when PadN > 0 -> + [$:]; % Padding in the middle or end +enc_IP6Address_address2([0,0], _, true, _First, _State) -> + [$0]; +enc_IP6Address_address2([N1,N2], 0, _Padding, _First, State) -> + [enc_hex4([N1, N2], State)]; +enc_IP6Address_address2([N1,N2], 1, _Padding, _First, State) -> + [$0, $:, enc_hex4([N1, N2], State)]; +enc_IP6Address_address2([N1,N2], PadN, false, true, State) when PadN > 1 -> + [$:, $:, enc_hex4([N1, N2], State)]; +enc_IP6Address_address2([N1,N2], PadN, false, false, State) when PadN > 1 -> + [$:, enc_hex4([N1, N2], State)]; +enc_IP6Address_address2([N1,N2], _PadN, true, _First, State) -> + [enc_hex4([N1, N2], State)]; +enc_IP6Address_address2([0, 0|Ns], PadN, false, First, State) -> + enc_IP6Address_address2(Ns, PadN+1, false, First, State); +enc_IP6Address_address2([0, 0|Ns], _PadN, true, _First, State) -> + [ + $0, + $:, + enc_IP6Address_address2(Ns, 0, true, false, State) + ]; +enc_IP6Address_address2([N1, N2|Ns], 0, Padded, _First, State) -> + [ + enc_hex4([N1, N2], State), + $:, + enc_IP6Address_address2(Ns, 0, Padded, false, State) + ]; +enc_IP6Address_address2([N1, N2|Ns], 1, Padded, _First, State) -> + [ + $0, + $:, + enc_hex4([N1, N2], State), + $:, + enc_IP6Address_address2(Ns, 0, Padded, false, State) + ]; +enc_IP6Address_address2([N1, N2|Ns], PadN, false, true, State) when PadN > 1 -> + %% Padding from the beginning + [ + $:, + $:, + enc_hex4([N1, N2], State), + $:, + enc_IP6Address_address2(Ns, 0, true, false, State) + ]; +enc_IP6Address_address2([N1, N2|Ns], PadN, false, false, State) + when PadN > 1 -> + [ + $:, %% The other ':' has already added + enc_hex4([N1, N2], State), + $:, + enc_IP6Address_address2(Ns, 0, true, false, State) + ]; +enc_IP6Address_address2([N1, N2|Ns], _PadN, true, _First, State) -> + [ + enc_hex4([N1, N2], State), + $:, + enc_IP6Address_address2(Ns, 0, true, false, State) + ]. + + +enc_hex4([0,0], _State) -> + $0; +enc_hex4([0,N], _State) -> + hex(N); +enc_hex4([N1, N2], _State) when N2 =< 15 -> + [hex(N1), $0, hex(N2)]; +enc_hex4([N1, N2], _State) -> + [hex(N1), hex(N2)]. + +enc_PathName({'PathName',Val}, State) -> + enc_PathName(Val, State); +enc_PathName(Val, State) -> + %% BUGBUG: ["*"] NAME *("/" / "*"/ ALPHA / DIGIT /"_" / "$" ) + %% BUGBUG: ["@" pathDomainName ] + enc_STRING(Val, State, 1, 64). + +enc_Transaction(Bin, _State) when is_binary(Bin) -> + [Bin]; %% Already encoded... +enc_Transaction({'Transaction',Val}, State) -> + enc_Transaction(Val, State); +enc_Transaction({Tag, Val}, State) -> + case Tag of + transactionRequest -> + enc_TransactionRequest(Val, State); + transactionPending -> + enc_TransactionPending(Val, State); + transactionReply -> + enc_TransactionReply(Val, State); + transactionResponseAck -> + enc_TransactionResponseAck(Val, State); + _ -> + error({invalid_Transaction_tag, Tag}) + end. + +enc_TransactionResponseAck([Mand], State) -> + [ + ?ResponseAckToken, + ?LBRKT_INDENT(State), + [enc_TransactionAck(Mand, State)], + ?RBRKT_INDENT(State) + ]; +enc_TransactionResponseAck([Mand | Opt], State) -> + [ + ?ResponseAckToken, + ?LBRKT_INDENT(State), + [enc_TransactionAck(Mand, State) | + [[?COMMA_INDENT(State), enc_TransactionAck(Val, State)] || Val <- Opt]], + ?RBRKT_INDENT(State) + ]. + +enc_TransactionAck(Val, State) + when is_record(Val, 'TransactionAck') -> + [ + enc_TransactionId(Val#'TransactionAck'.firstAck, ?INC_INDENT(State)), + case Val#'TransactionAck'.lastAck of + asn1_NOVALUE -> + []; + LastAck -> + ["-",enc_TransactionId(LastAck, State)] + end + ]. + +enc_TransactionId({'TransactionId',Val}, State) -> + enc_TransactionId(Val, State); +enc_TransactionId(Val, State) -> + enc_UINT32(Val, State). + +enc_TransactionRequest(#'TransactionRequest'{transactionId = Tid, + actions = Acts}, State) -> + [ + ?TransToken, + ?EQUAL, + enc_TransactionId(Tid, State), + ?LBRKT_INDENT(State), + enc_TransactionRequest_actions(Acts, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]; +enc_TransactionRequest(Bin, _State) when is_binary(Bin) -> + [Bin]. + +enc_TransactionRequest_actions(Bin, _State) when is_binary(Bin) -> + [Bin]; %% Already encoded... +enc_TransactionRequest_actions({'TransactionRequest_actions',Val}, State) -> + enc_TransactionRequest_actions(Val, State); +enc_TransactionRequest_actions([Mand], State) -> + [enc_ActionRequest(Mand, State)]; +enc_TransactionRequest_actions([Mand | Opt], State) -> + [enc_ActionRequest(Mand, State) | + [[?COMMA_INDENT(State), enc_ActionRequest(Val, State)] || Val <- Opt]]. + +enc_TransactionPending(#'TransactionPending'{transactionId = Tid}, State) -> + [?PendingToken, + ?EQUAL, + enc_TransactionId(Tid, State), + ?LBRKT_INDENT(State), + ?RBRKT_INDENT(State) + ]; +enc_TransactionPending(Bin, _State) when is_binary(Bin) -> + [Bin]. + +enc_TransactionReply(#'TransactionReply'{transactionId = Tid, + immAckRequired = asn1_NOVALUE, + transactionResult = Res}, + State) -> + [ + ?ReplyToken, + ?EQUAL, + enc_TransactionId(Tid, State), + ?LBRKT_INDENT(State), + enc_TransactionReply_transactionResult(Res, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]; +enc_TransactionReply(#'TransactionReply'{transactionId = Tid, + immAckRequired = Req, + transactionResult = Res}, State) -> + [ + ?ReplyToken, + ?EQUAL, + enc_TransactionId(Tid, State), + ?LBRKT_INDENT(State), + enc_immAckRequired(Req, State), + enc_TransactionReply_transactionResult(Res, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]; +enc_TransactionReply(Bin, _State) when is_binary(Bin) -> + [Bin]. + +enc_immAckRequired(Val, _State) -> + case Val of + asn1_NOVALUE -> + []; + 'NULL' -> + [?ImmAckRequiredToken, ?COMMA_INDENT(?INC_INDENT(_State))] + end. + +enc_TransactionReply_transactionResult({'TransactionReply_transactionResult', + Val}, State) -> + enc_TransactionReply_transactionResult(Val, State); +enc_TransactionReply_transactionResult({Tag, Val}, State) -> + case Tag of + transactionError -> + enc_ErrorDescriptor(Val, State); + actionReplies -> + enc_TransactionReply_transactionResult_actionReplies(Val, State); + _ -> + error({invalid_TransactionReply_transactionResult_tag, Tag}) + end. + +enc_TransactionReply_transactionResult_actionReplies({'TransactionReply_transactionResult_actionReplies',Val}, State) -> + enc_TransactionReply_transactionResult_actionReplies(Val, State); +enc_TransactionReply_transactionResult_actionReplies([Mand], State) -> + [enc_ActionReply(Mand, State)]; +enc_TransactionReply_transactionResult_actionReplies([Mand | Opt], State) -> + [enc_ActionReply(Mand, State), + [[?COMMA_INDENT(State), enc_ActionReply(Val, State)] || Val <- Opt]]. + +enc_ErrorDescriptor(#'ErrorDescriptor'{errorText = asn1_NOVALUE, + errorCode = Code}, State) -> + [ + ?ErrorToken, + ?EQUAL, + enc_ErrorCode(Code, State), + ?LBRKT, + ?RBRKT + ]; +enc_ErrorDescriptor(#'ErrorDescriptor'{errorText = Text, + errorCode = Code}, State) -> + [ + ?ErrorToken, + ?EQUAL, + enc_ErrorCode(Code, State), + ?LBRKT, + enc_ErrorText(Text, State), + ?RBRKT + ]. + +enc_ErrorCode({'ErrorCode',Val}, State)-> + enc_ErrorCode(Val, State); +enc_ErrorCode(Val, State) -> + enc_DIGIT(Val, State, 0, 999). + +enc_ErrorText({'ErrorText',Val}, State) -> + enc_ErrorText(Val, State); +enc_ErrorText(Val, State) -> + enc_QUOTED_STRING(Val, State). + +enc_ContextID({'ContextID',Val}, State) -> + enc_ContextID(Val, State); +enc_ContextID(Val, State) -> + case Val of + ?megaco_all_context_id -> $*; + ?megaco_null_context_id -> $-; + ?megaco_choose_context_id -> $$; + Int when is_integer(Int) -> enc_UINT32(Int, State) + end. + +enc_ActionRequest(Bin, _State) when is_binary(Bin) -> + [Bin]; %% Already encoded... +enc_ActionRequest(Val, State) + when is_record(Val, 'ActionRequest') -> + [ + ?CtxToken, + ?EQUAL, + enc_ContextID(Val#'ActionRequest'.contextId, State), + ?LBRKT_INDENT(State), + enc_list([{[Val#'ActionRequest'.contextAttrAuditReq], + fun enc_ContextAttrAuditRequest/2}] ++ + decompose_ContextRequest(Val#'ActionRequest'.contextRequest) ++ + [{Val#'ActionRequest'.commandRequests, + fun enc_CommandRequest/2}], + ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]. + +%% OTP-5085 +enc_ActionReply(#'ActionReply'{contextId = Id, + errorDescriptor = ED, + contextReply = CtxRep, + commandReply = CmdRep}, + State) -> + [ + ?CtxToken, + ?EQUAL, + enc_ContextID(Id, State), + ?LBRKT_INDENT(State), + do_enc_ActionReply(ED, CtxRep, CmdRep, State), + ?RBRKT_INDENT(State) + ]. + +do_enc_ActionReply(asn1_NOVALUE, CtxRep, CmdRep, State) + when (CtxRep =/= asn1_NOVALUE) orelse (CmdRep =/= []) -> + [ + enc_list(decompose_ContextRequest(CtxRep) ++ + [{CmdRep, fun enc_CommandReply/2}], + ?INC_INDENT(State)) + ]; +do_enc_ActionReply(ED, CtxRep, CmdRep, State) + when (CtxRep =/= asn1_NOVALUE) orelse (CmdRep =/= []) -> + [ + enc_list(decompose_ContextRequest(CtxRep) ++ + [{CmdRep, fun enc_CommandReply/2}, + {[ED], fun enc_ErrorDescriptor/2}], % Indention cosmetics + ?INC_INDENT(State)) + ]; +do_enc_ActionReply(ED, asn1_NOVALUE, [], State) + when (ED =/= asn1_NOVALUE) -> + [ + enc_ErrorDescriptor(ED, ?INC_INDENT(State)) + ]. + + +decompose_ContextRequest(asn1_NOVALUE) -> + [{[], dummy}] ; +decompose_ContextRequest(Val) + when is_record(Val, 'ContextRequest') -> + OptPriority = + case Val#'ContextRequest'.priority of + asn1_NOVALUE -> {[], dummy}; + Prio -> {[Prio], fun enc_priority/2} + end, + OptEmergency = + case Val#'ContextRequest'.emergency of + asn1_NOVALUE -> {[], dummy}; + false -> {[?EmergencyOffToken], fun(Elem, _) -> Elem end}; + true -> {[?EmergencyToken], fun(Elem, _) -> Elem end} + end, + OptTopologyReq = + case Val#'ContextRequest'.topologyReq of + asn1_NOVALUE -> + {[], dummy}; + {'ContextRequest_topologyReq', asn1_NOVALUE} -> + {[], dummy}; + {'ContextRequest_topologyReq', List} -> + {List, fun enc_TopologyRequest/2}; + List -> + {[List], fun enc_TopologyRequest/2} + end, + [OptPriority, OptEmergency, OptTopologyReq]. + +enc_priority(Val, State) -> + [ + ?PriorityToken, + ?EQUAL, + enc_UINT16(Val, State) + ]. + +enc_ContextAttrAuditRequest(Val, State) + when is_record(Val, 'ContextAttrAuditRequest') -> + [ + ?ContextAuditToken, + ?LBRKT_INDENT(State), + enc_list([{[Val#'ContextAttrAuditRequest'.topology], + fun('NULL', _) -> ?TopologyToken end}, + {[Val#'ContextAttrAuditRequest'.emergency], + fun('NULL', _) -> ?EmergencyToken end}, + {[Val#'ContextAttrAuditRequest'.priority], + fun('NULL', _) -> ?PriorityToken end}], + ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]. + +enc_CommandRequest(#'CommandRequest'{optional = asn1_NOVALUE, + wildcardReturn = asn1_NOVALUE, + command = Cmd}, State) -> + [ + enc_Command(Cmd, State) + ]; +enc_CommandRequest(#'CommandRequest'{optional = 'NULL', + wildcardReturn = asn1_NOVALUE, + command = Cmd}, State) -> + [ + "O-", + enc_Command(Cmd, State) + ]; +enc_CommandRequest(#'CommandRequest'{optional = asn1_NOVALUE, + wildcardReturn = 'NULL', + command = Cmd}, State) -> + [ + "W-", + enc_Command(Cmd, State) + ]; +enc_CommandRequest(#'CommandRequest'{optional = 'NULL', + wildcardReturn = 'NULL', + command = Cmd}, State) -> + [ + "O-", + "W-", + enc_Command(Cmd, State) + ]. + +enc_Command({'Command',Val}, State) -> + enc_Command(Val, State); +enc_Command({Tag, Val}, State) -> + case Tag of + addReq -> + [?AddToken, enc_AmmRequest(Val, State)]; + moveReq -> + [?MoveToken, enc_AmmRequest(Val, State)]; + modReq -> + [?ModifyToken, enc_AmmRequest(Val, State)]; + subtractReq -> + [?SubtractToken, enc_SubtractRequest(Val, State)]; + auditCapRequest -> + [?AuditCapToken, enc_AuditRequest(Val, State)]; + auditValueRequest -> + [?AuditValueToken, enc_AuditRequest(Val, State)]; + notifyReq -> + [?NotifyToken, enc_NotifyRequest(Val, State)]; + serviceChangeReq -> + [?ServiceChangeToken, enc_ServiceChangeRequest(Val, State)]; + _ -> + error({invalid_Command_tag, Tag}) + end. + +enc_CommandReply({'CommandReply',Val}, State) -> + enc_CommandReply(Val, State); +enc_CommandReply({Tag, Val}, State) -> + case Tag of + addReply -> + [?AddToken, enc_AmmsReply(Val, State)]; + moveReply -> + [?MoveToken, enc_AmmsReply(Val, State)]; + modReply -> + [?ModifyToken, enc_AmmsReply(Val, State)]; + subtractReply -> + [?SubtractToken, enc_AmmsReply(Val, State)]; + auditCapReply -> + [?AuditCapToken, enc_AuditReply(Val, State)]; + auditValueReply -> + [?AuditValueToken, enc_AuditReply(Val, State)]; + notifyReply -> + [?NotifyToken, enc_NotifyReply(Val, State)]; + serviceChangeReply -> + [?ServiceChangeToken, enc_ServiceChangeReply(Val, State)]; + _ -> + error({invalid_CommandReply_tag, Tag}) + end. + +enc_TopologyRequest(Val, State) + when is_list(Val) -> + [ + ?TopologyToken, + ?LBRKT_INDENT(State), + enc_list([{Val, fun enc_TopologyRequest1/2}],?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]. + +enc_TopologyRequest1(#'TopologyRequest'{terminationFrom = From, + terminationTo = To, + topologyDirection = Dir, + streamID = asn1_NOVALUE}, + State) -> + [ + fun(S) -> + [ + enc_TerminationID(From, S), + ?COMMA_INDENT(S), + enc_TerminationID(To, S), + ?COMMA_INDENT(S), + case Dir of + bothway -> ?BothwayToken; + isolate -> ?IsolateToken; + oneway -> ?OnewayToken + end + ] + end(?INC_INDENT(State)) + ]; +enc_TopologyRequest1(#'TopologyRequest'{terminationFrom = From, + terminationTo = To, + topologyDirection = Dir, + streamID = SID}, + State) -> + [ + fun(S) -> + [ + enc_TerminationID(From, S), + ?COMMA_INDENT(S), + enc_TerminationID(To, S), + ?COMMA_INDENT(S), + case Dir of + bothway -> ?BothwayToken; + isolate -> ?IsolateToken; + oneway -> ?OnewayToken + end, + ?COMMA_INDENT(S), + ?StreamToken, + ?EQUAL, + enc_StreamID(SID, S) + ] + end(?INC_INDENT(State)) + ]. + +enc_AmmRequest(Val, State) + when is_record(Val, 'AmmRequest') -> + [ + %% Assume that Token is added elsewhere + ?EQUAL, + enc_TerminationIDList1(Val#'AmmRequest'.terminationID, State), + enc_opt_brackets( + enc_list([{Val#'AmmRequest'.descriptors, fun enc_ammDescriptor/2}], + ?INC_INDENT(State)), + State) + ]. + +enc_ammDescriptor({Tag, Desc}, State) -> + case Tag of + mediaDescriptor -> enc_MediaDescriptor(Desc, State); + modemDescriptor -> enc_ModemDescriptor(Desc, State); + muxDescriptor -> enc_MuxDescriptor(Desc, State); + eventsDescriptor -> enc_EventsDescriptor(Desc, State); + eventBufferDescriptor -> enc_EventBufferDescriptor(Desc, State); + signalsDescriptor -> enc_SignalsDescriptor(Desc, State); + digitMapDescriptor -> enc_DigitMapDescriptor(Desc, State); + auditDescriptor -> enc_AuditDescriptor(Desc, State); + _ -> + error({invalid_ammDescriptor_tag, Tag}) + end. + +enc_AmmsReply(#'AmmsReply'{terminationID = ID, + terminationAudit = asn1_NOVALUE}, State) -> + [ + ?EQUAL, + enc_TerminationIDList1(ID, State) + ]; +enc_AmmsReply(#'AmmsReply'{terminationID = ID, + terminationAudit = []}, State) -> + [ + ?EQUAL, + enc_TerminationIDList1(ID, State) + ]; +enc_AmmsReply(#'AmmsReply'{terminationID = ID, + terminationAudit = Res}, State) -> + [ + ?EQUAL, + enc_TerminationIDList1(ID, State), + case lists:flatten(enc_TerminationAudit(Res, ?INC_INDENT(State))) of + [] -> + []; + L -> + [ + ?LBRKT_INDENT(State), + L, + ?RBRKT_INDENT(State) + ] + end + ]. + +enc_SubtractRequest(Val, State) + when is_record(Val, 'SubtractRequest') -> + [ + %% Assume that Token is added elsewhere + ?EQUAL, + enc_TerminationIDList1(Val#'SubtractRequest'.terminationID, State), + case Val#'SubtractRequest'.auditDescriptor of + asn1_NOVALUE -> + []; + AuditDescr -> + [ + ?LBRKT_INDENT(State) , + enc_AuditDescriptor(AuditDescr, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ] + end + ]. + +enc_AuditRequest(Val, State) + when is_record(Val, 'AuditRequest') -> + [ + %% Assume that Token is added elsewhere + ?EQUAL, + enc_TerminationIDList1([Val#'AuditRequest'.terminationID], State), + case Val#'AuditRequest'.auditDescriptor of + asn1_NOVALUE -> + []; + AuditDescr -> + [ + ?LBRKT_INDENT(State) , + enc_AuditDescriptor(AuditDescr, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ] + end + ]. + +%% auditReply = (AuditValueToken / AuditCapToken ) +%% ( contextTerminationAudit / auditOther) +%% auditOther = EQUAL TerminationID LBRKT +%% terminationAudit RBRKT +%% terminationAudit = auditReturnParameter *(COMMA auditReturnParameter) +%% +%% contextTerminationAudit = EQUAL CtxToken ( terminationIDList / +%% LBRKT errorDescriptor RBRKT ) +enc_AuditReply({Tag, Val}, State) -> + case Tag of + contextAuditResult -> + [ + ?EQUAL, + ?CtxToken, + enc_TerminationIDListN(Val, State) + ]; + error -> + [ + ?EQUAL, + ?CtxToken, + ?LBRKT_INDENT(State), + enc_ErrorDescriptor(Val, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]; + auditResult when is_record(Val, 'AuditResult') -> + enc_auditOther(Val, State); + auditResult -> + error({invalid_auditResult, Val}); + _ -> + error({invalid_AuditReply_tag, Tag}) + end. + +enc_auditOther(#'AuditResult'{terminationID = ID, + terminationAuditResult = asn1_NOVALUE}, State) -> + [ + ?EQUAL, + enc_TerminationID(ID, State) + ]; +enc_auditOther(#'AuditResult'{terminationID = ID, + terminationAuditResult = []}, State) -> + [ + ?EQUAL, + enc_TerminationID(ID, State) + ]; +enc_auditOther(#'AuditResult'{terminationID = ID, + terminationAuditResult = Res}, State) -> + [ + ?EQUAL, + enc_TerminationID(ID, State), + case lists:flatten(enc_TerminationAudit(Res, ?INC_INDENT(State))) of + [] -> + []; + L -> + [ + ?LBRKT_INDENT(State), + L, + ?RBRKT_INDENT(State) + ] + end + ]. + + +enc_AuditDescriptor(#'AuditDescriptor'{auditToken = asn1_NOVALUE, + auditPropertyToken = asn1_NOVALUE}, + _State) -> + [ + ?AuditToken, + [?LBRKT, ?RBRKT] + ]; +enc_AuditDescriptor(#'AuditDescriptor'{auditToken = [], + auditPropertyToken = asn1_NOVALUE}, + _State) -> + [ + ?AuditToken, + [?LBRKT, ?RBRKT] + ]; +enc_AuditDescriptor(#'AuditDescriptor'{auditToken = List, + auditPropertyToken = asn1_NOVALUE}, + State) -> + [ + ?AuditToken, + [ + ?LBRKT_INDENT(State), + enc_list([{List, fun enc_auditItem/2}], ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ] + ]; +%% - v2 - +enc_AuditDescriptor(#'AuditDescriptor'{auditToken = asn1_NOVALUE, + auditPropertyToken = Prop}, + State) -> + [ + ?AuditToken, + [ + ?LBRKT_INDENT(State), + enc_auditPropertyToken(Prop, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ] + ]; +enc_AuditDescriptor(#'AuditDescriptor'{auditToken = List, + auditPropertyToken = Prop}, + State) -> + [ + ?AuditToken, + [ + ?LBRKT_INDENT(State), + enc_list([{List, fun enc_auditItem/2}], ?INC_INDENT(State)), + ?COMMA_INDENT(State), + enc_auditPropertyToken(Prop, ?INC_INDENT(State)), % v2 + ?RBRKT_INDENT(State) + ] + ]. + +enc_auditItem(signalsToken, _State) -> + ?SignalsToken; +enc_auditItem(eventBufferToken, _State) -> + ?EventBufferToken; +enc_auditItem(eventsToken, _State) -> + ?EventsToken; +enc_auditItem(Val, State) -> + enc_auditReturnItem(Val, State). + + +enc_auditReturnItem(muxToken, _State) -> + ?MuxToken; +enc_auditReturnItem(modemToken, _State) -> + ?ModemToken; +enc_auditReturnItem(mediaToken, _State) -> + ?MediaToken; +enc_auditReturnItem(digitMapToken, _State) -> + ?DigitMapToken; +enc_auditReturnItem(statsToken, _State) -> + ?StatsToken; +enc_auditReturnItem(observedEventsToken, _State) -> + ?ObservedEventsToken; +enc_auditReturnItem(packagesToken, _State) -> + ?PackagesToken. + + +%% - v2 begin - + +enc_auditPropertyToken([], _State) -> + []; +enc_auditPropertyToken([Param | Params], State) -> + [enc_IndAudauditReturnParameter(Param, State), + [[?COMMA_INDENT(State), + enc_IndAudauditReturnParameter(P, State)] || P <- Params]]. + + +enc_IndAudauditReturnParameter({Tag, Val}, State) -> + case Tag of + indAudMediaDescriptor -> + enc_IndAudMediaDescriptor(Val, State); + indAudEventsDescriptor -> + enc_IndAudEventsDescriptor(Val, State); + indAudSignalsDescriptor -> + enc_IndAudSignalsDescriptor(Val, State); + indAudDigitMapDescriptor -> + enc_IndAudDigitMapDescriptor(Val, State); + indAudEventBufferDescriptor -> + enc_IndAudEventBufferDescriptor(Val, State); + indAudStatisticsDescriptor -> + enc_IndAudStatisticsDescriptor(Val, State); + indAudPackagesDescriptor -> + enc_IndAudPackagesDescriptor(Val, State); + _ -> + error({invalid_IndAudauditReturnParameter_tag, Tag}) + end. + +%% The ASN.1 does not limit to just one of termStateDescr or streams, +%% but the ABNF seams to do that... +enc_IndAudMediaDescriptor(#'IndAudMediaDescriptor'{termStateDescr = asn1_NOVALUE, + streams = Val}, State) -> + [ + ?MediaToken, + ?LBRKT_INDENT(State), + enc_IndAudMediaDescriptor_streams(Val, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]; +enc_IndAudMediaDescriptor(#'IndAudMediaDescriptor'{termStateDescr = Val, + streams = asn1_NOVALUE}, + State) -> + [ + ?MediaToken, + ?LBRKT_INDENT(State), + enc_IndAudTerminationStateDescriptor(Val, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]. + +enc_IndAudMediaDescriptor_streams({Tag, Val}, State) -> + case Tag of + oneStream -> + enc_IndAudStreamParms(Val, State); + multiStream -> + enc_IndAudMediaDescriptor_multiStream(Val, State); + _ -> + error({invalid_IndAudMediaDescriptor_streams_tag, Tag}) + end. + +enc_IndAudTerminationStateDescriptor( + #'IndAudTerminationStateDescriptor'{propertyParms = [], + eventBufferControl = asn1_NOVALUE, + serviceState = 'NULL'}, _State) -> + [ + ?TerminationStateToken, + ?LBRKT_INDENT(_State), + ?ServiceStatesToken, + ?RBRKT_INDENT(_State) + ]; +enc_IndAudTerminationStateDescriptor( + #'IndAudTerminationStateDescriptor'{propertyParms = [], + eventBufferControl = 'NULL', + serviceState = asn1_NOVALUE}, _State) -> + [ + ?TerminationStateToken, + ?LBRKT_INDENT(_State), + ?BufferToken, + ?RBRKT_INDENT(_State) + ]; +enc_IndAudTerminationStateDescriptor( + #'IndAudTerminationStateDescriptor'{propertyParms = [Parms], + eventBufferControl = asn1_NOVALUE, + serviceState = asn1_NOVALUE}, State) -> + #'IndAudPropertyParm'{name = Name} = Parms, + [ + ?TerminationStateToken, + ?LBRKT_INDENT(State), + enc_PkgdName(Name, State), + ?RBRKT_INDENT(State) + ]. + + +enc_IndAudStreamParms(#'IndAudStreamParms'{localControlDescriptor = Val, + localDescriptor = asn1_NOVALUE, + remoteDescriptor = asn1_NOVALUE}, + State) -> + [ + enc_IndAudLocalControlDescriptor(Val, ?INC_INDENT(State)) + ]. + +enc_IndAudLocalControlDescriptor(Val, State) + when is_record(Val, 'IndAudLocalControlDescriptor') -> + [ + ?LocalControlToken, + ?LBRKT_INDENT(State), + enc_list([{[Val#'IndAudLocalControlDescriptor'.streamMode], + fun('NULL', _) -> ?ModeToken end}, + {[Val#'IndAudLocalControlDescriptor'.reserveValue], + fun('NULL', _) -> ?ReservedValueToken end}, + {[Val#'IndAudLocalControlDescriptor'.reserveGroup], + fun('NULL', _) -> ?ReservedGroupToken end}, + {Val#'IndAudLocalControlDescriptor'.propertyParms, + fun enc_IndAudPropertyParm/2}], + ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]. + +enc_IndAudPropertyParm(#'IndAudPropertyParm'{name = PkgdName}, State) -> + enc_PkgdName(PkgdName, State). + +enc_IndAudMediaDescriptor_multiStream([Val], State) -> + [ + enc_IndAudStreamDescriptor(Val, ?INC_INDENT(State)) + ]; +enc_IndAudMediaDescriptor_multiStream(Vals, _State) when is_list(Vals) -> + error({invalid_IndAudMediaDescriptor_multiStream_length, Vals}); +enc_IndAudMediaDescriptor_multiStream(Val, _State) -> + error({invalid_IndAudMediaDescriptor_multiStream, Val}). + +enc_IndAudStreamDescriptor(#'IndAudStreamDescriptor'{streamID = SID, + streamParms = Parms}, + State) -> + [ + ?StreamToken, + ?EQUAL, + enc_StreamID(SID, State), + ?LBRKT_INDENT(State), + enc_IndAudStreamParms(Parms, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]. + +enc_IndAudEventBufferDescriptor(Val, State) + when is_record(Val, 'IndAudEventBufferDescriptor') -> + #'IndAudEventBufferDescriptor'{eventName = EvName, + streamID = ID} = Val, + [ + ?EventBufferToken, + ?LBRKT_INDENT(State), + enc_PkgdName(EvName, State), + enc_IndAudEventBufferDescriptor_eventSpec(ID, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]. + +enc_IndAudEventBufferDescriptor_eventSpec(asn1_NOVALUE, _State) -> + [ + ]; +enc_IndAudEventBufferDescriptor_eventSpec({eventParameterName, ParamName}, + State) -> + [ + ?LBRKT_INDENT(State), + enc_Name(ParamName, State), + ?RBRKT_INDENT(State) + ]; +enc_IndAudEventBufferDescriptor_eventSpec(ID, State) -> + [ + ?LBRKT_INDENT(State), + enc_eventStream(ID, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]. + +enc_IndAudEventsDescriptor(Val, State) + when is_record(Val, 'IndAudEventsDescriptor') -> + #'IndAudEventsDescriptor'{requestID = ReqID, + pkgdName = Name, + streamID = asn1_NOVALUE} = Val, + [ + ?EventsToken, + ?EQUAL, + enc_RequestID(ReqID, State), + ?LBRKT_INDENT(State), + enc_PkgdName(Name, State), + ?RBRKT_INDENT(State) + ]. + + +enc_IndAudSignalsDescriptor(Val, State) -> + [ + ?SignalsToken, + ?LBRKT_INDENT(State), + enc_IndAudSignalsDescriptor_value(Val, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]. + +enc_IndAudSignalsDescriptor_value({signal, Val}, State) -> + enc_IndAudSignal(Val, State); +enc_IndAudSignalsDescriptor_value({seqSigList, Val}, State) -> + enc_IndAudSeqSigList(Val, State). + +enc_IndAudSignal(#'IndAudSignal'{signalName = SignalName, + streamID = asn1_NOVALUE}, State) -> + [ + enc_SignalName(SignalName, State) + ]. + +enc_IndAudSeqSigList(#'IndAudSeqSigList'{id = ID, + signalList = Parm}, + State) -> + [ + ?SignalListToken, + ?EQUAL, + enc_UINT16(ID, State), + ?LBRKT_INDENT(State), + enc_IndAudSignal(Parm, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]. + +enc_IndAudDigitMapDescriptor(#'IndAudDigitMapDescriptor'{digitMapName = Name}, + State) -> + [ + ?DigitMapToken, + ?EQUAL, + enc_DigitMapName(Name, State) + ]. + +enc_IndAudStatisticsDescriptor(#'IndAudStatisticsDescriptor'{statName = Name}, + State) -> + [ + ?StatsToken, + ?LBRKT_INDENT(State), + enc_PkgdName(Name, State), + ?RBRKT_INDENT(State) + ]. + + +enc_IndAudPackagesDescriptor(#'IndAudPackagesDescriptor'{packageName = N, + packageVersion = V}, + State) -> + [ + ?PackagesToken, + ?LBRKT_INDENT(State), + enc_Name(N, State), + "-", + enc_UINT16(V, State), + ?RBRKT_INDENT(State) + ]. + + +%% - v2 end - + + +enc_TerminationAudit({'TerminationAudit',Val}, State) -> + enc_TerminationAudit(Val, State); +enc_TerminationAudit([], _State) -> + []; +enc_TerminationAudit([Mand | Opt], State) -> + [enc_AuditReturnParameter(Mand, State), + [[?COMMA_INDENT(State), enc_AuditReturnParameter(Val, State)] || Val <- Opt]]. + +enc_AuditReturnParameter({'AuditReturnParameter',Val}, State) -> + enc_AuditReturnParameter(Val, State); +enc_AuditReturnParameter({Tag, Val}, State) -> + case Tag of + mediaDescriptor -> + enc_MediaDescriptor(Val, State); + modemDescriptor -> + enc_ModemDescriptor(Val, State); + muxDescriptor -> + enc_MuxDescriptor(Val, State); + eventsDescriptor -> + enc_EventsDescriptor(Val, State); + signalsDescriptor -> + enc_SignalsDescriptor(Val, State); + digitMapDescriptor -> + enc_DigitMapDescriptor(Val, State); + observedEventsDescriptor -> + enc_ObservedEventsDescriptor(Val, State); + eventBufferDescriptor -> + enc_EventBufferDescriptor(Val, State); + statisticsDescriptor -> + enc_StatisticsDescriptor(Val, State); + packagesDescriptor -> + enc_PackagesDescriptor(Val, State); + errorDescriptor -> + enc_ErrorDescriptor(Val, State); + emptyDescriptors -> + enc_EmptyDescriptors(Val, State); + _ -> + error({invalid_AuditReturnParameter_tag, Tag}) + end. + +enc_EmptyDescriptors(#'AuditDescriptor'{auditToken = asn1_NOVALUE}, _State) -> + []; +enc_EmptyDescriptors(#'AuditDescriptor'{auditToken = []}, _State) -> + []; +enc_EmptyDescriptors(#'AuditDescriptor'{auditToken = List}, State) -> + enc_list([{List, fun enc_auditReturnItem/2}], ?INC_INDENT(State)). + + +enc_NotifyRequest(Val, State) + when is_record(Val, 'NotifyRequest') -> + [ + %% Assume that Token is added elsewhere + ?EQUAL, + enc_TerminationIDList1(Val#'NotifyRequest'.terminationID, State), + ?LBRKT_INDENT(State), + %% BUGBUG: Mismatch between ASN.1 and ABNF + %% BUGBUG: The following ought to be a 'choice' + case Val#'NotifyRequest'.errorDescriptor of + asn1_NOVALUE -> + OED = Val#'NotifyRequest'.observedEventsDescriptor, + enc_ObservedEventsDescriptor(OED, ?INC_INDENT(State)); + ErrorDescr -> + enc_ErrorDescriptor(ErrorDescr, ?INC_INDENT(State)) + end, + ?RBRKT_INDENT(State) + ]. + +enc_NotifyReply(Val, State) + when is_record(Val, 'NotifyReply') -> + [ + %% Assume that Token is added elsewhere + ?EQUAL, + case Val#'NotifyReply'.terminationID of + asn1_NOVALUE -> + error(asn1_not_compliant_with_abnf); + TermId -> + enc_TerminationIDList1(TermId, State) + end, + case Val#'NotifyReply'.errorDescriptor of + asn1_NOVALUE -> + []; + ErrorDescr -> + [ + ?LBRKT_INDENT(State), + enc_ErrorDescriptor(ErrorDescr, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ] + end + ]. + +enc_ObservedEventsDescriptor(Val, State) + when is_record(Val, 'ObservedEventsDescriptor') -> + [ + ?ObservedEventsToken, + ?EQUAL, + enc_RequestID(Val#'ObservedEventsDescriptor'.requestId, State), + ?LBRKT_INDENT(State), + enc_observedEventsDescriptors(Val#'ObservedEventsDescriptor'.observedEventLst, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]. + +enc_observedEventsDescriptors([Mand | Opt], State) -> + [enc_ObservedEvent(Mand, State), + [[?COMMA_INDENT(State), enc_ObservedEvent(Val, State)] || Val <- Opt]]. + +%% ;time per event, because it might be buffered +%% observedEvent = [ TimeStamp LWSP COLON] LWSP +%% pkgdName [ LBRKT observedEventParameter +%% *(COMMA observedEventParameter) RBRKT ] +%% +%% ;at-most-once eventStream, every eventParameterName at most once +%% observedEventParameter = eventStream / eventOther +enc_ObservedEvent(Val, State) + when is_record(Val, 'ObservedEvent') -> + [ + case Val#'ObservedEvent'.timeNotation of + asn1_NOVALUE -> + []; + TimeStamp -> + [ + enc_TimeNotation(TimeStamp, State), + ?LWSP, + ?COLON + ] + end, + ?LWSP, + enc_EventName(Val#'ObservedEvent'.eventName, State), + enc_opt_brackets( + enc_list([{[Val#'ObservedEvent'.streamID], fun enc_eventStream/2}, + {Val#'ObservedEvent'.eventParList, fun enc_eventOther/2}], + ?INC_INDENT(State)), + State) + ]. + +enc_EventName({'EventName',Val}, State) -> + enc_EventName(Val, State); +enc_EventName(Val, State) -> + PkgdName = ?META_ENC(event, Val), + enc_PkgdName(PkgdName, State). + +enc_eventStream(Val, State) -> + [ + ?StreamToken, + ?EQUAL, + enc_StreamID(Val, State) + ]. + +%% The value is already encoded +enc_eventOther(#megaco_event_parameter{name = Name, + value = Value}, State) + when is_list(Value) -> + [ + enc_Name(Name, State), + ?EqualToken, + Value + ]; +%% Special treatment of the ds parameter of the dd/ce event +enc_eventOther(#'EventParameter'{eventParameterName = "ds" = Name, + value = [DigitString], + extraInfo = asn1_NOVALUE}, State) -> + [ + enc_Name(Name, State), + ?EqualToken, + enc_DigitString(DigitString, State) + ]; +enc_eventOther(#'EventParameter'{eventParameterName = Name, + value = Value, + extraInfo = Extra}, State) -> + [ + enc_Name(Name, State), + enc_propertyParmValues(Value, Extra, State) + ]. + +enc_ServiceChangeRequest(Val, State) + when is_record(Val, 'ServiceChangeRequest') -> + [ + %% Assume that Token is added elsewhere + ?EQUAL, + enc_TerminationIDList1(Val#'ServiceChangeRequest'.terminationID, State), + ?LBRKT_INDENT(State), + enc_ServiceChangeParm(Val#'ServiceChangeRequest'.serviceChangeParms, + ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]. + +%% serviceChangeReply = ServiceChangeToken EQUAL TerminationID +%% [LBRKT (errorDescriptor / +%% serviceChangeReplyDescriptor) RBRKT] +%% serviceChangeReplyDescriptor = ServicesToken LBRKT +%% servChgReplyParm *(COMMA servChgReplyParm) RBRKT +%% +%% ;at-most-once. Version is REQUIRED on first ServiceChange response +%% servChgReplyParm = (serviceChangeAddress / serviceChangeMgcId / +%% serviceChangeProfile / serviceChangeVersion ) +enc_ServiceChangeReply(Val, State) + when is_record(Val, 'ServiceChangeReply') -> + [ + %% Assume that Token is added elsewhere + ?EQUAL, + enc_TerminationIDList1(Val#'ServiceChangeReply'.terminationID, State), + enc_ServiceChangeResult(Val#'ServiceChangeReply'.serviceChangeResult, State) + ]. + +enc_ServiceChangeResult({'ServiceChangeResult',Val}, State) -> + enc_ServiceChangeResult(Val, State); +enc_ServiceChangeResult({Tag, Val}, State) -> + case Tag of + errorDescriptor -> + [ + ?LBRKT_INDENT(State), + enc_ErrorDescriptor(Val, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]; + serviceChangeResParms -> + case enc_ServiceChangeResParm(Val, ?INC_INDENT(?INC_INDENT(State))) of + [] -> + []; + ResParms -> + [ + ?LBRKT_INDENT(State), + ?ServicesToken, + fun(_S) -> + [ + ?LBRKT_INDENT(_S), + ResParms, + ?RBRKT_INDENT(_S) + ] + end(?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ] + end; + _ -> + error({invalid_ServiceChangeResult_tag, Tag}) + end. + +%% Required length of termination ID list is 1 +enc_TerminationIDList1({'TerminationIDList',Val}, State) -> + enc_TerminationIDList1(Val, State); +enc_TerminationIDList1([Singleton], State) -> + enc_TerminationID(Singleton, State). + +%% No required length of termination ID list +enc_TerminationIDListN({'TerminationIDList',Val}, State) -> + enc_TerminationIDListN(Val, State); +enc_TerminationIDListN([TID], State) -> + [ + ?LBRKT_INDENT(State), + enc_TerminationID(TID, State), + ?RBRKT_INDENT(State) + ]; +enc_TerminationIDListN(TIDs, State) -> + [ + ?LBRKT_INDENT(State), + enc_list([{TIDs, fun enc_TerminationID/2}], State), + ?RBRKT_INDENT(State) + ]. + + +%% TerminationID = "ROOT" / pathNAME / "$" / "*" +%% ; Total length of pathNAME must not exceed 64 chars. +%% pathNAME = ["*"] NAME *("/" / "*"/ ALPHA / DIGIT /"_" / "$" ) +%% ["@" pathDomainName ] +enc_TerminationID(Tid, State) + when is_record(Tid, megaco_term_id) -> + List = [{Tid#megaco_term_id.id, fun enc_tid_component/2 }], + enc_list(List, State, fun(_S) -> ?SLASH end, false). + +enc_tid_component(Component, State) when is_list(Component) -> + [enc_tid_sub_component(Sub, State) || Sub <- Component]; +enc_tid_component(Invalid, _State) -> + error({invalid_id_list_component, Invalid}). + +enc_tid_sub_component(all = _Sub, _State) -> + ?megaco_all; +enc_tid_sub_component(choose = _Sub, _State) -> + ?megaco_choose; +enc_tid_sub_component(Char, _State) when is_integer(Char) -> + Char; +enc_tid_sub_component(Invalid, _State) -> + error({invalid_id_list_sub_component, Invalid}). + +%% enc_tid_sub_component(Sub, _State) -> +%% case Sub of +%% all -> ?megaco_all; +%% choose -> ?megaco_choose; +%% Char when is_integer(Char) -> Char +%% end. + +%% mediaDescriptor = MediaToken LBRKT mediaParm *(COMMA mediaParm) RBRKT +%% ; at-most-once per item +%% ; and either streamParm or streamDescriptor but not both +%% mediaParm = (streamParm / streamDescriptor / +%% terminationStateDescriptor) +%% ; at-most-once +%% streamParm = ( localDescriptor / remoteDescriptor / +%% localControlDescriptor ) +%% streamDescriptor = StreamToken EQUAL StreamID LBRKT streamParm +%% *(COMMA streamParm) RBRKT +enc_MediaDescriptor(Val, State) + when is_record(Val, 'MediaDescriptor') -> + [ + ?MediaToken, + ?LBRKT_INDENT(State), + enc_list([{[Val#'MediaDescriptor'.termStateDescr], + fun enc_TerminationStateDescriptor/2} | + decompose_streams(Val#'MediaDescriptor'.streams)], + ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]. + +decompose_streams(asn1_NOVALUE) -> + []; +decompose_streams({'MediaDescriptor_streams',Val}) -> + decompose_streams(Val); +decompose_streams({Tag, Val}) -> + case Tag of + oneStream -> + decompose_StreamParms(Val); + multiStream -> + [{Val, fun enc_StreamDescriptor/2}]; + _ -> + error({invalid_streams_tag, Tag}) + end. + +decompose_StreamParms(Val) + when is_record(Val, 'StreamParms') -> + [ + {[Val#'StreamParms'.localControlDescriptor], + fun enc_LocalControlDescriptor/2}, + {[Val#'StreamParms'.localDescriptor], + fun enc_localDescriptor/2}, + {[Val#'StreamParms'.remoteDescriptor], + fun enc_remoteDescriptor/2} + ]. + +enc_StreamDescriptor(Val, State) + when is_record(Val, 'StreamDescriptor') -> + [ + ?StreamToken, + ?EQUAL, + enc_StreamID(Val#'StreamDescriptor'.streamID, State), + ?LBRKT_INDENT(State), + enc_list(decompose_StreamParms(Val#'StreamDescriptor'.streamParms), + ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]. + +%% localControlDescriptor = LocalControlToken LBRKT localParm +%% *(COMMA localParm) RBRKT +%% +%% ; at-most-once per item +%% localParm = ( streamMode / propertyParm / +%% reservedValueMode / reservedGroupMode ) +%% reservedValueMode = ReservedValueToken EQUAL ( "ON" / "OFF" ) +%% reservedGroupMode = ReservedGroupToken EQUAL ( "ON" / "OFF" ) +%% +%% reservedMode = ReservedToken EQUAL ( "ON" / "OFF" ) +%% +%% streamMode = ModeToken EQUAL streamModes +enc_LocalControlDescriptor( + #'LocalControlDescriptor'{streamMode = asn1_NOVALUE, + reserveValue = asn1_NOVALUE, + reserveGroup = asn1_NOVALUE, + propertyParms = []}, _State) -> + error({invalid_LocalControlDescriptor, empty}); +enc_LocalControlDescriptor( + #'LocalControlDescriptor'{streamMode = SM, + reserveValue = RV, + reserveGroup = RG, + propertyParms = PPs}, State) -> + [ + ?LocalControlToken, + ?LBRKT_INDENT(State), + enc_list([{[SM], fun enc_StreamMode/2}, + {[RG], fun enc_reservedGroupMode/2}, + {[RV], fun enc_reservedValueMode/2}, + {PPs, fun enc_PropertyParm/2}], ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]. + +enc_reservedGroupMode(Val, _State) -> + [ + ?ReservedGroupToken, + ?EQUAL, + case Val of + false -> ?OffToken; + true -> ?OnToken + end + ]. + +enc_reservedValueMode(Val, _State) -> + [ + ?ReservedValueToken, + ?EQUAL, + case Val of + false -> ?OffToken; + true -> ?OnToken + end + ]. + +enc_StreamMode({'StreamMode',Val}, State) -> + enc_StreamMode(Val, State); +enc_StreamMode(Val, _State) -> + [ + ?ModeToken, + ?EQUAL, + case Val of + sendOnly -> ?SendonlyToken; + recvOnly -> ?RecvonlyToken; + sendRecv -> ?SendrecvToken; + inactive -> ?InactiveToken; + loopBack -> ?LoopbackToken + end + ]. + +enc_Name({'Name',Val}, State) -> + enc_Name(Val, State); +enc_Name(Val, State) -> + %% BUGBUG: NAME = ALPHA *63(ALPHA / DIGIT / "_" ) + enc_STRING(Val, State, 1, 64). + +enc_PkgdName({'PkgdName', Val}, State) -> + enc_PkgdName(Val, State); +enc_PkgdName(Val, _State) -> + %% BUGBUG: pkgdName = (NAME / "*") SLASH (ItemID / "*" ) + %% enc_OCTET_STRING(Val, _State, 1, 64). + if + is_list(Val) -> + Length = length(Val), + if + (Length >= 1) -> + if + (Length =< 64) -> + Val; + true -> + error({pkgdName_toolong, Length, 64}) + end; + true -> + error({pkgdName_tooshort, Length, 1}) + end; + true -> + error({invalid_PkgdName, Val}) + end. + +enc_localDescriptor(Val, State) + when is_record(Val, 'LocalRemoteDescriptor') -> + [ + ?LocalToken, + ?LBRKT, + enc_LocalRemoteDescriptor(Val, State), + ?RBRKT_INDENT(State) + ]. + +enc_remoteDescriptor(Val, State) + when is_record(Val, 'LocalRemoteDescriptor') -> + [ + ?RemoteToken, + ?LBRKT, + enc_LocalRemoteDescriptor(Val, State), + ?RBRKT_INDENT(State) + ]. + +%% When text encoding the protocol, the descriptors consist of session +%% descriptions as defined in SDP (RFC2327), except that the "s=", "t=" +%% and "o=" lines are optional. When multiple session descriptions are +%% provided in one descriptor, the "v=" lines are required as delimiters; +%% otherwise they are optional. Implementations shall accept session +%% descriptions that are fully conformant to RFC2327. When binary +%% encoding the protocol the descriptor consists of groups of properties +%% (tag-value pairs) as specified in Annex C. Each such group may +%% contain the parameters of a session description. +enc_LocalRemoteDescriptor(Val, State) + when is_record(Val, 'LocalRemoteDescriptor') -> + case Val#'LocalRemoteDescriptor'.propGrps of + [] -> + []; + [OptV | MandV] -> + [?LfToken, + enc_PropertyGroup(OptV, opt_v, State) | + [enc_PropertyGroup(M, mand_v, State) || M <- MandV]] + end. + +enc_PropertyGroup({'PropertyGroup',Val}, RequiresV, State) -> + enc_PropertyGroup(Val, RequiresV, State); +enc_PropertyGroup([H | _T] = List, mand_v, State) + when is_record(H, 'PropertyParm') andalso (H#'PropertyParm'.name =:= "v") -> + enc_PropertyGroup(List, opt_v, State); +enc_PropertyGroup(PG, opt_v, State) -> + [ + [[enc_PropertyGroupParm(PP, State), ?CrToken, ?LfToken] || PP <- PG] + ]. + +enc_PropertyGroupParm(Val, State) + when is_record(Val, 'PropertyParm') -> + [OctetString] = Val#'PropertyParm'.value, + [ + enc_PkgdName(Val#'PropertyParm'.name, State), + ?EqualToken, + enc_OCTET_STRING(OctetString, State, 0, infinity) + ]. + +%% propertyParm = pkgdName parmValue +%% parmValue = (EQUAL alternativeValue/ INEQUAL VALUE) +%% alternativeValue = ( VALUE / LSBRKT VALUE *(COMMA VALUE) RSBRKT / +%% LSBRKT VALUE DOT DOT VALUE RSBRKT ) +enc_PropertyParm(Val, State) + when is_record(Val, 'PropertyParm') -> + PkgdName = ?META_ENC(property, Val#'PropertyParm'.name), + [ + enc_PkgdName(PkgdName, State), + enc_propertyParmValues(Val#'PropertyParm'.value, + Val#'PropertyParm'.extraInfo, + State) + ]. + +enc_propertyParmValues([Single], asn1_NOVALUE, State) -> + [ + ?EqualToken, + enc_Value(Single, State) + ]; +enc_propertyParmValues([Single], {relation, Rel}, State) -> + case Rel of + greaterThan -> [$>, enc_Value(Single, State)]; + smallerThan -> [$<, enc_Value(Single, State)]; + unequalTo -> [$#, enc_Value(Single, State)] + end; +enc_propertyParmValues([Low, High], {range, true}, State)-> + %% Exact two values + [ + ?EqualToken, + ?LSBRKT, + enc_Value(Low, State), + ?COLON, + enc_Value(High, State), + ?RSBRKT + ]; +enc_propertyParmValues(Values, {sublist, true}, State)-> + %% sublist (i.e. A AND B AND ...) + [ + ?EqualToken, + ?LSBRKT, + enc_list([{Values, fun enc_Value/2}], State), + ?RSBRKT + ]; +enc_propertyParmValues(Values, {sublist, false}, State) -> + %% alternatives (i.e. A OR B OR ...) + [ + ?EqualToken, + ?LBRKT, + enc_list([{Values, fun enc_Value/2}], State), + ?RBRKT + ]; +enc_propertyParmValues(V, EI, _State) -> + error({invalid_property_parm_values, V, EI}). + +enc_TerminationStateDescriptor(Val, State) + when is_record(Val, 'TerminationStateDescriptor') -> + [ + ?TerminationStateToken, + ?LBRKT_INDENT(State), + enc_list([{Val#'TerminationStateDescriptor'.propertyParms, + fun enc_PropertyParm/2}, + {[Val#'TerminationStateDescriptor'.eventBufferControl], + fun enc_eventBufferControl/2}, + {[Val#'TerminationStateDescriptor'.serviceState], + fun enc_serviceState/2}], + ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]. + +enc_eventBufferControl(Val, _State) -> + [ + + ?BufferToken, + ?EQUAL, + case Val of + off -> ?OffToken; + lockStep -> ?LockStepToken + end + ]. + +enc_serviceState({'ServiceState',Val}, State) -> + enc_serviceState(Val, State); +enc_serviceState(Val, _State) -> + [ + ?ServiceStatesToken, + ?EQUAL, + case Val of + test -> ?TestToken; + outOfSvc -> ?OutOfSvcToken; + inSvc -> ?InSvcToken + end + ]. + +enc_MuxDescriptor(Val, State) + when is_record(Val, 'MuxDescriptor') -> + [ + ?MuxToken, + ?EQUAL, + enc_MuxType(Val#'MuxDescriptor'.muxType, State), + enc_TerminationIDListN(Val#'MuxDescriptor'.termList, State) + ]. + +enc_MuxType({'MuxType',Val}, State) -> + enc_MuxType(Val, State); +enc_MuxType(Val, _State) -> + case Val of + h221 -> ?H221Token; + h223 -> ?H223Token; + h226 -> ?H226Token; + v76 -> ?V76Token; + %% extensionParameter + nx64k -> ?Nx64kToken % v2 + end. + +enc_StreamID({'StreamID',Val}, State) -> + enc_StreamID(Val, State); +enc_StreamID(Val, State) -> + enc_UINT16(Val, State). + +enc_EventsDescriptor(Val, State) + when is_record(Val, 'EventsDescriptor') -> + #'EventsDescriptor'{requestID = RequestId, + eventList = Events} = Val, + if + RequestId == asn1_NOVALUE, Events == [] -> + [ + ?EventsToken + ]; + + RequestId /= asn1_NOVALUE, Events /= [] -> + [ + ?EventsToken, + ?EQUAL, + enc_RequestID(RequestId, State), + ?LBRKT_INDENT(State), + enc_list([{Events, fun enc_RequestedEvent/2}], + ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ] + end. + +enc_RequestedEvent(Val, State) + when is_record(Val, 'RequestedEvent') -> +%% d("enc_RequestedEvent -> entry with" +%% "~n Val: ~p", [Val]), + PkgdName = ?META_ENC(event, Val#'RequestedEvent'.pkgdName), +%% d("enc_RequestedEvent -> entry with" +%% "~n PkgdName: ~p", [PkgdName]), + [ + enc_PkgdName(PkgdName, State), + enc_opt_brackets( + enc_list([{[Val#'RequestedEvent'.streamID], fun enc_eventStream/2}, + {Val#'RequestedEvent'.evParList, fun enc_eventOther/2} | + decompose_requestedActions(Val#'RequestedEvent'.eventAction)], + ?INC_INDENT(State)), + State) + ]. + +decompose_requestedActions(asn1_NOVALUE) -> + []; + +%% +%% This in the ABNF: +%% at-most-once each of KeepActiveToken , eventDM and eventStream +%% at most one of either embedWithSig or embedNoSig but not both +%% KeepActiveToken and embedWithSig must not both be present +%% + +%% embedWithSig +decompose_requestedActions(#'RequestedActions'{keepActive = KA, + eventDM = EDM, + secondEvent = SE, + signalsDescriptor = SD}) + when (KA =/= true) andalso + (SD =/= asn1_NOVALUE) andalso + (SD =/= []) -> +%% d("decompose_requestedActions -> entry with" +%% "~n EDM: ~p" +%% "~n SE: ~p" +%% "~n SD: ~p", [EDM, SE, SD]), + [ + {[EDM], fun enc_EventDM/2}, + {[{SE, SD}], fun enc_embedWithSig/2} + ]; + +%% embedNoSig +decompose_requestedActions(#'RequestedActions'{keepActive = KA, + eventDM = EDM, + secondEvent = SE, + signalsDescriptor = SD}) + when (SD =:= asn1_NOVALUE) orelse (SD =:= []) -> +%% d("decompose_requestedActions -> entry with" +%% "~n KA: ~p" +%% "~n EDM: ~p" +%% "~n SE: ~p", [KA, EDM, SE]), + [ + {[KA], fun enc_keepActive/2}, + {[EDM], fun enc_EventDM/2}, + {[SE], fun enc_embedNoSig/2} + ]; + +%% Fallback, if everything else failes.... +decompose_requestedActions(#'RequestedActions'{keepActive = KA, + eventDM = EDM, + secondEvent = SE, + signalsDescriptor = SD}) -> +%% d("decompose_requestedActions -> entry with" +%% "~n KA: ~p" +%% "~n EDM: ~p" +%% "~n SE: ~p" +%% "~n SD: ~p", [KA, EDM, SE, SD]), + [ + {[KA], fun enc_keepActive/2}, + {[EDM], fun enc_EventDM/2}, + {[{SE, SD}], fun enc_embedWithSig/2} + ]. + + +enc_embedNoSig(#'SecondEventsDescriptor'{requestID = RID, + eventList = Evs}, State) -> +%% d("enc_embedNoSig -> entry with" +%% "~n RID: ~p" +%% "~n Evs: ~p", [RID, Evs]), + [ + ?EmbedToken, + ?LBRKT_INDENT(State), + enc_embedFirst(RID, Evs, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]. + +enc_embedWithSig({asn1_NOVALUE, SD}, State) -> +%% d("enc_embedWithSig -> entry with" +%% "~n SD: ~p", [SD]), + [ + ?EmbedToken, + ?LBRKT_INDENT(State), + enc_SignalsDescriptor(SD, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]; +enc_embedWithSig({#'SecondEventsDescriptor'{requestID = RID, + eventList = Evs}, SD}, State) -> +%% d("enc_embedWithSig -> entry with" +%% "~n RID: ~p" +%% "~n Evs: ~p" +%% "~n SD: ~p", [RID, Evs, SD]), + [ + ?EmbedToken, + ?LBRKT_INDENT(State), + enc_SignalsDescriptor(SD, ?INC_INDENT(State)), + ?COMMA_INDENT(?INC_INDENT(State)), + enc_embedFirst(RID, Evs, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]. + +enc_keepActive(Val, _State) -> +%% d("enc_keepActive -> entry with" +%% "~n Val: ~p", [Val]), + case Val of + true -> [?KeepActiveToken]; + false -> [] + end. + +enc_EventDM({'EventDM',Val}, State) -> + enc_EventDM(Val, State); +enc_EventDM({Tag, Val}, State) -> +%% d("enc_EventDM -> entry with" +%% "~n Tag: ~p" +%% "~n Val: ~p", [Tag, Val]), + case Tag of + digitMapName -> + [ + ?DigitMapToken, + ?EQUAL, + enc_DigitMapName(Val, State) + ]; + digitMapValue -> + [ + ?DigitMapToken, + ?LBRKT_INDENT(State), + enc_DigitMapValue(Val, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]; + _ -> + error({invalid_EventDM_tag, Tag}) + end. + +enc_embedFirst(RID, Evs, State) + when (RID =/= asn1_NOVALUE) andalso is_list(Evs) andalso (Evs =/= []) -> +%% d("enc_embedFirst -> entry with" +%% "~n RID: ~p" +%% "~n Evs: ~p", [RID, Evs]), + [ + ?EventsToken, + ?EQUAL, + enc_RequestID(RID, State), + ?LBRKT_INDENT(State), + enc_list([{Evs, fun enc_SecondRequestedEvent/2}], ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]; +enc_embedFirst(_RID, _Evs, _State) -> +%% d("enc_embedFirst -> entry"), + [ + ?EventsToken + ]. + +enc_SecondRequestedEvent(#'SecondRequestedEvent'{pkgdName = N, + streamID = SID, + evParList = EPL, + eventAction = EA}, + State) -> +%% d("enc_SecondRequestedEvent -> entry with" +%% "~n N: ~p" +%% "~n SID: ~p" +%% "~n EPL: ~p" +%% "~n EA: ~p", [N, SID, EPL, EA]), + PkgdName = ?META_ENC(event, N), + [ + enc_PkgdName(PkgdName, State), + enc_opt_brackets( + enc_list( + [{[SID], fun enc_eventStream/2}, + {EPL, fun enc_eventOther/2} | + decompose_secondRequestedActions(EA)], + ?INC_INDENT(State)), + State) + ]. + +decompose_secondRequestedActions(asn1_NOVALUE) -> + []; +decompose_secondRequestedActions(Val) + when is_record(Val, 'SecondRequestedActions') -> +%% d("decompose_secondRequestedActions -> entry with" +%% "~n Val: ~p", [Val]), + [ + {[Val#'SecondRequestedActions'.keepActive], + fun enc_keepActive/2}, + {[Val#'SecondRequestedActions'.eventDM], + fun enc_EventDM/2}, + {[Val#'SecondRequestedActions'.signalsDescriptor], + fun enc_embeddedSignalsDescriptor/2} + ]. + +enc_embeddedSignalsDescriptor(Val, State) -> + [ + ?EmbedToken, + ?LBRKT_INDENT(State), + enc_SignalsDescriptor(Val, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]. + +enc_EventBufferDescriptor({'EventBufferDescriptor',Val}, State) -> + enc_EventBufferDescriptor(Val, State); +enc_EventBufferDescriptor([], _State) -> + [ + ?EventBufferToken + ]; +enc_EventBufferDescriptor(EventSpecs, State) + when is_list(EventSpecs) and (length(EventSpecs) >= 1) -> + [ + ?EventBufferToken, + ?LBRKT_INDENT(State), + enc_eventSpecs(EventSpecs, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]; +enc_EventBufferDescriptor(EventSpecs, _State) -> + error({bad_eventSpecs, EventSpecs}). + +enc_eventSpecs([Mand | Opt], State) -> + [enc_eventSpec(Mand, State), + [[?COMMA_INDENT(State), enc_eventSpec(Val, State)] || Val <- Opt]]. + +enc_eventSpec(#'EventSpec'{eventName = Name, + streamID = SID, + eventParList = EPL}, State) -> + [ + enc_EventName(Name, State), + enc_opt_brackets( + enc_list([{[SID], fun enc_eventStream/2}, + {EPL, fun enc_eventOther/2}], + ?INC_INDENT(State)), + State) + ]. + +enc_SignalsDescriptor({'SignalsDescriptor',Val}, State) -> + enc_SignalsDescriptor(Val, State); +enc_SignalsDescriptor([], _State) -> + [ + ?SignalsToken + ]; +enc_SignalsDescriptor(List, State) when is_list(List) -> +% d("enc_SignalsDescriptor -> entry with" +% "~n List: ~p", [List]), + [ + ?SignalsToken, + ?LBRKT_INDENT(State), + enc_list([{List, fun enc_SignalRequest/2}], ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]. + +enc_SignalRequest({'SignalRequest',Val}, State) -> + enc_SignalRequest(Val, State); +enc_SignalRequest({Tag, Val}, State) -> +% d("enc_SignalsDescriptor -> entry with" +% "~n Tag: ~p" +% "~n Val: ~p", [Tag, Val]), + case Tag of + signal -> + enc_Signal(Val, State); + seqSigList -> + enc_SeqSigList(Val, State); + _ -> + error({invalid_SignalRequest_tag, Tag}) + end. + + +enc_SeqSigList(Val, State) + when is_record(Val, 'SeqSigList') -> + [ + ?SignalListToken, + ?EQUAL, + enc_UINT16(Val#'SeqSigList'.id, State), + ?LBRKT_INDENT(State), + enc_list([{Val#'SeqSigList'.signalList, fun enc_Signal/2}], + ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]. + +enc_Signal(Val, State) + when is_record(Val, 'Signal') -> + [ + enc_SignalName(Val#'Signal'.signalName, State), + enc_opt_brackets( + enc_list([{[Val#'Signal'.streamID], fun enc_sigStream/2}, + {[Val#'Signal'.sigType], fun enc_sigSignalType/2}, + {[Val#'Signal'.duration], fun enc_sigDuration/2}, + {[Val#'Signal'.notifyCompletion], fun enc_notifyCompletion/2}, + {[Val#'Signal'.keepActive], fun enc_keepActive/2}, + {Val#'Signal'.sigParList, fun enc_sigOther/2}], + ?INC_INDENT(State)), + State) + ]. + +enc_sigStream(Val, State) -> + [ + ?StreamToken, + ?EQUAL, + enc_StreamID(Val, State) + ]. + +enc_sigSignalType(Val, State) -> + [ + ?SignalTypeToken, + ?EQUAL, + enc_SignalType(Val, State) + ]. + +enc_sigDuration(Val, State) -> + [ + ?DurationToken, + ?EQUAL, + enc_UINT16(Val, State) + ]. + +enc_notifyCompletion(List, State) when is_list(List) -> + [ + ?NotifyCompletionToken, + ?EQUAL, + ?LBRKT_INDENT(State), + enc_list([{List, fun enc_notifyCompletionItem/2}], ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]. + +enc_notifyCompletionItem(Val, _State) -> + case Val of + onTimeOut -> ?TimeOutToken; + onInterruptByEvent -> ?InterruptByEventToken; + onInterruptByNewSignalDescr -> ?InterruptByNewSignalsDescrToken; + otherReason -> ?OtherReasonToken + end. + +enc_SignalType({'SignalType',Val}, State) -> + enc_SignalType(Val, State); +enc_SignalType(Val, _State) -> + case Val of + brief -> ?BriefToken; + onOff -> ?OnOffToken; + timeOut -> ?TimeOutToken + end. + +enc_SignalName({'SignalName',Val}, State)-> + enc_SignalName(Val, State); +enc_SignalName(Val, State) -> + PkgdName = ?META_ENC(signal, Val), + enc_PkgdName(PkgdName, State). + +enc_sigOther(Val, State) + when is_record(Val, 'SigParameter') -> + [ + enc_Name(Val#'SigParameter'.sigParameterName, State), + enc_propertyParmValues(Val#'SigParameter'.value, + Val#'SigParameter'.extraInfo, + State) + ]. + +enc_RequestID({'RequestID',Val}, State) -> + enc_RequestID(Val, State); +enc_RequestID(Val, _State) when (Val =:= ?megaco_all_request_id) -> + "*"; +enc_RequestID(Val, State) -> + enc_UINT32(Val, State). + +enc_ModemDescriptor(MD, _State) -> + error({deprecated, MD}). + +%% Corr1: +%% As of corr 1 ModemDescriptor has been deprecated. +%% 7.1.2: ...shall not be included as part of a transmitted content and, +%% if received, shall either be ignored or processed at the option +%% of the implementation. ... +%% enc_ModemDescriptor(#'ModemDescriptor'{mtl = [Val], +%% mpl = [], +%% nonStandardData = asn1_NOVALUE}, +%% State) -> +%% [ +%% ?ModemToken, +%% ?EQUAL, +%% enc_ModemType(Val, State) +%% ]; +%% enc_ModemDescriptor(Val, State) +%% when is_record(Val, 'ModemDescriptor') -> +%% [ +%% ?ModemToken, +%% ?LSBRKT, +%% enc_list([{Val#'ModemDescriptor'.mtl, fun enc_ModemType/2}], State), +%% ?RSBRKT, +%% enc_opt_brackets( +%% enc_list([{Val#'ModemDescriptor'.mpl, fun enc_PropertyParm/2}], +%% ?INC_INDENT(State)), +%% State) +%% %% BUGBUG: Is PropertyParm == NAME parmValue? +%% ]. + +%% enc_ModemDescriptor(Val, State) +%% when is_record(Val, 'ModemDescriptor') -> +%% [ +%% ?ModemToken, +%% %% BUGBUG: Does never generate: EQUAL modemType +%% ?LSBRKT, +%% enc_list([{Val#'ModemDescriptor'.mtl, fun enc_ModemType/2}], State), +%% ?RSBRKT, +%% enc_opt_brackets( +%% enc_list([{Val#'ModemDescriptor'.mpl, fun enc_PropertyParm/2}], +%% ?INC_INDENT(State)), +%% State) +%% %% BUGBUG: Is PropertyParm == NAME parmValue? +%% ]. + +%% Corr1: See ModemDescriptor above +%% enc_ModemType({'ModemType',Val}, State)-> +%% enc_ModemType(Val, State); +%% enc_ModemType(Val, _State) -> +%% %% BUGBUG: Does not handle extensionParameter +%% case Val of +%% v18 -> ?V18Token; +%% v22 -> ?V22Token; +%% v22bis -> ?V22bisToken; +%% v32 -> ?V32Token; +%% v32bis -> ?V32bisToken; +%% v34 -> ?V34Token; +%% v90 -> ?V90Token; +%% v91 -> ?V91Token; +%% synchISDN -> ?SynchISDNToken +%% end. + +enc_DigitMapDescriptor(#'DigitMapDescriptor'{digitMapName = asn1_NOVALUE, + digitMapValue = Value} = Val, + State) + when (Value =/= asn1_NOVALUE) -> + case is_empty_DigitMapValue(Value) of + true -> + error({invalid_DigitMapDescriptor, Val}); + false -> + [ + ?DigitMapToken, + ?EQUAL, + ?LBRKT_INDENT(State), + enc_DigitMapValue(Value, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ] + end; +enc_DigitMapDescriptor(#'DigitMapDescriptor'{digitMapName = Name, + digitMapValue = asn1_NOVALUE}, + State) + when (Name =/= asn1_NOVALUE) -> + [ + ?DigitMapToken, + ?EQUAL, + enc_DigitMapName(Name, State) + ]; +enc_DigitMapDescriptor(#'DigitMapDescriptor'{digitMapName = Name, + digitMapValue = Value}, + State) + when (Name =/= asn1_NOVALUE) andalso (Value =/= asn1_NOVALUE) -> + case is_empty_DigitMapValue(Value) of + true -> + [ + ?DigitMapToken, + ?EQUAL, + enc_DigitMapName(Name, State) + ]; + false -> + [ + ?DigitMapToken, + ?EQUAL, + enc_DigitMapName(Name, State), + ?LBRKT_INDENT(State), + enc_DigitMapValue(Value, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ] + end; +enc_DigitMapDescriptor(BadVal, _State) -> + error({invalid_DigitMapDescriptor, BadVal}). + +enc_DigitMapName({'DigitMapName',Val}, State) -> + enc_DigitMapName(Val, State); +enc_DigitMapName(Val, State) -> + enc_Name(Val, State). + +is_empty_DigitMapValue(#'DigitMapValue'{startTimer = asn1_NOVALUE, + shortTimer = asn1_NOVALUE, + longTimer = asn1_NOVALUE, + digitMapBody = [], + durationTimer = asn1_NOVALUE}) -> + true; +is_empty_DigitMapValue(#'DigitMapValue'{}) -> + false. + +enc_DigitMapValue(Val, State) + when is_record(Val, 'DigitMapValue') -> + [ + enc_timer(Val#'DigitMapValue'.startTimer, $T, State), + enc_timer(Val#'DigitMapValue'.shortTimer, $S, State), + enc_timer(Val#'DigitMapValue'.longTimer, $L, State), + enc_timer(Val#'DigitMapValue'.durationTimer, $Z, State), + %% BUGBUG: digitMapBody not handled at all + enc_STRING(Val#'DigitMapValue'.digitMapBody, State, 0, infinity) + ]. + +enc_timer(asn1_NOVALUE, _Prefix, _State) -> + []; +enc_timer(Timer, Prefix, State) -> + [ + Prefix, + ?COLON, + enc_DIGIT(Timer, State, 0, 99), + ?COMMA_INDENT(State) + ]. + + +enc_ServiceChangeParm(Val, State) + when is_record(Val, 'ServiceChangeParm') -> + [ + ?ServicesToken, + ?LBRKT_INDENT(State), + enc_list([{[Val#'ServiceChangeParm'.serviceChangeMethod], + fun enc_ServiceChangeMethod/2}, + {[Val#'ServiceChangeParm'.serviceChangeAddress], + fun enc_ServiceChangeAddress/2}, + {[Val#'ServiceChangeParm'.serviceChangeVersion], + fun enc_serviceChangeVersion/2}, + {[Val#'ServiceChangeParm'.serviceChangeProfile], + fun enc_ServiceChangeProfile/2}, + {[{reason, Val#'ServiceChangeParm'.serviceChangeReason}], + fun enc_serviceChangeReason/2}, + {[Val#'ServiceChangeParm'.serviceChangeDelay], + fun enc_serviceChangeDelay/2}, + {[Val#'ServiceChangeParm'.serviceChangeMgcId], + fun enc_serviceChangeMgcId/2}, + {[Val#'ServiceChangeParm'.timeStamp], + fun enc_TimeNotation/2}, + {Val#'ServiceChangeParm'.serviceChangeInfo, + fun enc_AuditDescriptor/2}], + ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]. + + +enc_ServiceChangeMethod({'ServiceChangeMethod',Val}, State) -> + enc_ServiceChangeMethod(Val, State); +enc_ServiceChangeMethod(Val, _State) -> + [ + ?MethodToken, + ?EQUAL, + case Val of + failover -> ?FailoverToken; + forced -> ?ForcedToken; + graceful -> ?GracefulToken; + restart -> ?RestartToken; + disconnected -> ?DisconnectedToken; + handOff -> ?HandOffToken + end + %% BUGBUG: extension + ]. + +enc_ServiceChangeAddress({'ServiceChangeAddress',Val}, State) -> + enc_ServiceChangeAddress(Val, State); +enc_ServiceChangeAddress({Tag, Val}, State) -> + [ + ?ServiceChangeAddressToken, + ?EQUAL, + case Tag of + portNumber -> + enc_portNumber(Val, State); + ip4Address -> + enc_IP4Address(Val, State); + ip6Address -> + enc_IP6Address(Val, State); + domainName -> + enc_DomainName(Val, State); + deviceName -> + enc_PathName(Val, State); + mtpAddress -> + enc_mtpAddress(Val, State); + _ -> + error({invalid_ServiceChangeAddress_tag, Tag}) + end + ]. + +enc_serviceChangeVersion(Val, State) -> + [ + ?VersionToken, + ?EQUAL, + enc_version(Val, State) + ]. + +enc_ServiceChangeProfile(#'ServiceChangeProfile'{profileName = Name, + version = Version}, + State) -> + [ + ?ProfileToken, + ?EQUAL, + enc_Name(Name, State), + ?SLASH, + enc_version(Version, State) + ]. + +enc_serviceChangeReason({reason, Val}, State) -> + case Val of + asn1_NOVALUE -> + []; + [List] when is_list(List) -> + [ + ?ReasonToken, + ?EQUAL, + enc_QUOTED_STRING(List,State) % OTP-4632 enc_Value(List, State) + ] + end. + +enc_serviceChangeDelay(Val, State) -> + [ + ?DelayToken, + ?EQUAL, + enc_UINT32(Val, State) + ]. + +enc_serviceChangeMgcId(Val, State) -> + [ + ?MgcIdToken, + ?EQUAL, + enc_MId(Val, State) + ]. + +enc_portNumber(Val, State) when is_integer(Val) andalso (Val >= 0) -> + enc_UINT16(Val, State). + +enc_ServiceChangeResParm(Val, State) + when is_record(Val, 'ServiceChangeResParm') -> + enc_list([{[Val#'ServiceChangeResParm'.serviceChangeAddress], + fun enc_ServiceChangeAddress/2}, + {[Val#'ServiceChangeResParm'.serviceChangeVersion], + fun enc_serviceChangeVersion/2}, + {[Val#'ServiceChangeResParm'.serviceChangeProfile], + fun enc_ServiceChangeProfile/2}, + {[Val#'ServiceChangeResParm'.serviceChangeMgcId], + fun enc_serviceChangeMgcId/2}, + {[Val#'ServiceChangeResParm'.timeStamp], + fun enc_TimeNotation/2}], + State). + +enc_PackagesDescriptor({'PackagesDescriptor',Val}, State) -> + enc_PackagesDescriptor(Val, State); +enc_PackagesDescriptor(Val, State) -> + [ + ?PackagesToken, + ?LBRKT_INDENT(State), + enc_list([{Val, fun enc_PackagesItem/2}], ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]. + +enc_PackagesItem(Val, State) + when is_record(Val, 'PackagesItem') -> + PkgdName = ?META_ENC(package, Val#'PackagesItem'.packageName), + [ + enc_Name(PkgdName, State), + "-", + enc_UINT16(Val#'PackagesItem'.packageVersion, State) + ]. + +enc_StatisticsDescriptor({'StatisticsDescriptor',Val}, State) -> + enc_StatisticsDescriptor(Val, State); +enc_StatisticsDescriptor(List, State) when is_list(List) -> + [ + ?StatsToken, + ?LBRKT_INDENT(State), + enc_list([{List, fun enc_StatisticsParameter/2}], ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]. + +enc_StatisticsParameter(Val, State) + when is_record(Val, 'StatisticsParameter') -> + PkgdName = ?META_ENC(statistics, Val#'StatisticsParameter'.statName), + case Val#'StatisticsParameter'.statValue of + asn1_NOVALUE -> + [ + enc_PkgdName(PkgdName, State) + ]; + [StatVal] when is_list(StatVal) -> + [ + enc_PkgdName(PkgdName, State), + ?EQUAL, + enc_Value(StatVal, State) + ] + end. + +enc_TimeNotation(Val, State) + when is_record(Val, 'TimeNotation') -> + [ + enc_STRING(Val#'TimeNotation'.date, State, 8, 8), % "yyyymmdd" + "T", + enc_STRING(Val#'TimeNotation'.time, State, 8, 8) % "hhmmssss" + ]. + +%% BUGBUG: Does not verify that string must contain at least one char +%% BUGBUG: This violation of the is required in order to comply with +%% BUGBUG: the dd/ce ds parameter that may possibly be empty. +enc_Value({'Value',Val}, State) -> + enc_Value(Val, State); +enc_Value(String, _State) -> + case quoted_string_count(String, 0, true, false) of + {_, 0, _} -> + [?DQUOTE, String, ?DQUOTE]; + {false, _, _} -> + [?DQUOTE, String, ?DQUOTE]; + {true, _, _} -> + [String] + end. + +quoted_string_count([?DoubleQuoteToken | T], 0 = Count, _IsSafe, _MaybeQuoted) -> + %% Already a quoted string. Make sure it ends + quoted_string_count(T, Count + 1, true, true); +quoted_string_count([?DoubleQuoteToken], Count, IsSafe, true = MaybeQuoted) -> + %% An explicitly quoted string + {IsSafe, Count, MaybeQuoted}; +quoted_string_count([H | T], Count, IsSafe, MaybeQuoted) -> + case ?classify_char(H) of + safe_char_upper -> quoted_string_count(T, Count + 1, IsSafe, MaybeQuoted); + safe_char -> quoted_string_count(T, Count + 1, IsSafe, MaybeQuoted); + rest_char -> quoted_string_count(T, Count + 1, false, MaybeQuoted); + white_space -> quoted_string_count(T, Count + 1, false, MaybeQuoted); + _ -> error({illegal_char, H}) + end; +quoted_string_count([], _Count, _IsSafe, true = _MaybeQuoted) -> + error({illegal_char, ?DoubleQuoteToken}); +quoted_string_count([], Count, IsSafe, MaybeQuoted) -> + {IsSafe, Count, MaybeQuoted}. + +enc_DigitString(String, _State) when is_list(String) -> + [?DQUOTE, String, ?DQUOTE]. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% Encode an octet string, escape } by \ if necessary +enc_OCTET_STRING(List, State, Min, Max) -> + do_enc_OCTET_STRING(List, State, Min, Max, 0). + +do_enc_OCTET_STRING([H | T], State, Min, Max, Count) -> + case H of + $} -> + [$\\, H | do_enc_OCTET_STRING(T, State, Min, Max, Count + 1)]; + _ -> + [H | do_enc_OCTET_STRING(T, State, Min, Max, Count + 1)] + end; +do_enc_OCTET_STRING([], _State, Min, Max, Count) -> + verify_count(Count, Min, Max), + []. + +enc_QUOTED_STRING(String, _State) when is_list(String) -> + case quoted_string_count(String, 0, true, false) of + {_IsSafe, Count, false = _QuotedString} -> + verify_count(Count, 1, infinity), + [?DQUOTE, String, ?DQUOTE]; + {_IsSafe, Count, true = _QuotedString} -> + verify_count(Count, 3, infinity), % quotes not included in the count + [String] + end. + +%% The internal format of hex digits is a list of octets +%% Min and Max means #hexDigits +%% Leading zeros are prepended in order to fulfill Min +enc_HEXDIG(Octets, State, Min, Max) when is_list(Octets) -> + do_enc_HEXDIG(Octets, State, Min, Max, 0, []). + +do_enc_HEXDIG([Octet | Rest], State, Min, Max, Count, Acc) + when (Octet >= 0) andalso (Octet =< 255) -> + Hex = hex(Octet), % OTP-4921 + if + Octet =< 15 -> + Acc2 = [[$0|Hex]|Acc], % OTP-4921 + do_enc_HEXDIG(Rest, State, Min, Max, Count + 2, ["0" | Acc2]); + true -> + Acc2 = [Hex|Acc], % OTP-4921 + do_enc_HEXDIG(Rest, State, Min, Max, Count + 2, Acc2) + end; +do_enc_HEXDIG([], State, Min, Max, Count, Acc) + when is_integer(Min) andalso (Count < Min) -> + do_enc_HEXDIG([0], State, Min, Max, Count, Acc); +do_enc_HEXDIG([], _State, Min, Max, Count, Acc) -> %% OTP-4710 + verify_count(Count, Min, Max), + lists:reverse(Acc). + +enc_DIGIT(Val, State, Min, Max) -> + enc_integer(Val, State, Min, Max). + +enc_STRING(String, _State, Min, Max) when is_list(String) -> + verify_count(length(String), Min, Max), + String. + +enc_UINT16(Val, State) -> + enc_integer(Val, State, 0, 65535). + +enc_UINT32(Val, State) -> + enc_integer(Val, State, 0, 4294967295). + +enc_integer(Val, _State, Min, Max) -> + verify_count(Val, Min, Max), + integer_to_list(Val). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Encodes a list of elements with separator tokens between +%% the elements. Optional asn1_NOVALUE values are ignored. + +enc_list(List, State) -> + enc_list(List, State, fun(_S) -> ?COMMA_INDENT(_S) end, false). + +enc_list([], _State, _SepEncoder, _NeedsSep) -> + []; +enc_list([{Elems, ElemEncoder} | Tail], State, SepEncoder, NeedsSep) -> + case do_enc_list(Elems, State, ElemEncoder, SepEncoder, NeedsSep) of + [] -> + enc_list(Tail, State, SepEncoder, NeedsSep); + List -> + [List, + enc_list(Tail, State, SepEncoder, true)] + end; +enc_list(A, B, C, D) -> + error({invlid_list, A, B, C, D}). + +do_enc_list(asn1_NOVALUE, _State, _ElemEncoder, _SepEncoder, _NeedsSep) -> + []; +do_enc_list([], _State, _ElemEncoder, _SepEncoder, _NeedsSep) -> + []; +do_enc_list([asn1_NOVALUE | T], State, ElemEncoder, SepEncoder, NeedsSep) -> + do_enc_list(T, State, ElemEncoder, SepEncoder, NeedsSep); +do_enc_list([H | T], State, ElemEncoder, SepEncoder, NeedsSep) + when is_function(ElemEncoder) andalso is_function(SepEncoder) -> + case ElemEncoder(H, State) of + [] -> + do_enc_list(T, State, ElemEncoder, SepEncoder, NeedsSep); + List when NeedsSep =:= true -> + [SepEncoder(State), + List, do_enc_list(T, State, ElemEncoder, SepEncoder, true)]; + List when NeedsSep =:= false -> + [List, + do_enc_list(T, State, ElemEncoder, SepEncoder, true)] + end. + +%% Add brackets if list is non-empty +enc_opt_brackets([], _State) -> + []; +enc_opt_brackets(List, _State) when is_list(List) -> + [?LBRKT_INDENT(_State), List, ?RBRKT_INDENT(_State)]. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% Int -> list of hex chars +hex(Int) -> + hexi(get_lo_bits(Int, 4), []). + +hexi({0, Lo}, Ack) -> + [hex4(Lo) | Ack]; +hexi({Hi, Lo} , Ack) -> + hexi(get_lo_bits(Hi, 4), [hex4(Lo) | Ack]). + +hex4(Int) when Int < 10 -> + Int + $0; +hex4(Int) -> + ($A - 10) + Int. + +get_lo_bits(Int, Size) -> + Lo = Int band ones_mask(Size), + Hi = Int bsr Size, + {Hi, Lo}. + +ones_mask(Ones) -> + (1 bsl Ones) - 1. + +%% Verify that Count is within the range of Min and Max +verify_count(Count, Min, Max) -> + if + is_integer(Count) -> + if + is_integer(Min) andalso (Count >= Min) -> + if + is_integer(Max) andalso (Count =< Max) -> + Count; + Max =:= infinity -> + Count; + true -> + error({count_too_large, Count, Max}) + end; + true -> + error({count_too_small, Count, Min}) + end; + true -> + error({count_not_an_integer, Count}) + end. + + +%% ------------------------------------------------------------------- + +error(Reason) -> + erlang:error(Reason). + + +%% ------------------------------------------------------------------- + +%% d(F) -> +%% d(F,[]). +%% d(F, A) -> +%% %% d(true, F, A). +%% d(get(dbg), F, A). + +%% d(true, F, A) -> +%% io:format("~p:" ++ F ++ "~n", [?MODULE | A]); +%% d(_, _, _) -> +%% ok. + + -- cgit v1.2.3