diff options
Diffstat (limited to 'lib/megaco/src/text')
40 files changed, 47508 insertions, 0 deletions
diff --git a/lib/megaco/src/text/Makefile b/lib/megaco/src/text/Makefile new file mode 100644 index 0000000000..b2e8e762dd --- /dev/null +++ b/lib/megaco/src/text/Makefile @@ -0,0 +1,148 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2000-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% + +include $(ERL_TOP)/make/target.mk + +EBIN = ../../ebin +MEGACO_INCLUDEDIR = ../../include + +include $(ERL_TOP)/make/$(TARGET)/otp.mk + + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include ../../vsn.mk +VSN=$(MEGACO_VSN) + + +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/lib/megaco-$(VSN) + + +# ---------------------------------------------------- +# Target Specs +# ---------------------------------------------------- + +include modules.mk + +ERL_FILES = \ + $(MODULES:%=%.erl) \ + $(INTERNAL_YRL_FILES:%.yrl=%.erl) + +ERL_TARGET_FILES = \ + $(INTERNAL_YRL_FILES:%.yrl=%.erl) + +BEAM_TARGET_FILES = \ + $(INTERNAL_YRL_FILES:%.yrl=$(EBIN)/%.$(EMULATOR)) \ + $(MODULES:%=$(EBIN)/%.$(EMULATOR)) + +TARGET_FILES = $(ERL_TARGET_FILES) $(BEAM_TARGET_FILES) + + +# ---------------------------------------------------- +# FLAGS +# ---------------------------------------------------- +ifeq ($(TYPE),debug) +ERL_COMPILE_FLAGS += -Ddebug +endif + +include ../app/megaco.mk + +ERL_COMPILE_FLAGS += \ + $(MEGACO_ERL_COMPILE_FLAGS) \ + -I../../include + +# YRL_FLAGS += -pa /clearcase/otp/tools/parsetools/ebin + +ifeq ($(YRL_VERBOSE),true) +YRL_FLAGS += -v +endif + + +# ---------------------------------------------------- +# Targets +# ---------------------------------------------------- +debug: + @${MAKE} TYPE=debug opt + +opt: $(TARGET_FILES) + +clean: + rm -f $(TARGET_FILES) + rm -f errs core *~ + +docs: + +info: + @echo "MODULES = $(MODULES)" + @echo "" + @echo "ERL_FILES = $(ERL_FILES)" + @echo "" + @echo "ERL_TARGET_FILES = $(ERL_TARGET_FILES)" + @echo "" + @echo "BEAM_TARGET_FILES = $(BEAM_TARGET_FILES)" + @echo "" + @echo "TARGET_FILES = $(TARGET_FILES)" + @echo "" + @echo "INTERNAL_YRL_FILES = $(INTERNAL_YRL_FILES)" + @echo "" + @echo "INTERNAL_HRL_FILES = $(INTERNAL_HRL_FILES)" + @echo "" + + +# ---------------------------------------------------- +# Special Build Targets +# ---------------------------------------------------- + +parser: parser_v1 parser_v2 parser_prev3a parser_prev3b + +parser_v1: megaco_text_parser_v1.$(EMULATOR) + +parser_v2: megaco_text_parser_v2.$(EMULATOR) + +parser_prev3a: megaco_text_parser_prev3a.$(EMULATOR) + +parser_prev3b: megaco_text_parser_prev3b.$(EMULATOR) + + +# ---------------------------------------------------- +# Release Target +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_release_targets.mk + + +release_spec: opt + $(INSTALL_DIR) $(RELSYSDIR)/ebin + $(INSTALL_DATA) $(BEAM_TARGET_FILES) $(RELSYSDIR)/ebin + $(INSTALL_DIR) $(RELSYSDIR)/src + $(INSTALL_DIR) $(RELSYSDIR)/src/text + $(INSTALL_DATA) $(ERL_FILES) $(INTERNAL_YRL_FILES) $(INTERNAL_HRL_FILES) $(RELSYSDIR)/src/text + + +release_docs_spec: + + +# ---------------------------------------------------- +# Include dependencies +# ---------------------------------------------------- + +include depend.mk + diff --git a/lib/megaco/src/text/depend.mk b/lib/megaco/src/text/depend.mk new file mode 100644 index 0000000000..62d0811692 --- /dev/null +++ b/lib/megaco/src/text/depend.mk @@ -0,0 +1,187 @@ +#-*-makefile-*- ; force emacs to enter makefile-mode + +# %CopyrightBegin% +# +# Copyright Ericsson AB 2001-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% + +megaco_text_parser_v1.erl: \ + megaco_text_parser_v1.yrl \ + megaco_text_parser_v1.hrl +megaco_text_parser_v2.erl: \ + megaco_text_parser_v2.yrl \ + megaco_text_parser_v2.hrl +megaco_text_parser_v3.erl: \ + megaco_text_parser_v3.yrl \ + megaco_text_parser_v3.hrl +megaco_text_parser_prev3a.erl: \ + megaco_text_parser_prev3a.yrl \ + megaco_text_parser_prev3a.hrl +megaco_text_parser_prev3b.erl: \ + megaco_text_parser_prev3b.yrl \ + megaco_text_parser_prev3b.hrl +megaco_text_parser_prev3c.erl: \ + megaco_text_parser_prev3c.yrl \ + megaco_text_parser_prev3c.hrl + +megaco_text_mini_parser.erl: \ + megaco_text_mini_parser.yrl \ + megaco_text_mini_parser.hrl + +$(EBIN)/megaco_compact_text_encoder.$(EMULATOR): \ + megaco_compact_text_encoder.erl + +$(EBIN)/megaco_compact_text_encoder.$(EMULATOR): \ + megaco_compact_text_encoder.erl + +$(EBIN)/megaco_compact_text_encoder_v1.$(EMULATOR): \ + megaco_compact_text_encoder_v1.erl \ + $(MEGACO_INCLUDEDIR)/megaco.hrl \ + $(MEGACO_INCLUDEDIR)/megaco_message_v1.hrl \ + megaco_text_tokens.hrl \ + megaco_text_gen_v1.hrl + +$(EBIN)/megaco_compact_text_encoder_v2.$(EMULATOR): \ + megaco_compact_text_encoder_v2.erl \ + $(MEGACO_INCLUDEDIR)/megaco.hrl \ + $(MEGACO_INCLUDEDIR)/megaco_message_v2.hrl \ + megaco_text_tokens.hrl \ + megaco_text_gen_v2.hrl + +$(EBIN)/megaco_compact_text_encoder_v3.$(EMULATOR): \ + megaco_compact_text_encoder_v3.erl \ + $(MEGACO_INCLUDEDIR)/megaco.hrl \ + $(MEGACO_INCLUDEDIR)/megaco_message_v3.hrl \ + megaco_text_tokens.hrl \ + megaco_text_gen_v3.hrl + +$(EBIN)/megaco_compact_text_encoder_prev3a.$(EMULATOR): \ + megaco_compact_text_encoder_prev3a.erl \ + $(MEGACO_INCLUDEDIR)/megaco.hrl \ + $(MEGACO_INCLUDEDIR)/megaco_message_prev3a.hrl \ + megaco_text_tokens.hrl \ + megaco_text_gen_prev3a.hrl + +$(EBIN)/megaco_compact_text_encoder_prev3b.$(EMULATOR): \ + megaco_compact_text_encoder_prev3b.erl \ + $(MEGACO_INCLUDEDIR)/megaco.hrl \ + $(MEGACO_INCLUDEDIR)/megaco_message_prev3b.hrl \ + megaco_text_tokens.hrl \ + megaco_text_gen_prev3b.hrl + +$(EBIN)/megaco_compact_text_encoder_prev3c.$(EMULATOR): \ + megaco_compact_text_encoder_prev3c.erl \ + $(MEGACO_INCLUDEDIR)/megaco.hrl \ + $(MEGACO_INCLUDEDIR)/megaco_message_prev3c.hrl \ + megaco_text_tokens.hrl \ + megaco_text_gen_prev3c.hrl + +$(EBIN)/megaco_pretty_text_encoder.$(EMULATOR): \ + megaco_pretty_text_encoder.erl + +$(EBIN)/megaco_pretty_text_encoder_v1.$(EMULATOR): \ + megaco_pretty_text_encoder_v1.erl \ + $(MEGACO_INCLUDEDIR)/megaco.hrl \ + $(MEGACO_INCLUDEDIR)/megaco_message_v1.hrl \ + megaco_text_tokens.hrl \ + megaco_text_gen_v1.hrl + +$(EBIN)/megaco_pretty_text_encoder_v2.$(EMULATOR): \ + megaco_pretty_text_encoder_v2.erl \ + $(MEGACO_INCLUDEDIR)/megaco.hrl \ + $(MEGACO_INCLUDEDIR)/megaco_message_v2.hrl \ + megaco_text_tokens.hrl \ + megaco_text_gen_v2.hrl + +$(EBIN)/megaco_pretty_text_encoder_v3.$(EMULATOR): \ + megaco_pretty_text_encoder_v3.erl \ + $(MEGACO_INCLUDEDIR)/megaco.hrl \ + $(MEGACO_INCLUDEDIR)/megaco_message_v3.hrl \ + megaco_text_tokens.hrl \ + megaco_text_gen_v3.hrl + +$(EBIN)/megaco_pretty_text_encoder_prev3a.$(EMULATOR): \ + megaco_pretty_text_encoder_prev3a.erl \ + $(MEGACO_INCLUDEDIR)/megaco.hrl \ + $(MEGACO_INCLUDEDIR)/megaco_message_prev3a.hrl \ + megaco_text_tokens.hrl \ + megaco_text_gen_prev3a.hrl + +$(EBIN)/megaco_pretty_text_encoder_prev3b.$(EMULATOR): \ + megaco_pretty_text_encoder_prev3b.erl \ + $(MEGACO_INCLUDEDIR)/megaco.hrl \ + $(MEGACO_INCLUDEDIR)/megaco_message_prev3b.hrl \ + megaco_text_tokens.hrl \ + megaco_text_gen_prev3b.hrl + +$(EBIN)/megaco_pretty_text_encoder_prev3c.$(EMULATOR): \ + megaco_pretty_text_encoder_prev3c.erl \ + $(MEGACO_INCLUDEDIR)/megaco.hrl \ + $(MEGACO_INCLUDEDIR)/megaco_message_prev3c.hrl \ + megaco_text_tokens.hrl \ + megaco_text_gen_prev3c.hrl + +$(EBIN)/megaco_text_parser_v1.$(EMULATOR): \ + megaco_text_parser_v1.erl \ + $(MEGACO_INCLUDEDIR)/megaco.hrl \ + $(MEGACO_INCLUDEDIR)/megaco_message_v1.hrl \ + megaco_text_tokens.hrl \ + megaco_text_parser_v1.hrl + +$(EBIN)/megaco_text_parser_v2.$(EMULATOR): \ + megaco_text_parser_v2.erl \ + $(MEGACO_INCLUDEDIR)/megaco.hrl \ + $(MEGACO_INCLUDEDIR)/megaco_message_v2.hrl \ + megaco_text_tokens.hrl \ + megaco_text_parser_v2.hrl + +$(EBIN)/megaco_text_parser_v3.$(EMULATOR): \ + megaco_text_parser_v3.erl \ + $(MEGACO_INCLUDEDIR)/megaco.hrl \ + $(MEGACO_INCLUDEDIR)/megaco_message_v3.hrl \ + megaco_text_tokens.hrl \ + megaco_text_parser_v3.hrl + +$(EBIN)/megaco_text_parser_prev3a.$(EMULATOR): \ + megaco_text_parser_prev3a.erl \ + $(MEGACO_INCLUDEDIR)/megaco.hrl \ + $(MEGACO_INCLUDEDIR)/megaco_message_prev3a.hrl \ + megaco_text_tokens.hrl \ + megaco_text_parser_prev3a.hrl + +$(EBIN)/megaco_text_parser_prev3b.$(EMULATOR): \ + megaco_text_parser_prev3b.erl \ + $(MEGACO_INCLUDEDIR)/megaco.hrl \ + $(MEGACO_INCLUDEDIR)/megaco_message_prev3b.hrl \ + megaco_text_tokens.hrl \ + megaco_text_parser_prev3b.hrl + +$(EBIN)/megaco_text_parser_prev3c.$(EMULATOR): \ + megaco_text_parser_prev3c.erl \ + $(MEGACO_INCLUDEDIR)/megaco.hrl \ + $(MEGACO_INCLUDEDIR)/megaco_message_prev3c.hrl \ + megaco_text_tokens.hrl \ + megaco_text_parser_prev3c.hrl + +$(EBIN)/megaco_text_scanner.$(EMULATOR): megaco_text_scanner.erl \ + $(MEGACO_INCLUDEDIR)/megaco.hrl \ + ../engine/megaco_message_internal.hrl \ + megaco_text_tokens.hrl + +$(EBIN)/megaco_text_mini_decoder.$(EMULATOR): \ + megaco_text_mini_decoder.erl \ + ../engine/megaco_message_internal.hrl \ + megaco_text_tokens.hrl + diff --git a/lib/megaco/src/text/megaco_compact_text_encoder.erl b/lib/megaco/src/text/megaco_compact_text_encoder.erl new file mode 100644 index 0000000000..f5195bda14 --- /dev/null +++ b/lib/megaco/src/text/megaco_compact_text_encoder.erl @@ -0,0 +1,560 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2000-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 COMPACT Megaco/H.248 text messages from internal form +%%---------------------------------------------------------------------- + +-module(megaco_compact_text_encoder). + +-behaviour(megaco_encoder). + +-export([encode_message/3, decode_message/3, + decode_mini_message/3, + + version_of/2, + + encode_transaction/3, + encode_action_requests/3, + encode_action_request/3, + encode_command_request/3, + encode_action_reply/3]). + +-export([token_tag2string/1, token_tag2string/2]). + +%% Backward compatible funcs: +-export([encode_message/2, decode_message/2]). + + +-include_lib("megaco/src/engine/megaco_message_internal.hrl"). + +-define(V1_PARSE_MOD, megaco_text_parser_v1). +-define(V2_PARSE_MOD, megaco_text_parser_v2). +-define(V3_PARSE_MOD, megaco_text_parser_v3). +-define(PREV3A_PARSE_MOD, megaco_text_parser_prev3a). +-define(PREV3B_PARSE_MOD, megaco_text_parser_prev3b). +-define(PREV3C_PARSE_MOD, megaco_text_parser_prev3c). + + +%%---------------------------------------------------------------------- +%% Convert a 'MegacoMessage' record into a binary +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- + +encode_message(EncodingConfig, + #'MegacoMessage'{mess = #'Message'{version = V}} = MegaMsg) -> + encode_message(EncodingConfig, V, MegaMsg). + +encode_message([{version3,_}|EC], 1, MegaMsg) -> + megaco_compact_text_encoder_v1:encode_message(EC, MegaMsg); +encode_message(EC, 1, MegaMsg) -> + megaco_compact_text_encoder_v1:encode_message(EC, MegaMsg); +encode_message([{version3,_}|EC], 2, MegaMsg) -> + megaco_compact_text_encoder_v2:encode_message(EC, MegaMsg); +encode_message(EC, 2, MegaMsg) -> + megaco_compact_text_encoder_v2:encode_message(EC, MegaMsg); +encode_message([{version3,v3}|EC], 3, MegaMsg) -> + megaco_compact_text_encoder_v3:encode_message(EC, MegaMsg); +encode_message([{version3,prev3c}|EC], 3, MegaMsg) -> + megaco_compact_text_encoder_prev3c:encode_message(EC, MegaMsg); +encode_message([{version3,prev3b}|EC], 3, MegaMsg) -> + megaco_compact_text_encoder_prev3b:encode_message(EC, MegaMsg); +encode_message([{version3,prev3a}|EC], 3, MegaMsg) -> + megaco_compact_text_encoder_prev3a:encode_message(EC, MegaMsg); +encode_message(EC, 3, MegaMsg) -> + megaco_compact_text_encoder_v3:encode_message(EC, MegaMsg); +encode_message(_EC, V, _MegaMsg) -> + {error, {bad_version, V}}. + + +%%---------------------------------------------------------------------- +%% Convert a binary into a 'MegacoMessage' record +%% Return {ok, MegacoMessageRecord} | {error, Reason} +%%---------------------------------------------------------------------- + +version_of(_EC, Bin) -> + case megaco_text_scanner:scan(Bin) of + {ok, _Tokens, V, _LastLine} -> + {ok, V}; + {error, Reason, Line} -> + {error, {decode_failed, Reason, Line}} + end. + +decode_message(EC, Bin) -> + %% d("decode_message -> entry with" + %% "~n EC: ~p", [EC]), + decode_message(EC, dynamic, Bin). + +decode_message([], _, Bin) when is_binary(Bin) -> + %% d("decode_message([]) -> entry"), + case megaco_text_scanner:scan(Bin) of + {ok, Tokens, 1, _LastLine} -> + do_decode_message(?V1_PARSE_MOD, Tokens, Bin); + + {ok, Tokens, 2, _LastLine} -> + do_decode_message(?V2_PARSE_MOD, Tokens, Bin); + + {ok, Tokens, 3, _LastLine} -> + do_decode_message(?V3_PARSE_MOD, Tokens, Bin); + + {ok, _Tokens, V, _LastLine} -> + {error, {unsupported_version, V}}; + + {error, Reason, Tokens, Line} -> + scan_error(Reason, Line, Tokens, Bin); + + {error, Reason, Line} -> %% OTP-4007 + scan_error(Reason, Line, Bin) %% OTP-4007 + end; +decode_message([{version3,v3}], _, Bin) when is_binary(Bin) -> + %% d("decode_message(v3) -> entry"), + case megaco_text_scanner:scan(Bin) of + {ok, Tokens, 1, _LastLine} -> + do_decode_message(?V1_PARSE_MOD, Tokens, Bin); + + {ok, Tokens, 2, _LastLine} -> + do_decode_message(?V2_PARSE_MOD, Tokens, Bin); + + {ok, Tokens, 3, _LastLine} -> + do_decode_message(?V3_PARSE_MOD, Tokens, Bin); + + {ok, _Tokens, V, _LastLine} -> + {error, {unsupported_version, V}}; + + {error, Reason, Tokens, Line} -> + scan_error(Reason, Line, Tokens, Bin); + + {error, Reason, Line} -> %% OTP-4007 + scan_error(Reason, Line, Bin) %% OTP-4007 + end; +decode_message([{version3,prev3c}], _, Bin) when is_binary(Bin) -> + %% d("decode_message(prev3c) -> entry"), + case megaco_text_scanner:scan(Bin) of + {ok, Tokens, 1, _LastLine} -> + do_decode_message(?V1_PARSE_MOD, Tokens, Bin); + + {ok, Tokens, 2, _LastLine} -> + do_decode_message(?V2_PARSE_MOD, Tokens, Bin); + + {ok, Tokens, 3, _LastLine} -> + do_decode_message(?PREV3C_PARSE_MOD, Tokens, Bin); + + {ok, _Tokens, V, _LastLine} -> + {error, {unsupported_version, V}}; + + {error, Reason, Tokens, Line} -> + scan_error(Reason, Line, Tokens, Bin); + + {error, Reason, Line} -> %% OTP-4007 + scan_error(Reason, Line, Bin) %% OTP-4007 + end; +decode_message([{version3,prev3b}], _, Bin) when is_binary(Bin) -> + %% d("decode_message(prev3b) -> entry"), + case megaco_text_scanner:scan(Bin) of + {ok, Tokens, 1, _LastLine} -> + do_decode_message(?V1_PARSE_MOD, Tokens, Bin); + + {ok, Tokens, 2, _LastLine} -> + do_decode_message(?V2_PARSE_MOD, Tokens, Bin); + + {ok, Tokens, 3, _LastLine} -> + do_decode_message(?PREV3B_PARSE_MOD, Tokens, Bin); + + {ok, _Tokens, V, _LastLine} -> + {error, {unsupported_version, V}}; + + {error, Reason, Tokens, Line} -> + scan_error(Reason, Line, Tokens, Bin); + + {error, Reason, Line} -> %% OTP-4007 + scan_error(Reason, Line, Bin) %% OTP-4007 + end; +decode_message([{version3,prev3a}], _, Bin) when is_binary(Bin) -> + %% d("decode_message(prev3a) -> entry"), + case megaco_text_scanner:scan(Bin) of + {ok, Tokens, 1, _LastLine} -> + do_decode_message(?V1_PARSE_MOD, Tokens, Bin); + + {ok, Tokens, 2, _LastLine} -> + do_decode_message(?V2_PARSE_MOD, Tokens, Bin); + + {ok, Tokens, 3, _LastLine} -> + do_decode_message(?PREV3A_PARSE_MOD, Tokens, Bin); + + {ok, _Tokens, V, _LastLine} -> + {error, {unsupported_version, V}}; + + {error, Reason, Tokens, Line} -> + scan_error(Reason, Line, Tokens, Bin); + + {error, Reason, Line} -> %% OTP-4007 + scan_error(Reason, Line, Bin) %% OTP-4007 + end; +decode_message([{flex, Port}], _, Bin) when is_binary(Bin) -> + %% d("decode_message(flex) -> entry"), + case megaco_flex_scanner:scan(Bin, Port) of + {ok, Tokens, 1, _LastLine} -> + do_decode_message(?V1_PARSE_MOD, Tokens, Bin); + + {ok, Tokens, 2, _LastLine} -> + do_decode_message(?V2_PARSE_MOD, Tokens, Bin); + + {ok, Tokens, 3, _LastLine} -> + do_decode_message(?V3_PARSE_MOD, Tokens, Bin); + + {ok, _Tokens, V, _LastLine} -> + {error, {unsupported_version, V}}; + + %% {error, Reason, Tokens, Line} -> + %% scan_error(Reason, Line, Tokens, Bin); + + {error, Reason, Line} -> %% OTP-4007 + scan_error(Reason, Line, Bin) %% OTP-4007 + end; +decode_message([{version3,v3},{flex, Port}], _, Bin) when is_binary(Bin) -> + %% d("decode_message(v3,flex) -> entry"), + case megaco_flex_scanner:scan(Bin, Port) of + {ok, Tokens, 1, _LastLine} -> + do_decode_message(?V1_PARSE_MOD, Tokens, Bin); + + {ok, Tokens, 2, _LastLine} -> + do_decode_message(?V2_PARSE_MOD, Tokens, Bin); + + {ok, Tokens, 3, _LastLine} -> + do_decode_message(?V3_PARSE_MOD, Tokens, Bin); + + {ok, _Tokens, V, _LastLine} -> + {error, {unsupported_version, V}}; + + %% {error, Reason, Tokens, Line} -> + %% scan_error(Reason, Line, Tokens, Bin); + + {error, Reason, Line} -> %% OTP-4007 + scan_error(Reason, Line, Bin) %% OTP-4007 + end; +decode_message([{version3,prev3c},{flex, Port}], _, Bin) when is_binary(Bin) -> + %% d("decode_message(prev3c,flex) -> entry"), + case megaco_flex_scanner:scan(Bin, Port) of + {ok, Tokens, 1, _LastLine} -> + do_decode_message(?V1_PARSE_MOD, Tokens, Bin); + + {ok, Tokens, 2, _LastLine} -> + do_decode_message(?V2_PARSE_MOD, Tokens, Bin); + + {ok, Tokens, 3, _LastLine} -> + do_decode_message(?PREV3C_PARSE_MOD, Tokens, Bin); + + {ok, _Tokens, V, _LastLine} -> + {error, {unsupported_version, V}}; + + %% {error, Reason, Tokens, Line} -> + %% scan_error(Reason, Line, Tokens, Bin); + + {error, Reason, Line} -> + scan_error(Reason, Line, Bin) + end; +decode_message([{version3,prev3b},{flex, Port}], _, Bin) when is_binary(Bin) -> + %% d("decode_message(prev3b,flex) -> entry"), + case megaco_flex_scanner:scan(Bin, Port) of + {ok, Tokens, 1, _LastLine} -> + do_decode_message(?V1_PARSE_MOD, Tokens, Bin); + + {ok, Tokens, 2, _LastLine} -> + do_decode_message(?V2_PARSE_MOD, Tokens, Bin); + + {ok, Tokens, 3, _LastLine} -> + do_decode_message(?PREV3B_PARSE_MOD, Tokens, Bin); + + {ok, _Tokens, V, _LastLine} -> + {error, {unsupported_version, V}}; + + %% {error, Reason, Tokens, Line} -> + %% scan_error(Reason, Line, Tokens, Bin); + + {error, Reason, Line} -> %% OTP-4007 + scan_error(Reason, Line, Bin) %% OTP-4007 + end; +decode_message([{version3,prev3a},{flex, Port}], _, Bin) when is_binary(Bin) -> + %% d("decode_message(prev3a,flex) -> entry"), + case megaco_flex_scanner:scan(Bin, Port) of + {ok, Tokens, 1, _LastLine} -> + do_decode_message(?V1_PARSE_MOD, Tokens, Bin); + + {ok, Tokens, 2, _LastLine} -> + do_decode_message(?V2_PARSE_MOD, Tokens, Bin); + + {ok, Tokens, 3, _LastLine} -> + do_decode_message(?PREV3A_PARSE_MOD, Tokens, Bin); + + {ok, _Tokens, V, _LastLine} -> + {error, {unsupported_version, V}}; + + %% {error, Reason, Tokens, Line} -> + %% scan_error(Reason, Line, Tokens, Bin); + + {error, Reason, Line} -> %% OTP-4007 + scan_error(Reason, Line, Bin) %% OTP-4007 + end; +decode_message(EC, _, Bin) when is_binary(Bin) -> + {error, {bad_encoding_config, EC}}; +decode_message(_EC, _, _BadBin) -> + {error, bad_binary}. + + +do_decode_message(ParseMod, Tokens, Bin) -> +%% d("do_decode_message -> entry with" +%% "~n ParseMod: ~p" +%% "~n Tokens: ~p", [ParseMod, Tokens]), + case (catch ParseMod:parse(Tokens)) of + {ok, MegacoMessage} -> +%% d("do_decode_message -> " +%% "~n MegacoMessage: ~p", [MegacoMessage]), + {ok, MegacoMessage}; + {error, Reason} -> + parse_error(Reason, Tokens, Bin); + + %% OTP-4007 + {'EXIT', Reason} -> + parse_error(Reason, Tokens, Bin) + end. + + +decode_mini_message(EC, _, Bin) when is_binary(Bin) -> + megaco_text_mini_decoder:decode_message(EC, Bin). + + +scan_error(Reason, Line, Bin) -> + scan_error(Reason, Line, [], Bin). + +scan_error("bad_property_parm: " ++ Reason, _Line, _Tokens, _Bin) -> + {error, {bad_property_parm, Reason}}; +scan_error(Reason, Line, Tokens, Bin) -> + %% io:format("scanner error: " + %% "~n Reason: ~p" + %% "~n Line: ~p" + %% "~n Tokens: ~p" + %% "~n Bin: ~p" + %% "~n", [Reason, Line, Tokens, Bin]), + {error, [{reason, Reason, Line}, {token, Tokens}, {chars, Bin}]}. + +parse_error(Reason, Tokens, Chars) -> + %% io:format("parser error -> entry with" + %% "~n Reason: ~p" + %% "~n Tokens: ~p" + %% "~n", [Reason, Tokens]), + case Reason of + {Line, Mod, [Prefix, [$[, TokenStringRaw, $]]]} when + is_integer(Line) andalso + is_atom(Mod) andalso + is_list(Prefix) andalso + is_list(TokenStringRaw) -> + TokenString = [l2i(X) || X <- TokenStringRaw, is_list(X)], + ReasonStr = Prefix ++ TokenString, + {error, [{reason, ReasonStr, Line}, {tokens, Tokens}, {chars, Chars}, {module, Mod}]}; + _ -> + {error, [{reason, Reason}, {token, Tokens}, {chars, Chars}]} + end. + + +l2i(L) when is_list(L) -> + case (catch list_to_integer(L)) of + I when is_integer(I) -> + I; + _ -> + L + end. + + +%%---------------------------------------------------------------------- +%% Convert a transaction record into a deep io list +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- +encode_transaction([{version3,_}|EC], 1, Trans) -> + megaco_compact_text_encoder_v1:encode_transaction(EC, Trans); +encode_transaction(EC, 1, Trans) -> + megaco_compact_text_encoder_v1:encode_transaction(EC, Trans); +encode_transaction([{version3,_}|EC], 2, Trans) -> + megaco_compact_text_encoder_v2:encode_transaction(EC, Trans); +encode_transaction(EC, 2, Trans) -> + megaco_compact_text_encoder_v2:encode_transaction(EC, Trans); +encode_transaction([{version3,prev3c}|EC], 3, Trans) -> + megaco_compact_text_encoder_prev3c:encode_transaction(EC, Trans); +encode_transaction([{version3,prev3b}|EC], 3, Trans) -> + megaco_compact_text_encoder_prev3b:encode_transaction(EC, Trans); +encode_transaction([{version3,prev3a}|EC], 3, Trans) -> + megaco_compact_text_encoder_prev3a:encode_transaction(EC, Trans); +encode_transaction([{version3,v3}|EC], 3, Trans) -> + megaco_compact_text_encoder_v3:encode_transaction(EC, Trans); +encode_transaction(EC, 3, Trans) -> + megaco_compact_text_encoder_v3:encode_transaction(EC, Trans); +encode_transaction(_EC, V, _Trans) -> + {error, {bad_version, V}}. + + +%%---------------------------------------------------------------------- +%% Convert a list of ActionRequest record's into a binary +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- +encode_action_requests([{version3,_}|EC], 1, ActReqs) + when is_list(ActReqs) -> + megaco_compact_text_encoder_v1:encode_action_requests(EC, ActReqs); +encode_action_requests(EC, 1, ActReqs) when is_list(ActReqs) -> + megaco_compact_text_encoder_v1:encode_action_requests(EC, ActReqs); +encode_action_requests([{version3,_}|EC], 2, ActReqs) + when is_list(ActReqs) -> + megaco_compact_text_encoder_v2:encode_action_requests(EC, ActReqs); +encode_action_requests(EC, 2, ActReqs) when is_list(ActReqs) -> + megaco_compact_text_encoder_v2:encode_action_requests(EC, ActReqs); +encode_action_requests([{version3,prev3c}|EC], 3, ActReqs) + when is_list(ActReqs) -> + megaco_compact_text_encoder_prev3c:encode_action_requests(EC, ActReqs); +encode_action_requests([{version3,prev3b}|EC], 3, ActReqs) + when is_list(ActReqs) -> + megaco_compact_text_encoder_prev3b:encode_action_requests(EC, ActReqs); +encode_action_requests([{version3,prev3a}|EC], 3, ActReqs) + when is_list(ActReqs) -> + megaco_compact_text_encoder_prev3a:encode_action_requests(EC, ActReqs); +encode_action_requests([{version3,v3}|EC], 3, ActReqs) + when is_list(ActReqs) -> + megaco_compact_text_encoder_v3:encode_action_requests(EC, ActReqs); +encode_action_requests(EC, 3, ActReqs) when is_list(ActReqs) -> + megaco_compact_text_encoder_v3:encode_action_requests(EC, ActReqs); +encode_action_requests(_EC, V, _ActReqs) -> + {error, {bad_version, V}}. + + +%%---------------------------------------------------------------------- +%% Convert a ActionRequest record into a binary +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- +encode_action_request([{version3,_}|EC], 1, ActReq) -> + megaco_compact_text_encoder_v1:encode_action_request(EC, ActReq); +encode_action_request(EC, 1, ActReq) -> + megaco_compact_text_encoder_v1:encode_action_request(EC, ActReq); +encode_action_request([{version3,_}|EC], 2, ActReq) -> + megaco_compact_text_encoder_v2:encode_action_request(EC, ActReq); +encode_action_request(EC, 2, ActReq) -> + megaco_compact_text_encoder_v2:encode_action_request(EC, ActReq); +encode_action_request([{version3,prev3c}|EC], 3, ActReq) -> + megaco_compact_text_encoder_prev3c:encode_action_request(EC, ActReq); +encode_action_request([{version3,prev3b}|EC], 3, ActReq) -> + megaco_compact_text_encoder_prev3b:encode_action_request(EC, ActReq); +encode_action_request([{version3,prev3a}|EC], 3, ActReq) -> + megaco_compact_text_encoder_prev3a:encode_action_request(EC, ActReq); +encode_action_request([{version3,v3}|EC], 3, ActReq) -> + megaco_compact_text_encoder_v3:encode_action_request(EC, ActReq); +encode_action_request(EC, 3, ActReq) -> + megaco_compact_text_encoder_v3:encode_action_request(EC, ActReq); +encode_action_request(_EC, V, _ActReq) -> + {error, {bad_version, V}}. + + +%%---------------------------------------------------------------------- +%% Convert a CommandRequest record into a deep io list +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- +encode_command_request([{version3,_}|EC], 1, CmdReq) -> + megaco_compact_text_encoder_v1:encode_command_request(EC, CmdReq); +encode_command_request(EC, 1, CmdReq) -> + megaco_compact_text_encoder_v1:encode_command_request(EC, CmdReq); +encode_command_request([{version3,_}|EC], 2, CmdReq) -> + megaco_compact_text_encoder_v2:encode_command_request(EC, CmdReq); +encode_command_request(EC, 2, CmdReq) -> + megaco_compact_text_encoder_v2:encode_command_request(EC, CmdReq); +encode_command_request([{version3,prev3c}|EC], 3, CmdReq) -> + megaco_compact_text_encoder_prev3c:encode_command_request(EC, CmdReq); +encode_command_request([{version3,prev3b}|EC], 3, CmdReq) -> + megaco_compact_text_encoder_prev3b:encode_command_request(EC, CmdReq); +encode_command_request([{version3,prev3a}|EC], 3, CmdReq) -> + megaco_compact_text_encoder_prev3a:encode_command_request(EC, CmdReq); +encode_command_request([{version3,v3}|EC], 3, CmdReq) -> + megaco_compact_text_encoder_v3:encode_command_request(EC, CmdReq); +encode_command_request(EC, 3, CmdReq) -> + megaco_compact_text_encoder_v3:encode_command_request(EC, CmdReq); +encode_command_request(_EC, V, _CmdReq) -> + {error, {bad_version, V}}. + + +%%---------------------------------------------------------------------- +%% Convert a action reply into a deep io list +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- +encode_action_reply([{version3,_}|EC], 1, ActRep) -> + megaco_compact_text_encoder_v1:encode_action_reply(EC, ActRep); +encode_action_reply(EC, 1, ActRep) -> + megaco_compact_text_encoder_v1:encode_action_reply(EC, ActRep); +encode_action_reply([{version3,_}|EC], 2, ActRep) -> + megaco_compact_text_encoder_v2:encode_action_reply(EC, ActRep); +encode_action_reply(EC, 2, ActRep) -> + megaco_compact_text_encoder_v2:encode_action_reply(EC, ActRep); +encode_action_reply([{version3,prev3c}|EC], 3, ActRep) -> + megaco_compact_text_encoder_prev3c:encode_action_reply(EC, ActRep); +encode_action_reply([{version3,prev3b}|EC], 3, ActRep) -> + megaco_compact_text_encoder_prev3b:encode_action_reply(EC, ActRep); +encode_action_reply([{version3,prev3a}|EC], 3, ActRep) -> + megaco_compact_text_encoder_prev3a:encode_action_reply(EC, ActRep); +encode_action_reply([{version3,v3}|EC], 3, ActRep) -> + megaco_compact_text_encoder_v3:encode_action_reply(EC, ActRep); +encode_action_reply(EC, 3, ActRep) -> + megaco_compact_text_encoder_v3:encode_action_reply(EC, ActRep); +encode_action_reply(_EC, V, _ActRep) -> + {error, {bad_version, V}}. + + + +%%---------------------------------------------------------------------- +%% A utility function to pretty print the tags found in a megaco message +%%---------------------------------------------------------------------- + +-define(TT2S_BEST_VERSION, v3). + +token_tag2string(Tag) -> + token_tag2string(Tag, ?TT2S_BEST_VERSION). + +token_tag2string(Tag, 1) -> + token_tag2string(Tag, v1); +token_tag2string(Tag, v1) -> + megaco_compact_text_encoder_v1:token_tag2string(Tag); +token_tag2string(Tag, 2) -> + token_tag2string(Tag, v2); +token_tag2string(Tag, v2) -> + megaco_compact_text_encoder_v2:token_tag2string(Tag); +token_tag2string(Tag, 3) -> + token_tag2string(Tag, v3); +token_tag2string(Tag, v3) -> + megaco_compact_text_encoder_v3:token_tag2string(Tag); +token_tag2string(Tag, prev3b) -> + megaco_compact_text_encoder_prev3b:token_tag2string(Tag); +token_tag2string(Tag, prev3c) -> + megaco_compact_text_encoder_prev3c:token_tag2string(Tag); +token_tag2string(Tag, _Vsn) -> + token_tag2string(Tag, ?TT2S_BEST_VERSION). + + +%% d(F) -> +%% d(F, []). + +%% d(F, A) -> +%% d(get(dbg), F, A). + +%% d(true, F, A) -> +%% io:format("~p:" ++ F ++ "~n", [?MODULE|A]); +%% d(_, _, _) -> +%% ok. diff --git a/lib/megaco/src/text/megaco_compact_text_encoder_prev3a.erl b/lib/megaco/src/text/megaco_compact_text_encoder_prev3a.erl new file mode 100644 index 0000000000..a45d35cc43 --- /dev/null +++ b/lib/megaco/src/text/megaco_compact_text_encoder_prev3a.erl @@ -0,0 +1,297 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2004-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 COMPACT Megaco/H.248 text messages from internal form +%%---------------------------------------------------------------------- + +-module(megaco_compact_text_encoder_prev3a). + +-export([encode_message/2, + encode_transaction/2, + encode_action_requests/2, + encode_action_request/2, + encode_command_request/2, + encode_action_reply/2]). + + +-include_lib("megaco/include/megaco.hrl"). +-include_lib("megaco/include/megaco_message_prev3a.hrl"). +-define(encoder_version_pre_prev3c,true). +-include("megaco_text_tokens.hrl"). + + +%%---------------------------------------------------------------------- +%% Convert a 'MegacoMessage' record into a binary +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- + +encode_message(EC, MegaMsg) + when is_list(EC) andalso is_record(MegaMsg, 'MegacoMessage') -> + case (catch enc_MegacoMessage(MegaMsg)) of + {'EXIT', Reason} -> + {error, Reason}; + Bin when is_binary(Bin) -> + {ok, Bin}; + DeepIoList -> + Bin = erlang:list_to_binary(DeepIoList), + {ok, Bin} + end; +encode_message(EncodingConfig, MegaMsg) + when is_record(MegaMsg, 'MegacoMessage') -> + {error, {bad_encoding_config, EncodingConfig}}; +encode_message(_EncodingConfig, _MegaMsg) -> + {error, bad_megaco_message}. + + +%%---------------------------------------------------------------------- +%% Convert a transaction record into a deep io list +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- +encode_transaction(_EC, Trans) -> + case (catch enc_Transaction(Trans)) of + {'EXIT', Reason} -> + {error, Reason}; + Bin when is_binary(Bin) -> + {ok, Bin}; + DeepIoList -> + Bin = erlang:list_to_binary(DeepIoList), + {ok, Bin} + end. + + +%%---------------------------------------------------------------------- +%% Convert a list of ActionRequest record's into a binary +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- +encode_action_requests(_EC, ActReqs) -> + case (catch enc_ActionRequests(ActReqs)) of + {'EXIT', Reason} -> + {error, Reason}; + Bin when is_binary(Bin) -> + {ok, Bin}; + DeepIoList -> + Bin = erlang:list_to_binary(DeepIoList), + {ok, Bin} + end. + +%%---------------------------------------------------------------------- +%% Convert a ActionRequest record into a binary +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- +encode_action_request(_EC, ActReq) + when is_record(ActReq, 'ActionRequest') -> + case (catch enc_ActionRequest(ActReq)) of + {'EXIT', Reason} -> + {error, Reason}; + Bin when is_binary(Bin) -> + {ok, Bin}; + DeepIoList -> + Bin = erlang:list_to_binary(DeepIoList), + {ok, Bin} + end. + + +%%---------------------------------------------------------------------- +%% Convert a CommandRequest record into a deep io list +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- +encode_command_request(_EC, CmdReq) + when is_record(CmdReq, 'CommandRequest') -> + case (catch enc_CommandRequest(CmdReq)) of + {'EXIT', Reason} -> + {error, Reason}; + Bin when is_binary(Bin) -> + {ok, Bin}; + DeepIoList -> + Bin = erlang:list_to_binary(DeepIoList), + {ok, Bin} + end. + + +%%---------------------------------------------------------------------- +%% Convert a action reply into a deep io list +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- +encode_action_reply(_EC, ActRep) + when is_record(ActRep, 'ActionReply') -> + case (catch enc_ActionReply(ActRep)) of + {'EXIT', Reason} -> + {error, Reason}; + Bin when is_binary(Bin) -> + {ok, Bin}; + DeepIoList -> + Bin = erlang:list_to_binary(DeepIoList), + {ok, Bin} + end. + + +%%---------------------------------------------------------------------- +%% Define various macros used by the actual generator code +%%---------------------------------------------------------------------- + +-define(EQUAL, [?EqualToken]). +-define(COLON, [?ColonToken]). +-define(LBRKT, [?LbrktToken]). +-define(RBRKT, [?RbrktToken]). +-define(LSBRKT, [?LsbrktToken]). +-define(RSBRKT, [?RsbrktToken]). +-define(COMMA, [?CommaToken]). +-define(DOT, [?DotToken]). +-define(SLASH, [?SlashToken]). +-define(DQUOTE, [?DoubleQuoteToken]). +-define(SP, [?SpToken]). +-define(HTAB, [?HtabToken]). +-define(CR, [?CrToken]). +-define(LF, [?LfToken]). +-define(LWSP, []). +-define(EOL, ?LF). +-define(WSP, ?SP). +-define(SEP, ?WSP). + +-define(INIT_INDENT, []). +-define(INC_INDENT(State), State). +-define(INDENT(State), State). +-define(LBRKT_INDENT(_State), [?LbrktToken]). +-define(RBRKT_INDENT(_State), [?RbrktToken]). +-define(LSBRKT_INDENT(_State), [?LsbrktToken]). +-define(RSBRKT_INDENT(_State), [?RsbrktToken]). +-define(COMMA_INDENT(_State), [?CommaToken]). +-define(SEP_INDENT(_State), [?LfToken]). + +%%---------------------------------------------------------------------- +%% Define token macros +%%---------------------------------------------------------------------- + +-define(AddToken , ?CompactAddToken). +-define(AuditToken , ?CompactAuditToken). +-define(AuditCapToken , ?CompactAuditCapToken). +-define(AuditValueToken , ?CompactAuditValueToken). +-define(AuthToken , ?CompactAuthToken). +-define(BothToken , ?CompactBothToken). +-define(BothwayToken , ?CompactBothwayToken). +-define(BriefToken , ?CompactBriefToken). +-define(BufferToken , ?CompactBufferToken). +-define(CtxToken , ?CompactCtxToken). +-define(ContextAuditToken , ?CompactContextAuditToken). +-define(ContextAttrToken , ?CompactContextAttrToken). +-define(DigitMapToken , ?CompactDigitMapToken). +-define(DirectionToken , ?CompactDirectionToken). +-define(DiscardToken , ?CompactDiscardToken). +-define(DisconnectedToken , ?CompactDisconnectedToken). +-define(DelayToken , ?CompactDelayToken). +-define(DeleteToken , ?CompactDeleteToken). +-define(DurationToken , ?CompactDurationToken). +-define(EmbedToken , ?CompactEmbedToken). +-define(EmergencyToken , ?CompactEmergencyToken). +-define(EmergencyOffToken , ?CompactEmergencyOffToken). +-define(ErrorToken , ?CompactErrorToken). +-define(EventBufferToken , ?CompactEventBufferToken). +-define(EventsToken , ?CompactEventsToken). +-define(ExternalToken , ?CompactExternalToken). +-define(FailoverToken , ?CompactFailoverToken). +-define(ForcedToken , ?CompactForcedToken). +-define(GracefulToken , ?CompactGracefulToken). +-define(H221Token , ?CompactH221Token). +-define(H223Token , ?CompactH223Token). +-define(H226Token , ?CompactH226Token). +-define(HandOffToken , ?CompactHandOffToken). +-define(IEPSToken , ?CompactIEPSToken). +-define(ImmAckRequiredToken , ?CompactImmAckRequiredToken). +-define(InactiveToken , ?CompactInactiveToken). +-define(InternalToken , ?CompactInternalToken). +-define(InterruptByEventToken , ?CompactInterruptByEventToken). +-define(InterruptByNewSignalsDescrToken, ?CompactInterruptByNewSignalsDescrToken). +-define(IsolateToken , ?CompactIsolateToken). +-define(InSvcToken , ?CompactInSvcToken). +-define(KeepActiveToken , ?CompactKeepActiveToken). +-define(LocalToken , ?CompactLocalToken). +-define(LocalControlToken , ?CompactLocalControlToken). +-define(LockStepToken , ?CompactLockStepToken). +-define(LoopbackToken , ?CompactLoopbackToken). +-define(MediaToken , ?CompactMediaToken). +-define(MegacopToken , ?CompactMegacopToken). +-define(MethodToken , ?CompactMethodToken). +-define(MgcIdToken , ?CompactMgcIdToken). +-define(ModeToken , ?CompactModeToken). +-define(ModifyToken , ?CompactModifyToken). +-define(ModemToken , ?CompactModemToken). +-define(MoveToken , ?CompactMoveToken). +-define(MtpToken , ?CompactMtpToken). +-define(MuxToken , ?CompactMuxToken). +-define(NotifyToken , ?CompactNotifyToken). +-define(NotifyCompletionToken , ?CompactNotifyCompletionToken). +-define(Nx64kToken , ?CompactNx64kToken). +-define(ObservedEventsToken , ?CompactObservedEventsToken). +-define(OffToken , ?CompactOffToken). +-define(OnewayToken , ?CompactOnewayToken). +-define(OnOffToken , ?CompactOnOffToken). +-define(OnToken , ?CompactOnToken). +-define(OtherReasonToken , ?CompactOtherReasonToken). +-define(OutOfSvcToken , ?CompactOutOfSvcToken). +-define(PackagesToken , ?CompactPackagesToken). +-define(PendingToken , ?CompactPendingToken). +-define(PriorityToken , ?CompactPriorityToken). +-define(ProfileToken , ?CompactProfileToken). +-define(ReasonToken , ?CompactReasonToken). +-define(RecvonlyToken , ?CompactRecvonlyToken). +-define(ReplyToken , ?CompactReplyToken). +-define(ResponseAckToken , ?CompactResponseAckToken). +-define(RestartToken , ?CompactRestartToken). +-define(RemoteToken , ?CompactRemoteToken). +-define(RequestIDToken , ?CompactRequestIDToken). +-define(ReservedGroupToken , ?CompactReservedGroupToken). +-define(ReservedValueToken , ?CompactReservedValueToken). +-define(SendonlyToken , ?CompactSendonlyToken). +-define(SendrecvToken , ?CompactSendrecvToken). +-define(ServicesToken , ?CompactServicesToken). +-define(ServiceStatesToken , ?CompactServiceStatesToken). +-define(ServiceChangeToken , ?CompactServiceChangeToken). +-define(ServiceChangeAddressToken , ?CompactServiceChangeAddressToken). +-define(ServiceChangeIncompleteToken , ?CompactServiceChangeIncompleteToken). +-define(SignalListToken , ?CompactSignalListToken). +-define(SignalsToken , ?CompactSignalsToken). +-define(SignalTypeToken , ?CompactSignalTypeToken). +-define(StatsToken , ?CompactStatsToken). +-define(StreamToken , ?CompactStreamToken). +-define(SubtractToken , ?CompactSubtractToken). +-define(SynchISDNToken , ?CompactSynchISDNToken). +-define(TerminationStateToken , ?CompactTerminationStateToken). +-define(TestToken , ?CompactTestToken). +-define(TimeOutToken , ?CompactTimeOutToken). +-define(TopologyToken , ?CompactTopologyToken). +-define(TransToken , ?CompactTransToken). +-define(V18Token , ?CompactV18Token). +-define(V22Token , ?CompactV22Token). +-define(V22bisToken , ?CompactV22bisToken). +-define(V32Token , ?CompactV32Token). +-define(V32bisToken , ?CompactV32bisToken). +-define(V34Token , ?CompactV34Token). +-define(V76Token , ?CompactV76Token). +-define(V90Token , ?CompactV90Token). +-define(V91Token , ?CompactV91Token). +-define(VersionToken , ?CompactVersionToken). + +%%---------------------------------------------------------------------- +%% Include the generator code +%%---------------------------------------------------------------------- + +-include("megaco_text_gen_prev3a.hrl"). + diff --git a/lib/megaco/src/text/megaco_compact_text_encoder_prev3b.erl b/lib/megaco/src/text/megaco_compact_text_encoder_prev3b.erl new file mode 100644 index 0000000000..63f76040ce --- /dev/null +++ b/lib/megaco/src/text/megaco_compact_text_encoder_prev3b.erl @@ -0,0 +1,432 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2005-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 COMPACT Megaco/H.248 text messages from internal form +%%---------------------------------------------------------------------- + +-module(megaco_compact_text_encoder_prev3b). + +-export([encode_message/2, + encode_transaction/2, + encode_action_requests/2, + encode_action_request/2, + encode_command_request/2, + encode_action_reply/2]). + +-export([token_tag2string/1]). + +-include_lib("megaco/include/megaco.hrl"). +-include_lib("megaco/include/megaco_message_prev3b.hrl"). +-define(encoder_version_pre_prev3c,true). +-include("megaco_text_tokens.hrl"). + + +%%---------------------------------------------------------------------- +%% Convert a 'MegacoMessage' record into a binary +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- + +encode_message(EC, MegaMsg) + when is_list(EC) andalso is_record(MegaMsg, 'MegacoMessage') -> + case (catch enc_MegacoMessage(MegaMsg)) of + {'EXIT', Reason} -> + {error, Reason}; + Bin when is_binary(Bin) -> + {ok, Bin}; + DeepIoList -> + Bin = erlang:list_to_binary(DeepIoList), + {ok, Bin} + end; +encode_message(EncodingConfig, MegaMsg) + when is_record(MegaMsg, 'MegacoMessage') -> + {error, {bad_encoding_config, EncodingConfig}}; +encode_message(_EncodingConfig, _MegaMsg) -> + {error, bad_megaco_message}. + + + + +%%---------------------------------------------------------------------- +%% Convert a transaction record into a deep io list +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- +encode_transaction(_EC, Trans) -> + case (catch enc_Transaction(Trans)) of + {'EXIT', Reason} -> + {error, Reason}; + Bin when is_binary(Bin) -> + {ok, Bin}; + DeepIoList -> + Bin = erlang:list_to_binary(DeepIoList), + {ok, Bin} + end. + + +%%---------------------------------------------------------------------- +%% Convert a list of ActionRequest record's into a binary +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- +encode_action_requests(_EC, ActReqs) -> + case (catch enc_ActionRequests(ActReqs)) of + {'EXIT', Reason} -> + {error, Reason}; + Bin when is_binary(Bin) -> + {ok, Bin}; + DeepIoList -> + Bin = erlang:list_to_binary(DeepIoList), + {ok, Bin} + end. + +%%---------------------------------------------------------------------- +%% Convert a ActionRequest record into a binary +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- +encode_action_request(_EC, ActReq) + when is_record(ActReq, 'ActionRequest') -> + case (catch enc_ActionRequest(ActReq)) of + {'EXIT', Reason} -> + {error, Reason}; + Bin when is_binary(Bin) -> + {ok, Bin}; + DeepIoList -> + Bin = erlang:list_to_binary(DeepIoList), + {ok, Bin} + end. + +%%---------------------------------------------------------------------- +%% Convert a CommandRequest record into a deep io list +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- +encode_command_request(_EC, CmdReq) + when is_record(CmdReq, 'CommandRequest') -> + case (catch enc_CommandRequest(CmdReq)) of + {'EXIT', Reason} -> + {error, Reason}; + Bin when is_binary(Bin) -> + {ok, Bin}; + DeepIoList -> + Bin = erlang:list_to_binary(DeepIoList), + {ok, Bin} + end. + +%%---------------------------------------------------------------------- +%% Convert a action reply into a deep io list +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- +encode_action_reply(_EC, ActRep) + when is_record(ActRep, 'ActionReply') -> + case (catch enc_ActionReply(ActRep)) of + {'EXIT', Reason} -> + {error, Reason}; + Bin when is_binary(Bin) -> + {ok, Bin}; + DeepIoList -> + Bin = erlang:list_to_binary(DeepIoList), + {ok, Bin} + end. + + +%%---------------------------------------------------------------------- +%% A utility function to pretty print the tags found in a megaco message +%%---------------------------------------------------------------------- + +token_tag2string(addReq) -> ?CompactAddToken; +token_tag2string(addReply) -> ?CompactAddToken; +token_tag2string(auditDescriptor) -> ?CompactAuditToken; +token_tag2string(auditCapRequest) -> ?CompactAuditCapToken; +token_tag2string(auditCapReply) -> ?CompactAuditCapToken; +token_tag2string(auditValueRequest) -> ?CompactAuditValueToken; +token_tag2string(auditValueReply) -> ?CompactAuditValueToken; +%% token_tag2string(X) -> ?CompactAuthToken; +token_tag2string(both) -> ?CompactBothToken; +token_tag2string(bothway) -> ?CompactBothwayToken; +token_tag2string(brief) -> ?CompactBriefToken; +%% token_tag2string(X) -> ?CompactBufferToken; +%% token_tag2string(X) -> ?CompactCtxToken; +%% token_tag2string(X) -> ?CompactContextAttrToken; +%% token_tag2string(X) -> ?CompactContextAuditToken; +%% token_tag2string(X) -> ?CompactContextListToken; +token_tag2string(digitMapDescriptor) -> ?CompactDigitMapToken; +token_tag2string(digitMapToken) -> ?CompactDigitMapToken; +%% token_tag2string(X) -> ?CompactDirectionToken; +%% token_tag2string(X) -> ?CompactDiscardToken; +%% token_tag2string(X) -> ?CompactDisconnectedToken; +%% token_tag2string(X) -> ?CompactDelayToken; +token_tag2string(duration) -> ?CompactDurationToken; +%% token_tag2string(X) -> ?CompactEmbedToken; +token_tag2string(emergencyAudit) -> ?CompactEmergencyToken; +%% token_tag2string(X) -> ?CompactEmergencyOffToken; +token_tag2string(errorDescriptor) -> ?CompactErrorToken; +token_tag2string(eventBufferDescriptor) -> ?CompactEventBufferToken; +token_tag2string(eventBufferToken) -> ?CompactEventBufferToken; +token_tag2string(eventsDescriptor) -> ?CompactEventsToken; +token_tag2string(eventsToken) -> ?CompactEventsToken; +token_tag2string(external) -> ?CompactExternalToken; +%% token_tag2string(X) -> ?CompactFailoverToken; +%% token_tag2string(X) -> ?CompactForcedToken; +%% token_tag2string(X) -> ?CompactGracefulToken; +%% token_tag2string(X) -> ?CompactH221Token; +%% token_tag2string(X) -> ?CompactH223Token; +%% token_tag2string(X) -> ?CompactH226Token; +%% token_tag2string(X) -> ?CompactHandOffToken; +token_tag2string(iepsCallind) -> ?CompactIEPSToken; +%% token_tag2string(X) -> ?CompactImmAckRequiredToken; +token_tag2string(inactive) -> ?CompactInactiveToken; +token_tag2string(internal) -> ?CompactInternalToken; +token_tag2string(onInterruptByEvent) -> ?CompactInterruptByEventToken; +token_tag2string(onInterruptByNewSignalDescr) -> ?CompactInterruptByNewSignalsDescrToken; +token_tag2string(isolate) -> ?CompactIsolateToken; +token_tag2string(inSvc) -> ?CompactInSvcToken; +token_tag2string(keepActive) -> ?CompactKeepActiveToken; +token_tag2string(localDescriptor) -> ?CompactLocalToken; +token_tag2string(localControlDescriptor) -> ?CompactLocalControlToken; +token_tag2string(lockStep) -> ?CompactLockStepToken; +token_tag2string(loopBack) -> ?CompactLoopbackToken; +token_tag2string(mediaDescriptor) -> ?CompactMediaToken; +token_tag2string(mediaToken) -> ?CompactMediaToken; +%% token_tag2string(X) -> ?CompactMegacopToken; +%% token_tag2string(X) -> ?CompactMethodToken; +%% token_tag2string(X) -> ?CompactMgcIdToken; +%% token_tag2string(X) -> ?CompactModeToken; +token_tag2string(modReq) -> ?CompactModifyToken; +token_tag2string(modReply) -> ?CompactModifyToken; +token_tag2string(modemDescriptor) -> ?CompactModemToken; +token_tag2string(modemToken) -> ?CompactModemToken; +token_tag2string(moveReq) -> ?CompactMoveToken; +token_tag2string(moveReply) -> ?CompactMoveToken; +%% token_tag2string(X) -> ?CompactMtpToken; +token_tag2string(muxDescriptor) -> ?CompactMuxToken; +token_tag2string(muxToken) -> ?CompactMuxToken; +token_tag2string(notifyReq) -> ?CompactNotifyToken; +%% token_tag2string(X) -> ?CompactNotifyCompletionToken; +%% token_tag2string(X) -> ?CompactNx64kToken; +token_tag2string(observedEventsDescriptor) -> ?CompactObservedEventsToken; +token_tag2string(observedEventsToken) -> ?CompactObservedEventsToken; +token_tag2string(false) -> ?CompactOffToken; +token_tag2string(off) -> ?CompactOffToken; +token_tag2string(oneway) -> ?CompactOnewayToken; +token_tag2string(onOff) -> ?CompactOnOffToken; +token_tag2string(true) -> ?CompactOnToken; +token_tag2string(otherReason) -> ?CompactOtherReasonToken; +token_tag2string(outOfSvc) -> ?CompactOutOfSvcToken; +token_tag2string(packagesDescriptor) -> ?CompactPackagesToken; +token_tag2string(packagesToken) -> ?CompactPackagesToken; +%% token_tag2string(X) -> ?CompactPendingToken; +token_tag2string(priorityAudit) -> ?CompactPriorityToken; +%% token_tag2string(X) -> ?CompactProfileToken; +%% token_tag2string(X) -> ?CompactReasonToken; +token_tag2string(recvOnly) -> ?CompactRecvonlyToken; +%% token_tag2string(X) -> ?CompactReplyToken; +%% token_tag2string(X) -> ?CompactRequestIDToken; +%% token_tag2string(X) -> ?CompactResponseAckToken; +%% token_tag2string(X) -> ?CompactRestartToken; +token_tag2string(remoteDescriptor) -> ?CompactRemoteToken; +%% token_tag2string(X) -> ?CompactReservedGroupToken; +%% token_tag2string(X) -> ?CompactReservedValueToken; +token_tag2string(sendOnly) -> ?CompactSendonlyToken; +token_tag2string(sendRecv) -> ?CompactSendrecvToken; +%% token_tag2string(X) -> ?CompactServicesToken; +%% token_tag2string(X) -> ?CompactServiceStatesToken; +token_tag2string(serviceChangeReq) -> ?CompactServiceChangeToken; +%% token_tag2string(X) -> ?CompactServiceChangeAddressToken; +token_tag2string(incomplete) -> ?CompactServiceChangeIncompleteToken; +%% token_tag2string(X) -> ?CompactSignalListToken; +token_tag2string(signalsDescriptor) -> ?CompactSignalsToken; +token_tag2string(signalsToken) -> ?CompactSignalsToken; +%% token_tag2string(X) -> ?CompactSignalTypeToken; +token_tag2string(statisticsDescriptor) -> ?CompactStatsToken; +token_tag2string(statsToken) -> ?CompactStatsToken; +%% token_tag2string(X) -> ?CompactStreamToken; +token_tag2string(subtractReq) -> ?CompactSubtractToken; +token_tag2string(subtractReply) -> ?CompactSubtractToken; +%% token_tag2string(X) -> ?CompactSynchISDNToken; +%% token_tag2string(X) -> ?CompactTerminationStateToken; +token_tag2string(test) -> ?CompactTestToken; +token_tag2string(timeOut) -> ?CompactTimeOutToken; +token_tag2string(onTimeOut) -> ?CompactTimeOutToken; +token_tag2string(topologyAudit) -> ?CompactTopologyToken; +%% token_tag2string(X) -> ?CompactTransToken; +%% token_tag2string(X) -> ?CompactV18Token; +%% token_tag2string(X) -> ?CompactV22Token; +%% token_tag2string(X) -> ?CompactV22bisToken; +%% token_tag2string(X) -> ?CompactV32Token; +%% token_tag2string(X) -> ?CompactV32bisToken; +%% token_tag2string(X) -> ?CompactV34Token; +%% token_tag2string(X) -> ?CompactV76Token; +%% token_tag2string(X) -> ?CompactV90Token; +%% token_tag2string(X) -> ?CompactV91Token; +%% token_tag2string(X) -> ?CompactVersionToken; +token_tag2string(_) -> []. + + + +%%---------------------------------------------------------------------- +%% Define various macros used by the actual generator code +%%---------------------------------------------------------------------- + +-define(EQUAL, [?EqualToken]). +-define(COLON, [?ColonToken]). +-define(LBRKT, [?LbrktToken]). +-define(RBRKT, [?RbrktToken]). +-define(LSBRKT, [?LsbrktToken]). +-define(RSBRKT, [?RsbrktToken]). +-define(COMMA, [?CommaToken]). +-define(DOT, [?DotToken]). +-define(SLASH, [?SlashToken]). +-define(DQUOTE, [?DoubleQuoteToken]). +-define(SP, [?SpToken]). +-define(HTAB, [?HtabToken]). +-define(CR, [?CrToken]). +-define(LF, [?LfToken]). +-define(LWSP, []). +-define(EOL, ?LF). +-define(WSP, ?SP). +-define(SEP, ?WSP). + +-define(INIT_INDENT, []). +-define(INC_INDENT(State), State). +-define(INDENT(State), State). +-define(LBRKT_INDENT(_State), [?LbrktToken]). +-define(RBRKT_INDENT(_State), [?RbrktToken]). +-define(LSBRKT_INDENT(_State), [?LsbrktToken]). +-define(RSBRKT_INDENT(_State), [?RsbrktToken]). +-define(COMMA_INDENT(_State), [?CommaToken]). +-define(SEP_INDENT(_State), [?LfToken]). + +%%---------------------------------------------------------------------- +%% Define token macros +%%---------------------------------------------------------------------- + +-define(AddToken , ?CompactAddToken). +-define(AuditToken , ?CompactAuditToken). +-define(AuditCapToken , ?CompactAuditCapToken). +-define(AuditValueToken , ?CompactAuditValueToken). +-define(AuthToken , ?CompactAuthToken). +-define(BothToken , ?CompactBothToken). +-define(BothwayToken , ?CompactBothwayToken). +-define(BriefToken , ?CompactBriefToken). +-define(BufferToken , ?CompactBufferToken). +-define(CtxToken , ?CompactCtxToken). +-define(ContextAuditToken , ?CompactContextAuditToken). +-define(ContextAttrToken , ?CompactContextAttrToken). +-define(DigitMapToken , ?CompactDigitMapToken). +-define(DirectionToken , ?CompactDirectionToken). +-define(DiscardToken , ?CompactDiscardToken). +-define(DisconnectedToken , ?CompactDisconnectedToken). +-define(DelayToken , ?CompactDelayToken). +-define(DeleteToken , ?CompactDeleteToken). +-define(DurationToken , ?CompactDurationToken). +-define(EmbedToken , ?CompactEmbedToken). +-define(EmergencyToken , ?CompactEmergencyToken). +-define(EmergencyOffToken , ?CompactEmergencyOffToken). +-define(ErrorToken , ?CompactErrorToken). +-define(EventBufferToken , ?CompactEventBufferToken). +-define(EventsToken , ?CompactEventsToken). +-define(ExternalToken , ?CompactExternalToken). +-define(FailoverToken , ?CompactFailoverToken). +-define(ForcedToken , ?CompactForcedToken). +-define(GracefulToken , ?CompactGracefulToken). +-define(H221Token , ?CompactH221Token). +-define(H223Token , ?CompactH223Token). +-define(H226Token , ?CompactH226Token). +-define(HandOffToken , ?CompactHandOffToken). +-define(IEPSToken , ?CompactIEPSToken). +-define(ImmAckRequiredToken , ?CompactImmAckRequiredToken). +-define(InactiveToken , ?CompactInactiveToken). +-define(InternalToken , ?CompactInternalToken). +-define(InterruptByEventToken , ?CompactInterruptByEventToken). +-define(InterruptByNewSignalsDescrToken, ?CompactInterruptByNewSignalsDescrToken). +-define(IsolateToken , ?CompactIsolateToken). +-define(InSvcToken , ?CompactInSvcToken). +-define(KeepActiveToken , ?CompactKeepActiveToken). +-define(LocalToken , ?CompactLocalToken). +-define(LocalControlToken , ?CompactLocalControlToken). +-define(LockStepToken , ?CompactLockStepToken). +-define(LoopbackToken , ?CompactLoopbackToken). +-define(MediaToken , ?CompactMediaToken). +-define(MegacopToken , ?CompactMegacopToken). +-define(MethodToken , ?CompactMethodToken). +-define(MgcIdToken , ?CompactMgcIdToken). +-define(ModeToken , ?CompactModeToken). +-define(ModifyToken , ?CompactModifyToken). +-define(ModemToken , ?CompactModemToken). +-define(MoveToken , ?CompactMoveToken). +-define(MtpToken , ?CompactMtpToken). +-define(MuxToken , ?CompactMuxToken). +-define(NotifyToken , ?CompactNotifyToken). +-define(NotifyCompletionToken , ?CompactNotifyCompletionToken). +-define(Nx64kToken , ?CompactNx64kToken). +-define(ObservedEventsToken , ?CompactObservedEventsToken). +-define(OffToken , ?CompactOffToken). +-define(OnewayToken , ?CompactOnewayToken). +-define(OnOffToken , ?CompactOnOffToken). +-define(OnToken , ?CompactOnToken). +-define(OtherReasonToken , ?CompactOtherReasonToken). +-define(OutOfSvcToken , ?CompactOutOfSvcToken). +-define(PackagesToken , ?CompactPackagesToken). +-define(PendingToken , ?CompactPendingToken). +-define(PriorityToken , ?CompactPriorityToken). +-define(ProfileToken , ?CompactProfileToken). +-define(ReasonToken , ?CompactReasonToken). +-define(RecvonlyToken , ?CompactRecvonlyToken). +-define(ReplyToken , ?CompactReplyToken). +-define(ResponseAckToken , ?CompactResponseAckToken). +-define(RestartToken , ?CompactRestartToken). +-define(RemoteToken , ?CompactRemoteToken). +-define(RequestIDToken , ?CompactRequestIDToken). +-define(ReservedGroupToken , ?CompactReservedGroupToken). +-define(ReservedValueToken , ?CompactReservedValueToken). +-define(SendonlyToken , ?CompactSendonlyToken). +-define(SendrecvToken , ?CompactSendrecvToken). +-define(ServicesToken , ?CompactServicesToken). +-define(ServiceStatesToken , ?CompactServiceStatesToken). +-define(ServiceChangeToken , ?CompactServiceChangeToken). +-define(ServiceChangeAddressToken , ?CompactServiceChangeAddressToken). +-define(ServiceChangeIncompleteToken , ?CompactServiceChangeIncompleteToken). +-define(SignalListToken , ?CompactSignalListToken). +-define(SignalsToken , ?CompactSignalsToken). +-define(SignalTypeToken , ?CompactSignalTypeToken). +-define(StatsToken , ?CompactStatsToken). +-define(StreamToken , ?CompactStreamToken). +-define(SubtractToken , ?CompactSubtractToken). +-define(SynchISDNToken , ?CompactSynchISDNToken). +-define(TerminationStateToken , ?CompactTerminationStateToken). +-define(TestToken , ?CompactTestToken). +-define(TimeOutToken , ?CompactTimeOutToken). +-define(TopologyToken , ?CompactTopologyToken). +-define(TransToken , ?CompactTransToken). +-define(V18Token , ?CompactV18Token). +-define(V22Token , ?CompactV22Token). +-define(V22bisToken , ?CompactV22bisToken). +-define(V32Token , ?CompactV32Token). +-define(V32bisToken , ?CompactV32bisToken). +-define(V34Token , ?CompactV34Token). +-define(V76Token , ?CompactV76Token). +-define(V90Token , ?CompactV90Token). +-define(V91Token , ?CompactV91Token). +-define(VersionToken , ?CompactVersionToken). + +%%---------------------------------------------------------------------- +%% Include the generator code +%%---------------------------------------------------------------------- + +-include("megaco_text_gen_prev3b.hrl"). + diff --git a/lib/megaco/src/text/megaco_compact_text_encoder_prev3c.erl b/lib/megaco/src/text/megaco_compact_text_encoder_prev3c.erl new file mode 100644 index 0000000000..10d7b7e732 --- /dev/null +++ b/lib/megaco/src/text/megaco_compact_text_encoder_prev3c.erl @@ -0,0 +1,455 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2005-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 COMPACT Megaco/H.248 text messages from internal form +%%---------------------------------------------------------------------- + +-module(megaco_compact_text_encoder_prev3c). + +-export([encode_message/2, + encode_transaction/2, + encode_action_requests/2, + encode_action_request/2, + encode_command_request/2, + encode_action_reply/2]). + +-export([token_tag2string/1]). + +-include_lib("megaco/include/megaco.hrl"). +-include_lib("megaco/include/megaco_message_prev3c.hrl"). +-include("megaco_text_tokens.hrl"). + + +%%---------------------------------------------------------------------- +%% Convert a 'MegacoMessage' record into a binary +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- + +encode_message(EC, MegaMsg) + when is_list(EC) andalso is_record(MegaMsg, 'MegacoMessage') -> + case (catch enc_MegacoMessage(MegaMsg)) of + {'EXIT', Reason} -> + {error, Reason}; + Bin when is_binary(Bin) -> + {ok, Bin}; + DeepIoList -> + Bin = erlang:list_to_binary(DeepIoList), + {ok, Bin} + end; +encode_message(EncodingConfig, MegaMsg) + when is_record(MegaMsg, 'MegacoMessage') -> + {error, {bad_encoding_config, EncodingConfig}}; +encode_message(_EncodingConfig, _MegaMsg) -> + {error, bad_megaco_message}. + + + + +%%---------------------------------------------------------------------- +%% Convert a transaction record into a deep io list +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- +encode_transaction(_EC, Trans) -> + case (catch enc_Transaction(Trans)) of + {'EXIT', Reason} -> + {error, Reason}; + Bin when is_binary(Bin) -> + {ok, Bin}; + DeepIoList -> + Bin = erlang:list_to_binary(DeepIoList), + {ok, Bin} + end. + + +%%---------------------------------------------------------------------- +%% Convert a list of ActionRequest record's into a binary +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- +encode_action_requests(_EC, ActReqs) when is_list(ActReqs) -> + case (catch enc_ActionRequests(ActReqs)) of + {'EXIT', Reason} -> + {error, Reason}; + Bin when is_binary(Bin) -> + {ok, Bin}; + DeepIoList -> + Bin = erlang:list_to_binary(DeepIoList), + {ok, Bin} + end. + +%%---------------------------------------------------------------------- +%% Convert a ActionRequest record into a binary +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- +encode_action_request(_EC, ActReq) + when is_record(ActReq, 'ActionRequest') -> + case (catch enc_ActionRequest(ActReq)) of + {'EXIT', Reason} -> + {error, Reason}; + Bin when is_binary(Bin) -> + {ok, Bin}; + DeepIoList -> + Bin = erlang:list_to_binary(DeepIoList), + {ok, Bin} + end. + +%%---------------------------------------------------------------------- +%% Convert a CommandRequest record into a deep io list +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- +encode_command_request(_EC, CmdReq) + when is_record(CmdReq, 'CommandRequest') -> + case (catch enc_CommandRequest(CmdReq)) of + {'EXIT', Reason} -> + {error, Reason}; + Bin when is_binary(Bin) -> + {ok, Bin}; + DeepIoList -> + Bin = erlang:list_to_binary(DeepIoList), + {ok, Bin} + end. + +%%---------------------------------------------------------------------- +%% Convert a action reply into a deep io list +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- +encode_action_reply(_EC, ActRep) + when is_record(ActRep, 'ActionReply') -> + case (catch enc_ActionReply(ActRep)) of + {'EXIT', Reason} -> + {error, Reason}; + Bin when is_binary(Bin) -> + {ok, Bin}; + DeepIoList -> + Bin = erlang:list_to_binary(DeepIoList), + {ok, Bin} + end. + + +%%---------------------------------------------------------------------- +%% A utility function to pretty print the tags found in a megaco message +%%---------------------------------------------------------------------- + +token_tag2string(addReq) -> ?CompactAddToken; +token_tag2string(addReply) -> ?CompactAddToken; +%% token_tag2string(X) -> ?CompactAndAUDITSelectToken; +token_tag2string(auditDescriptor) -> ?CompactAuditToken; +token_tag2string(auditCapRequest) -> ?CompactAuditCapToken; +token_tag2string(auditCapReply) -> ?CompactAuditCapToken; +token_tag2string(auditValueRequest) -> ?CompactAuditValueToken; +token_tag2string(auditValueReply) -> ?CompactAuditValueToken; +%% token_tag2string(X) -> ?CompactAuthToken; +token_tag2string(both) -> ?CompactBothToken; +token_tag2string(bothway) -> ?CompactBothwayToken; +token_tag2string(brief) -> ?CompactBriefToken; +%% token_tag2string(X) -> ?CompactBufferToken; +%% token_tag2string(X) -> ?CompactCtxToken; +%% token_tag2string(X) -> ?CompactContextAuditToken; +%% token_tag2string(X) -> ?CompactContextAttrToken; +%% token_tag2string(X) -> ?CompactContextListToken; +token_tag2string(digitMapDescriptor) -> ?CompactDigitMapToken; +token_tag2string(digitMapToken) -> ?CompactDigitMapToken; +%% token_tag2string(X) -> ?CompactDirectionToken; +%% token_tag2string(X) -> ?CompactDiscardToken; +%% token_tag2string(X) -> ?CompactDisconnectedToken; +%% token_tag2string(X) -> ?CompactDelayToken; +token_tag2string(duration) -> ?CompactDurationToken; +%% token_tag2string(X) -> ?CompactEmbedToken; +token_tag2string(emergencyAudit) -> ?CompactEmergencyToken; +%% token_tag2string(X) -> ?CompactEmergencyOffToken; +%% token_tag2string(X) -> ?CompactEmergencyValueToken; +token_tag2string(errorDescriptor) -> ?CompactErrorToken; +token_tag2string(eventBufferDescriptor) -> ?CompactEventBufferToken; +token_tag2string(eventBufferToken) -> ?CompactEventBufferToken; +token_tag2string(eventsDescriptor) -> ?CompactEventsToken; +token_tag2string(eventsToken) -> ?CompactEventsToken; +token_tag2string(external) -> ?CompactExternalToken; +%% token_tag2string(X) -> ?CompactFailoverToken; +%% token_tag2string(X) -> ?CompactForcedToken; +%% token_tag2string(X) -> ?CompactGracefulToken; +%% token_tag2string(X) -> ?CompactH221Token; +%% token_tag2string(X) -> ?CompactH223Token; +%% token_tag2string(X) -> ?CompactH226Token; +%% token_tag2string(X) -> ?CompactHandOffToken; +token_tag2string(iepsCallind) -> ?CompactIEPSToken; +%% token_tag2string(X) -> ?CompactImmAckRequiredToken; +token_tag2string(inactive) -> ?CompactInactiveToken; +token_tag2string(internal) -> ?CompactInternalToken; +%% token_tag2string(X) -> ?CompactIntsigDelayToken; +token_tag2string(onInterruptByEvent) -> ?CompactInterruptByEventToken; +token_tag2string(onInterruptByNewSignalDescr) -> ?CompactInterruptByNewSignalsDescrToken; +token_tag2string(isolate) -> ?CompactIsolateToken; +token_tag2string(inSvc) -> ?CompactInSvcToken; +token_tag2string(iteration) -> ?CompactIterationToken; +token_tag2string(keepActive) -> ?CompactKeepActiveToken; +token_tag2string(localDescriptor) -> ?CompactLocalToken; +token_tag2string(localControlDescriptor) -> ?CompactLocalControlToken; +token_tag2string(lockStep) -> ?CompactLockStepToken; +token_tag2string(loopBack) -> ?CompactLoopbackToken; +token_tag2string(mediaDescriptor) -> ?CompactMediaToken; +token_tag2string(mediaToken) -> ?CompactMediaToken; +%% token_tag2string(X) -> ?CompactMegacopToken; +%% token_tag2string(X) -> ?CompactMethodToken; +%% token_tag2string(X) -> ?CompactMgcIdToken; +%% token_tag2string(X) -> ?CompactModeToken; +token_tag2string(modReq) -> ?CompactModifyToken; +token_tag2string(modReply) -> ?CompactModifyToken; +token_tag2string(modemDescriptor) -> ?CompactModemToken; +token_tag2string(modemToken) -> ?CompactModemToken; +token_tag2string(moveReq) -> ?CompactMoveToken; +token_tag2string(moveReply) -> ?CompactMoveToken; +%% token_tag2string(X) -> ?CompactMtpToken; +token_tag2string(muxDescriptor) -> ?CompactMuxToken; +token_tag2string(muxToken) -> ?CompactMuxToken; +%% token_tag2string(X) -> ?CompactNeverNotifyToken; +token_tag2string(notifyReq) -> ?CompactNotifyToken; +%% token_tag2string(X) -> ?CompactNotifyCompletionToken; +%% token_tag2string(X) -> ?CompactNotifyImmediateToken; +%% token_tag2string(X) -> ?CompactNotifyRegulatedToken; +%% token_tag2string(X) -> ?CompactNx64kToken; +token_tag2string(observedEventsDescriptor) -> ?CompactObservedEventsToken; +token_tag2string(observedEventsToken) -> ?CompactObservedEventsToken; +token_tag2string(false) -> ?CompactOffToken; +token_tag2string(off) -> ?CompactOffToken; +token_tag2string(oneway) -> ?CompactOnewayToken; +token_tag2string(onewayboth) -> ?CompactOnewayBothToken; +token_tag2string(onewayexternal) -> ?CompactOnewayExternalToken; +token_tag2string(onOff) -> ?CompactOnOffToken; +%% token_tag2string(X) -> ?CompactOrAUDITselectToken; +token_tag2string(true) -> ?CompactOnToken; +token_tag2string(otherReason) -> ?CompactOtherReasonToken; +token_tag2string(outOfSvc) -> ?CompactOutOfSvcToken; +token_tag2string(packagesDescriptor) -> ?CompactPackagesToken; +token_tag2string(packagesToken) -> ?CompactPackagesToken; +%% token_tag2string(X) -> ?CompactPendingToken; +token_tag2string(priorityAudit) -> ?CompactPriorityToken; +%% token_tag2string(X) -> ?CompactProfileToken; +%% token_tag2string(X) -> ?CompactReasonToken; +token_tag2string(recvOnly) -> ?CompactRecvonlyToken; +%% token_tag2string(X) -> ?CompactReplyToken; +token_tag2string(resetEventsDescriptor) -> ?CompactResetEventsDescriptorToken; +%% token_tag2string(X) -> ?CompactRequestIDToken; +%% token_tag2string(X) -> ?CompactResponseAckToken; +%% token_tag2string(X) -> ?CompactRestartToken; +token_tag2string(remoteDescriptor) -> ?CompactRemoteToken; +%% token_tag2string(X) -> ?CompactReservedGroupToken; +%% token_tag2string(X) -> ?CompactReservedValueToken; +token_tag2string(sendOnly) -> ?CompactSendonlyToken; +token_tag2string(sendRecv) -> ?CompactSendrecvToken; +%% token_tag2string(X) -> ?CompactServicesToken; +%% token_tag2string(X) -> ?CompactServiceStatesToken; +token_tag2string(serviceChangeReq) -> ?CompactServiceChangeToken; +%% token_tag2string(X) -> ?CompactServiceChangeAddressToken; +token_tag2string(incomplete) -> ?CompactServiceChangeIncompleteToken; +%% token_tag2string(X) -> ?CompactSignalListToken; +token_tag2string(signalsDescriptor) -> ?CompactSignalsToken; +token_tag2string(signalsToken) -> ?CompactSignalsToken; +%% token_tag2string(X) -> ?CompactSignalTypeToken; +token_tag2string(statisticsDescriptor) -> ?CompactStatsToken; +token_tag2string(statsToken) -> ?CompactStatsToken; +%% token_tag2string(X) -> ?CompactStreamToken; +token_tag2string(subtractReq) -> ?CompactSubtractToken; +token_tag2string(subtractReply) -> ?CompactSubtractToken; +%% token_tag2string(X) -> ?CompactSynchISDNToken; +%% token_tag2string(X) -> ?CompactTerminationStateToken; +token_tag2string(test) -> ?CompactTestToken; +token_tag2string(timeOut) -> ?CompactTimeOutToken; +token_tag2string(onTimeOut) -> ?CompactTimeOutToken; +token_tag2string(topologyAudit) -> ?CompactTopologyToken; +%% token_tag2string(X) -> ?CompactTransToken; +%% token_tag2string(X) -> ?CompactV18Token; +%% token_tag2string(X) -> ?CompactV22Token; +%% token_tag2string(X) -> ?CompactV22bisToken; +%% token_tag2string(X) -> ?CompactV32Token; +%% token_tag2string(X) -> ?CompactV32bisToken; +%% token_tag2string(X) -> ?CompactV34Token; +%% token_tag2string(X) -> ?CompactV76Token; +%% token_tag2string(X) -> ?CompactV90Token; +%% token_tag2string(X) -> ?CompactV91Token; +%% token_tag2string(X) -> ?CompactVersionToken; +token_tag2string(_) -> []. + + +%%---------------------------------------------------------------------- +%% Define various macros used by the actual generator code +%%---------------------------------------------------------------------- + +-define(EQUAL, [?EqualToken]). +-define(COLON, [?ColonToken]). +-define(LBRKT, [?LbrktToken]). +-define(RBRKT, [?RbrktToken]). +-define(LSBRKT, [?LsbrktToken]). +-define(RSBRKT, [?RsbrktToken]). +-define(COMMA, [?CommaToken]). +-define(DOT, [?DotToken]). +-define(SLASH, [?SlashToken]). +-define(DQUOTE, [?DoubleQuoteToken]). +-define(SP, [?SpToken]). +-define(HTAB, [?HtabToken]). +-define(CR, [?CrToken]). +-define(LF, [?LfToken]). +-define(LWSP, []). +-define(EOL, ?LF). +-define(WSP, ?SP). +-define(SEP, ?WSP). + +-define(INIT_INDENT, []). +-define(INC_INDENT(State), State). +-define(INDENT(State), State). +-define(LBRKT_INDENT(_State), [?LbrktToken]). +-define(RBRKT_INDENT(_State), [?RbrktToken]). +-define(LSBRKT_INDENT(_State), [?LsbrktToken]). +-define(RSBRKT_INDENT(_State), [?RsbrktToken]). +-define(COMMA_INDENT(_State), [?CommaToken]). +-define(SEP_INDENT(_State), [?LfToken]). + +%%---------------------------------------------------------------------- +%% Define token macros +%%---------------------------------------------------------------------- + +-define(AddToken , ?CompactAddToken). +-define(AndAUDITSelectToken , ?CompactAndAUDITSelectToken). +-define(AuditToken , ?CompactAuditToken). +-define(AuditCapToken , ?CompactAuditCapToken). +-define(AuditValueToken , ?CompactAuditValueToken). +-define(AuthToken , ?CompactAuthToken). +-define(BothToken , ?CompactBothToken). +-define(BothwayToken , ?CompactBothwayToken). +-define(BriefToken , ?CompactBriefToken). +-define(BufferToken , ?CompactBufferToken). +-define(CtxToken , ?CompactCtxToken). +-define(ContextAuditToken , ?CompactContextAuditToken). +-define(ContextAttrToken , ?CompactContextAttrToken). +-define(ContextListToken , ?CompactContextListToken). +-define(DigitMapToken , ?CompactDigitMapToken). +-define(DirectionToken , ?CompactDirectionToken). +-define(DiscardToken , ?CompactDiscardToken). +-define(DisconnectedToken , ?CompactDisconnectedToken). +-define(DelayToken , ?CompactDelayToken). +-define(DeleteToken , ?CompactDeleteToken). +-define(DurationToken , ?CompactDurationToken). +-define(EmbedToken , ?CompactEmbedToken). +-define(EmergencyToken , ?CompactEmergencyToken). +-define(EmergencyOffToken , ?CompactEmergencyOffToken). +-define(EmergencyValueToken , ?CompactEmergencyValueToken). +-define(ErrorToken , ?CompactErrorToken). +-define(EventBufferToken , ?CompactEventBufferToken). +-define(EventsToken , ?CompactEventsToken). +-define(ExternalToken , ?CompactExternalToken). +-define(FailoverToken , ?CompactFailoverToken). +-define(ForcedToken , ?CompactForcedToken). +-define(GracefulToken , ?CompactGracefulToken). +-define(H221Token , ?CompactH221Token). +-define(H223Token , ?CompactH223Token). +-define(H226Token , ?CompactH226Token). +-define(HandOffToken , ?CompactHandOffToken). +-define(IEPSToken , ?CompactIEPSToken). +-define(ImmAckRequiredToken , ?CompactImmAckRequiredToken). +-define(InactiveToken , ?CompactInactiveToken). +-define(InternalToken , ?CompactInternalToken). +-define(IntsigDelayToken , ?CompactIntsigDelayToken). +-define(IsolateToken , ?CompactIsolateToken). +-define(InSvcToken , ?CompactInSvcToken). +-define(InterruptByEventToken , ?CompactInterruptByEventToken). +-define(InterruptByNewSignalsDescrToken, ?CompactInterruptByNewSignalsDescrToken). +-define(IterationToken , ?CompactIterationToken). +-define(KeepActiveToken , ?CompactKeepActiveToken). +-define(LocalToken , ?CompactLocalToken). +-define(LocalControlToken , ?CompactLocalControlToken). +-define(LockStepToken , ?CompactLockStepToken). +-define(LoopbackToken , ?CompactLoopbackToken). +-define(MediaToken , ?CompactMediaToken). +-define(MegacopToken , ?CompactMegacopToken). +%% -define(MessageSegmentToken , ?CompactMessageSegmentToken). +-define(MethodToken , ?CompactMethodToken). +-define(MgcIdToken , ?CompactMgcIdToken). +-define(ModeToken , ?CompactModeToken). +-define(ModifyToken , ?CompactModifyToken). +-define(ModemToken , ?CompactModemToken). +-define(MoveToken , ?CompactMoveToken). +-define(MtpToken , ?CompactMtpToken). +-define(MuxToken , ?CompactMuxToken). +-define(NeverNotifyToken , ?CompactNeverNotifyToken). +-define(NotifyToken , ?CompactNotifyToken). +-define(NotifyCompletionToken , ?CompactNotifyCompletionToken). +-define(NotifyImmediateToken , ?CompactNotifyImmediateToken). +-define(NotifyRegulatedToken , ?CompactNotifyRegulatedToken). +-define(Nx64kToken , ?CompactNx64kToken). +-define(ObservedEventsToken , ?CompactObservedEventsToken). +-define(OffToken , ?CompactOffToken). +-define(OnewayToken , ?CompactOnewayToken). +-define(OnewayBothToken , ?CompactOnewayBothToken). +-define(OnewayExternalToken , ?CompactOnewayExternalToken). +-define(OnOffToken , ?CompactOnOffToken). +-define(OnToken , ?CompactOnToken). +-define(OrAUDITselectToken , ?CompactOrAUDITselectToken). +-define(OtherReasonToken , ?CompactOtherReasonToken). +-define(OutOfSvcToken , ?CompactOutOfSvcToken). +-define(PackagesToken , ?CompactPackagesToken). +-define(PendingToken , ?CompactPendingToken). +-define(PriorityToken , ?CompactPriorityToken). +-define(ProfileToken , ?CompactProfileToken). +-define(ReasonToken , ?CompactReasonToken). +-define(RecvonlyToken , ?CompactRecvonlyToken). +-define(ReplyToken , ?CompactReplyToken). +-define(ResetEventsDescriptorToken , ?CompactResetEventsDescriptorToken). +-define(ResponseAckToken , ?CompactResponseAckToken). +-define(RestartToken , ?CompactRestartToken). +-define(RemoteToken , ?CompactRemoteToken). +-define(RequestIDToken , ?CompactRequestIDToken). +-define(ReservedGroupToken , ?CompactReservedGroupToken). +-define(ReservedValueToken , ?CompactReservedValueToken). +%% -define(SegmentationCompleteToken , ?CompactSegmentationCompleteToken). +-define(SendonlyToken , ?CompactSendonlyToken). +-define(SendrecvToken , ?CompactSendrecvToken). +-define(ServicesToken , ?CompactServicesToken). +-define(ServiceStatesToken , ?CompactServiceStatesToken). +-define(ServiceChangeToken , ?CompactServiceChangeToken). +-define(ServiceChangeAddressToken , ?CompactServiceChangeAddressToken). +-define(ServiceChangeIncompleteToken , ?CompactServiceChangeIncompleteToken). +-define(SignalListToken , ?CompactSignalListToken). +-define(SignalsToken , ?CompactSignalsToken). +-define(SignalTypeToken , ?CompactSignalTypeToken). +-define(StatsToken , ?CompactStatsToken). +-define(StreamToken , ?CompactStreamToken). +-define(SubtractToken , ?CompactSubtractToken). +-define(SynchISDNToken , ?CompactSynchISDNToken). +-define(TerminationStateToken , ?CompactTerminationStateToken). +-define(TestToken , ?CompactTestToken). +-define(TimeOutToken , ?CompactTimeOutToken). +-define(TopologyToken , ?CompactTopologyToken). +-define(TransToken , ?CompactTransToken). +-define(V18Token , ?CompactV18Token). +-define(V22Token , ?CompactV22Token). +-define(V22bisToken , ?CompactV22bisToken). +-define(V32Token , ?CompactV32Token). +-define(V32bisToken , ?CompactV32bisToken). +-define(V34Token , ?CompactV34Token). +-define(V76Token , ?CompactV76Token). +-define(V90Token , ?CompactV90Token). +-define(V91Token , ?CompactV91Token). +-define(VersionToken , ?CompactVersionToken). + +%%---------------------------------------------------------------------- +%% Include the generator code +%%---------------------------------------------------------------------- + +-include("megaco_text_gen_prev3c.hrl"). + diff --git a/lib/megaco/src/text/megaco_compact_text_encoder_v1.erl b/lib/megaco/src/text/megaco_compact_text_encoder_v1.erl new file mode 100644 index 0000000000..c1b454dc0f --- /dev/null +++ b/lib/megaco/src/text/megaco_compact_text_encoder_v1.erl @@ -0,0 +1,407 @@ +%% +%% %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 COMPACT Megaco/H.248 text messages from internal form +%%---------------------------------------------------------------------- + +-module(megaco_compact_text_encoder_v1). + +-export([encode_message/2, + encode_transaction/2, + encode_action_requests/2, + encode_action_request/2, + encode_command_request/2, + encode_action_reply/2]). + +-export([token_tag2string/1]). + +-include_lib("megaco/include/megaco.hrl"). +-include_lib("megaco/include/megaco_message_v1.hrl"). +-define(encoder_version_pre_prev3c,true). +-include("megaco_text_tokens.hrl"). + + +%%---------------------------------------------------------------------- +%% Convert a 'MegacoMessage' record into a binary +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- + +encode_message(EC, MegaMsg) + when is_list(EC) andalso is_record(MegaMsg, 'MegacoMessage') -> + case (catch enc_MegacoMessage(MegaMsg)) of + {'EXIT', Reason} -> + {error, Reason}; + Bin when is_binary(Bin) -> + {ok, Bin}; + DeepIoList -> + Bin = erlang:list_to_binary(DeepIoList), + {ok, Bin} + end; +encode_message(EncodingConfig, MegaMsg) + when is_record(MegaMsg, 'MegacoMessage') -> + {error, {bad_encoding_config, EncodingConfig}}; +encode_message(_EncodingConfig, _MegaMsg) -> + {error, bad_megaco_message}. + + +%%---------------------------------------------------------------------- +%% Convert a transaction record into a deep io list +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- +encode_transaction(_EC, Trans) -> + case (catch enc_Transaction(Trans)) of + {'EXIT', Reason} -> + {error, Reason}; + Bin when is_binary(Bin) -> + {ok, Bin}; + DeepIoList -> + Bin = erlang:list_to_binary(DeepIoList), + {ok, Bin} + end. + + +%%---------------------------------------------------------------------- +%% Convert a list of ActionRequest record's into a binary +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- +encode_action_requests(_EC, ActReqs) -> + case (catch enc_ActionRequests(ActReqs)) of + {'EXIT', Reason} -> + {error, Reason}; + Bin when is_binary(Bin) -> + {ok, Bin}; + DeepIoList -> + Bin = erlang:list_to_binary(DeepIoList), + {ok, Bin} + end. + +%%---------------------------------------------------------------------- +%% Convert a ActionRequest record into a binary +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- +encode_action_request(_EC, ActReq) + when is_record(ActReq, 'ActionRequest') -> + case (catch enc_ActionRequest(ActReq)) of + {'EXIT', Reason} -> + {error, Reason}; + Bin when is_binary(Bin) -> + {ok, Bin}; + DeepIoList -> + Bin = erlang:list_to_binary(DeepIoList), + {ok, Bin} + end. + +%%---------------------------------------------------------------------- +%% Convert a CommandRequest record into a deep io list +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- +encode_command_request(_EC, CmdReq) + when is_record(CmdReq, 'CommandRequest') -> + case (catch enc_CommandRequest(CmdReq)) of + {'EXIT', Reason} -> + {error, Reason}; + Bin when is_binary(Bin) -> + {ok, Bin}; + DeepIoList -> + Bin = erlang:list_to_binary(DeepIoList), + {ok, Bin} + end. + +%%---------------------------------------------------------------------- +%% Convert a action reply into a deep io list +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- +encode_action_reply(_EC, ActRep) + when is_record(ActRep, 'ActionReply') -> + case (catch enc_ActionReply(ActRep)) of + {'EXIT', Reason} -> + {error, Reason}; + Bin when is_binary(Bin) -> + {ok, Bin}; + DeepIoList -> + Bin = erlang:list_to_binary(DeepIoList), + {ok, Bin} + end. + + +%%---------------------------------------------------------------------- +%% A utility function to pretty print the tags found in a megaco message +%%---------------------------------------------------------------------- + +token_tag2string(addReq) -> ?CompactAddToken; +token_tag2string(addReply) -> ?CompactAddToken; +token_tag2string(auditDescriptor) -> ?CompactAuditToken; +token_tag2string(auditCapRequest) -> ?CompactAuditCapToken; +token_tag2string(auditCapReply) -> ?CompactAuditCapToken; +token_tag2string(auditValueRequest) -> ?CompactAuditValueToken; +token_tag2string(auditValueReply) -> ?CompactAuditValueToken; +%% token_tag2string(X) -> ?CompactAuthToken; +token_tag2string(bothway) -> ?CompactBothwayToken; +token_tag2string(brief) -> ?CompactBriefToken; +%% token_tag2string(X) -> ?CompactBufferToken; +%% token_tag2string(X) -> ?CompactCtxToken; +%% token_tag2string(X) -> ?CompactContextAuditToken; +token_tag2string(digitMapDescriptor) -> ?CompactDigitMapToken; +token_tag2string(digitMapToken) -> ?CompactDigitMapToken; +%% token_tag2string(X) -> ?CompactDiscardToken; +%% token_tag2string(X) -> ?CompactDisconnectedToken; +%% token_tag2string(X) -> ?CompactDelayToken; +token_tag2string(duration) -> ?CompactDurationToken; +%% token_tag2string(X) -> ?CompactEmbedToken; +token_tag2string(emergencyAudit) -> ?CompactEmergencyToken; +token_tag2string(errorDescriptor) -> ?CompactErrorToken; +token_tag2string(eventBufferDescriptor) -> ?CompactEventBufferToken; +token_tag2string(eventBufferToken) -> ?CompactEventBufferToken; +token_tag2string(eventsDescriptor) -> ?CompactEventsToken; +token_tag2string(eventsToken) -> ?CompactEventsToken; +%% token_tag2string(X) -> ?CompactFailoverToken; +%% token_tag2string(X) -> ?CompactForcedToken; +%% token_tag2string(X) -> ?CompactGracefulToken; +%% token_tag2string(X) -> ?CompactH221Token; +%% token_tag2string(X) -> ?CompactH223Token; +%% token_tag2string(X) -> ?CompactH226Token; +%% token_tag2string(X) -> ?CompactHandOffToken; +%% token_tag2string(X) -> ?CompactImmAckRequiredToken; +token_tag2string(inactive) -> ?CompactInactiveToken; +token_tag2string(onInterruptByEvent) -> ?CompactInterruptByEventToken; +token_tag2string(onInterruptByNewSignalDescr) -> ?CompactInterruptByNewSignalsDescrToken; +token_tag2string(isolate) -> ?CompactIsolateToken; +token_tag2string(inSvc) -> ?CompactInSvcToken; +token_tag2string(keepActive) -> ?CompactKeepActiveToken; +token_tag2string(localDescriptor) -> ?CompactLocalToken; +token_tag2string(localControlDescriptor) -> ?CompactLocalControlToken; +token_tag2string(lockStep) -> ?CompactLockStepToken; +token_tag2string(loopBack) -> ?CompactLoopbackToken; +token_tag2string(mediaDescriptor) -> ?CompactMediaToken; +token_tag2string(mediaToken) -> ?CompactMediaToken; +%% token_tag2string(X) -> ?CompactMegacopToken; +%% token_tag2string(X) -> ?CompactMethodToken; +%% token_tag2string(X) -> ?CompactMgcIdToken; +%% token_tag2string(X) -> ?CompactModeToken; +token_tag2string(modReq) -> ?CompactModifyToken; +token_tag2string(modReply) -> ?CompactModifyToken; +token_tag2string(modemDescriptor) -> ?CompactModemToken; +token_tag2string(modemToken) -> ?CompactModemToken; +token_tag2string(moveReq) -> ?CompactMoveToken; +token_tag2string(moveReply) -> ?CompactMoveToken; +%% token_tag2string(X) -> ?CompactMtpToken; +token_tag2string(muxDescriptor) -> ?CompactMuxToken; +token_tag2string(muxToken) -> ?CompactMuxToken; +token_tag2string(notifyReq) -> ?CompactNotifyToken; +%% token_tag2string(X) -> ?CompactNotifyCompletionToken; +token_tag2string(observedEventsDescriptor) -> ?CompactObservedEventsToken; +token_tag2string(observedEventsToken) -> ?CompactObservedEventsToken; +token_tag2string(false) -> ?CompactOffToken; +token_tag2string(off) -> ?CompactOffToken; +token_tag2string(oneway) -> ?CompactOnewayToken; +token_tag2string(onOff) -> ?CompactOnOffToken; +token_tag2string(true) -> ?CompactOnToken; +token_tag2string(otherReason) -> ?CompactOtherReasonToken; +token_tag2string(outOfSvc) -> ?CompactOutOfSvcToken; +token_tag2string(packagesDescriptor) -> ?CompactPackagesToken; +token_tag2string(packagesToken) -> ?CompactPackagesToken; +%% token_tag2string(X) -> ?CompactPendingToken; +token_tag2string(priorityAudit) -> ?CompactPriorityToken; +%% token_tag2string(X) -> ?CompactProfileToken; +%% token_tag2string(X) -> ?CompactReasonToken; +token_tag2string(recvOnly) -> ?CompactRecvonlyToken; +%% token_tag2string(X) -> ?CompactReplyToken; +%% token_tag2string(X) -> ?CompactResponseAckToken; +%% token_tag2string(X) -> ?CompactRestartToken; +token_tag2string(remoteDescriptor) -> ?CompactRemoteToken; +%% token_tag2string(X) -> ?CompactReservedGroupToken; +%% token_tag2string(X) -> ?CompactReservedValueToken; +token_tag2string(sendOnly) -> ?CompactSendonlyToken; +token_tag2string(sendRecv) -> ?CompactSendrecvToken; +%% token_tag2string(X) -> ?CompactServicesToken; +%% token_tag2string(X) -> ?CompactServiceStatesToken; +token_tag2string(serviceChangeReq) -> ?CompactServiceChangeToken; +%% token_tag2string(X) -> ?CompactServiceChangeAddressToken; +%% token_tag2string(X) -> ?CompactSignalListToken; +token_tag2string(signalsDescriptor) -> ?CompactSignalsToken; +token_tag2string(signalsToken) -> ?CompactSignalsToken; +%% token_tag2string(X) -> ?CompactSignalTypeToken; +token_tag2string(statisticsDescriptor) -> ?CompactStatsToken; +token_tag2string(statsToken) -> ?CompactStatsToken; +%% token_tag2string(X) -> ?CompactStreamToken; +token_tag2string(subtractReq) -> ?CompactSubtractToken; +token_tag2string(subtractReply) -> ?CompactSubtractToken; +%% token_tag2string(X) -> ?CompactSynchISDNToken; +%% token_tag2string(X) -> ?CompactTerminationStateToken; +token_tag2string(test) -> ?CompactTestToken; +token_tag2string(timeOut) -> ?CompactTimeOutToken; +token_tag2string(onTimeOut) -> ?CompactTimeOutToken; +token_tag2string(topologyAudit) -> ?CompactTopologyToken; +%% token_tag2string(X) -> ?CompactTransToken; +%% token_tag2string(X) -> ?CompactV18Token; +%% token_tag2string(X) -> ?CompactV22Token; +%% token_tag2string(X) -> ?CompactV22bisToken; +%% token_tag2string(X) -> ?CompactV32Token; +%% token_tag2string(X) -> ?CompactV32bisToken; +%% token_tag2string(X) -> ?CompactV34Token; +%% token_tag2string(X) -> ?CompactV76Token; +%% token_tag2string(X) -> ?CompactV90Token; +%% token_tag2string(X) -> ?CompactV91Token; +%% token_tag2string(X) -> ?CompactVersionToken; +token_tag2string(_) -> []. + + + +%%---------------------------------------------------------------------- +%% Define various macros used by the actual generator code +%%---------------------------------------------------------------------- + +-define(EQUAL, [?EqualToken]). +-define(COLON, [?ColonToken]). +-define(LBRKT, [?LbrktToken]). +-define(RBRKT, [?RbrktToken]). +-define(LSBRKT, [?LsbrktToken]). +-define(RSBRKT, [?RsbrktToken]). +-define(COMMA, [?CommaToken]). +-define(DOT, [?DotToken]). +-define(SLASH, [?SlashToken]). +-define(DQUOTE, [?DoubleQuoteToken]). +-define(SP, [?SpToken]). +-define(HTAB, [?HtabToken]). +-define(CR, [?CrToken]). +-define(LF, [?LfToken]). +-define(LWSP, []). +-define(EOL, ?LF). +-define(WSP, ?SP). +-define(SEP, ?WSP). + +-define(INIT_INDENT, []). +-define(INC_INDENT(State), State). +-define(INDENT(State), State). +-define(LBRKT_INDENT(_State), [?LbrktToken]). +-define(RBRKT_INDENT(_State), [?RbrktToken]). +-define(COMMA_INDENT(_State), [?CommaToken]). +-define(SEP_INDENT(_State), [?LfToken]). + +%%---------------------------------------------------------------------- +%% Define token macros +%%---------------------------------------------------------------------- + +-define(AddToken , ?CompactAddToken). +-define(AuditToken , ?CompactAuditToken). +-define(AuditCapToken , ?CompactAuditCapToken). +-define(AuditValueToken , ?CompactAuditValueToken). +-define(AuthToken , ?CompactAuthToken). +-define(BothwayToken , ?CompactBothwayToken). +-define(BriefToken , ?CompactBriefToken). +-define(BufferToken , ?CompactBufferToken). +-define(CtxToken , ?CompactCtxToken). +-define(ContextAuditToken , ?CompactContextAuditToken). +-define(DigitMapToken , ?CompactDigitMapToken). +-define(DiscardToken , ?CompactDiscardToken). +-define(DisconnectedToken , ?CompactDisconnectedToken). +-define(DelayToken , ?CompactDelayToken). +-define(DeleteToken , ?CompactDeleteToken). +-define(DurationToken , ?CompactDurationToken). +-define(EmbedToken , ?CompactEmbedToken). +-define(EmergencyToken , ?CompactEmergencyToken). +-define(ErrorToken , ?CompactErrorToken). +-define(EventBufferToken , ?CompactEventBufferToken). +-define(EventsToken , ?CompactEventsToken). +-define(FailoverToken , ?CompactFailoverToken). +-define(ForcedToken , ?CompactForcedToken). +-define(GracefulToken , ?CompactGracefulToken). +-define(H221Token , ?CompactH221Token). +-define(H223Token , ?CompactH223Token). +-define(H226Token , ?CompactH226Token). +-define(HandOffToken , ?CompactHandOffToken). +-define(ImmAckRequiredToken , ?CompactImmAckRequiredToken). +-define(InactiveToken , ?CompactInactiveToken). +-define(InterruptByEventToken , ?CompactInterruptByEventToken). +-define(InterruptByNewSignalsDescrToken, ?CompactInterruptByNewSignalsDescrToken). +-define(IsolateToken , ?CompactIsolateToken). +-define(InSvcToken , ?CompactInSvcToken). +-define(KeepActiveToken , ?CompactKeepActiveToken). +-define(LocalToken , ?CompactLocalToken). +-define(LocalControlToken , ?CompactLocalControlToken). +-define(LockStepToken , ?CompactLockStepToken). +-define(LoopbackToken , ?CompactLoopbackToken). +-define(MediaToken , ?CompactMediaToken). +-define(MegacopToken , ?CompactMegacopToken). +-define(MethodToken , ?CompactMethodToken). +-define(MgcIdToken , ?CompactMgcIdToken). +-define(ModeToken , ?CompactModeToken). +-define(ModifyToken , ?CompactModifyToken). +-define(ModemToken , ?CompactModemToken). +-define(MoveToken , ?CompactMoveToken). +-define(MtpToken , ?CompactMtpToken). +-define(MuxToken , ?CompactMuxToken). +-define(NotifyToken , ?CompactNotifyToken). +-define(NotifyCompletionToken , ?CompactNotifyCompletionToken). +-define(ObservedEventsToken , ?CompactObservedEventsToken). +-define(OffToken , ?CompactOffToken). +-define(OnewayToken , ?CompactOnewayToken). +-define(OnOffToken , ?CompactOnOffToken). +-define(OnToken , ?CompactOnToken). +-define(OtherReasonToken , ?CompactOtherReasonToken). +-define(OutOfSvcToken , ?CompactOutOfSvcToken). +-define(PackagesToken , ?CompactPackagesToken). +-define(PendingToken , ?CompactPendingToken). +-define(PriorityToken , ?CompactPriorityToken). +-define(ProfileToken , ?CompactProfileToken). +-define(ReasonToken , ?CompactReasonToken). +-define(RecvonlyToken , ?CompactRecvonlyToken). +-define(ReplyToken , ?CompactReplyToken). +-define(ResponseAckToken , ?CompactResponseAckToken). +-define(RestartToken , ?CompactRestartToken). +-define(RemoteToken , ?CompactRemoteToken). +-define(ReservedGroupToken , ?CompactReservedGroupToken). +-define(ReservedValueToken , ?CompactReservedValueToken). +-define(SendonlyToken , ?CompactSendonlyToken). +-define(SendrecvToken , ?CompactSendrecvToken). +-define(ServicesToken , ?CompactServicesToken). +-define(ServiceStatesToken , ?CompactServiceStatesToken). +-define(ServiceChangeToken , ?CompactServiceChangeToken). +-define(ServiceChangeAddressToken , ?CompactServiceChangeAddressToken). +-define(SignalListToken , ?CompactSignalListToken). +-define(SignalsToken , ?CompactSignalsToken). +-define(SignalTypeToken , ?CompactSignalTypeToken). +-define(StatsToken , ?CompactStatsToken). +-define(StreamToken , ?CompactStreamToken). +-define(SubtractToken , ?CompactSubtractToken). +-define(SynchISDNToken , ?CompactSynchISDNToken). +-define(TerminationStateToken , ?CompactTerminationStateToken). +-define(TestToken , ?CompactTestToken). +-define(TimeOutToken , ?CompactTimeOutToken). +-define(TopologyToken , ?CompactTopologyToken). +-define(TransToken , ?CompactTransToken). +-define(V18Token , ?CompactV18Token). +-define(V22Token , ?CompactV22Token). +-define(V22bisToken , ?CompactV22bisToken). +-define(V32Token , ?CompactV32Token). +-define(V32bisToken , ?CompactV32bisToken). +-define(V34Token , ?CompactV34Token). +-define(V76Token , ?CompactV76Token). +-define(V90Token , ?CompactV90Token). +-define(V91Token , ?CompactV91Token). +-define(VersionToken , ?CompactVersionToken). + +%%---------------------------------------------------------------------- +%% Include the generator code +%%---------------------------------------------------------------------- + +-include("megaco_text_gen_v1.hrl"). + diff --git a/lib/megaco/src/text/megaco_compact_text_encoder_v2.erl b/lib/megaco/src/text/megaco_compact_text_encoder_v2.erl new file mode 100644 index 0000000000..ac0877da2f --- /dev/null +++ b/lib/megaco/src/text/megaco_compact_text_encoder_v2.erl @@ -0,0 +1,413 @@ +%% +%% %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 COMPACT Megaco/H.248 text messages from internal form +%%---------------------------------------------------------------------- + +-module(megaco_compact_text_encoder_v2). + +-export([encode_message/2, + encode_transaction/2, + encode_action_requests/2, + encode_action_request/2, + encode_command_request/2, + encode_action_reply/2]). + +-export([token_tag2string/1]). + +-include_lib("megaco/include/megaco.hrl"). +-include_lib("megaco/include/megaco_message_v2.hrl"). +-define(encoder_version_pre_prev3c,true). +-include("megaco_text_tokens.hrl"). + + +%%---------------------------------------------------------------------- +%% Convert a 'MegacoMessage' record into a binary +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- + +encode_message(EC, MegaMsg) + when is_list(EC) andalso is_record(MegaMsg, 'MegacoMessage') -> + case (catch enc_MegacoMessage(MegaMsg)) of + {'EXIT', Reason} -> + {error, Reason}; + Bin when is_binary(Bin) -> + {ok, Bin}; + DeepIoList -> + Bin = erlang:list_to_binary(DeepIoList), + {ok, Bin} + end; +encode_message(EncodingConfig, MegaMsg) + when is_record(MegaMsg, 'MegacoMessage') -> + {error, {bad_encoding_config, EncodingConfig}}; +encode_message(_EncodingConfig, _MegaMsg) -> + {error, bad_megaco_message}. + + + + +%%---------------------------------------------------------------------- +%% Convert a transaction record into a deep io list +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- +encode_transaction(_EC, Trans) -> + case (catch enc_Transaction(Trans)) of + {'EXIT', Reason} -> + {error, Reason}; + Bin when is_binary(Bin) -> + {ok, Bin}; + DeepIoList -> + Bin = erlang:list_to_binary(DeepIoList), + {ok, Bin} + end. + + +%%---------------------------------------------------------------------- +%% Convert a list of ActionRequest record's into a binary +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- +encode_action_requests(_EC, ActReqs) -> + case (catch enc_ActionRequests(ActReqs)) of + {'EXIT', Reason} -> + {error, Reason}; + Bin when is_binary(Bin) -> + {ok, Bin}; + DeepIoList -> + Bin = erlang:list_to_binary(DeepIoList), + {ok, Bin} + end. + +%%---------------------------------------------------------------------- +%% Convert a ActionRequest record into a binary +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- +encode_action_request(_EC, ActReq) + when is_record(ActReq, 'ActionRequest') -> + case (catch enc_ActionRequest(ActReq)) of + {'EXIT', Reason} -> + {error, Reason}; + Bin when is_binary(Bin) -> + {ok, Bin}; + DeepIoList -> + Bin = erlang:list_to_binary(DeepIoList), + {ok, Bin} + end. + +%%---------------------------------------------------------------------- +%% Convert a CommandRequest record into a deep io list +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- +encode_command_request(_EC, CmdReq) + when is_record(CmdReq, 'CommandRequest') -> + case (catch enc_CommandRequest(CmdReq)) of + {'EXIT', Reason} -> + {error, Reason}; + Bin when is_binary(Bin) -> + {ok, Bin}; + DeepIoList -> + Bin = erlang:list_to_binary(DeepIoList), + {ok, Bin} + end. + +%%---------------------------------------------------------------------- +%% Convert a action reply into a deep io list +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- +encode_action_reply(_EC, ActRep) + when is_record(ActRep, 'ActionReply') -> + case (catch enc_ActionReply(ActRep)) of + {'EXIT', Reason} -> + {error, Reason}; + Bin when is_binary(Bin) -> + {ok, Bin}; + DeepIoList -> + Bin = erlang:list_to_binary(DeepIoList), + {ok, Bin} + end. + + +%%---------------------------------------------------------------------- +%% A utility function to pretty print the tags found in a megaco message +%%---------------------------------------------------------------------- + +token_tag2string(addReq) -> ?CompactAddToken; +token_tag2string(addReply) -> ?CompactAddToken; +token_tag2string(auditDescriptor) -> ?CompactAuditToken; +token_tag2string(auditCapRequest) -> ?CompactAuditCapToken; +token_tag2string(auditCapReply) -> ?CompactAuditCapToken; +token_tag2string(auditValueRequest) -> ?CompactAuditValueToken; +token_tag2string(auditValueReply) -> ?CompactAuditValueToken; +%% token_tag2string(X) -> ?CompactAuthToken; +token_tag2string(bothway) -> ?CompactBothwayToken; +token_tag2string(brief) -> ?CompactBriefToken; +%% token_tag2string(X) -> ?CompactBufferToken; +%% token_tag2string(X) -> ?CompactCtxToken; +%% token_tag2string(X) -> ?CompactContextAuditToken; +token_tag2string(digitMapDescriptor) -> ?CompactDigitMapToken; +token_tag2string(digitMapToken) -> ?CompactDigitMapToken; +%% token_tag2string(X) -> ?CompactDiscardToken; +%% token_tag2string(X) -> ?CompactDisconnectedToken; +%% token_tag2string(X) -> ?CompactDelayToken; +token_tag2string(duration) -> ?CompactDurationToken; +%% token_tag2string(X) -> ?CompactEmbedToken; +token_tag2string(emergencyAudit) -> ?CompactEmergencyToken; +%% token_tag2string(X) -> ?CompactEmergencyOffToken; +token_tag2string(errorDescriptor) -> ?CompactErrorToken; +token_tag2string(eventBufferDescriptor) -> ?CompactEventBufferToken; +token_tag2string(eventBufferToken) -> ?CompactEventBufferToken; +token_tag2string(eventsDescriptor) -> ?CompactEventsToken; +token_tag2string(eventsToken) -> ?CompactEventsToken; +%% token_tag2string(X) -> ?CompactFailoverToken; +%% token_tag2string(X) -> ?CompactForcedToken; +%% token_tag2string(X) -> ?CompactGracefulToken; +%% token_tag2string(X) -> ?CompactH221Token; +%% token_tag2string(X) -> ?CompactH223Token; +%% token_tag2string(X) -> ?CompactH226Token; +%% token_tag2string(X) -> ?CompactHandOffToken; +%% token_tag2string(X) -> ?CompactImmAckRequiredToken; +token_tag2string(inactive) -> ?CompactInactiveToken; +token_tag2string(onInterruptByEvent) -> ?CompactInterruptByEventToken; +token_tag2string(onInterruptByNewSignalDescr) -> ?CompactInterruptByNewSignalsDescrToken; +token_tag2string(isolate) -> ?CompactIsolateToken; +token_tag2string(inSvc) -> ?CompactInSvcToken; +token_tag2string(keepActive) -> ?CompactKeepActiveToken; +token_tag2string(localDescriptor) -> ?CompactLocalToken; +token_tag2string(localControlDescriptor) -> ?CompactLocalControlToken; +token_tag2string(lockStep) -> ?CompactLockStepToken; +token_tag2string(loopBack) -> ?CompactLoopbackToken; +token_tag2string(mediaDescriptor) -> ?CompactMediaToken; +token_tag2string(mediaToken) -> ?CompactMediaToken; +%% token_tag2string(X) -> ?CompactMegacopToken; +%% token_tag2string(X) -> ?CompactMethodToken; +%% token_tag2string(X) -> ?CompactMgcIdToken; +%% token_tag2string(X) -> ?CompactModeToken; +token_tag2string(modReq) -> ?CompactModifyToken; +token_tag2string(modReply) -> ?CompactModifyToken; +token_tag2string(modemDescriptor) -> ?CompactModemToken; +token_tag2string(modemToken) -> ?CompactModemToken; +token_tag2string(moveReq) -> ?CompactMoveToken; +token_tag2string(moveReply) -> ?CompactMoveToken; +%% token_tag2string(X) -> ?CompactMtpToken; +token_tag2string(muxDescriptor) -> ?CompactMuxToken; +token_tag2string(muxToken) -> ?CompactMuxToken; +token_tag2string(notifyReq) -> ?CompactNotifyToken; +%% token_tag2string(X) -> ?CompactNotifyCompletionToken; +%% token_tag2string(X) -> ?CompactNx64kToken; +token_tag2string(observedEventsDescriptor) -> ?CompactObservedEventsToken; +token_tag2string(observedEventsToken) -> ?CompactObservedEventsToken; +token_tag2string(false) -> ?CompactOffToken; +token_tag2string(off) -> ?CompactOffToken; +token_tag2string(oneway) -> ?CompactOnewayToken; +token_tag2string(onOff) -> ?CompactOnOffToken; +token_tag2string(true) -> ?CompactOnToken; +token_tag2string(otherReason) -> ?CompactOtherReasonToken; +token_tag2string(outOfSvc) -> ?CompactOutOfSvcToken; +token_tag2string(packagesDescriptor) -> ?CompactPackagesToken; +token_tag2string(packagesToken) -> ?CompactPackagesToken; +%% token_tag2string(X) -> ?CompactPendingToken; +token_tag2string(priorityAudit) -> ?CompactPriorityToken; +%% token_tag2string(X) -> ?CompactProfileToken; +%% token_tag2string(X) -> ?CompactReasonToken; +token_tag2string(recvOnly) -> ?CompactRecvonlyToken; +%% token_tag2string(X) -> ?CompactReplyToken; +%% token_tag2string(X) -> ?CompactResponseAckToken; +%% token_tag2string(X) -> ?CompactRestartToken; +token_tag2string(remoteDescriptor) -> ?CompactRemoteToken; +%% token_tag2string(X) -> ?CompactReservedGroupToken; +%% token_tag2string(X) -> ?CompactReservedValueToken; +token_tag2string(sendOnly) -> ?CompactSendonlyToken; +token_tag2string(sendRecv) -> ?CompactSendrecvToken; +%% token_tag2string(X) -> ?CompactServicesToken; +%% token_tag2string(X) -> ?CompactServiceStatesToken; +token_tag2string(serviceChangeReq) -> ?CompactServiceChangeToken; +%% token_tag2string(X) -> ?CompactServiceChangeAddressToken; +%% token_tag2string(X) -> ?CompactSignalListToken; +token_tag2string(signalsDescriptor) -> ?CompactSignalsToken; +token_tag2string(signalsToken) -> ?CompactSignalsToken; +%% token_tag2string(X) -> ?CompactSignalTypeToken; +token_tag2string(statisticsDescriptor) -> ?CompactStatsToken; +token_tag2string(statsToken) -> ?CompactStatsToken; +%% token_tag2string(X) -> ?CompactStreamToken; +token_tag2string(subtractReq) -> ?CompactSubtractToken; +token_tag2string(subtractReply) -> ?CompactSubtractToken; +%% token_tag2string(X) -> ?CompactSynchISDNToken; +%% token_tag2string(X) -> ?CompactTerminationStateToken; +token_tag2string(test) -> ?CompactTestToken; +token_tag2string(timeOut) -> ?CompactTimeOutToken; +token_tag2string(onTimeOut) -> ?CompactTimeOutToken; +token_tag2string(topologyAudit) -> ?CompactTopologyToken; +%% token_tag2string(X) -> ?CompactTransToken; +%% token_tag2string(X) -> ?CompactV18Token; +%% token_tag2string(X) -> ?CompactV22Token; +%% token_tag2string(X) -> ?CompactV22bisToken; +%% token_tag2string(X) -> ?CompactV32Token; +%% token_tag2string(X) -> ?CompactV32bisToken; +%% token_tag2string(X) -> ?CompactV34Token; +%% token_tag2string(X) -> ?CompactV76Token; +%% token_tag2string(X) -> ?CompactV90Token; +%% token_tag2string(X) -> ?CompactV91Token; +%% token_tag2string(X) -> ?CompactVersionToken; +token_tag2string(_) -> []. + + + +%%---------------------------------------------------------------------- +%% Define various macros used by the actual generator code +%%---------------------------------------------------------------------- + +-define(EQUAL, [?EqualToken]). +-define(COLON, [?ColonToken]). +-define(LBRKT, [?LbrktToken]). +-define(RBRKT, [?RbrktToken]). +-define(LSBRKT, [?LsbrktToken]). +-define(RSBRKT, [?RsbrktToken]). +-define(COMMA, [?CommaToken]). +-define(DOT, [?DotToken]). +-define(SLASH, [?SlashToken]). +-define(DQUOTE, [?DoubleQuoteToken]). +-define(SP, [?SpToken]). +-define(HTAB, [?HtabToken]). +-define(CR, [?CrToken]). +-define(LF, [?LfToken]). +-define(LWSP, []). +-define(EOL, ?LF). +-define(WSP, ?SP). +-define(SEP, ?WSP). + +-define(INIT_INDENT, []). +-define(INC_INDENT(State), State). +-define(INDENT(State), State). +-define(LBRKT_INDENT(_State), [?LbrktToken]). +-define(RBRKT_INDENT(_State), [?RbrktToken]). +-define(COMMA_INDENT(_State), [?CommaToken]). +-define(SEP_INDENT(_State), [?LfToken]). + +%%---------------------------------------------------------------------- +%% Define token macros +%%---------------------------------------------------------------------- + +-define(AddToken , ?CompactAddToken). +-define(AuditToken , ?CompactAuditToken). +-define(AuditCapToken , ?CompactAuditCapToken). +-define(AuditValueToken , ?CompactAuditValueToken). +-define(AuthToken , ?CompactAuthToken). +-define(BothwayToken , ?CompactBothwayToken). +-define(BriefToken , ?CompactBriefToken). +-define(BufferToken , ?CompactBufferToken). +-define(CtxToken , ?CompactCtxToken). +-define(ContextAuditToken , ?CompactContextAuditToken). +-define(DigitMapToken , ?CompactDigitMapToken). +-define(DiscardToken , ?CompactDiscardToken). +-define(DisconnectedToken , ?CompactDisconnectedToken). +-define(DelayToken , ?CompactDelayToken). +-define(DeleteToken , ?CompactDeleteToken). +-define(DurationToken , ?CompactDurationToken). +-define(EmbedToken , ?CompactEmbedToken). +-define(EmergencyToken , ?CompactEmergencyToken). +-define(EmergencyOffToken , ?CompactEmergencyOffToken). +-define(ErrorToken , ?CompactErrorToken). +-define(EventBufferToken , ?CompactEventBufferToken). +-define(EventsToken , ?CompactEventsToken). +-define(FailoverToken , ?CompactFailoverToken). +-define(ForcedToken , ?CompactForcedToken). +-define(GracefulToken , ?CompactGracefulToken). +-define(H221Token , ?CompactH221Token). +-define(H223Token , ?CompactH223Token). +-define(H226Token , ?CompactH226Token). +-define(HandOffToken , ?CompactHandOffToken). +-define(ImmAckRequiredToken , ?CompactImmAckRequiredToken). +-define(InactiveToken , ?CompactInactiveToken). +-define(InterruptByEventToken , ?CompactInterruptByEventToken). +-define(InterruptByNewSignalsDescrToken, ?CompactInterruptByNewSignalsDescrToken). +-define(IsolateToken , ?CompactIsolateToken). +-define(InSvcToken , ?CompactInSvcToken). +-define(KeepActiveToken , ?CompactKeepActiveToken). +-define(LocalToken , ?CompactLocalToken). +-define(LocalControlToken , ?CompactLocalControlToken). +-define(LockStepToken , ?CompactLockStepToken). +-define(LoopbackToken , ?CompactLoopbackToken). +-define(MediaToken , ?CompactMediaToken). +-define(MegacopToken , ?CompactMegacopToken). +-define(MethodToken , ?CompactMethodToken). +-define(MgcIdToken , ?CompactMgcIdToken). +-define(ModeToken , ?CompactModeToken). +-define(ModifyToken , ?CompactModifyToken). +-define(ModemToken , ?CompactModemToken). +-define(MoveToken , ?CompactMoveToken). +-define(MtpToken , ?CompactMtpToken). +-define(MuxToken , ?CompactMuxToken). +-define(NotifyToken , ?CompactNotifyToken). +-define(NotifyCompletionToken , ?CompactNotifyCompletionToken). +-define(Nx64kToken , ?CompactNx64kToken). +-define(ObservedEventsToken , ?CompactObservedEventsToken). +-define(OffToken , ?CompactOffToken). +-define(OnewayToken , ?CompactOnewayToken). +-define(OnOffToken , ?CompactOnOffToken). +-define(OnToken , ?CompactOnToken). +-define(OtherReasonToken , ?CompactOtherReasonToken). +-define(OutOfSvcToken , ?CompactOutOfSvcToken). +-define(PackagesToken , ?CompactPackagesToken). +-define(PendingToken , ?CompactPendingToken). +-define(PriorityToken , ?CompactPriorityToken). +-define(ProfileToken , ?CompactProfileToken). +-define(ReasonToken , ?CompactReasonToken). +-define(RecvonlyToken , ?CompactRecvonlyToken). +-define(ReplyToken , ?CompactReplyToken). +-define(ResponseAckToken , ?CompactResponseAckToken). +-define(RestartToken , ?CompactRestartToken). +-define(RemoteToken , ?CompactRemoteToken). +-define(ReservedGroupToken , ?CompactReservedGroupToken). +-define(ReservedValueToken , ?CompactReservedValueToken). +-define(SendonlyToken , ?CompactSendonlyToken). +-define(SendrecvToken , ?CompactSendrecvToken). +-define(ServicesToken , ?CompactServicesToken). +-define(ServiceStatesToken , ?CompactServiceStatesToken). +-define(ServiceChangeToken , ?CompactServiceChangeToken). +-define(ServiceChangeAddressToken , ?CompactServiceChangeAddressToken). +-define(SignalListToken , ?CompactSignalListToken). +-define(SignalsToken , ?CompactSignalsToken). +-define(SignalTypeToken , ?CompactSignalTypeToken). +-define(StatsToken , ?CompactStatsToken). +-define(StreamToken , ?CompactStreamToken). +-define(SubtractToken , ?CompactSubtractToken). +-define(SynchISDNToken , ?CompactSynchISDNToken). +-define(TerminationStateToken , ?CompactTerminationStateToken). +-define(TestToken , ?CompactTestToken). +-define(TimeOutToken , ?CompactTimeOutToken). +-define(TopologyToken , ?CompactTopologyToken). +-define(TransToken , ?CompactTransToken). +-define(V18Token , ?CompactV18Token). +-define(V22Token , ?CompactV22Token). +-define(V22bisToken , ?CompactV22bisToken). +-define(V32Token , ?CompactV32Token). +-define(V32bisToken , ?CompactV32bisToken). +-define(V34Token , ?CompactV34Token). +-define(V76Token , ?CompactV76Token). +-define(V90Token , ?CompactV90Token). +-define(V91Token , ?CompactV91Token). +-define(VersionToken , ?CompactVersionToken). + +%%---------------------------------------------------------------------- +%% Include the generator code +%%---------------------------------------------------------------------- + +-include("megaco_text_gen_v2.hrl"). + diff --git a/lib/megaco/src/text/megaco_compact_text_encoder_v3.erl b/lib/megaco/src/text/megaco_compact_text_encoder_v3.erl new file mode 100644 index 0000000000..5dd239222b --- /dev/null +++ b/lib/megaco/src/text/megaco_compact_text_encoder_v3.erl @@ -0,0 +1,455 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2005-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 COMPACT Megaco/H.248 text messages from internal form +%%---------------------------------------------------------------------- + +-module(megaco_compact_text_encoder_v3). + +-export([encode_message/2, + encode_transaction/2, + encode_action_requests/2, + encode_action_request/2, + encode_command_request/2, + encode_action_reply/2]). + +-export([token_tag2string/1]). + + +-include_lib("megaco/include/megaco.hrl"). +-include_lib("megaco/include/megaco_message_v3.hrl"). +-include("megaco_text_tokens.hrl"). + + +%%---------------------------------------------------------------------- +%% Convert a 'MegacoMessage' record into a binary +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- + +encode_message(EC, MegaMsg) + when is_list(EC) andalso is_record(MegaMsg, 'MegacoMessage') -> + case (catch enc_MegacoMessage(MegaMsg)) of + {'EXIT', Reason} -> + {error, Reason}; + Bin when is_binary(Bin) -> + {ok, Bin}; + DeepIoList -> + Bin = erlang:list_to_binary(DeepIoList), + {ok, Bin} + end; +encode_message(EncodingConfig, MegaMsg) + when is_record(MegaMsg, 'MegacoMessage') -> + {error, {bad_encoding_config, EncodingConfig}}; +encode_message(_EncodingConfig, _MegaMsg) -> + {error, bad_megaco_message}. + + + +%%---------------------------------------------------------------------- +%% Convert a transaction record into a deep io list +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- +encode_transaction(_EC, Trans) -> + case (catch enc_Transaction(Trans)) of + {'EXIT', Reason} -> + {error, Reason}; + Bin when is_binary(Bin) -> + {ok, Bin}; + DeepIoList -> + Bin = erlang:list_to_binary(DeepIoList), + {ok, Bin} + end. + + +%%---------------------------------------------------------------------- +%% Convert a list of ActionRequest record's into a binary +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- +encode_action_requests(_EC, ActReqs) when is_list(ActReqs) -> + case (catch enc_ActionRequests(ActReqs)) of + {'EXIT', Reason} -> + {error, Reason}; + Bin when is_binary(Bin) -> + {ok, Bin}; + DeepIoList -> + Bin = erlang:list_to_binary(DeepIoList), + {ok, Bin} + end. + +%%---------------------------------------------------------------------- +%% Convert a ActionRequest record into a binary +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- +encode_action_request(_EC, ActReq) + when is_record(ActReq, 'ActionRequest') -> + case (catch enc_ActionRequest(ActReq)) of + {'EXIT', Reason} -> + {error, Reason}; + Bin when is_binary(Bin) -> + {ok, Bin}; + DeepIoList -> + Bin = erlang:list_to_binary(DeepIoList), + {ok, Bin} + end. + +%%---------------------------------------------------------------------- +%% Convert a CommandRequest record into a deep io list +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- +encode_command_request(_EC, CmdReq) + when is_record(CmdReq, 'CommandRequest') -> + case (catch enc_CommandRequest(CmdReq)) of + {'EXIT', Reason} -> + {error, Reason}; + Bin when is_binary(Bin) -> + {ok, Bin}; + DeepIoList -> + Bin = erlang:list_to_binary(DeepIoList), + {ok, Bin} + end. + +%%---------------------------------------------------------------------- +%% Convert a action reply into a deep io list +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- +encode_action_reply(_EC, ActRep) + when is_record(ActRep, 'ActionReply') -> + case (catch enc_ActionReply(ActRep)) of + {'EXIT', Reason} -> + {error, Reason}; + Bin when is_binary(Bin) -> + {ok, Bin}; + DeepIoList -> + Bin = erlang:list_to_binary(DeepIoList), + {ok, Bin} + end. + + +%%---------------------------------------------------------------------- +%% A utility function to pretty print the tags found in a megaco message +%%---------------------------------------------------------------------- + +token_tag2string(addReq) -> ?CompactAddToken; +token_tag2string(addReply) -> ?CompactAddToken; +%% token_tag2string(X) -> ?CompactAndAUDITSelectToken; +token_tag2string(auditDescriptor) -> ?CompactAuditToken; +token_tag2string(auditCapRequest) -> ?CompactAuditCapToken; +token_tag2string(auditCapReply) -> ?CompactAuditCapToken; +token_tag2string(auditValueRequest) -> ?CompactAuditValueToken; +token_tag2string(auditValueReply) -> ?CompactAuditValueToken; +%% token_tag2string(X) -> ?CompactAuthToken; +token_tag2string(both) -> ?CompactBothToken; +token_tag2string(bothway) -> ?CompactBothwayToken; +token_tag2string(brief) -> ?CompactBriefToken; +%% token_tag2string(X) -> ?CompactBufferToken; +%% token_tag2string(X) -> ?CompactCtxToken; +%% token_tag2string(X) -> ?CompactContextAuditToken; +%% token_tag2string(X) -> ?CompactContextAttrToken; +%% token_tag2string(X) -> ?CompactContextListToken; +token_tag2string(digitMapDescriptor) -> ?CompactDigitMapToken; +token_tag2string(digitMapToken) -> ?CompactDigitMapToken; +%% token_tag2string(X) -> ?CompactDirectionToken; +%% token_tag2string(X) -> ?CompactDiscardToken; +%% token_tag2string(X) -> ?CompactDisconnectedToken; +%% token_tag2string(X) -> ?CompactDelayToken; +token_tag2string(duration) -> ?CompactDurationToken; +%% token_tag2string(X) -> ?CompactEmbedToken; +token_tag2string(emergencyAudit) -> ?CompactEmergencyToken; +%% token_tag2string(X) -> ?CompactEmergencyOffToken; +%% token_tag2string(X) -> ?CompactEmergencyValueToken; +token_tag2string(errorDescriptor) -> ?CompactErrorToken; +token_tag2string(eventBufferDescriptor) -> ?CompactEventBufferToken; +token_tag2string(eventBufferToken) -> ?CompactEventBufferToken; +token_tag2string(eventsDescriptor) -> ?CompactEventsToken; +token_tag2string(eventsToken) -> ?CompactEventsToken; +token_tag2string(external) -> ?CompactExternalToken; +%% token_tag2string(X) -> ?CompactFailoverToken; +%% token_tag2string(X) -> ?CompactForcedToken; +%% token_tag2string(X) -> ?CompactGracefulToken; +%% token_tag2string(X) -> ?CompactH221Token; +%% token_tag2string(X) -> ?CompactH223Token; +%% token_tag2string(X) -> ?CompactH226Token; +%% token_tag2string(X) -> ?CompactHandOffToken; +token_tag2string(iepsCallind) -> ?CompactIEPSToken; +%% token_tag2string(X) -> ?CompactImmAckRequiredToken; +token_tag2string(inactive) -> ?CompactInactiveToken; +token_tag2string(internal) -> ?CompactInternalToken; +%% token_tag2string(X) -> ?CompactIntsigDelayToken; +token_tag2string(onInterruptByEvent) -> ?CompactInterruptByEventToken; +token_tag2string(onInterruptByNewSignalDescr) -> ?CompactInterruptByNewSignalsDescrToken; +token_tag2string(isolate) -> ?CompactIsolateToken; +token_tag2string(inSvc) -> ?CompactInSvcToken; +token_tag2string(iteration) -> ?CompactIterationToken; +token_tag2string(keepActive) -> ?CompactKeepActiveToken; +token_tag2string(localDescriptor) -> ?CompactLocalToken; +token_tag2string(localControlDescriptor) -> ?CompactLocalControlToken; +token_tag2string(lockStep) -> ?CompactLockStepToken; +token_tag2string(loopBack) -> ?CompactLoopbackToken; +token_tag2string(mediaDescriptor) -> ?CompactMediaToken; +token_tag2string(mediaToken) -> ?CompactMediaToken; +%% token_tag2string(X) -> ?CompactMegacopToken; +%% token_tag2string(X) -> ?CompactMethodToken; +%% token_tag2string(X) -> ?CompactMgcIdToken; +%% token_tag2string(X) -> ?CompactModeToken; +token_tag2string(modReq) -> ?CompactModifyToken; +token_tag2string(modReply) -> ?CompactModifyToken; +token_tag2string(modemDescriptor) -> ?CompactModemToken; +token_tag2string(modemToken) -> ?CompactModemToken; +token_tag2string(moveReq) -> ?CompactMoveToken; +token_tag2string(moveReply) -> ?CompactMoveToken; +%% token_tag2string(X) -> ?CompactMtpToken; +token_tag2string(muxDescriptor) -> ?CompactMuxToken; +token_tag2string(muxToken) -> ?CompactMuxToken; +%% token_tag2string(X) -> ?CompactNeverNotifyToken; +token_tag2string(notifyReq) -> ?CompactNotifyToken; +%% token_tag2string(X) -> ?CompactNotifyCompletionToken; +%% token_tag2string(X) -> ?CompactNotifyImmediateToken; +%% token_tag2string(X) -> ?CompactNotifyRegulatedToken; +%% token_tag2string(X) -> ?CompactNx64kToken; +token_tag2string(observedEventsDescriptor) -> ?CompactObservedEventsToken; +token_tag2string(observedEventsToken) -> ?CompactObservedEventsToken; +token_tag2string(false) -> ?CompactOffToken; +token_tag2string(off) -> ?CompactOffToken; +token_tag2string(oneway) -> ?CompactOnewayToken; +token_tag2string(onewayboth) -> ?CompactOnewayBothToken; +token_tag2string(onewayexternal) -> ?CompactOnewayExternalToken; +token_tag2string(onOff) -> ?CompactOnOffToken; +%% token_tag2string(X) -> ?CompactOrAUDITselectToken; +token_tag2string(true) -> ?CompactOnToken; +token_tag2string(otherReason) -> ?CompactOtherReasonToken; +token_tag2string(outOfSvc) -> ?CompactOutOfSvcToken; +token_tag2string(packagesDescriptor) -> ?CompactPackagesToken; +token_tag2string(packagesToken) -> ?CompactPackagesToken; +%% token_tag2string(X) -> ?CompactPendingToken; +token_tag2string(priorityAudit) -> ?CompactPriorityToken; +%% token_tag2string(X) -> ?CompactProfileToken; +%% token_tag2string(X) -> ?CompactReasonToken; +token_tag2string(recvOnly) -> ?CompactRecvonlyToken; +%% token_tag2string(X) -> ?CompactReplyToken; +token_tag2string(resetEventsDescriptor) -> ?CompactResetEventsDescriptorToken; +%% token_tag2string(X) -> ?CompactRequestIDToken; +%% token_tag2string(X) -> ?CompactResponseAckToken; +%% token_tag2string(X) -> ?CompactRestartToken; +token_tag2string(remoteDescriptor) -> ?CompactRemoteToken; +%% token_tag2string(X) -> ?CompactReservedGroupToken; +%% token_tag2string(X) -> ?CompactReservedValueToken; +token_tag2string(sendOnly) -> ?CompactSendonlyToken; +token_tag2string(sendRecv) -> ?CompactSendrecvToken; +%% token_tag2string(X) -> ?CompactServicesToken; +%% token_tag2string(X) -> ?CompactServiceStatesToken; +token_tag2string(serviceChangeReq) -> ?CompactServiceChangeToken; +%% token_tag2string(X) -> ?CompactServiceChangeAddressToken; +token_tag2string(incomplete) -> ?CompactServiceChangeIncompleteToken; +%% token_tag2string(X) -> ?CompactSignalListToken; +token_tag2string(signalsDescriptor) -> ?CompactSignalsToken; +token_tag2string(signalsToken) -> ?CompactSignalsToken; +%% token_tag2string(X) -> ?CompactSignalTypeToken; +token_tag2string(statisticsDescriptor) -> ?CompactStatsToken; +token_tag2string(statsToken) -> ?CompactStatsToken; +%% token_tag2string(X) -> ?CompactStreamToken; +token_tag2string(subtractReq) -> ?CompactSubtractToken; +token_tag2string(subtractReply) -> ?CompactSubtractToken; +%% token_tag2string(X) -> ?CompactSynchISDNToken; +%% token_tag2string(X) -> ?CompactTerminationStateToken; +token_tag2string(test) -> ?CompactTestToken; +token_tag2string(timeOut) -> ?CompactTimeOutToken; +token_tag2string(onTimeOut) -> ?CompactTimeOutToken; +token_tag2string(topologyAudit) -> ?CompactTopologyToken; +%% token_tag2string(X) -> ?CompactTransToken; +%% token_tag2string(X) -> ?CompactV18Token; +%% token_tag2string(X) -> ?CompactV22Token; +%% token_tag2string(X) -> ?CompactV22bisToken; +%% token_tag2string(X) -> ?CompactV32Token; +%% token_tag2string(X) -> ?CompactV32bisToken; +%% token_tag2string(X) -> ?CompactV34Token; +%% token_tag2string(X) -> ?CompactV76Token; +%% token_tag2string(X) -> ?CompactV90Token; +%% token_tag2string(X) -> ?CompactV91Token; +%% token_tag2string(X) -> ?CompactVersionToken; +token_tag2string(_) -> []. + + +%%---------------------------------------------------------------------- +%% Define various macros used by the actual generator code +%%---------------------------------------------------------------------- + +-define(EQUAL, [?EqualToken]). +-define(COLON, [?ColonToken]). +-define(LBRKT, [?LbrktToken]). +-define(RBRKT, [?RbrktToken]). +-define(LSBRKT, [?LsbrktToken]). +-define(RSBRKT, [?RsbrktToken]). +-define(COMMA, [?CommaToken]). +-define(DOT, [?DotToken]). +-define(SLASH, [?SlashToken]). +-define(DQUOTE, [?DoubleQuoteToken]). +-define(SP, [?SpToken]). +-define(HTAB, [?HtabToken]). +-define(CR, [?CrToken]). +-define(LF, [?LfToken]). +-define(LWSP, []). +-define(EOL, ?LF). +-define(WSP, ?SP). +-define(SEP, ?WSP). + +-define(INIT_INDENT, []). +-define(INC_INDENT(State), State). +-define(INDENT(State), State). +-define(LBRKT_INDENT(_State), [?LbrktToken]). +-define(RBRKT_INDENT(_State), [?RbrktToken]). +-define(LSBRKT_INDENT(_State), [?LsbrktToken]). +-define(RSBRKT_INDENT(_State), [?RsbrktToken]). +-define(COMMA_INDENT(_State), [?CommaToken]). +-define(SEP_INDENT(_State), [?LfToken]). + +%%---------------------------------------------------------------------- +%% Define token macros +%%---------------------------------------------------------------------- + +-define(AddToken , ?CompactAddToken). +-define(AndAUDITSelectToken , ?CompactAndAUDITSelectToken). +-define(AuditToken , ?CompactAuditToken). +-define(AuditCapToken , ?CompactAuditCapToken). +-define(AuditValueToken , ?CompactAuditValueToken). +-define(AuthToken , ?CompactAuthToken). +-define(BothToken , ?CompactBothToken). +-define(BothwayToken , ?CompactBothwayToken). +-define(BriefToken , ?CompactBriefToken). +-define(BufferToken , ?CompactBufferToken). +-define(CtxToken , ?CompactCtxToken). +-define(ContextAuditToken , ?CompactContextAuditToken). +-define(ContextAttrToken , ?CompactContextAttrToken). +-define(ContextListToken , ?CompactContextListToken). +-define(DigitMapToken , ?CompactDigitMapToken). +-define(DirectionToken , ?CompactDirectionToken). +-define(DiscardToken , ?CompactDiscardToken). +-define(DisconnectedToken , ?CompactDisconnectedToken). +-define(DelayToken , ?CompactDelayToken). +-define(DeleteToken , ?CompactDeleteToken). +-define(DurationToken , ?CompactDurationToken). +-define(EmbedToken , ?CompactEmbedToken). +-define(EmergencyToken , ?CompactEmergencyToken). +-define(EmergencyOffToken , ?CompactEmergencyOffToken). +-define(EmergencyValueToken , ?CompactEmergencyValueToken). +-define(ErrorToken , ?CompactErrorToken). +-define(EventBufferToken , ?CompactEventBufferToken). +-define(EventsToken , ?CompactEventsToken). +-define(ExternalToken , ?CompactExternalToken). +-define(FailoverToken , ?CompactFailoverToken). +-define(ForcedToken , ?CompactForcedToken). +-define(GracefulToken , ?CompactGracefulToken). +-define(H221Token , ?CompactH221Token). +-define(H223Token , ?CompactH223Token). +-define(H226Token , ?CompactH226Token). +-define(HandOffToken , ?CompactHandOffToken). +-define(IEPSToken , ?CompactIEPSToken). +-define(ImmAckRequiredToken , ?CompactImmAckRequiredToken). +-define(InactiveToken , ?CompactInactiveToken). +-define(InternalToken , ?CompactInternalToken). +-define(IntsigDelayToken , ?CompactIntsigDelayToken). +-define(IsolateToken , ?CompactIsolateToken). +-define(InSvcToken , ?CompactInSvcToken). +-define(InterruptByEventToken , ?CompactInterruptByEventToken). +-define(InterruptByNewSignalsDescrToken, ?CompactInterruptByNewSignalsDescrToken). +-define(IterationToken , ?CompactIterationToken). +-define(KeepActiveToken , ?CompactKeepActiveToken). +-define(LocalToken , ?CompactLocalToken). +-define(LocalControlToken , ?CompactLocalControlToken). +-define(LockStepToken , ?CompactLockStepToken). +-define(LoopbackToken , ?CompactLoopbackToken). +-define(MediaToken , ?CompactMediaToken). +-define(MegacopToken , ?CompactMegacopToken). +-define(MessageSegmentToken , ?CompactMessageSegmentToken). +-define(MethodToken , ?CompactMethodToken). +-define(MgcIdToken , ?CompactMgcIdToken). +-define(ModeToken , ?CompactModeToken). +-define(ModifyToken , ?CompactModifyToken). +-define(ModemToken , ?CompactModemToken). +-define(MoveToken , ?CompactMoveToken). +-define(MtpToken , ?CompactMtpToken). +-define(MuxToken , ?CompactMuxToken). +-define(NeverNotifyToken , ?CompactNeverNotifyToken). +-define(NotifyToken , ?CompactNotifyToken). +-define(NotifyCompletionToken , ?CompactNotifyCompletionToken). +-define(NotifyImmediateToken , ?CompactNotifyImmediateToken). +-define(NotifyRegulatedToken , ?CompactNotifyRegulatedToken). +-define(Nx64kToken , ?CompactNx64kToken). +-define(ObservedEventsToken , ?CompactObservedEventsToken). +-define(OffToken , ?CompactOffToken). +-define(OnewayToken , ?CompactOnewayToken). +-define(OnewayBothToken , ?CompactOnewayBothToken). +-define(OnewayExternalToken , ?CompactOnewayExternalToken). +-define(OnOffToken , ?CompactOnOffToken). +-define(OnToken , ?CompactOnToken). +-define(OrAUDITselectToken , ?CompactOrAUDITselectToken). +-define(OtherReasonToken , ?CompactOtherReasonToken). +-define(OutOfSvcToken , ?CompactOutOfSvcToken). +-define(PackagesToken , ?CompactPackagesToken). +-define(PendingToken , ?CompactPendingToken). +-define(PriorityToken , ?CompactPriorityToken). +-define(ProfileToken , ?CompactProfileToken). +-define(ReasonToken , ?CompactReasonToken). +-define(RecvonlyToken , ?CompactRecvonlyToken). +-define(ReplyToken , ?CompactReplyToken). +-define(ResetEventsDescriptorToken , ?CompactResetEventsDescriptorToken). +-define(ResponseAckToken , ?CompactResponseAckToken). +-define(RestartToken , ?CompactRestartToken). +-define(RemoteToken , ?CompactRemoteToken). +-define(RequestIDToken , ?CompactRequestIDToken). +-define(ReservedGroupToken , ?CompactReservedGroupToken). +-define(ReservedValueToken , ?CompactReservedValueToken). +-define(SegmentationCompleteToken , ?CompactSegmentationCompleteToken). +-define(SendonlyToken , ?CompactSendonlyToken). +-define(SendrecvToken , ?CompactSendrecvToken). +-define(ServicesToken , ?CompactServicesToken). +-define(ServiceStatesToken , ?CompactServiceStatesToken). +-define(ServiceChangeToken , ?CompactServiceChangeToken). +-define(ServiceChangeAddressToken , ?CompactServiceChangeAddressToken). +-define(ServiceChangeIncompleteToken , ?CompactServiceChangeIncompleteToken). +-define(SignalListToken , ?CompactSignalListToken). +-define(SignalsToken , ?CompactSignalsToken). +-define(SignalTypeToken , ?CompactSignalTypeToken). +-define(StatsToken , ?CompactStatsToken). +-define(StreamToken , ?CompactStreamToken). +-define(SubtractToken , ?CompactSubtractToken). +-define(SynchISDNToken , ?CompactSynchISDNToken). +-define(TerminationStateToken , ?CompactTerminationStateToken). +-define(TestToken , ?CompactTestToken). +-define(TimeOutToken , ?CompactTimeOutToken). +-define(TopologyToken , ?CompactTopologyToken). +-define(TransToken , ?CompactTransToken). +-define(V18Token , ?CompactV18Token). +-define(V22Token , ?CompactV22Token). +-define(V22bisToken , ?CompactV22bisToken). +-define(V32Token , ?CompactV32Token). +-define(V32bisToken , ?CompactV32bisToken). +-define(V34Token , ?CompactV34Token). +-define(V76Token , ?CompactV76Token). +-define(V90Token , ?CompactV90Token). +-define(V91Token , ?CompactV91Token). +-define(VersionToken , ?CompactVersionToken). + +%%---------------------------------------------------------------------- +%% Include the generator code +%%---------------------------------------------------------------------- + +-include("megaco_text_gen_v3.hrl"). + diff --git a/lib/megaco/src/text/megaco_pretty_text_encoder.erl b/lib/megaco/src/text/megaco_pretty_text_encoder.erl new file mode 100644 index 0000000000..6a9a7df041 --- /dev/null +++ b/lib/megaco/src/text/megaco_pretty_text_encoder.erl @@ -0,0 +1,613 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2000-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 PRETTY Megaco/H.248 text messages from internal form +%%---------------------------------------------------------------------- + +-module(megaco_pretty_text_encoder). + +-behaviour(megaco_encoder). + +-export([encode_message/3, decode_message/3, + decode_mini_message/3, + + version_of/2, + + encode_transaction/3, + encode_action_requests/3, + encode_action_request/3, + encode_command_request/3, + encode_action_reply/3]). + +%% Backward compatible funcs: +-export([encode_message/2, decode_message/2, + + encode_transaction/1, + encode_command_request/1, + encode_action_reply/1]). + +%% Do we need these here? +-export([trim_quoted_string/1, + term_to_compact_string/1, + term_to_pretty_string/1]). + +-export([token_tag2string/1, token_tag2string/2]). + + +-include("megaco_text_tokens.hrl"). +-include_lib("megaco/src/engine/megaco_message_internal.hrl"). + +-define(V1_PARSE_MOD, megaco_text_parser_v1). +-define(V2_PARSE_MOD, megaco_text_parser_v2). +-define(V3_PARSE_MOD, megaco_text_parser_v3). +-define(PREV3A_PARSE_MOD, megaco_text_parser_prev3a). +-define(PREV3B_PARSE_MOD, megaco_text_parser_prev3b). +-define(PREV3C_PARSE_MOD, megaco_text_parser_prev3c). + + +%%---------------------------------------------------------------------- +%% Convert a 'MegacoMessage' record into a binary +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- + +encode_message(EncodingConfig, + #'MegacoMessage'{mess = #'Message'{version = V}} = MegaMsg) -> + encode_message(EncodingConfig, V, MegaMsg). + + +encode_message([{version3,_}|EC], 1, MegaMsg) -> + megaco_pretty_text_encoder_v1:encode_message(EC, MegaMsg); +encode_message(EC, 1, MegaMsg) -> + megaco_pretty_text_encoder_v1:encode_message(EC, MegaMsg); +encode_message([{version3,_}|EC], 2, MegaMsg) -> + megaco_pretty_text_encoder_v2:encode_message(EC, MegaMsg); +encode_message(EC, 2, MegaMsg) -> + megaco_pretty_text_encoder_v2:encode_message(EC, MegaMsg); +encode_message([{version3,prev3c}|EC], 3, MegaMsg) -> + megaco_pretty_text_encoder_prev3c:encode_message(EC, MegaMsg); +encode_message([{version3,prev3b}|EC], 3, MegaMsg) -> + megaco_pretty_text_encoder_prev3b:encode_message(EC, MegaMsg); +encode_message([{version3,prev3a}|EC], 3, MegaMsg) -> + megaco_pretty_text_encoder_prev3a:encode_message(EC, MegaMsg); +encode_message([{version3,v3}|EC], 3, MegaMsg) -> + megaco_pretty_text_encoder_v3:encode_message(EC, MegaMsg); +encode_message(EC, 3, MegaMsg) -> + megaco_pretty_text_encoder_v3:encode_message(EC, MegaMsg); +encode_message(_EC, V, _MegaMsg) -> + {error, {bad_version, V}}. + + +%%---------------------------------------------------------------------- +%% Convert a binary into a 'MegacoMessage' record +%% Return {ok, MegacoMessageRecord} | {error, Reason} +%%---------------------------------------------------------------------- + +version_of(_EC, Bin) -> + case megaco_text_scanner:scan(Bin) of + {ok, _Tokens, V, _LastLine} -> + {ok, V}; + {error, Reason, Line} -> + {error, {decode_failed, Reason, Line}} + end. + + +decode_message(EC, Bin) -> + decode_message(EC, dynamic, Bin). + +decode_message([], _, Bin) when is_binary(Bin) -> + case megaco_text_scanner:scan(Bin) of + {ok, Tokens, 1, _LastLine} -> + do_decode_message(?V1_PARSE_MOD, Tokens, Bin); + + {ok, Tokens, 2, _LastLine} -> + do_decode_message(?V2_PARSE_MOD, Tokens, Bin); + + {ok, Tokens, 3, _LastLine} -> + do_decode_message(?V3_PARSE_MOD, Tokens, Bin); + + {ok, _Tokens, V, _LastLine} -> + {error, {unsupported_version, V}}; + + %% {error, Reason, Tokens, Line} -> + %% scan_error(Reason, Line, Tokens, Bin); + + {error, Reason, Line} -> %% OTP-4007 + scan_error(Reason, Line, Bin) %% OTP-4007 + end; +decode_message([{version3,v3}], _, Bin) when is_binary(Bin) -> + case megaco_text_scanner:scan(Bin) of + {ok, Tokens, 1, _LastLine} -> + do_decode_message(?V1_PARSE_MOD, Tokens, Bin); + + {ok, Tokens, 2, _LastLine} -> + do_decode_message(?V2_PARSE_MOD, Tokens, Bin); + + {ok, Tokens, 3, _LastLine} -> + do_decode_message(?V3_PARSE_MOD, Tokens, Bin); + + {ok, _Tokens, V, _LastLine} -> + {error, {unsupported_version, V}}; + + {error, Reason, Tokens, Line} -> + scan_error(Reason, Line, Tokens, Bin); + + {error, Reason, Line} -> %% OTP-4007 + scan_error(Reason, Line, Bin) %% OTP-4007 + end; +decode_message([{version3,prev3c}], _, Bin) when is_binary(Bin) -> + case megaco_text_scanner:scan(Bin) of + {ok, Tokens, 1, _LastLine} -> + do_decode_message(?V1_PARSE_MOD, Tokens, Bin); + + {ok, Tokens, 2, _LastLine} -> + do_decode_message(?V2_PARSE_MOD, Tokens, Bin); + + {ok, Tokens, 3, _LastLine} -> + do_decode_message(?PREV3C_PARSE_MOD, Tokens, Bin); + + {ok, _Tokens, V, _LastLine} -> + {error, {unsupported_version, V}}; + + {error, Reason, Tokens, Line} -> + scan_error(Reason, Line, Tokens, Bin); + + {error, Reason, Line} -> + scan_error(Reason, Line, Bin) + end; +decode_message([{version3,prev3b}], _, Bin) when is_binary(Bin) -> + case megaco_text_scanner:scan(Bin) of + {ok, Tokens, 1, _LastLine} -> + do_decode_message(?V1_PARSE_MOD, Tokens, Bin); + + {ok, Tokens, 2, _LastLine} -> + do_decode_message(?V2_PARSE_MOD, Tokens, Bin); + + {ok, Tokens, 3, _LastLine} -> + do_decode_message(?PREV3B_PARSE_MOD, Tokens, Bin); + + {ok, _Tokens, V, _LastLine} -> + {error, {unsupported_version, V}}; + + {error, Reason, Tokens, Line} -> + scan_error(Reason, Line, Tokens, Bin); + + {error, Reason, Line} -> %% OTP-4007 + scan_error(Reason, Line, Bin) %% OTP-4007 + end; +decode_message([{version3,prev3a}], _, Bin) when is_binary(Bin) -> + case megaco_text_scanner:scan(Bin) of + {ok, Tokens, 1, _LastLine} -> + do_decode_message(?V1_PARSE_MOD, Tokens, Bin); + + {ok, Tokens, 2, _LastLine} -> + do_decode_message(?V2_PARSE_MOD, Tokens, Bin); + + {ok, Tokens, 3, _LastLine} -> + do_decode_message(?PREV3A_PARSE_MOD, Tokens, Bin); + + {ok, _Tokens, V, _LastLine} -> + {error, {unsupported_version, V}}; + + {error, Reason, Tokens, Line} -> + scan_error(Reason, Line, Tokens, Bin); + + {error, Reason, Line} -> %% OTP-4007 + scan_error(Reason, Line, Bin) %% OTP-4007 + end; +decode_message([{flex, Port}], _, Bin) when is_binary(Bin) -> + case megaco_flex_scanner:scan(Bin, Port) of + {ok, Tokens, 1, _LastLine} -> + do_decode_message(?V1_PARSE_MOD, Tokens, Bin); + + {ok, Tokens, 2, _LastLine} -> + do_decode_message(?V2_PARSE_MOD, Tokens, Bin); + + {ok, Tokens, 3, _LastLine} -> + do_decode_message(?V3_PARSE_MOD, Tokens, Bin); + + {ok, _Tokens, V, _LastLine} -> + {error, {unsupported_version, V}}; + + %% {error, Reason, Tokens, Line} -> + %% scan_error(Reason, Line, Tokens, Bin); + + {error, Reason, Line} -> %% OTP-4007 + scan_error(Reason, Line, Bin) %% OTP-4007 + end; +decode_message([{version3,v3},{flex, Port}], _, Bin) when is_binary(Bin) -> + case megaco_flex_scanner:scan(Bin, Port) of + {ok, Tokens, 1, _LastLine} -> + do_decode_message(?V1_PARSE_MOD, Tokens, Bin); + + {ok, Tokens, 2, _LastLine} -> + do_decode_message(?V2_PARSE_MOD, Tokens, Bin); + + {ok, Tokens, 3, _LastLine} -> + do_decode_message(?V3_PARSE_MOD, Tokens, Bin); + + {ok, _Tokens, V, _LastLine} -> + {error, {unsupported_version, V}}; + + %% {error, Reason, Tokens, Line} -> + %% scan_error(Reason, Line, Tokens, Bin); + + {error, Reason, Line} -> %% OTP-4007 + scan_error(Reason, Line, Bin) %% OTP-4007 + end; +decode_message([{version3,prev3c},{flex, Port}], _, Bin) when is_binary(Bin) -> + case megaco_flex_scanner:scan(Bin, Port) of + {ok, Tokens, 1, _LastLine} -> + do_decode_message(?V1_PARSE_MOD, Tokens, Bin); + + {ok, Tokens, 2, _LastLine} -> + do_decode_message(?V2_PARSE_MOD, Tokens, Bin); + + {ok, Tokens, 3, _LastLine} -> + do_decode_message(?PREV3C_PARSE_MOD, Tokens, Bin); + + {ok, _Tokens, V, _LastLine} -> + {error, {unsupported_version, V}}; + + %% {error, Reason, Tokens, Line} -> + %% scan_error(Reason, Line, Tokens, Bin); + + {error, Reason, Line} -> %% OTP-4007 + scan_error(Reason, Line, Bin) %% OTP-4007 + end; +decode_message([{version3,prev3b},{flex, Port}], _, Bin) when is_binary(Bin) -> + case megaco_flex_scanner:scan(Bin, Port) of + {ok, Tokens, 1, _LastLine} -> + do_decode_message(?V1_PARSE_MOD, Tokens, Bin); + + {ok, Tokens, 2, _LastLine} -> + do_decode_message(?V2_PARSE_MOD, Tokens, Bin); + + {ok, Tokens, 3, _LastLine} -> + do_decode_message(?PREV3B_PARSE_MOD, Tokens, Bin); + + {ok, _Tokens, V, _LastLine} -> + {error, {unsupported_version, V}}; + + %% {error, Reason, Tokens, Line} -> + %% scan_error(Reason, Line, Tokens, Bin); + + {error, Reason, Line} -> %% OTP-4007 + scan_error(Reason, Line, Bin) %% OTP-4007 + end; +decode_message([{version3,prev3a},{flex, Port}], _, Bin) when is_binary(Bin) -> + case megaco_flex_scanner:scan(Bin, Port) of + {ok, Tokens, 1, _LastLine} -> + do_decode_message(?V1_PARSE_MOD, Tokens, Bin); + + {ok, Tokens, 2, _LastLine} -> + do_decode_message(?V2_PARSE_MOD, Tokens, Bin); + + {ok, Tokens, 3, _LastLine} -> + do_decode_message(?PREV3A_PARSE_MOD, Tokens, Bin); + + {ok, _Tokens, V, _LastLine} -> + {error, {unsupported_version, V}}; + + %% {error, Reason, Tokens, Line} -> + %% scan_error(Reason, Line, Tokens, Bin); + + {error, Reason, Line} -> %% OTP-4007 + scan_error(Reason, Line, Bin) %% OTP-4007 + end; +decode_message(EC, _, Bin) when is_binary(Bin) -> + {error, {bad_encoding_config, EC}}; +decode_message(_EC, _, _BadBin) -> + {error, bad_binary}. + + +do_decode_message(ParseMod, Tokens, Bin) -> + case (catch ParseMod:parse(Tokens)) of + {ok, MegacoMessage} -> + {ok, MegacoMessage}; + {error, Reason} -> + parse_error(Reason, Tokens, Bin); + + %% OTP-4007 + {'EXIT', Reason} -> + parse_error(Reason, Tokens, Bin) + end. + + +decode_mini_message(EC, _, Bin) when is_binary(Bin) -> + megaco_text_mini_decoder:decode_message(EC, Bin). + + +scan_error(Reason, Line, Bin) -> + scan_error(Reason, Line, [], Bin). + +scan_error("bad_property_parm: " ++ Reason, _Line, _Tokens, _Bin) -> + {error, {bad_property_parm, Reason}}; +scan_error(Reason, Line, Tokens, Bin) -> + %% io:format("scanner error: " + %% "~n Reason: ~p" + %% "~n Line: ~p" + %% "~n Tokens: ~p" + %% "~n Bin: ~p" + %% "~n", [Reason, Line, Tokens, Bin]), + {error, [{reason, Reason, Line}, {token, Tokens}, {chars, Bin}]}. + +parse_error(Reason, Tokens, Chars) -> +%% io:format("parse_error -> entry with" +%% "~n Reason: ~p" +%% "~n Tokens: ~p" +%% "~n Chars: ~p" +%% "~n", [Reason, Tokens, Chars]), + case Reason of + {Line, Mod, [Prefix, [$[, TokenStringRaw, $]]]} when + is_integer(Line) andalso + is_atom(Mod) andalso + is_list(Prefix) andalso + is_list(TokenStringRaw) -> + TokenString = [l2i(X) || X <- TokenStringRaw, is_list(X)], + ReasonStr = Prefix ++ TokenString, + {error, [{reason, ReasonStr, Line}, {tokens, Tokens}, {chars, Chars}, {module, Mod}]}; + _ -> + {error, [{reason, Reason}, {token, Tokens}, {chars, Chars}]} + end. + + +l2i(L) when is_list(L) -> + case (catch list_to_integer(L)) of + I when is_integer(I) -> + I; + _ -> + L + end. + + +%%---------------------------------------------------------------------- +%% Convert a transaction record into a binary +%% Return {ok, Bin} | {error, Reason} +%%---------------------------------------------------------------------- +encode_transaction(Trans) -> + encode_transaction([], 1, Trans). + +encode_transaction([{version3,_}|EC], 1, Trans) -> + megaco_pretty_text_encoder_v1:encode_transaction(EC, Trans); +encode_transaction(EC, 1, Trans) -> + megaco_pretty_text_encoder_v1:encode_transaction(EC, Trans); +encode_transaction([{version3,_}|EC], 2, Trans) -> + megaco_pretty_text_encoder_v2:encode_transaction(EC, Trans); +encode_transaction(EC, 2, Trans) -> + megaco_pretty_text_encoder_v2:encode_transaction(EC, Trans); +encode_transaction([{version3,v3}|EC], 3, Trans) -> + megaco_pretty_text_encoder_v3:encode_transaction(EC, Trans); +encode_transaction([{version3,prev3c}|EC], 3, Trans) -> + megaco_pretty_text_encoder_prev3c:encode_transaction(EC, Trans); +encode_transaction([{version3,prev3b}|EC], 3, Trans) -> + megaco_pretty_text_encoder_prev3b:encode_transaction(EC, Trans); +encode_transaction([{version3,prev3a}|EC], 3, Trans) -> + megaco_pretty_text_encoder_prev3a:encode_transaction(EC, Trans); +encode_transaction(EC, 3, Trans) -> + megaco_pretty_text_encoder_v3:encode_transaction(EC, Trans); +encode_transaction(_EC, V, _Trans) -> + {error, {bad_version, V}}. + + +%%---------------------------------------------------------------------- +%% Convert a list of ActionRequest record's into a binary +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- +encode_action_requests([{version3,_}|EC], 1, ActReqs) when is_list(ActReqs) -> + megaco_pretty_text_encoder_v1:encode_action_requests(EC, ActReqs); +encode_action_requests(EC, 1, ActReqs) when is_list(ActReqs) -> + megaco_pretty_text_encoder_v1:encode_action_requests(EC, ActReqs); +encode_action_requests([{version3,_}|EC], 2, ActReqs) when is_list(ActReqs) -> + megaco_pretty_text_encoder_v2:encode_action_requests(EC, ActReqs); +encode_action_requests(EC, 2, ActReqs) when is_list(ActReqs) -> + megaco_pretty_text_encoder_v2:encode_action_requests(EC, ActReqs); +encode_action_requests([{version3,v3}|EC], 3, ActReqs) + when is_list(ActReqs) -> + megaco_pretty_text_encoder_v3:encode_action_requests(EC, ActReqs); +encode_action_requests([{version3,prev3c}|EC], 3, ActReqs) + when is_list(ActReqs) -> + megaco_pretty_text_encoder_prev3c:encode_action_requests(EC, ActReqs); +encode_action_requests([{version3,prev3b}|EC], 3, ActReqs) + when is_list(ActReqs) -> + megaco_pretty_text_encoder_prev3b:encode_action_requests(EC, ActReqs); +encode_action_requests([{version3,prev3a}|EC], 3, ActReqs) + when is_list(ActReqs) -> + megaco_pretty_text_encoder_prev3a:encode_action_requests(EC, ActReqs); +encode_action_requests(EC, 3, ActReqs) when is_list(ActReqs) -> + megaco_pretty_text_encoder_v3:encode_action_requests(EC, ActReqs); +encode_action_requests(_EC, V, _ActReqs) -> + {error, {bad_version, V}}. + + +%%---------------------------------------------------------------------- +%% Convert a ActionRequest record into a binary +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- +encode_action_request([{version3,_}|EC], 1, ActReq) -> + megaco_pretty_text_encoder_v1:encode_action_request(EC, ActReq); +encode_action_request(EC, 1, ActReq) -> + megaco_pretty_text_encoder_v1:encode_action_request(EC, ActReq); +encode_action_request([{version3,_}|EC], 2, ActReq) -> + megaco_pretty_text_encoder_v2:encode_action_request(EC, ActReq); +encode_action_request(EC, 2, ActReq) -> + megaco_pretty_text_encoder_v2:encode_action_request(EC, ActReq); +encode_action_request([{version3,v3}|EC], 3, ActReq) -> + megaco_pretty_text_encoder_v3:encode_action_request(EC, ActReq); +encode_action_request([{version3,prev3c}|EC], 3, ActReq) -> + megaco_pretty_text_encoder_prev3c:encode_action_request(EC, ActReq); +encode_action_request([{version3,prev3b}|EC], 3, ActReq) -> + megaco_pretty_text_encoder_prev3b:encode_action_request(EC, ActReq); +encode_action_request([{version3,prev3a}|EC], 3, ActReq) -> + megaco_pretty_text_encoder_prev3a:encode_action_request(EC, ActReq); +encode_action_request(EC, 3, ActReq) -> + megaco_pretty_text_encoder_v3:encode_action_request(EC, ActReq); +encode_action_request(_EC, V, _ActReq) -> + {error, {bad_version, V}}. + + +%%---------------------------------------------------------------------- +%% Convert a CommandRequest record into a binary +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- +encode_command_request(CmdReq) -> + encode_command_request([], 1, CmdReq). + +encode_command_request([{version3,_}|EC], 1, CmdReq) -> + megaco_pretty_text_encoder_v1:encode_command_request(EC, CmdReq); +encode_command_request(EC, 1, CmdReq) -> + megaco_pretty_text_encoder_v1:encode_command_request(EC, CmdReq); +encode_command_request([{version3,_}|EC], 2, CmdReq) -> + megaco_pretty_text_encoder_v2:encode_command_request(EC, CmdReq); +encode_command_request(EC, 2, CmdReq) -> + megaco_pretty_text_encoder_v2:encode_command_request(EC, CmdReq); +encode_command_request([{version3,v3}|EC], 3, CmdReq) -> + megaco_pretty_text_encoder_v3:encode_command_request(EC, CmdReq); +encode_command_request([{version3,prev3c}|EC], 3, CmdReq) -> + megaco_pretty_text_encoder_prev3c:encode_command_request(EC, CmdReq); +encode_command_request([{version3,prev3b}|EC], 3, CmdReq) -> + megaco_pretty_text_encoder_prev3b:encode_command_request(EC, CmdReq); +encode_command_request([{version3,prev3a}|EC], 3, CmdReq) -> + megaco_pretty_text_encoder_prev3a:encode_command_request(EC, CmdReq); +encode_command_request(EC, 3, CmdReq) -> + megaco_pretty_text_encoder_v3:encode_command_request(EC, CmdReq); +encode_command_request(_EC, V, _CmdReq) -> + {error, {bad_version, V}}. + + +%%---------------------------------------------------------------------- +%% Convert a action reply into a deep io list +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- +encode_action_reply(ActRep) -> +%% io:format("~p:encode_action_reply -> entry with" +%% "~n ActRep: ~p" +%% "~n", [?MODULE, ActRep]), + encode_action_reply([], 1, ActRep). + +encode_action_reply([{version3,_}|EC], 1, ActRep) -> + megaco_pretty_text_encoder_v1:encode_action_reply(EC, ActRep); +encode_action_reply(EC, 1, ActRep) -> + megaco_pretty_text_encoder_v1:encode_action_reply(EC, ActRep); +encode_action_reply([{version3,_}|EC], 2, ActRep) -> + megaco_pretty_text_encoder_v2:encode_action_reply(EC, ActRep); +encode_action_reply(EC, 2, ActRep) -> + megaco_pretty_text_encoder_v2:encode_action_reply(EC, ActRep); +encode_action_reply([{version3,v3}|EC], 3, ActRep) -> + megaco_pretty_text_encoder_v3:encode_action_reply(EC, ActRep); +encode_action_reply([{version3,prev3c}|EC], 3, ActRep) -> + megaco_pretty_text_encoder_prev3c:encode_action_reply(EC, ActRep); +encode_action_reply([{version3,prev3b}|EC], 3, ActRep) -> + megaco_pretty_text_encoder_prev3b:encode_action_reply(EC, ActRep); +encode_action_reply([{version3,prev3a}|EC], 3, ActRep) -> + megaco_pretty_text_encoder_prev3a:encode_action_reply(EC, ActRep); +encode_action_reply(EC, 3, ActRep) -> + megaco_pretty_text_encoder_v3:encode_action_reply(EC, ActRep); +encode_action_reply(_EC, V, _ActRep) -> + {error, {bad_version, V}}. + + +%%---------------------------------------------------------------------- +term_to_compact_string(Term) -> + case catch io_lib:format("~s", [Term]) of + {'EXIT', _} -> lists:flatten(io_lib:format("~w", [Term])); + GoodString -> lists:flatten(GoodString) + end. + +%%---------------------------------------------------------------------- +term_to_pretty_string(Term) -> + case catch io_lib:format("~s", [Term]) of + {'EXIT', _} -> lists:flatten(io_lib:format("~p", [Term])); + GoodString -> lists:flatten(GoodString) + end. + +%%---------------------------------------------------------------------- +trim_quoted_string([H | T]) -> + case ?classify_char(H) of + safe_char -> [H | trim_quoted_string(T)]; + rest_char -> [H | trim_quoted_string(T)]; + white_space -> [H | trim_quoted_string(T)]; + _BadChar -> [$? | trim_quoted_string(T)] + end; +trim_quoted_string([]) -> + []. + + +%%---------------------------------------------------------------------- +%% A utility function to pretty print the tags found in a megaco message +%%---------------------------------------------------------------------- + +-define(TT2S_BEST_VERSION, v3). + +token_tag2string(Tag) -> + token_tag2string(Tag, ?TT2S_BEST_VERSION). + +token_tag2string(Tag, 1) -> + token_tag2string(Tag, v1); +token_tag2string(Tag, v1) -> + megaco_pretty_text_encoder_v1:token_tag2string(Tag); +token_tag2string(Tag, 2) -> + token_tag2string(Tag, v2); +token_tag2string(Tag, v2) -> + megaco_pretty_text_encoder_v2:token_tag2string(Tag); +token_tag2string(Tag, 3) -> + token_tag2string(Tag, v3); +token_tag2string(Tag, v3) -> + megaco_pretty_text_encoder_v3:token_tag2string(Tag); +token_tag2string(Tag, prev3b) -> + megaco_pretty_text_encoder_prev3b:token_tag2string(Tag); +token_tag2string(Tag, prev3c) -> + megaco_pretty_text_encoder_prev3c:token_tag2string(Tag); +token_tag2string(Tag, _Vsn) -> + token_tag2string(Tag, ?TT2S_BEST_VERSION). + + + +%% d(F) -> +%% d(F, []). + +%% d(F, A) -> +%% %% d(get(dbg), F, A). +%% d(true, F, A). + +%% d(true, F, A) -> +%% io:format("~p:" ++ F ++ "~n", [?MODULE|A]); +%% d(_, _, _) -> +%% ok. + +%% p(F, A) -> +%% io:format("*** [~s] ***" +%% "~n " ++ F ++ "~n", [formated_timestamp() | A]), +%% sleep(5000), +%% ok. + +%% sleep(X) -> receive after X -> ok end. + +%% formated_timestamp() -> +%% format_timestamp(now()). + +%% format_timestamp({_N1, _N2, N3} = Now) -> +%% {Date, Time} = calendar:now_to_datetime(Now), +%% {YYYY,MM,DD} = Date, +%% {Hour,Min,Sec} = Time, +%% FormatDate = +%% io_lib:format("~.4w:~.2.0w:~.2.0w ~.2.0w:~.2.0w:~.2.0w 4~w", +%% [YYYY,MM,DD,Hour,Min,Sec,round(N3/1000)]), +%% lists:flatten(FormatDate). diff --git a/lib/megaco/src/text/megaco_pretty_text_encoder_prev3a.erl b/lib/megaco/src/text/megaco_pretty_text_encoder_prev3a.erl new file mode 100644 index 0000000000..6f42bf963c --- /dev/null +++ b/lib/megaco/src/text/megaco_pretty_text_encoder_prev3a.erl @@ -0,0 +1,303 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2004-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 PRETTY Megaco/H.248 text messages from internal form +%%---------------------------------------------------------------------- + +-module(megaco_pretty_text_encoder_prev3a). + +-export([encode_message/2, + encode_transaction/2, + encode_action_requests/2, + encode_action_request/2, + encode_command_request/2, + encode_action_reply/2]). + + +-include_lib("megaco/include/megaco.hrl"). +-include_lib("megaco/include/megaco_message_prev3a.hrl"). +-define(encoder_version_pre_prev3c,true). +-include("megaco_text_tokens.hrl"). + + +%%---------------------------------------------------------------------- +%% Convert a 'MegacoMessage' record into a binary +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- + +encode_message(EC, MegaMsg) + when is_list(EC) andalso is_record(MegaMsg, 'MegacoMessage') -> + case (catch enc_MegacoMessage(MegaMsg)) of + {'EXIT', Reason} -> + {error, Reason}; + Bin when is_binary(Bin) -> + {ok, Bin}; + DeepIoList -> + Bin = erlang:list_to_binary(DeepIoList), + {ok, Bin} + end; +encode_message(EncodingConfig, MegaMsg) + when is_record(MegaMsg, 'MegacoMessage') -> + {error, {bad_encoding_config, EncodingConfig}}; +encode_message(_EncodingConfig, _MegaMsg) -> + {error, bad_megaco_message}. + + +%%---------------------------------------------------------------------- +%% Convert a binary into a 'MegacoMessage' record +%% Return {ok, MegacoMessageRecord} | {error, Reason} +%% +%% See megaco_pretty_text_encoder:decode_message/2 +%% +%%---------------------------------------------------------------------- + + +%%---------------------------------------------------------------------- +%% Convert a transaction record into a deep io list +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- +encode_transaction(_EC, Trans) -> + case (catch enc_Transaction(Trans)) of + {'EXIT', Reason} -> + {error, Reason}; + Bin when is_binary(Bin) -> + {ok, Bin}; + DeepIoList -> + Bin = erlang:list_to_binary(DeepIoList), + {ok, Bin} + end. + +%%---------------------------------------------------------------------- +%% Convert a list of ActionRequest record's into a binary +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- +encode_action_requests(_EC, ActReqs) when is_list(ActReqs) -> + case (catch enc_ActionRequests(ActReqs)) of + {'EXIT', Reason} -> + {error, Reason}; + Bin when is_binary(Bin) -> + {ok, Bin}; + DeepIoList -> + Bin = erlang:list_to_binary(DeepIoList), + {ok, Bin} + end. + +%%---------------------------------------------------------------------- +%% Convert a ActionRequest record into a binary +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- +encode_action_request(_EC, ActReq) + when is_record(ActReq, 'ActionRequest') -> + case (catch enc_ActionRequest(ActReq)) of + {'EXIT', Reason} -> + {error, Reason}; + Bin when is_binary(Bin) -> + {ok, Bin}; + DeepIoList -> + Bin = erlang:list_to_binary(DeepIoList), + {ok, Bin} + end. + +%%---------------------------------------------------------------------- +%% Convert a CommandRequest record into a deep io list +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- +encode_command_request(_EC, CmdReq) + when is_record(CmdReq, 'CommandRequest') -> + case (catch enc_CommandRequest(CmdReq)) of + {'EXIT', Reason} -> + {error, Reason}; + Bin when is_binary(Bin) -> + {ok, Bin}; + DeepIoList -> + Bin = erlang:list_to_binary(DeepIoList), + {ok, Bin} + end. + +%%---------------------------------------------------------------------- +%% Convert a action reply into a deep io list +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- +encode_action_reply(_EC, ActRep) + when is_record(ActRep, 'ActionReply') -> + case (catch enc_ActionReply(ActRep)) of + {'EXIT', Reason} -> + {error, Reason}; + Bin when is_binary(Bin) -> + {ok, Bin}; + DeepIoList -> + Bin = erlang:list_to_binary(DeepIoList), + {ok, Bin} + end. + + +%%---------------------------------------------------------------------- +%% Define various macros used by the actual generator code +%%---------------------------------------------------------------------- + +-define(EQUAL, [?SpToken, ?EqualToken, ?SpToken]). +-define(COLON, [?ColonToken]). +-define(LBRKT, [?SpToken, ?LbrktToken, ?SpToken]). +-define(RBRKT, [?SpToken, ?RbrktToken, ?SpToken]). +-define(LSBRKT, [?SpToken, ?LsbrktToken, ?SpToken]). +-define(RSBRKT, [?SpToken, ?RsbrktToken, ?SpToken]). +-define(COMMA, [?CommaToken, ?SpToken]). +-define(DOT, [?DotToken]). +-define(SLASH, [?SlashToken]). +-define(DQUOTE, [?DoubleQuoteToken]). +-define(SP, [?SpToken]). +-define(HTAB, [?HtabToken]). +-define(CR, [?CrToken]). +-define(LF, [?LfToken]). +-define(LWSP, []). +-define(EOL, ?LF). +-define(WSP, ?SP). +-define(SEP, ?WSP). + +-define(INIT_INDENT, []). +-define(INC_INDENT(State), [?HtabToken | State]). +-define(INDENT(State), [?LfToken | State]). +-define(LBRKT_INDENT(State), [?SpToken, ?LbrktToken, ?INDENT(?INC_INDENT(State))]). +-define(RBRKT_INDENT(State), [?INDENT(State), ?RbrktToken]). +-define(LSBRKT_INDENT(State), [?SpToken, ?LsbrktToken, ?INDENT(?INC_INDENT(State))]). +-define(RSBRKT_INDENT(State), [?INDENT(State), ?RsbrktToken]). +-define(COMMA_INDENT(State), [?CommaToken, ?INDENT(State)]). +-define(SEP_INDENT(_State), [?LfToken]). + +%%---------------------------------------------------------------------- +%% Define token macros +%%---------------------------------------------------------------------- + +-define(AddToken , ?PrettyAddToken). +-define(AuditToken , ?PrettyAuditToken). +-define(AuditCapToken , ?PrettyAuditCapToken). +-define(AuditValueToken , ?PrettyAuditValueToken). +-define(AuthToken , ?PrettyAuthToken). +-define(BothToken , ?PrettyBothToken). +-define(BothwayToken , ?PrettyBothwayToken). +-define(BriefToken , ?PrettyBriefToken). +-define(BufferToken , ?PrettyBufferToken). +-define(CtxToken , ?PrettyCtxToken). +-define(ContextAuditToken , ?PrettyContextAuditToken). +-define(ContextAttrToken , ?PrettyContextAttrToken). +-define(DigitMapToken , ?PrettyDigitMapToken). +-define(DirectionToken , ?PrettyDirectionToken). +-define(DiscardToken , ?PrettyDiscardToken). +-define(DisconnectedToken , ?PrettyDisconnectedToken). +-define(DelayToken , ?PrettyDelayToken). +-define(DeleteToken , ?PrettyDeleteToken). +-define(DurationToken , ?PrettyDurationToken). +-define(EmbedToken , ?PrettyEmbedToken). +-define(EmergencyToken , ?PrettyEmergencyToken). +-define(EmergencyOffToken , ?PrettyEmergencyOffToken). +-define(ErrorToken , ?PrettyErrorToken). +-define(EventBufferToken , ?PrettyEventBufferToken). +-define(EventsToken , ?PrettyEventsToken). +-define(ExternalToken , ?PrettyExternalToken). +-define(FailoverToken , ?PrettyFailoverToken). +-define(ForcedToken , ?PrettyForcedToken). +-define(GracefulToken , ?PrettyGracefulToken). +-define(H221Token , ?PrettyH221Token). +-define(H223Token , ?PrettyH223Token). +-define(H226Token , ?PrettyH226Token). +-define(HandOffToken , ?PrettyHandOffToken). +-define(IEPSToken , ?PrettyIEPSToken). +-define(ImmAckRequiredToken , ?PrettyImmAckRequiredToken). +-define(InactiveToken , ?PrettyInactiveToken). +-define(InternalToken , ?PrettyInternalToken). +-define(IsolateToken , ?PrettyIsolateToken). +-define(InSvcToken , ?PrettyInSvcToken). +-define(InterruptByEventToken , ?PrettyInterruptByEventToken). +-define(InterruptByNewSignalsDescrToken, ?PrettyInterruptByNewSignalsDescrToken). +-define(KeepActiveToken , ?PrettyKeepActiveToken). +-define(LocalToken , ?PrettyLocalToken). +-define(LocalControlToken , ?PrettyLocalControlToken). +-define(LockStepToken , ?PrettyLockStepToken). +-define(LoopbackToken , ?PrettyLoopbackToken). +-define(MediaToken , ?PrettyMediaToken). +-define(MegacopToken , ?PrettyMegacopToken). +-define(MethodToken , ?PrettyMethodToken). +-define(MgcIdToken , ?PrettyMgcIdToken). +-define(ModeToken , ?PrettyModeToken). +-define(ModifyToken , ?PrettyModifyToken). +-define(ModemToken , ?PrettyModemToken). +-define(MoveToken , ?PrettyMoveToken). +-define(MtpToken , ?PrettyMtpToken). +-define(MuxToken , ?PrettyMuxToken). +-define(NotifyToken , ?PrettyNotifyToken). +-define(NotifyCompletionToken , ?PrettyNotifyCompletionToken). +-define(Nx64kToken , ?PrettyNx64kToken). +-define(ObservedEventsToken , ?PrettyObservedEventsToken). +-define(OffToken , ?PrettyOffToken). +-define(OnewayToken , ?PrettyOnewayToken). +-define(OnOffToken , ?PrettyOnOffToken). +-define(OnToken , ?PrettyOnToken). +-define(OtherReasonToken , ?PrettyOtherReasonToken). +-define(OutOfSvcToken , ?PrettyOutOfSvcToken). +-define(PackagesToken , ?PrettyPackagesToken). +-define(PendingToken , ?PrettyPendingToken). +-define(PriorityToken , ?PrettyPriorityToken). +-define(ProfileToken , ?PrettyProfileToken). +-define(ReasonToken , ?PrettyReasonToken). +-define(RecvonlyToken , ?PrettyRecvonlyToken). +-define(ReplyToken , ?PrettyReplyToken). +-define(RequestIDToken , ?PrettyRequestIDToken). +-define(ResponseAckToken , ?PrettyResponseAckToken). +-define(RestartToken , ?PrettyRestartToken). +-define(RemoteToken , ?PrettyRemoteToken). +-define(ReservedGroupToken , ?PrettyReservedGroupToken). +-define(ReservedValueToken , ?PrettyReservedValueToken). +-define(SendonlyToken , ?PrettySendonlyToken). +-define(SendrecvToken , ?PrettySendrecvToken). +-define(ServicesToken , ?PrettyServicesToken). +-define(ServiceStatesToken , ?PrettyServiceStatesToken). +-define(ServiceChangeToken , ?PrettyServiceChangeToken). +-define(ServiceChangeAddressToken , ?PrettyServiceChangeAddressToken). +-define(ServiceChangeIncompleteToken , ?PrettyServiceChangeIncompleteToken). +-define(SignalListToken , ?PrettySignalListToken). +-define(SignalsToken , ?PrettySignalsToken). +-define(SignalTypeToken , ?PrettySignalTypeToken). +-define(StatsToken , ?PrettyStatsToken). +-define(StreamToken , ?PrettyStreamToken). +-define(SubtractToken , ?PrettySubtractToken). +-define(SynchISDNToken , ?PrettySynchISDNToken). +-define(TerminationStateToken , ?PrettyTerminationStateToken). +-define(TestToken , ?PrettyTestToken). +-define(TimeOutToken , ?PrettyTimeOutToken). +-define(TopologyToken , ?PrettyTopologyToken). +-define(TransToken , ?PrettyTransToken). +-define(V18Token , ?PrettyV18Token). +-define(V22Token , ?PrettyV22Token). +-define(V22bisToken , ?PrettyV22bisToken). +-define(V32Token , ?PrettyV32Token). +-define(V32bisToken , ?PrettyV32bisToken). +-define(V34Token , ?PrettyV34Token). +-define(V76Token , ?PrettyV76Token). +-define(V90Token , ?PrettyV90Token). +-define(V91Token , ?PrettyV91Token). +-define(VersionToken , ?PrettyVersionToken). + +%%---------------------------------------------------------------------- +%% Include the generator code +%%---------------------------------------------------------------------- + +-include("megaco_text_gen_prev3a.hrl"). + diff --git a/lib/megaco/src/text/megaco_pretty_text_encoder_prev3b.erl b/lib/megaco/src/text/megaco_pretty_text_encoder_prev3b.erl new file mode 100644 index 0000000000..44bdc4690d --- /dev/null +++ b/lib/megaco/src/text/megaco_pretty_text_encoder_prev3b.erl @@ -0,0 +1,437 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2005-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 PRETTY Megaco/H.248 text messages from internal form +%%---------------------------------------------------------------------- + +-module(megaco_pretty_text_encoder_prev3b). + +-export([encode_message/2, + encode_transaction/2, + encode_action_requests/2, + encode_action_request/2, + encode_command_request/2, + encode_action_reply/2]). + +-export([token_tag2string/1]). + +-include_lib("megaco/include/megaco.hrl"). +-include_lib("megaco/include/megaco_message_prev3b.hrl"). +-define(encoder_version_pre_prev3c,true). +-include("megaco_text_tokens.hrl"). + + +%%---------------------------------------------------------------------- +%% Convert a 'MegacoMessage' record into a binary +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- + +encode_message(EC, MegaMsg) + when is_list(EC) andalso is_record(MegaMsg, 'MegacoMessage') -> + case (catch enc_MegacoMessage(MegaMsg)) of + {'EXIT', Reason} -> + {error, Reason}; + Bin when is_binary(Bin) -> + {ok, Bin}; + DeepIoList -> + Bin = erlang:list_to_binary(DeepIoList), + {ok, Bin} + end; +encode_message(EncodingConfig, MegaMsg) + when is_record(MegaMsg, 'MegacoMessage') -> + {error, {bad_encoding_config, EncodingConfig}}; +encode_message(_EncodingConfig, _MegaMsg) -> + {error, bad_megaco_message}. + + +%%---------------------------------------------------------------------- +%% Convert a binary into a 'MegacoMessage' record +%% Return {ok, MegacoMessageRecord} | {error, Reason} +%% +%% See megaco_pretty_text_encoder:decode_message/2 +%% +%%---------------------------------------------------------------------- + + +%%---------------------------------------------------------------------- +%% Convert a transaction record into a deep io list +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- +encode_transaction(_EC, Trans) -> + case (catch enc_Transaction(Trans)) of + {'EXIT', Reason} -> + {error, Reason}; + Bin when is_binary(Bin) -> + {ok, Bin}; + DeepIoList -> + Bin = erlang:list_to_binary(DeepIoList), + {ok, Bin} + end. + +%%---------------------------------------------------------------------- +%% Convert a list of ActionRequest record's into a binary +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- +encode_action_requests(_EC, ActReqs) when is_list(ActReqs) -> + case (catch enc_ActionRequests(ActReqs)) of + {'EXIT', Reason} -> + {error, Reason}; + Bin when is_binary(Bin) -> + {ok, Bin}; + DeepIoList -> + Bin = erlang:list_to_binary(DeepIoList), + {ok, Bin} + end. + +%%---------------------------------------------------------------------- +%% Convert a ActionRequest record into a binary +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- +encode_action_request(_EC, ActReq) + when is_record(ActReq, 'ActionRequest') -> + case (catch enc_ActionRequest(ActReq)) of + {'EXIT', Reason} -> + {error, Reason}; + Bin when is_binary(Bin) -> + {ok, Bin}; + DeepIoList -> + Bin = erlang:list_to_binary(DeepIoList), + {ok, Bin} + end. + +%%---------------------------------------------------------------------- +%% Convert a CommandRequest record into a deep io list +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- +encode_command_request(_EC, CmdReq) + when is_record(CmdReq, 'CommandRequest') -> + case (catch enc_CommandRequest(CmdReq)) of + {'EXIT', Reason} -> + {error, Reason}; + Bin when is_binary(Bin) -> + {ok, Bin}; + DeepIoList -> + Bin = erlang:list_to_binary(DeepIoList), + {ok, Bin} + end. + +%%---------------------------------------------------------------------- +%% Convert a action reply into a deep io list +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- +encode_action_reply(_EC, ActRep) + when is_record(ActRep, 'ActionReply') -> + case (catch enc_ActionReply(ActRep)) of + {'EXIT', Reason} -> + {error, Reason}; + Bin when is_binary(Bin) -> + {ok, Bin}; + DeepIoList -> + Bin = erlang:list_to_binary(DeepIoList), + {ok, Bin} + end. + + +%%---------------------------------------------------------------------- +%% A utility function to pretty print the tags found in a megaco message +%%---------------------------------------------------------------------- + +token_tag2string(addReq) -> ?PrettyAddToken; +token_tag2string(addReply) -> ?PrettyAddToken; +token_tag2string(auditDescriptor) -> ?PrettyAuditToken; +token_tag2string(auditCapRequest) -> ?PrettyAuditCapToken; +token_tag2string(auditCapReply) -> ?PrettyAuditCapToken; +token_tag2string(auditValueRequest) -> ?PrettyAuditValueToken; +token_tag2string(auditValueReply) -> ?PrettyAuditValueToken; +%% token_tag2string(X) -> ?PrettyAuthToken; +token_tag2string(both) -> ?PrettyBothToken; +token_tag2string(bothway) -> ?PrettyBothwayToken; +token_tag2string(brief) -> ?PrettyBriefToken; +%% token_tag2string(X) -> ?PrettyBufferToken; +%% token_tag2string(X) -> ?PrettyCtxToken; +%% token_tag2string(X) -> ?PrettyContextAttrToken; +%% token_tag2string(X) -> ?PrettyContextAuditToken; +%% token_tag2string(X) -> ?PrettyContextListToken; +token_tag2string(digitMapDescriptor) -> ?PrettyDigitMapToken; +token_tag2string(digitMapToken) -> ?PrettyDigitMapToken; +%% token_tag2string(X) -> ?PrettyDirectionToken; +%% token_tag2string(X) -> ?PrettyDiscardToken; +%% token_tag2string(X) -> ?PrettyDisconnectedToken; +%% token_tag2string(X) -> ?PrettyDelayToken; +token_tag2string(duration) -> ?PrettyDurationToken; +%% token_tag2string(X) -> ?PrettyEmbedToken; +token_tag2string(emergencyAudit) -> ?PrettyEmergencyToken; +%% token_tag2string(X) -> ?PrettyEmergencyOffToken; +token_tag2string(errorDescriptor) -> ?PrettyErrorToken; +token_tag2string(eventBufferDescriptor) -> ?PrettyEventBufferToken; +token_tag2string(eventBufferToken) -> ?PrettyEventBufferToken; +token_tag2string(eventsDescriptor) -> ?PrettyEventsToken; +token_tag2string(eventsToken) -> ?PrettyEventsToken; +token_tag2string(external) -> ?PrettyExternalToken; +%% token_tag2string(X) -> ?PrettyFailoverToken; +%% token_tag2string(X) -> ?PrettyForcedToken; +%% token_tag2string(X) -> ?PrettyGracefulToken; +%% token_tag2string(X) -> ?PrettyH221Token; +%% token_tag2string(X) -> ?PrettyH223Token; +%% token_tag2string(X) -> ?PrettyH226Token; +%% token_tag2string(X) -> ?PrettyHandOffToken; +token_tag2string(iepsCallind) -> ?PrettyIEPSToken; +%% token_tag2string(X) -> ?PrettyImmAckRequiredToken; +token_tag2string(inactive) -> ?PrettyInactiveToken; +token_tag2string(internal) -> ?PrettyInternalToken; +token_tag2string(onInterruptByEvent) -> ?PrettyInterruptByEventToken; +token_tag2string(onInterruptByNewSignalDescr) -> ?PrettyInterruptByNewSignalsDescrToken; +token_tag2string(isolate) -> ?PrettyIsolateToken; +token_tag2string(inSvc) -> ?PrettyInSvcToken; +token_tag2string(keepActive) -> ?PrettyKeepActiveToken; +token_tag2string(localDescriptor) -> ?PrettyLocalToken; +token_tag2string(localControlDescriptor) -> ?PrettyLocalControlToken; +token_tag2string(lockStep) -> ?PrettyLockStepToken; +token_tag2string(loopBack) -> ?PrettyLoopbackToken; +token_tag2string(mediaDescriptor) -> ?PrettyMediaToken; +token_tag2string(mediaToken) -> ?PrettyMediaToken; +%% token_tag2string(X) -> ?PrettyMegacopToken; +%% token_tag2string(X) -> ?PrettyMethodToken; +%% token_tag2string(X) -> ?PrettyMgcIdToken; +%% token_tag2string(X) -> ?PrettyModeToken; +token_tag2string(modReq) -> ?PrettyModifyToken; +token_tag2string(modReply) -> ?PrettyModifyToken; +token_tag2string(modemDescriptor) -> ?PrettyModemToken; +token_tag2string(modemToken) -> ?PrettyModemToken; +token_tag2string(moveReq) -> ?PrettyMoveToken; +token_tag2string(moveReply) -> ?PrettyMoveToken; +%% token_tag2string(X) -> ?PrettyMtpToken; +token_tag2string(muxDescriptor) -> ?PrettyMuxToken; +token_tag2string(muxToken) -> ?PrettyMuxToken; +token_tag2string(notifyReq) -> ?PrettyNotifyToken; +%% token_tag2string(X) -> ?PrettyNotifyCompletionToken; +%% token_tag2string(X) -> ?PrettyNx64kToken; +token_tag2string(observedEventsDescriptor) -> ?PrettyObservedEventsToken; +token_tag2string(observedEventsToken) -> ?PrettyObservedEventsToken; +token_tag2string(false) -> ?PrettyOffToken; +token_tag2string(off) -> ?PrettyOffToken; +token_tag2string(oneway) -> ?PrettyOnewayToken; +token_tag2string(onOff) -> ?PrettyOnOffToken; +token_tag2string(true) -> ?PrettyOnToken; +token_tag2string(otherReason) -> ?PrettyOtherReasonToken; +token_tag2string(outOfSvc) -> ?PrettyOutOfSvcToken; +token_tag2string(packagesDescriptor) -> ?PrettyPackagesToken; +token_tag2string(packagesToken) -> ?PrettyPackagesToken; +%% token_tag2string(X) -> ?PrettyPendingToken; +token_tag2string(priorityAudit) -> ?PrettyPriorityToken; +%% token_tag2string(X) -> ?PrettyProfileToken; +%% token_tag2string(X) -> ?PrettyReasonToken; +token_tag2string(recvOnly) -> ?PrettyRecvonlyToken; +%% token_tag2string(X) -> ?PrettyReplyToken; +%% token_tag2string(X) -> ?PrettyRequestIDToken; +%% token_tag2string(X) -> ?PrettyResponseAckToken; +%% token_tag2string(X) -> ?PrettyRestartToken; +token_tag2string(remoteDescriptor) -> ?PrettyRemoteToken; +%% token_tag2string(X) -> ?PrettyReservedGroupToken; +%% token_tag2string(X) -> ?PrettyReservedValueToken; +token_tag2string(sendOnly) -> ?PrettySendonlyToken; +token_tag2string(sendRecv) -> ?PrettySendrecvToken; +%% token_tag2string(X) -> ?PrettyServicesToken; +%% token_tag2string(X) -> ?PrettyServiceStatesToken; +token_tag2string(serviceChangeReq) -> ?PrettyServiceChangeToken; +%% token_tag2string(X) -> ?PrettyServiceChangeAddressToken; +token_tag2string(incomplete) -> ?PrettyServiceChangeIncompleteToken; +%% token_tag2string(X) -> ?PrettySignalListToken; +token_tag2string(signalsDescriptor) -> ?PrettySignalsToken; +token_tag2string(signalsToken) -> ?PrettySignalsToken; +%% token_tag2string(X) -> ?PrettySignalTypeToken; +token_tag2string(statisticsDescriptor) -> ?PrettyStatsToken; +token_tag2string(statsToken) -> ?PrettyStatsToken; +%% token_tag2string(X) -> ?PrettyStreamToken; +token_tag2string(subtractReq) -> ?PrettySubtractToken; +token_tag2string(subtractReply) -> ?PrettySubtractToken; +%% token_tag2string(X) -> ?PrettySynchISDNToken; +%% token_tag2string(X) -> ?PrettyTerminationStateToken; +token_tag2string(test) -> ?PrettyTestToken; +token_tag2string(timeOut) -> ?PrettyTimeOutToken; +token_tag2string(onTimeOut) -> ?PrettyTimeOutToken; +token_tag2string(topologyAudit) -> ?PrettyTopologyToken; +%% token_tag2string(X) -> ?PrettyTransToken; +%% token_tag2string(X) -> ?PrettyV18Token; +%% token_tag2string(X) -> ?PrettyV22Token; +%% token_tag2string(X) -> ?PrettyV22bisToken; +%% token_tag2string(X) -> ?PrettyV32Token; +%% token_tag2string(X) -> ?PrettyV32bisToken; +%% token_tag2string(X) -> ?PrettyV34Token; +%% token_tag2string(X) -> ?PrettyV76Token; +%% token_tag2string(X) -> ?PrettyV90Token; +%% token_tag2string(X) -> ?PrettyV91Token; +%% token_tag2string(X) -> ?PrettyVersionToken; +token_tag2string(_) -> []. + + +%%---------------------------------------------------------------------- +%% Define various macros used by the actual generator code +%%---------------------------------------------------------------------- + +-define(EQUAL, [?SpToken, ?EqualToken, ?SpToken]). +-define(COLON, [?ColonToken]). +-define(LBRKT, [?SpToken, ?LbrktToken, ?SpToken]). +-define(RBRKT, [?SpToken, ?RbrktToken, ?SpToken]). +-define(LSBRKT, [?SpToken, ?LsbrktToken, ?SpToken]). +-define(RSBRKT, [?SpToken, ?RsbrktToken, ?SpToken]). +-define(COMMA, [?CommaToken, ?SpToken]). +-define(DOT, [?DotToken]). +-define(SLASH, [?SlashToken]). +-define(DQUOTE, [?DoubleQuoteToken]). +-define(SP, [?SpToken]). +-define(HTAB, [?HtabToken]). +-define(CR, [?CrToken]). +-define(LF, [?LfToken]). +-define(LWSP, []). +-define(EOL, ?LF). +-define(WSP, ?SP). +-define(SEP, ?WSP). + +-define(INIT_INDENT, []). +-define(INC_INDENT(State), [?HtabToken | State]). +-define(INDENT(State), [?LfToken | State]). +-define(LBRKT_INDENT(State), [?SpToken, ?LbrktToken, ?INDENT(?INC_INDENT(State))]). +-define(RBRKT_INDENT(State), [?INDENT(State), ?RbrktToken]). +-define(LSBRKT_INDENT(State), [?SpToken, ?LsbrktToken, ?INDENT(?INC_INDENT(State))]). +-define(RSBRKT_INDENT(State), [?INDENT(State), ?RsbrktToken]). +-define(COMMA_INDENT(State), [?CommaToken, ?INDENT(State)]). +-define(SEP_INDENT(_State), [?LfToken]). + +%%---------------------------------------------------------------------- +%% Define token macros +%%---------------------------------------------------------------------- + +-define(AddToken , ?PrettyAddToken). +-define(AuditToken , ?PrettyAuditToken). +-define(AuditCapToken , ?PrettyAuditCapToken). +-define(AuditValueToken , ?PrettyAuditValueToken). +-define(AuthToken , ?PrettyAuthToken). +-define(BothToken , ?PrettyBothToken). +-define(BothwayToken , ?PrettyBothwayToken). +-define(BriefToken , ?PrettyBriefToken). +-define(BufferToken , ?PrettyBufferToken). +-define(CtxToken , ?PrettyCtxToken). +-define(ContextAuditToken , ?PrettyContextAuditToken). +-define(ContextAttrToken , ?PrettyContextAttrToken). +-define(DigitMapToken , ?PrettyDigitMapToken). +-define(DirectionToken , ?PrettyDirectionToken). +-define(DiscardToken , ?PrettyDiscardToken). +-define(DisconnectedToken , ?PrettyDisconnectedToken). +-define(DelayToken , ?PrettyDelayToken). +-define(DeleteToken , ?PrettyDeleteToken). +-define(DurationToken , ?PrettyDurationToken). +-define(EmbedToken , ?PrettyEmbedToken). +-define(EmergencyToken , ?PrettyEmergencyToken). +-define(EmergencyOffToken , ?PrettyEmergencyOffToken). +-define(ErrorToken , ?PrettyErrorToken). +-define(EventBufferToken , ?PrettyEventBufferToken). +-define(EventsToken , ?PrettyEventsToken). +-define(ExternalToken , ?PrettyExternalToken). +-define(FailoverToken , ?PrettyFailoverToken). +-define(ForcedToken , ?PrettyForcedToken). +-define(GracefulToken , ?PrettyGracefulToken). +-define(H221Token , ?PrettyH221Token). +-define(H223Token , ?PrettyH223Token). +-define(H226Token , ?PrettyH226Token). +-define(HandOffToken , ?PrettyHandOffToken). +-define(IEPSToken , ?PrettyIEPSToken). +-define(ImmAckRequiredToken , ?PrettyImmAckRequiredToken). +-define(InactiveToken , ?PrettyInactiveToken). +-define(InternalToken , ?PrettyInternalToken). +-define(IsolateToken , ?PrettyIsolateToken). +-define(InSvcToken , ?PrettyInSvcToken). +-define(InterruptByEventToken , ?PrettyInterruptByEventToken). +-define(InterruptByNewSignalsDescrToken, ?PrettyInterruptByNewSignalsDescrToken). +-define(KeepActiveToken , ?PrettyKeepActiveToken). +-define(LocalToken , ?PrettyLocalToken). +-define(LocalControlToken , ?PrettyLocalControlToken). +-define(LockStepToken , ?PrettyLockStepToken). +-define(LoopbackToken , ?PrettyLoopbackToken). +-define(MediaToken , ?PrettyMediaToken). +-define(MegacopToken , ?PrettyMegacopToken). +-define(MethodToken , ?PrettyMethodToken). +-define(MgcIdToken , ?PrettyMgcIdToken). +-define(ModeToken , ?PrettyModeToken). +-define(ModifyToken , ?PrettyModifyToken). +-define(ModemToken , ?PrettyModemToken). +-define(MoveToken , ?PrettyMoveToken). +-define(MtpToken , ?PrettyMtpToken). +-define(MuxToken , ?PrettyMuxToken). +-define(NotifyToken , ?PrettyNotifyToken). +-define(NotifyCompletionToken , ?PrettyNotifyCompletionToken). +-define(Nx64kToken , ?PrettyNx64kToken). +-define(ObservedEventsToken , ?PrettyObservedEventsToken). +-define(OffToken , ?PrettyOffToken). +-define(OnewayToken , ?PrettyOnewayToken). +-define(OnOffToken , ?PrettyOnOffToken). +-define(OnToken , ?PrettyOnToken). +-define(OtherReasonToken , ?PrettyOtherReasonToken). +-define(OutOfSvcToken , ?PrettyOutOfSvcToken). +-define(PackagesToken , ?PrettyPackagesToken). +-define(PendingToken , ?PrettyPendingToken). +-define(PriorityToken , ?PrettyPriorityToken). +-define(ProfileToken , ?PrettyProfileToken). +-define(ReasonToken , ?PrettyReasonToken). +-define(RecvonlyToken , ?PrettyRecvonlyToken). +-define(ReplyToken , ?PrettyReplyToken). +-define(RequestIDToken , ?PrettyRequestIDToken). +-define(ResponseAckToken , ?PrettyResponseAckToken). +-define(RestartToken , ?PrettyRestartToken). +-define(RemoteToken , ?PrettyRemoteToken). +-define(ReservedGroupToken , ?PrettyReservedGroupToken). +-define(ReservedValueToken , ?PrettyReservedValueToken). +-define(SendonlyToken , ?PrettySendonlyToken). +-define(SendrecvToken , ?PrettySendrecvToken). +-define(ServicesToken , ?PrettyServicesToken). +-define(ServiceStatesToken , ?PrettyServiceStatesToken). +-define(ServiceChangeToken , ?PrettyServiceChangeToken). +-define(ServiceChangeAddressToken , ?PrettyServiceChangeAddressToken). +-define(ServiceChangeIncompleteToken , ?PrettyServiceChangeIncompleteToken). +-define(SignalListToken , ?PrettySignalListToken). +-define(SignalsToken , ?PrettySignalsToken). +-define(SignalTypeToken , ?PrettySignalTypeToken). +-define(StatsToken , ?PrettyStatsToken). +-define(StreamToken , ?PrettyStreamToken). +-define(SubtractToken , ?PrettySubtractToken). +-define(SynchISDNToken , ?PrettySynchISDNToken). +-define(TerminationStateToken , ?PrettyTerminationStateToken). +-define(TestToken , ?PrettyTestToken). +-define(TimeOutToken , ?PrettyTimeOutToken). +-define(TopologyToken , ?PrettyTopologyToken). +-define(TransToken , ?PrettyTransToken). +-define(V18Token , ?PrettyV18Token). +-define(V22Token , ?PrettyV22Token). +-define(V22bisToken , ?PrettyV22bisToken). +-define(V32Token , ?PrettyV32Token). +-define(V32bisToken , ?PrettyV32bisToken). +-define(V34Token , ?PrettyV34Token). +-define(V76Token , ?PrettyV76Token). +-define(V90Token , ?PrettyV90Token). +-define(V91Token , ?PrettyV91Token). +-define(VersionToken , ?PrettyVersionToken). + +%%---------------------------------------------------------------------- +%% Include the generator code +%%---------------------------------------------------------------------- + +-include("megaco_text_gen_prev3b.hrl"). + diff --git a/lib/megaco/src/text/megaco_pretty_text_encoder_prev3c.erl b/lib/megaco/src/text/megaco_pretty_text_encoder_prev3c.erl new file mode 100644 index 0000000000..1511056f00 --- /dev/null +++ b/lib/megaco/src/text/megaco_pretty_text_encoder_prev3c.erl @@ -0,0 +1,483 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2005-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 PRETTY Megaco/H.248 text messages from internal form +%%---------------------------------------------------------------------- + +-module(megaco_pretty_text_encoder_prev3c). + +-export([encode_message/2, + encode_transaction/2, + encode_action_requests/2, + encode_action_request/2, + encode_command_request/2, + encode_action_reply/2]). + +-export([token_tag2string/1]). + +-export([test/1]). + +-include_lib("megaco/include/megaco.hrl"). +-include_lib("megaco/include/megaco_message_prev3c.hrl"). +-include("megaco_text_tokens.hrl"). + + + +%%---------------------------------------------------------------------- +%% Convert a 'MegacoMessage' record into a binary +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- + +encode_message(EC, MegaMsg) + when is_list(EC) andalso is_record(MegaMsg, 'MegacoMessage') -> + case (catch enc_MegacoMessage(MegaMsg)) of + {'EXIT', Reason} -> + {error, Reason}; + Bin when is_binary(Bin) -> + {ok, Bin}; + DeepIoList -> + Bin = erlang:list_to_binary(DeepIoList), + {ok, Bin} + end; +encode_message(EncodingConfig, MegaMsg) + when is_record(MegaMsg, 'MegacoMessage') -> + {error, {bad_encoding_config, EncodingConfig}}; +encode_message(_EncodingConfig, _MegaMsg) -> + {error, bad_megaco_message}. + + +%%---------------------------------------------------------------------- +%% Convert a binary into a 'MegacoMessage' record +%% Return {ok, MegacoMessageRecord} | {error, Reason} +%% +%% See megaco_pretty_text_encoder:decode_message/2 +%% +%%---------------------------------------------------------------------- + + +%%---------------------------------------------------------------------- +%% Convert a transaction record into a deep io list +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- +encode_transaction(_EC, Trans) -> + case (catch enc_Transaction(Trans)) of + {'EXIT', Reason} -> + {error, Reason}; + Bin when is_binary(Bin) -> + {ok, Bin}; + DeepIoList -> + Bin = erlang:list_to_binary(DeepIoList), + {ok, Bin} + end. + +%%---------------------------------------------------------------------- +%% Convert a list of ActionRequest record's into a binary +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- +encode_action_requests(_EC, ActReqs) when is_list(ActReqs) -> + case (catch enc_ActionRequests(ActReqs)) of + {'EXIT', Reason} -> + {error, Reason}; + Bin when is_binary(Bin) -> + {ok, Bin}; + DeepIoList -> + Bin = erlang:list_to_binary(DeepIoList), + {ok, Bin} + end. + +%%---------------------------------------------------------------------- +%% Convert a ActionRequest record into a binary +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- +encode_action_request(_EC, ActReq) + when is_record(ActReq, 'ActionRequest') -> + case (catch enc_ActionRequest(ActReq)) of + {'EXIT', Reason} -> + {error, Reason}; + Bin when is_binary(Bin) -> + {ok, Bin}; + DeepIoList -> + Bin = erlang:list_to_binary(DeepIoList), + {ok, Bin} + end. + +%%---------------------------------------------------------------------- +%% Convert a CommandRequest record into a deep io list +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- +encode_command_request(_EC, CmdReq) + when is_record(CmdReq, 'CommandRequest') -> + case (catch enc_CommandRequest(CmdReq)) of + {'EXIT', Reason} -> + {error, Reason}; + Bin when is_binary(Bin) -> + {ok, Bin}; + DeepIoList -> + Bin = erlang:list_to_binary(DeepIoList), + {ok, Bin} + end. + +%%---------------------------------------------------------------------- +%% Convert a action reply into a deep io list +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- +encode_action_reply(_EC, ActRep) + when is_record(ActRep, 'ActionReply') -> + case (catch enc_ActionReply(ActRep)) of + {'EXIT', Reason} -> + {error, Reason}; + Bin when is_binary(Bin) -> + {ok, Bin}; + DeepIoList -> + Bin = erlang:list_to_binary(DeepIoList), + {ok, Bin} + end. + + +%%---------------------------------------------------------------------- +%% A utility function to pretty print the tags found in a megaco message +%%---------------------------------------------------------------------- + +token_tag2string(addReq) -> ?PrettyAddToken; +token_tag2string(addReply) -> ?PrettyAddToken; +%% token_tag2string(X) -> ?PrettyAndAUDITSelectToken; +token_tag2string(auditDescriptor) -> ?PrettyAuditToken; +token_tag2string(auditCapRequest) -> ?PrettyAuditCapToken; +token_tag2string(auditCapReply) -> ?PrettyAuditCapToken; +token_tag2string(auditValueRequest) -> ?PrettyAuditValueToken; +token_tag2string(auditValueReply) -> ?PrettyAuditValueToken; +%% token_tag2string(X) -> ?PrettyAuthToken; +token_tag2string(both) -> ?PrettyBothToken; +token_tag2string(bothway) -> ?PrettyBothwayToken; +token_tag2string(brief) -> ?PrettyBriefToken; +%% token_tag2string(X) -> ?PrettyBufferToken; +%% token_tag2string(X) -> ?PrettyCtxToken; +%% token_tag2string(X) -> ?PrettyContextAuditToken; +%% token_tag2string(X) -> ?PrettyContextAttrToken; +%% token_tag2string(X) -> ?PrettyContextListToken; +token_tag2string(digitMapDescriptor) -> ?PrettyDigitMapToken; +token_tag2string(digitMapToken) -> ?PrettyDigitMapToken; +%% token_tag2string(X) -> ?PrettyDirectionToken; +%% token_tag2string(X) -> ?PrettyDiscardToken; +%% token_tag2string(X) -> ?PrettyDisconnectedToken; +%% token_tag2string(X) -> ?PrettyDelayToken; +token_tag2string(duration) -> ?PrettyDurationToken; +%% token_tag2string(X) -> ?PrettyEmbedToken; +token_tag2string(emergencyAudit) -> ?PrettyEmergencyToken; +%% token_tag2string(X) -> ?PrettyEmergencyOffToken; +%% token_tag2string(X) -> ?PrettyEmergencyValueToken; +token_tag2string(errorDescriptor) -> ?PrettyErrorToken; +token_tag2string(eventBufferDescriptor) -> ?PrettyEventBufferToken; +token_tag2string(eventBufferToken) -> ?PrettyEventBufferToken; +token_tag2string(eventsDescriptor) -> ?PrettyEventsToken; +token_tag2string(eventsToken) -> ?PrettyEventsToken; +token_tag2string(external) -> ?PrettyExternalToken; +%% token_tag2string(X) -> ?PrettyFailoverToken; +%% token_tag2string(X) -> ?PrettyForcedToken; +%% token_tag2string(X) -> ?PrettyGracefulToken; +%% token_tag2string(X) -> ?PrettyH221Token; +%% token_tag2string(X) -> ?PrettyH223Token; +%% token_tag2string(X) -> ?PrettyH226Token; +%% token_tag2string(X) -> ?PrettyHandOffToken; +token_tag2string(iepsCallind) -> ?PrettyIEPSToken; +%% token_tag2string(X) -> ?PrettyImmAckRequiredToken; +token_tag2string(inactive) -> ?PrettyInactiveToken; +token_tag2string(internal) -> ?PrettyInternalToken; +%% token_tag2string(X) -> ?PrettyIntsigDelayToken; +token_tag2string(onInterruptByEvent) -> ?PrettyInterruptByEventToken; +token_tag2string(onInterruptByNewSignalDescr) -> ?PrettyInterruptByNewSignalsDescrToken; +token_tag2string(isolate) -> ?PrettyIsolateToken; +token_tag2string(inSvc) -> ?PrettyInSvcToken; +token_tag2string(iteration) -> ?PrettyIterationToken; +token_tag2string(keepActive) -> ?PrettyKeepActiveToken; +token_tag2string(localDescriptor) -> ?PrettyLocalToken; +token_tag2string(localControlDescriptor) -> ?PrettyLocalControlToken; +token_tag2string(lockStep) -> ?PrettyLockStepToken; +token_tag2string(loopBack) -> ?PrettyLoopbackToken; +token_tag2string(mediaDescriptor) -> ?PrettyMediaToken; +token_tag2string(mediaToken) -> ?PrettyMediaToken; +%% token_tag2string(X) -> ?PrettyMegacopToken; +%% token_tag2string(X) -> ?PrettyMethodToken; +%% token_tag2string(X) -> ?PrettyMgcIdToken; +%% token_tag2string(X) -> ?PrettyModeToken; +token_tag2string(modReq) -> ?PrettyModifyToken; +token_tag2string(modReply) -> ?PrettyModifyToken; +token_tag2string(modemDescriptor) -> ?PrettyModemToken; +token_tag2string(modemToken) -> ?PrettyModemToken; +token_tag2string(moveReq) -> ?PrettyMoveToken; +token_tag2string(moveReply) -> ?PrettyMoveToken; +%% token_tag2string(X) -> ?PrettyMtpToken; +token_tag2string(muxDescriptor) -> ?PrettyMuxToken; +token_tag2string(muxToken) -> ?PrettyMuxToken; +%% token_tag2string(X) -> ?PrettyNeverNotifyToken; +token_tag2string(notifyReq) -> ?PrettyNotifyToken; +%% token_tag2string(X) -> ?PrettyNotifyCompletionToken; +%% token_tag2string(X) -> ?PrettyNotifyImmediateToken; +%% token_tag2string(X) -> ?PrettyNotifyRegulatedToken; +%% token_tag2string(X) -> ?PrettyNx64kToken; +token_tag2string(observedEventsDescriptor) -> ?PrettyObservedEventsToken; +token_tag2string(observedEventsToken) -> ?PrettyObservedEventsToken; +token_tag2string(false) -> ?PrettyOffToken; +token_tag2string(off) -> ?PrettyOffToken; +token_tag2string(oneway) -> ?PrettyOnewayToken; +token_tag2string(onewayboth) -> ?PrettyOnewayBothToken; +token_tag2string(onewayexternal) -> ?PrettyOnewayExternalToken; +token_tag2string(onOff) -> ?PrettyOnOffToken; +%% token_tag2string(X) -> ?PrettyOrAUDITselectToken; +token_tag2string(true) -> ?PrettyOnToken; +token_tag2string(otherReason) -> ?PrettyOtherReasonToken; +token_tag2string(outOfSvc) -> ?PrettyOutOfSvcToken; +token_tag2string(packagesDescriptor) -> ?PrettyPackagesToken; +token_tag2string(packagesToken) -> ?PrettyPackagesToken; +%% token_tag2string(X) -> ?PrettyPendingToken; +token_tag2string(priorityAudit) -> ?PrettyPriorityToken; +%% token_tag2string(X) -> ?PrettyProfileToken; +%% token_tag2string(X) -> ?PrettyReasonToken; +token_tag2string(recvOnly) -> ?PrettyRecvonlyToken; +%% token_tag2string(X) -> ?PrettyReplyToken; +token_tag2string(resetEventsDescriptor) -> ?PrettyResetEventsDescriptorToken; +%% token_tag2string(X) -> ?PrettyRequestIDToken; +%% token_tag2string(X) -> ?PrettyResponseAckToken; +%% token_tag2string(X) -> ?PrettyRestartToken; +token_tag2string(remoteDescriptor) -> ?PrettyRemoteToken; +%% token_tag2string(X) -> ?PrettyReservedGroupToken; +%% token_tag2string(X) -> ?PrettyReservedValueToken; +token_tag2string(sendOnly) -> ?PrettySendonlyToken; +token_tag2string(sendRecv) -> ?PrettySendrecvToken; +%% token_tag2string(X) -> ?PrettyServicesToken; +%% token_tag2string(X) -> ?PrettyServiceStatesToken; +token_tag2string(serviceChangeReq) -> ?PrettyServiceChangeToken; +%% token_tag2string(X) -> ?PrettyServiceChangeAddressToken; +token_tag2string(incomplete) -> ?PrettyServiceChangeIncompleteToken; +%% token_tag2string(X) -> ?PrettySignalListToken; +token_tag2string(signalsDescriptor) -> ?PrettySignalsToken; +token_tag2string(signalsToken) -> ?PrettySignalsToken; +%% token_tag2string(X) -> ?PrettySignalTypeToken; +token_tag2string(statisticsDescriptor) -> ?PrettyStatsToken; +token_tag2string(statsToken) -> ?PrettyStatsToken; +%% token_tag2string(X) -> ?PrettyStreamToken; +token_tag2string(subtractReq) -> ?PrettySubtractToken; +token_tag2string(subtractReply) -> ?PrettySubtractToken; +%% token_tag2string(X) -> ?PrettySynchISDNToken; +%% token_tag2string(X) -> ?PrettyTerminationStateToken; +token_tag2string(test) -> ?PrettyTestToken; +token_tag2string(timeOut) -> ?PrettyTimeOutToken; +token_tag2string(onTimeOut) -> ?PrettyTimeOutToken; +token_tag2string(topologyAudit) -> ?PrettyTopologyToken; +%% token_tag2string(X) -> ?PrettyTransToken; +%% token_tag2string(X) -> ?PrettyV18Token; +%% token_tag2string(X) -> ?PrettyV22Token; +%% token_tag2string(X) -> ?PrettyV22bisToken; +%% token_tag2string(X) -> ?PrettyV32Token; +%% token_tag2string(X) -> ?PrettyV32bisToken; +%% token_tag2string(X) -> ?PrettyV34Token; +%% token_tag2string(X) -> ?PrettyV76Token; +%% token_tag2string(X) -> ?PrettyV90Token; +%% token_tag2string(X) -> ?PrettyV91Token; +%% token_tag2string(X) -> ?PrettyVersionToken; +token_tag2string(_) -> []. + + +%%---------------------------------------------------------------------- +%% Define various macros used by the actual generator code +%%---------------------------------------------------------------------- + +-define(EQUAL, [?SpToken, ?EqualToken, ?SpToken]). +-define(COLON, [?ColonToken]). +-define(LBRKT, [?SpToken, ?LbrktToken, ?SpToken]). +-define(RBRKT, [?SpToken, ?RbrktToken, ?SpToken]). +-define(LSBRKT, [?SpToken, ?LsbrktToken, ?SpToken]). +-define(RSBRKT, [?SpToken, ?RsbrktToken, ?SpToken]). +-define(COMMA, [?CommaToken, ?SpToken]). +-define(DOT, [?DotToken]). +-define(SLASH, [?SlashToken]). +-define(DQUOTE, [?DoubleQuoteToken]). +-define(SP, [?SpToken]). +-define(HTAB, [?HtabToken]). +-define(CR, [?CrToken]). +-define(LF, [?LfToken]). +-define(LWSP, []). +-define(EOL, ?LF). +-define(WSP, ?SP). +-define(SEP, ?WSP). + +-define(INIT_INDENT, []). +-define(INC_INDENT(State), [?HtabToken | State]). +-define(INDENT(State), [?LfToken | State]). +-define(LBRKT_INDENT(State), [?SpToken, ?LbrktToken, ?INDENT(?INC_INDENT(State))]). +-define(RBRKT_INDENT(State), [?INDENT(State), ?RbrktToken]). +-define(LSBRKT_INDENT(State), [?SpToken, ?LsbrktToken, ?INDENT(?INC_INDENT(State))]). +-define(RSBRKT_INDENT(State), [?INDENT(State), ?RsbrktToken]). +-define(COMMA_INDENT(State), [?CommaToken, ?INDENT(State)]). +-define(SEP_INDENT(_State), [?LfToken]). + +%%---------------------------------------------------------------------- +%% Define token macros +%%---------------------------------------------------------------------- + +-define(AddToken , ?PrettyAddToken). +-define(AndAUDITSelectToken , ?PrettytAndAUDITSelectToken). +-define(AuditToken , ?PrettyAuditToken). +-define(AuditCapToken , ?PrettyAuditCapToken). +-define(AuditValueToken , ?PrettyAuditValueToken). +-define(AuthToken , ?PrettyAuthToken). +-define(BothToken , ?PrettyBothToken). +-define(BothwayToken , ?PrettyBothwayToken). +-define(BriefToken , ?PrettyBriefToken). +-define(BufferToken , ?PrettyBufferToken). +-define(CtxToken , ?PrettyCtxToken). +-define(ContextAuditToken , ?PrettyContextAuditToken). +-define(ContextAttrToken , ?PrettyContextAttrToken). +-define(ContextListToken , ?PrettyContextListToken). +-define(DigitMapToken , ?PrettyDigitMapToken). +-define(DirectionToken , ?PrettyDirectionToken). +-define(DiscardToken , ?PrettyDiscardToken). +-define(DisconnectedToken , ?PrettyDisconnectedToken). +-define(DelayToken , ?PrettyDelayToken). +-define(DeleteToken , ?PrettyDeleteToken). +-define(DurationToken , ?PrettyDurationToken). +-define(EmbedToken , ?PrettyEmbedToken). +-define(EmergencyToken , ?PrettyEmergencyToken). +-define(EmergencyOffToken , ?PrettyEmergencyOffToken). +-define(EmergencyValueToken , ?PrettyEmergencyValueToken). +-define(ErrorToken , ?PrettyErrorToken). +-define(EventBufferToken , ?PrettyEventBufferToken). +-define(EventsToken , ?PrettyEventsToken). +-define(ExternalToken , ?PrettyExternalToken). +-define(FailoverToken , ?PrettyFailoverToken). +-define(ForcedToken , ?PrettyForcedToken). +-define(GracefulToken , ?PrettyGracefulToken). +-define(H221Token , ?PrettyH221Token). +-define(H223Token , ?PrettyH223Token). +-define(H226Token , ?PrettyH226Token). +-define(HandOffToken , ?PrettyHandOffToken). +-define(IEPSToken , ?PrettyIEPSToken). +-define(ImmAckRequiredToken , ?PrettyImmAckRequiredToken). +-define(InactiveToken , ?PrettyInactiveToken). +-define(InternalToken , ?PrettyInternalToken). +-define(IntsigDelayToken , ?PrettyIntsigDelayToken). +-define(IsolateToken , ?PrettyIsolateToken). +-define(InSvcToken , ?PrettyInSvcToken). +-define(InterruptByEventToken , ?PrettyInterruptByEventToken). +-define(InterruptByNewSignalsDescrToken, ?PrettyInterruptByNewSignalsDescrToken). +-define(IterationToken , ?PrettyIterationToken). +-define(KeepActiveToken , ?PrettyKeepActiveToken). +-define(LocalToken , ?PrettyLocalToken). +-define(LocalControlToken , ?PrettyLocalControlToken). +-define(LockStepToken , ?PrettyLockStepToken). +-define(LoopbackToken , ?PrettyLoopbackToken). +-define(MediaToken , ?PrettyMediaToken). +-define(MegacopToken , ?PrettyMegacopToken). +%% -define(MessageSegmentToken , ?PrettyMessageSegmentToken). +-define(MethodToken , ?PrettyMethodToken). +-define(MgcIdToken , ?PrettyMgcIdToken). +-define(ModeToken , ?PrettyModeToken). +-define(ModifyToken , ?PrettyModifyToken). +-define(ModemToken , ?PrettyModemToken). +-define(MoveToken , ?PrettyMoveToken). +-define(MtpToken , ?PrettyMtpToken). +-define(MuxToken , ?PrettyMuxToken). +-define(NeverNotifyToken , ?PrettyNeverNotifyToken). +-define(NotifyToken , ?PrettyNotifyToken). +-define(NotifyCompletionToken , ?PrettyNotifyCompletionToken). +-define(NotifyImmediateToken , ?PrettyNotifyImmediateToken). +-define(NotifyRegulatedToken , ?PrettyNotifyRegulatedToken). +-define(Nx64kToken , ?PrettyNx64kToken). +-define(ObservedEventsToken , ?PrettyObservedEventsToken). +-define(OffToken , ?PrettyOffToken). +-define(OnewayToken , ?PrettyOnewayToken). +-define(OnewayBothToken , ?PrettyOnewayBothToken). +-define(OnewayExternalToken , ?PrettyOnewayExternalToken). +-define(OnOffToken , ?PrettyOnOffToken). +-define(OnToken , ?PrettyOnToken). +-define(OrAUDITselectToken , ?PrettyOrAUDITselectToken). +-define(OtherReasonToken , ?PrettyOtherReasonToken). +-define(OutOfSvcToken , ?PrettyOutOfSvcToken). +-define(PackagesToken , ?PrettyPackagesToken). +-define(PendingToken , ?PrettyPendingToken). +-define(PriorityToken , ?PrettyPriorityToken). +-define(ProfileToken , ?PrettyProfileToken). +-define(ReasonToken , ?PrettyReasonToken). +-define(RecvonlyToken , ?PrettyRecvonlyToken). +-define(ReplyToken , ?PrettyReplyToken). +-define(ResetEventsDescriptorToken , ?PrettyResetEventsDescriptorToken). +-define(ResponseAckToken , ?PrettyResponseAckToken). +-define(RestartToken , ?PrettyRestartToken). +-define(RemoteToken , ?PrettyRemoteToken). +-define(RequestIDToken , ?PrettyRequestIDToken). +-define(ReservedGroupToken , ?PrettyReservedGroupToken). +-define(ReservedValueToken , ?PrettyReservedValueToken). +%% -define(SegmentationCompleteToken , ?PrettySegmentationCompleteToken). +-define(SendonlyToken , ?PrettySendonlyToken). +-define(SendrecvToken , ?PrettySendrecvToken). +-define(ServicesToken , ?PrettyServicesToken). +-define(ServiceStatesToken , ?PrettyServiceStatesToken). +-define(ServiceChangeToken , ?PrettyServiceChangeToken). +-define(ServiceChangeAddressToken , ?PrettyServiceChangeAddressToken). +-define(ServiceChangeIncompleteToken , ?PrettyServiceChangeIncompleteToken). +-define(SignalListToken , ?PrettySignalListToken). +-define(SignalsToken , ?PrettySignalsToken). +-define(SignalTypeToken , ?PrettySignalTypeToken). +-define(StatsToken , ?PrettyStatsToken). +-define(StreamToken , ?PrettyStreamToken). +-define(SubtractToken , ?PrettySubtractToken). +-define(SynchISDNToken , ?PrettySynchISDNToken). +-define(TerminationStateToken , ?PrettyTerminationStateToken). +-define(TestToken , ?PrettyTestToken). +-define(TimeOutToken , ?PrettyTimeOutToken). +-define(TopologyToken , ?PrettyTopologyToken). +-define(TransToken , ?PrettyTransToken). +-define(V18Token , ?PrettyV18Token). +-define(V22Token , ?PrettyV22Token). +-define(V22bisToken , ?PrettyV22bisToken). +-define(V32Token , ?PrettyV32Token). +-define(V32bisToken , ?PrettyV32bisToken). +-define(V34Token , ?PrettyV34Token). +-define(V76Token , ?PrettyV76Token). +-define(V90Token , ?PrettyV90Token). +-define(V91Token , ?PrettyV91Token). +-define(VersionToken , ?PrettyVersionToken). + +%%---------------------------------------------------------------------- +%% Include the generator code +%%---------------------------------------------------------------------- + +-include("megaco_text_gen_prev3c.hrl"). + +%% start() -> +%% Fun = fun() -> +%% Val = lists:flatten([$", $e, $r, $i, $c, $s, $s, $o, $n, $"]), +%% %% Val = [$e, $r, $i, $c, $s, $s, $o, $n], +%% PP = {'PropertyParm',"ipdc/realm",[Val],asn1_NOVALUE}, +%% enc_PropertyParm(PP, []) +%% end, +%% test(Fun). + +%% start() -> +%% Fun = fun() -> +%% PP = {'PropertyParm',"ipdc/realm",["ericsson"],asn1_NOVALUE}, +%% enc_PropertyParm(PP, []) +%% end, +%% test(Fun). + +test(Fun) when is_function(Fun) -> + Fun(). + diff --git a/lib/megaco/src/text/megaco_pretty_text_encoder_v1.erl b/lib/megaco/src/text/megaco_pretty_text_encoder_v1.erl new file mode 100644 index 0000000000..6f65bc7337 --- /dev/null +++ b/lib/megaco/src/text/megaco_pretty_text_encoder_v1.erl @@ -0,0 +1,407 @@ +%% +%% %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 PRETTY Megaco/H.248 text messages from internal form +%%---------------------------------------------------------------------- + +-module(megaco_pretty_text_encoder_v1). + +-export([encode_message/2, + encode_transaction/2, + encode_action_requests/2, + encode_action_request/2, + encode_command_request/2, + encode_action_reply/2]). + +-export([token_tag2string/1]). + + +-include_lib("megaco/include/megaco.hrl"). +-include_lib("megaco/include/megaco_message_v1.hrl"). +-define(encoder_version_pre_prev3c,true). +-include("megaco_text_tokens.hrl"). + + +%%---------------------------------------------------------------------- +%% Convert a 'MegacoMessage' record into a binary +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- + +encode_message(EC, MegaMsg) + when is_list(EC) andalso is_record(MegaMsg, 'MegacoMessage') -> + case (catch enc_MegacoMessage(MegaMsg)) of + {'EXIT', Reason} -> + {error, Reason}; + Bin when is_binary(Bin) -> + {ok, Bin}; + DeepIoList -> + Bin = erlang:list_to_binary(DeepIoList), + {ok, Bin} + end; +encode_message(EC, MegaMsg) + when is_record(MegaMsg, 'MegacoMessage') -> + {error, {bad_encoding_config, EC}}; +encode_message(_EC, _MegaMsg) -> + {error, bad_megaco_message}. + + +%%---------------------------------------------------------------------- +%% Convert a transaction record into a deep io list +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- +encode_transaction(_EC, Trans) -> + case (catch enc_Transaction(Trans)) of + {'EXIT', Reason} -> + {error, Reason}; + Bin when is_binary(Bin) -> + {ok, Bin}; + DeepIoList -> + Bin = erlang:list_to_binary(DeepIoList), + {ok, Bin} + end. + +%%---------------------------------------------------------------------- +%% Convert a list of ActionRequest record's into a binary +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- +encode_action_requests(_EC, ActReqs) when is_list(ActReqs) -> + case (catch enc_ActionRequests(ActReqs)) of + {'EXIT', Reason} -> + {error, Reason}; + Bin when is_binary(Bin) -> + {ok, Bin}; + DeepIoList -> + Bin = erlang:list_to_binary(DeepIoList), + {ok, Bin} + end. + +%%---------------------------------------------------------------------- +%% Convert a ActionRequest record into a binary +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- +encode_action_request(_EC, ActReq) + when is_record(ActReq, 'ActionRequest') -> + case (catch enc_ActionRequest(ActReq)) of + {'EXIT', Reason} -> + {error, Reason}; + Bin when is_binary(Bin) -> + {ok, Bin}; + DeepIoList -> + Bin = erlang:list_to_binary(DeepIoList), + {ok, Bin} + end. + +%%---------------------------------------------------------------------- +%% Convert a CommandRequest record into a binary +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- +encode_command_request(_EC, CmdReq) + when is_record(CmdReq, 'CommandRequest') -> + case (catch enc_CommandRequest(CmdReq)) of + {'EXIT', Reason} -> + {error, Reason}; + Bin when is_binary(Bin) -> + {ok, Bin}; + DeepIoList -> + Bin = erlang:list_to_binary(DeepIoList), + {ok, Bin} + end. + +%%---------------------------------------------------------------------- +%% Convert a action reply into a deep io list +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- +encode_action_reply(_EC, ActRep) + when is_record(ActRep, 'ActionReply') -> + case (catch enc_ActionReply(ActRep)) of + {'EXIT', Reason} -> + {error, Reason}; + Bin when is_binary(Bin) -> + {ok, Bin}; + DeepIoList -> + Bin = erlang:list_to_binary(DeepIoList), + {ok, Bin} + end. + + +%%---------------------------------------------------------------------- +%% A utility function to pretty print the tags found in a megaco message +%%---------------------------------------------------------------------- + +token_tag2string(addReq) -> ?PrettyAddToken; +token_tag2string(addReply) -> ?PrettyAddToken; +token_tag2string(auditDescriptor) -> ?PrettyAuditToken; +token_tag2string(auditCapRequest) -> ?PrettyAuditCapToken; +token_tag2string(auditCapReply) -> ?PrettyAuditCapToken; +token_tag2string(auditValueRequest) -> ?PrettyAuditValueToken; +token_tag2string(auditValueReply) -> ?PrettyAuditValueToken; +%% token_tag2string(X) -> ?PrettyAuthToken; +token_tag2string(bothway) -> ?PrettyBothwayToken; +token_tag2string(brief) -> ?PrettyBriefToken; +%% token_tag2string(X) -> ?PrettyBufferToken; +%% token_tag2string(X) -> ?PrettyCtxToken; +%% token_tag2string(X) -> ?PrettyContextAuditToken; +token_tag2string(digitMapDescriptor) -> ?PrettyDigitMapToken; +token_tag2string(digitMapToken) -> ?PrettyDigitMapToken; +%% token_tag2string(X) -> ?PrettyDiscardToken; +%% token_tag2string(X) -> ?PrettyDisconnectedToken; +%% token_tag2string(X) -> ?PrettyDelayToken; +token_tag2string(duration) -> ?PrettyDurationToken; +%% token_tag2string(X) -> ?PrettyEmbedToken; +token_tag2string(emergencyAudit) -> ?PrettyEmergencyToken; +token_tag2string(errorDescriptor) -> ?PrettyErrorToken; +token_tag2string(eventBufferDescriptor) -> ?PrettyEventBufferToken; +token_tag2string(eventBufferToken) -> ?PrettyEventBufferToken; +token_tag2string(eventsDescriptor) -> ?PrettyEventsToken; +token_tag2string(eventsToken) -> ?PrettyEventsToken; +%% token_tag2string(X) -> ?PrettyFailoverToken; +%% token_tag2string(X) -> ?PrettyForcedToken; +%% token_tag2string(X) -> ?PrettyGracefulToken; +%% token_tag2string(X) -> ?PrettyH221Token; +%% token_tag2string(X) -> ?PrettyH223Token; +%% token_tag2string(X) -> ?PrettyH226Token; +%% token_tag2string(X) -> ?PrettyHandOffToken; +%% token_tag2string(X) -> ?PrettyImmAckRequiredToken; +token_tag2string(inactive) -> ?PrettyInactiveToken; +token_tag2string(onInterruptByEvent) -> ?PrettyInterruptByEventToken; +token_tag2string(onInterruptByNewSignalDescr) -> ?PrettyInterruptByNewSignalsDescrToken; +token_tag2string(isolate) -> ?PrettyIsolateToken; +token_tag2string(inSvc) -> ?PrettyInSvcToken; +token_tag2string(keepActive) -> ?PrettyKeepActiveToken; +token_tag2string(localDescriptor) -> ?PrettyLocalToken; +token_tag2string(localControlDescriptor) -> ?PrettyLocalControlToken; +token_tag2string(lockStep) -> ?PrettyLockStepToken; +token_tag2string(loopBack) -> ?PrettyLoopbackToken; +token_tag2string(mediaDescriptor) -> ?PrettyMediaToken; +token_tag2string(mediaToken) -> ?PrettyMediaToken; +%% token_tag2string(X) -> ?PrettyMegacopToken; +%% token_tag2string(X) -> ?PrettyMethodToken; +%% token_tag2string(X) -> ?PrettyMgcIdToken; +%% token_tag2string(X) -> ?PrettyModeToken; +token_tag2string(modReq) -> ?PrettyModifyToken; +token_tag2string(modReply) -> ?PrettyModifyToken; +token_tag2string(modemDescriptor) -> ?PrettyModemToken; +token_tag2string(modemToken) -> ?PrettyModemToken; +token_tag2string(moveReq) -> ?PrettyMoveToken; +token_tag2string(moveReply) -> ?PrettyMoveToken; +%% token_tag2string(X) -> ?PrettyMtpToken; +token_tag2string(muxDescriptor) -> ?PrettyMuxToken; +token_tag2string(muxToken) -> ?PrettyMuxToken; +token_tag2string(notifyReq) -> ?PrettyNotifyToken; +%% token_tag2string(X) -> ?PrettyNotifyCompletionToken; +token_tag2string(observedEventsDescriptor) -> ?PrettyObservedEventsToken; +token_tag2string(observedEventsToken) -> ?PrettyObservedEventsToken; +token_tag2string(false) -> ?PrettyOffToken; +token_tag2string(off) -> ?PrettyOffToken; +token_tag2string(oneway) -> ?PrettyOnewayToken; +token_tag2string(onOff) -> ?PrettyOnOffToken; +token_tag2string(true) -> ?PrettyOnToken; +token_tag2string(otherReason) -> ?PrettyOtherReasonToken; +token_tag2string(outOfSvc) -> ?PrettyOutOfSvcToken; +token_tag2string(packagesDescriptor) -> ?PrettyPackagesToken; +token_tag2string(packagesToken) -> ?PrettyPackagesToken; +%% token_tag2string(X) -> ?PrettyPendingToken; +token_tag2string(priorityAudit) -> ?PrettyPriorityToken; +%% token_tag2string(X) -> ?PrettyProfileToken; +%% token_tag2string(X) -> ?PrettyReasonToken; +token_tag2string(recvOnly) -> ?PrettyRecvonlyToken; +%% token_tag2string(X) -> ?PrettyReplyToken; +%% token_tag2string(X) -> ?PrettyResponseAckToken; +%% token_tag2string(X) -> ?PrettyRestartToken; +token_tag2string(remoteDescriptor) -> ?PrettyRemoteToken; +%% token_tag2string(X) -> ?PrettyReservedGroupToken; +%% token_tag2string(X) -> ?PrettyReservedValueToken; +token_tag2string(sendOnly) -> ?PrettySendonlyToken; +token_tag2string(sendRecv) -> ?PrettySendrecvToken; +%% token_tag2string(X) -> ?PrettyServicesToken; +%% token_tag2string(X) -> ?PrettyServiceStatesToken; +token_tag2string(serviceChangeReq) -> ?PrettyServiceChangeToken; +%% token_tag2string(X) -> ?PrettyServiceChangeAddressToken; +%% token_tag2string(X) -> ?PrettySignalListToken; +token_tag2string(signalsDescriptor) -> ?PrettySignalsToken; +token_tag2string(signalsToken) -> ?PrettySignalsToken; +%% token_tag2string(X) -> ?PrettySignalTypeToken; +token_tag2string(statisticsDescriptor) -> ?PrettyStatsToken; +token_tag2string(statsToken) -> ?PrettyStatsToken; +%% token_tag2string(X) -> ?PrettyStreamToken; +token_tag2string(subtractReq) -> ?PrettySubtractToken; +token_tag2string(subtractReply) -> ?PrettySubtractToken; +%% token_tag2string(X) -> ?PrettySynchISDNToken; +%% token_tag2string(X) -> ?PrettyTerminationStateToken; +token_tag2string(test) -> ?PrettyTestToken; +token_tag2string(timeOut) -> ?PrettyTimeOutToken; +token_tag2string(onTimeOut) -> ?PrettyTimeOutToken; +token_tag2string(topologyAudit) -> ?PrettyTopologyToken; +%% token_tag2string(X) -> ?PrettyTransToken; +%% token_tag2string(X) -> ?PrettyV18Token; +%% token_tag2string(X) -> ?PrettyV22Token; +%% token_tag2string(X) -> ?PrettyV22bisToken; +%% token_tag2string(X) -> ?PrettyV32Token; +%% token_tag2string(X) -> ?PrettyV32bisToken; +%% token_tag2string(X) -> ?PrettyV34Token; +%% token_tag2string(X) -> ?PrettyV76Token; +%% token_tag2string(X) -> ?PrettyV90Token; +%% token_tag2string(X) -> ?PrettyV91Token; +%% token_tag2string(X) -> ?PrettyVersionToken; +token_tag2string(_) -> []. + + +%%---------------------------------------------------------------------- +%% Define various macros used by the actual generator code +%%---------------------------------------------------------------------- + +-define(EQUAL, [?SpToken, ?EqualToken, ?SpToken]). +-define(COLON, [?ColonToken]). +-define(LBRKT, [?SpToken, ?LbrktToken, ?SpToken]). +-define(RBRKT, [?SpToken, ?RbrktToken, ?SpToken]). +-define(LSBRKT, [?LsbrktToken]). +-define(RSBRKT, [?RsbrktToken]). +-define(COMMA, [?CommaToken, ?SpToken]). +-define(DOT, [?DotToken]). +-define(SLASH, [?SlashToken]). +-define(DQUOTE, [?DoubleQuoteToken]). +-define(SP, [?SpToken]). +-define(HTAB, [?HtabToken]). +-define(CR, [?CrToken]). +-define(LF, [?LfToken]). +-define(LWSP, []). +-define(EOL, ?LF). +-define(WSP, ?SP). +-define(SEP, ?WSP). + +-define(INIT_INDENT, []). +-define(INC_INDENT(State), [?HtabToken | State]). +-define(INDENT(State), [?LfToken | State]). +-define(LBRKT_INDENT(State), [?SpToken, ?LbrktToken, ?INDENT(?INC_INDENT(State))]). +-define(RBRKT_INDENT(State), [?INDENT(State), ?RbrktToken]). +-define(COMMA_INDENT(State), [?CommaToken, ?INDENT(State)]). +-define(SEP_INDENT(_State), [?LfToken]). + +%%---------------------------------------------------------------------- +%% Define token macros +%%---------------------------------------------------------------------- + +-define(AddToken , ?PrettyAddToken). +-define(AuditToken , ?PrettyAuditToken). +-define(AuditCapToken , ?PrettyAuditCapToken). +-define(AuditValueToken , ?PrettyAuditValueToken). +-define(AuthToken , ?PrettyAuthToken). +-define(BothwayToken , ?PrettyBothwayToken). +-define(BriefToken , ?PrettyBriefToken). +-define(BufferToken , ?PrettyBufferToken). +-define(CtxToken , ?PrettyCtxToken). +-define(ContextAuditToken , ?PrettyContextAuditToken). +-define(DigitMapToken , ?PrettyDigitMapToken). +-define(DiscardToken , ?PrettyDiscardToken). +-define(DisconnectedToken , ?PrettyDisconnectedToken). +-define(DelayToken , ?PrettyDelayToken). +-define(DeleteToken , ?PrettyDeleteToken). +-define(DurationToken , ?PrettyDurationToken). +-define(EmbedToken , ?PrettyEmbedToken). +-define(EmergencyToken , ?PrettyEmergencyToken). +-define(ErrorToken , ?PrettyErrorToken). +-define(EventBufferToken , ?PrettyEventBufferToken). +-define(EventsToken , ?PrettyEventsToken). +-define(FailoverToken , ?PrettyFailoverToken). +-define(ForcedToken , ?PrettyForcedToken). +-define(GracefulToken , ?PrettyGracefulToken). +-define(H221Token , ?PrettyH221Token). +-define(H223Token , ?PrettyH223Token). +-define(H226Token , ?PrettyH226Token). +-define(HandOffToken , ?PrettyHandOffToken). +-define(ImmAckRequiredToken , ?PrettyImmAckRequiredToken). +-define(InactiveToken , ?PrettyInactiveToken). +-define(IsolateToken , ?PrettyIsolateToken). +-define(InSvcToken , ?PrettyInSvcToken). +-define(InterruptByEventToken , ?PrettyInterruptByEventToken). +-define(InterruptByNewSignalsDescrToken, ?PrettyInterruptByNewSignalsDescrToken). +-define(KeepActiveToken , ?PrettyKeepActiveToken). +-define(LocalToken , ?PrettyLocalToken). +-define(LocalControlToken , ?PrettyLocalControlToken). +-define(LockStepToken , ?PrettyLockStepToken). +-define(LoopbackToken , ?PrettyLoopbackToken). +-define(MediaToken , ?PrettyMediaToken). +-define(MegacopToken , ?PrettyMegacopToken). +-define(MethodToken , ?PrettyMethodToken). +-define(MgcIdToken , ?PrettyMgcIdToken). +-define(ModeToken , ?PrettyModeToken). +-define(ModifyToken , ?PrettyModifyToken). +-define(ModemToken , ?PrettyModemToken). +-define(MoveToken , ?PrettyMoveToken). +-define(MtpToken , ?PrettyMtpToken). +-define(MuxToken , ?PrettyMuxToken). +-define(NotifyToken , ?PrettyNotifyToken). +-define(NotifyCompletionToken , ?PrettyNotifyCompletionToken). +-define(Nx64kToken , ?PrettyNx64kToken). +-define(ObservedEventsToken , ?PrettyObservedEventsToken). +-define(OffToken , ?PrettyOffToken). +-define(OnewayToken , ?PrettyOnewayToken). +-define(OnOffToken , ?PrettyOnOffToken). +-define(OnToken , ?PrettyOnToken). +-define(OtherReasonToken , ?PrettyOtherReasonToken). +-define(OutOfSvcToken , ?PrettyOutOfSvcToken). +-define(PackagesToken , ?PrettyPackagesToken). +-define(PendingToken , ?PrettyPendingToken). +-define(PriorityToken , ?PrettyPriorityToken). +-define(ProfileToken , ?PrettyProfileToken). +-define(ReasonToken , ?PrettyReasonToken). +-define(RecvonlyToken , ?PrettyRecvonlyToken). +-define(ReplyToken , ?PrettyReplyToken). +-define(ResponseAckToken , ?PrettyResponseAckToken). +-define(RestartToken , ?PrettyRestartToken). +-define(RemoteToken , ?PrettyRemoteToken). +-define(ReservedGroupToken , ?PrettyReservedGroupToken). +-define(ReservedValueToken , ?PrettyReservedValueToken). +-define(SendonlyToken , ?PrettySendonlyToken). +-define(SendrecvToken , ?PrettySendrecvToken). +-define(ServicesToken , ?PrettyServicesToken). +-define(ServiceStatesToken , ?PrettyServiceStatesToken). +-define(ServiceChangeToken , ?PrettyServiceChangeToken). +-define(ServiceChangeAddressToken , ?PrettyServiceChangeAddressToken). +-define(SignalListToken , ?PrettySignalListToken). +-define(SignalsToken , ?PrettySignalsToken). +-define(SignalTypeToken , ?PrettySignalTypeToken). +-define(StatsToken , ?PrettyStatsToken). +-define(StreamToken , ?PrettyStreamToken). +-define(SubtractToken , ?PrettySubtractToken). +-define(SynchISDNToken , ?PrettySynchISDNToken). +-define(TerminationStateToken , ?PrettyTerminationStateToken). +-define(TestToken , ?PrettyTestToken). +-define(TimeOutToken , ?PrettyTimeOutToken). +-define(TopologyToken , ?PrettyTopologyToken). +-define(TransToken , ?PrettyTransToken). +-define(V18Token , ?PrettyV18Token). +-define(V22Token , ?PrettyV22Token). +-define(V22bisToken , ?PrettyV22bisToken). +-define(V32Token , ?PrettyV32Token). +-define(V32bisToken , ?PrettyV32bisToken). +-define(V34Token , ?PrettyV34Token). +-define(V76Token , ?PrettyV76Token). +-define(V90Token , ?PrettyV90Token). +-define(V91Token , ?PrettyV91Token). +-define(VersionToken , ?PrettyVersionToken). + +%%---------------------------------------------------------------------- +%% Include the generator code +%%---------------------------------------------------------------------- + +-include("megaco_text_gen_v1.hrl"). + diff --git a/lib/megaco/src/text/megaco_pretty_text_encoder_v2.erl b/lib/megaco/src/text/megaco_pretty_text_encoder_v2.erl new file mode 100644 index 0000000000..37c067b937 --- /dev/null +++ b/lib/megaco/src/text/megaco_pretty_text_encoder_v2.erl @@ -0,0 +1,430 @@ +%% +%% %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 PRETTY Megaco/H.248 text messages from internal form +%%---------------------------------------------------------------------- + +-module(megaco_pretty_text_encoder_v2). + +-export([encode_message/2, + encode_transaction/2, + encode_action_requests/2, + encode_action_request/2, + encode_command_request/2, + encode_action_reply/2]). + +-export([token_tag2string/1]). + +-export([test/1]). + +-include_lib("megaco/include/megaco.hrl"). +-include_lib("megaco/include/megaco_message_v2.hrl"). +-define(encoder_version_pre_prev3c,true). +-include("megaco_text_tokens.hrl"). + + +%%---------------------------------------------------------------------- +%% Convert a 'MegacoMessage' record into a binary +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- + +encode_message(EC, MegaMsg) + when is_list(EC) andalso is_record(MegaMsg, 'MegacoMessage') -> + case (catch enc_MegacoMessage(MegaMsg)) of + {'EXIT', Reason} -> + {error, Reason}; + Bin when is_binary(Bin) -> + {ok, Bin}; + DeepIoList -> + Bin = erlang:list_to_binary(DeepIoList), + {ok, Bin} + end; +encode_message(EncodingConfig, MegaMsg) + when is_record(MegaMsg, 'MegacoMessage') -> + {error, {bad_encoding_config, EncodingConfig}}; +encode_message(_EncodingConfig, _MegaMsg) -> + {error, bad_megaco_message}. + + +%%---------------------------------------------------------------------- +%% Convert a binary into a 'MegacoMessage' record +%% Return {ok, MegacoMessageRecord} | {error, Reason} +%% +%% See megaco_pretty_text_encoder:decode_message/2 +%% +%%---------------------------------------------------------------------- + + +%%---------------------------------------------------------------------- +%% Convert a transaction record into a deep io list +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- +encode_transaction(_EC, Trans) -> + case (catch enc_Transaction(Trans)) of + {'EXIT', Reason} -> + {error, Reason}; + Bin when is_binary(Bin) -> + {ok, Bin}; + DeepIoList -> + Bin = erlang:list_to_binary(DeepIoList), + {ok, Bin} + end. + +%%---------------------------------------------------------------------- +%% Convert a list of ActionRequest record's into a binary +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- +encode_action_requests(_EC, ActReqs) when is_list(ActReqs) -> + case (catch enc_ActionRequests(ActReqs)) of + {'EXIT', Reason} -> + {error, Reason}; + Bin when is_binary(Bin) -> + {ok, Bin}; + DeepIoList -> + Bin = erlang:list_to_binary(DeepIoList), + {ok, Bin} + end. + +%%---------------------------------------------------------------------- +%% Convert a ActionRequest record into a binary +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- +encode_action_request(_EC, ActReq) + when is_record(ActReq, 'ActionRequest') -> + case (catch enc_ActionRequest(ActReq)) of + {'EXIT', Reason} -> + {error, Reason}; + Bin when is_binary(Bin) -> + {ok, Bin}; + DeepIoList -> + Bin = erlang:list_to_binary(DeepIoList), + {ok, Bin} + end. + +%%---------------------------------------------------------------------- +%% Convert a CommandRequest record into a deep io list +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- +encode_command_request(_EC, CmdReq) + when is_record(CmdReq, 'CommandRequest') -> + case (catch enc_CommandRequest(CmdReq)) of + {'EXIT', Reason} -> + {error, Reason}; + Bin when is_binary(Bin) -> + {ok, Bin}; + DeepIoList -> + Bin = erlang:list_to_binary(DeepIoList), + {ok, Bin} + end. + +%%---------------------------------------------------------------------- +%% Convert a action reply into a deep io list +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- +encode_action_reply(_EC, ActRep) + when is_record(ActRep, 'ActionReply') -> + case (catch enc_ActionReply(ActRep)) of + {'EXIT', Reason} -> + {error, Reason}; + Bin when is_binary(Bin) -> + {ok, Bin}; + DeepIoList -> + Bin = erlang:list_to_binary(DeepIoList), + {ok, Bin} + end. + + +%%---------------------------------------------------------------------- +%% A utility function to pretty print the tags found in a megaco message +%%---------------------------------------------------------------------- + +token_tag2string(addReq) -> ?PrettyAddToken; +token_tag2string(addReply) -> ?PrettyAddToken; +token_tag2string(auditDescriptor) -> ?PrettyAuditToken; +token_tag2string(auditCapRequest) -> ?PrettyAuditCapToken; +token_tag2string(auditCapReply) -> ?PrettyAuditCapToken; +token_tag2string(auditValueRequest) -> ?PrettyAuditValueToken; +token_tag2string(auditValueReply) -> ?PrettyAuditValueToken; +%% token_tag2string(X) -> ?PrettyAuthToken; +token_tag2string(bothway) -> ?PrettyBothwayToken; +token_tag2string(brief) -> ?PrettyBriefToken; +%% token_tag2string(X) -> ?PrettyBufferToken; +%% token_tag2string(X) -> ?PrettyCtxToken; +%% token_tag2string(X) -> ?PrettyContextAuditToken; +token_tag2string(digitMapDescriptor) -> ?PrettyDigitMapToken; +token_tag2string(digitMapToken) -> ?PrettyDigitMapToken; +%% token_tag2string(X) -> ?PrettyDiscardToken; +%% token_tag2string(X) -> ?PrettyDisconnectedToken; +%% token_tag2string(X) -> ?PrettyDelayToken; +token_tag2string(duration) -> ?PrettyDurationToken; +%% token_tag2string(X) -> ?PrettyEmbedToken; +token_tag2string(emergencyAudit) -> ?PrettyEmergencyToken; +%% token_tag2string(X) -> ?PrettyEmergencyOffToken; +token_tag2string(errorDescriptor) -> ?PrettyErrorToken; +token_tag2string(eventBufferDescriptor) -> ?PrettyEventBufferToken; +token_tag2string(eventBufferToken) -> ?PrettyEventBufferToken; +token_tag2string(eventsDescriptor) -> ?PrettyEventsToken; +token_tag2string(eventsToken) -> ?PrettyEventsToken; +%% token_tag2string(X) -> ?PrettyFailoverToken; +%% token_tag2string(X) -> ?PrettyForcedToken; +%% token_tag2string(X) -> ?PrettyGracefulToken; +%% token_tag2string(X) -> ?PrettyH221Token; +%% token_tag2string(X) -> ?PrettyH223Token; +%% token_tag2string(X) -> ?PrettyH226Token; +%% token_tag2string(X) -> ?PrettyHandOffToken; +%% token_tag2string(X) -> ?PrettyImmAckRequiredToken; +token_tag2string(inactive) -> ?PrettyInactiveToken; +token_tag2string(onInterruptByEvent) -> ?PrettyInterruptByEventToken; +token_tag2string(onInterruptByNewSignalDescr) -> ?PrettyInterruptByNewSignalsDescrToken; +token_tag2string(isolate) -> ?PrettyIsolateToken; +token_tag2string(inSvc) -> ?PrettyInSvcToken; +token_tag2string(keepActive) -> ?PrettyKeepActiveToken; +token_tag2string(localDescriptor) -> ?PrettyLocalToken; +token_tag2string(localControlDescriptor) -> ?PrettyLocalControlToken; +token_tag2string(lockStep) -> ?PrettyLockStepToken; +token_tag2string(loopBack) -> ?PrettyLoopbackToken; +token_tag2string(mediaDescriptor) -> ?PrettyMediaToken; +token_tag2string(mediaToken) -> ?PrettyMediaToken; +%% token_tag2string(X) -> ?PrettyMegacopToken; +%% token_tag2string(X) -> ?PrettyMethodToken; +%% token_tag2string(X) -> ?PrettyMgcIdToken; +%% token_tag2string(X) -> ?PrettyModeToken; +token_tag2string(modReq) -> ?PrettyModifyToken; +token_tag2string(modReply) -> ?PrettyModifyToken; +token_tag2string(modemDescriptor) -> ?PrettyModemToken; +token_tag2string(modemToken) -> ?PrettyModemToken; +token_tag2string(moveReq) -> ?PrettyMoveToken; +token_tag2string(moveReply) -> ?PrettyMoveToken; +%% token_tag2string(X) -> ?PrettyMtpToken; +token_tag2string(muxDescriptor) -> ?PrettyMuxToken; +token_tag2string(muxToken) -> ?PrettyMuxToken; +token_tag2string(notifyReq) -> ?PrettyNotifyToken; +%% token_tag2string(X) -> ?PrettyNotifyCompletionToken; +%% token_tag2string(X) -> ?PrettyNx64kToken; +token_tag2string(observedEventsDescriptor) -> ?PrettyObservedEventsToken; +token_tag2string(observedEventsToken) -> ?PrettyObservedEventsToken; +token_tag2string(false) -> ?PrettyOffToken; +token_tag2string(off) -> ?PrettyOffToken; +token_tag2string(oneway) -> ?PrettyOnewayToken; +token_tag2string(onOff) -> ?PrettyOnOffToken; +token_tag2string(true) -> ?PrettyOnToken; +token_tag2string(otherReason) -> ?PrettyOtherReasonToken; +token_tag2string(outOfSvc) -> ?PrettyOutOfSvcToken; +token_tag2string(packagesDescriptor) -> ?PrettyPackagesToken; +token_tag2string(packagesToken) -> ?PrettyPackagesToken; +%% token_tag2string(X) -> ?PrettyPendingToken; +token_tag2string(priorityAudit) -> ?PrettyPriorityToken; +%% token_tag2string(X) -> ?PrettyProfileToken; +%% token_tag2string(X) -> ?PrettyReasonToken; +token_tag2string(recvOnly) -> ?PrettyRecvonlyToken; +%% token_tag2string(X) -> ?PrettyReplyToken; +%% token_tag2string(X) -> ?PrettyResponseAckToken; +%% token_tag2string(X) -> ?PrettyRestartToken; +token_tag2string(remoteDescriptor) -> ?PrettyRemoteToken; +%% token_tag2string(X) -> ?PrettyReservedGroupToken; +%% token_tag2string(X) -> ?PrettyReservedValueToken; +token_tag2string(sendOnly) -> ?PrettySendonlyToken; +token_tag2string(sendRecv) -> ?PrettySendrecvToken; +%% token_tag2string(X) -> ?PrettyServicesToken; +%% token_tag2string(X) -> ?PrettyServiceStatesToken; +token_tag2string(serviceChangeReq) -> ?PrettyServiceChangeToken; +%% token_tag2string(X) -> ?PrettyServiceChangeAddressToken; +%% token_tag2string(X) -> ?PrettySignalListToken; +token_tag2string(signalsDescriptor) -> ?PrettySignalsToken; +token_tag2string(signalsToken) -> ?PrettySignalsToken; +%% token_tag2string(X) -> ?PrettySignalTypeToken; +token_tag2string(statisticsDescriptor) -> ?PrettyStatsToken; +token_tag2string(statsToken) -> ?PrettyStatsToken; +%% token_tag2string(X) -> ?PrettyStreamToken; +token_tag2string(subtractReq) -> ?PrettySubtractToken; +token_tag2string(subtractReply) -> ?PrettySubtractToken; +%% token_tag2string(X) -> ?PrettySynchISDNToken; +%% token_tag2string(X) -> ?PrettyTerminationStateToken; +token_tag2string(test) -> ?PrettyTestToken; +token_tag2string(timeOut) -> ?PrettyTimeOutToken; +token_tag2string(onTimeOut) -> ?PrettyTimeOutToken; +token_tag2string(topologyAudit) -> ?PrettyTopologyToken; +%% token_tag2string(X) -> ?PrettyTransToken; +%% token_tag2string(X) -> ?PrettyV18Token; +%% token_tag2string(X) -> ?PrettyV22Token; +%% token_tag2string(X) -> ?PrettyV22bisToken; +%% token_tag2string(X) -> ?PrettyV32Token; +%% token_tag2string(X) -> ?PrettyV32bisToken; +%% token_tag2string(X) -> ?PrettyV34Token; +%% token_tag2string(X) -> ?PrettyV76Token; +%% token_tag2string(X) -> ?PrettyV90Token; +%% token_tag2string(X) -> ?PrettyV91Token; +%% token_tag2string(X) -> ?PrettyVersionToken; +token_tag2string(_) -> []. + + +%%---------------------------------------------------------------------- +%% Define various macros used by the actual generator code +%%---------------------------------------------------------------------- + +-define(EQUAL, [?SpToken, ?EqualToken, ?SpToken]). +-define(COLON, [?ColonToken]). +-define(LBRKT, [?SpToken, ?LbrktToken, ?SpToken]). +-define(RBRKT, [?SpToken, ?RbrktToken, ?SpToken]). +-define(LSBRKT, [?LsbrktToken]). +-define(RSBRKT, [?RsbrktToken]). +-define(COMMA, [?CommaToken, ?SpToken]). +-define(DOT, [?DotToken]). +-define(SLASH, [?SlashToken]). +-define(DQUOTE, [?DoubleQuoteToken]). +-define(SP, [?SpToken]). +-define(HTAB, [?HtabToken]). +-define(CR, [?CrToken]). +-define(LF, [?LfToken]). +-define(LWSP, []). +-define(EOL, ?LF). +-define(WSP, ?SP). +-define(SEP, ?WSP). + +-define(INIT_INDENT, []). +-define(INC_INDENT(State), [?HtabToken | State]). +-define(INDENT(State), [?LfToken | State]). +-define(LBRKT_INDENT(State), [?SpToken, ?LbrktToken, ?INDENT(?INC_INDENT(State))]). +-define(RBRKT_INDENT(State), [?INDENT(State), ?RbrktToken]). +-define(COMMA_INDENT(State), [?CommaToken, ?INDENT(State)]). +-define(SEP_INDENT(_State), [?LfToken]). + +%%---------------------------------------------------------------------- +%% Define token macros +%%---------------------------------------------------------------------- + +-define(AddToken , ?PrettyAddToken). +-define(AuditToken , ?PrettyAuditToken). +-define(AuditCapToken , ?PrettyAuditCapToken). +-define(AuditValueToken , ?PrettyAuditValueToken). +-define(AuthToken , ?PrettyAuthToken). +-define(BothwayToken , ?PrettyBothwayToken). +-define(BriefToken , ?PrettyBriefToken). +-define(BufferToken , ?PrettyBufferToken). +-define(CtxToken , ?PrettyCtxToken). +-define(ContextAuditToken , ?PrettyContextAuditToken). +-define(DigitMapToken , ?PrettyDigitMapToken). +-define(DiscardToken , ?PrettyDiscardToken). +-define(DisconnectedToken , ?PrettyDisconnectedToken). +-define(DelayToken , ?PrettyDelayToken). +-define(DeleteToken , ?PrettyDeleteToken). +-define(DurationToken , ?PrettyDurationToken). +-define(EmbedToken , ?PrettyEmbedToken). +-define(EmergencyToken , ?PrettyEmergencyToken). +-define(EmergencyOffToken , ?PrettyEmergencyOffToken). +-define(ErrorToken , ?PrettyErrorToken). +-define(EventBufferToken , ?PrettyEventBufferToken). +-define(EventsToken , ?PrettyEventsToken). +-define(FailoverToken , ?PrettyFailoverToken). +-define(ForcedToken , ?PrettyForcedToken). +-define(GracefulToken , ?PrettyGracefulToken). +-define(H221Token , ?PrettyH221Token). +-define(H223Token , ?PrettyH223Token). +-define(H226Token , ?PrettyH226Token). +-define(HandOffToken , ?PrettyHandOffToken). +-define(ImmAckRequiredToken , ?PrettyImmAckRequiredToken). +-define(InactiveToken , ?PrettyInactiveToken). +-define(IsolateToken , ?PrettyIsolateToken). +-define(InSvcToken , ?PrettyInSvcToken). +-define(InterruptByEventToken , ?PrettyInterruptByEventToken). +-define(InterruptByNewSignalsDescrToken, ?PrettyInterruptByNewSignalsDescrToken). +-define(KeepActiveToken , ?PrettyKeepActiveToken). +-define(LocalToken , ?PrettyLocalToken). +-define(LocalControlToken , ?PrettyLocalControlToken). +-define(LockStepToken , ?PrettyLockStepToken). +-define(LoopbackToken , ?PrettyLoopbackToken). +-define(MediaToken , ?PrettyMediaToken). +-define(MegacopToken , ?PrettyMegacopToken). +-define(MethodToken , ?PrettyMethodToken). +-define(MgcIdToken , ?PrettyMgcIdToken). +-define(ModeToken , ?PrettyModeToken). +-define(ModifyToken , ?PrettyModifyToken). +-define(ModemToken , ?PrettyModemToken). +-define(MoveToken , ?PrettyMoveToken). +-define(MtpToken , ?PrettyMtpToken). +-define(MuxToken , ?PrettyMuxToken). +-define(NotifyToken , ?PrettyNotifyToken). +-define(NotifyCompletionToken , ?PrettyNotifyCompletionToken). +-define(Nx64kToken , ?PrettyNx64kToken). +-define(ObservedEventsToken , ?PrettyObservedEventsToken). +-define(OffToken , ?PrettyOffToken). +-define(OnewayToken , ?PrettyOnewayToken). +-define(OnOffToken , ?PrettyOnOffToken). +-define(OnToken , ?PrettyOnToken). +-define(OtherReasonToken , ?PrettyOtherReasonToken). +-define(OutOfSvcToken , ?PrettyOutOfSvcToken). +-define(PackagesToken , ?PrettyPackagesToken). +-define(PendingToken , ?PrettyPendingToken). +-define(PriorityToken , ?PrettyPriorityToken). +-define(ProfileToken , ?PrettyProfileToken). +-define(ReasonToken , ?PrettyReasonToken). +-define(RecvonlyToken , ?PrettyRecvonlyToken). +-define(ReplyToken , ?PrettyReplyToken). +-define(ResponseAckToken , ?PrettyResponseAckToken). +-define(RestartToken , ?PrettyRestartToken). +-define(RemoteToken , ?PrettyRemoteToken). +-define(ReservedGroupToken , ?PrettyReservedGroupToken). +-define(ReservedValueToken , ?PrettyReservedValueToken). +-define(SendonlyToken , ?PrettySendonlyToken). +-define(SendrecvToken , ?PrettySendrecvToken). +-define(ServicesToken , ?PrettyServicesToken). +-define(ServiceStatesToken , ?PrettyServiceStatesToken). +-define(ServiceChangeToken , ?PrettyServiceChangeToken). +-define(ServiceChangeAddressToken , ?PrettyServiceChangeAddressToken). +-define(SignalListToken , ?PrettySignalListToken). +-define(SignalsToken , ?PrettySignalsToken). +-define(SignalTypeToken , ?PrettySignalTypeToken). +-define(StatsToken , ?PrettyStatsToken). +-define(StreamToken , ?PrettyStreamToken). +-define(SubtractToken , ?PrettySubtractToken). +-define(SynchISDNToken , ?PrettySynchISDNToken). +-define(TerminationStateToken , ?PrettyTerminationStateToken). +-define(TestToken , ?PrettyTestToken). +-define(TimeOutToken , ?PrettyTimeOutToken). +-define(TopologyToken , ?PrettyTopologyToken). +-define(TransToken , ?PrettyTransToken). +-define(V18Token , ?PrettyV18Token). +-define(V22Token , ?PrettyV22Token). +-define(V22bisToken , ?PrettyV22bisToken). +-define(V32Token , ?PrettyV32Token). +-define(V32bisToken , ?PrettyV32bisToken). +-define(V34Token , ?PrettyV34Token). +-define(V76Token , ?PrettyV76Token). +-define(V90Token , ?PrettyV90Token). +-define(V91Token , ?PrettyV91Token). +-define(VersionToken , ?PrettyVersionToken). + +%%---------------------------------------------------------------------- +%% Include the generator code +%%---------------------------------------------------------------------- + +-include("megaco_text_gen_v2.hrl"). + +%% start() -> +%% Fun = fun() -> +%% PP = {'PropertyParm',"ipdc/realm",["ericsson"],asn1_NOVALUE}, +%% enc_PropertyParm(PP, []) +%% end, +%% test(Fun). + +test(Fun) when is_function(Fun) -> + Fun(). + diff --git a/lib/megaco/src/text/megaco_pretty_text_encoder_v3.erl b/lib/megaco/src/text/megaco_pretty_text_encoder_v3.erl new file mode 100644 index 0000000000..833b6ea00f --- /dev/null +++ b/lib/megaco/src/text/megaco_pretty_text_encoder_v3.erl @@ -0,0 +1,462 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2005-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 PRETTY Megaco/H.248 text messages from internal form +%%---------------------------------------------------------------------- + +-module(megaco_pretty_text_encoder_v3). + +-export([encode_message/2, + encode_transaction/2, + encode_action_requests/2, + encode_action_request/2, + encode_command_request/2, + encode_action_reply/2]). + +-export([token_tag2string/1]). + + +-include_lib("megaco/include/megaco.hrl"). +-include_lib("megaco/include/megaco_message_v3.hrl"). +-include("megaco_text_tokens.hrl"). + + +%%---------------------------------------------------------------------- +%% Convert a 'MegacoMessage' record into a binary +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- + +encode_message(EC, MegaMsg) + when is_list(EC) andalso is_record(MegaMsg, 'MegacoMessage') -> + case (catch enc_MegacoMessage(MegaMsg)) of + {'EXIT', Reason} -> + {error, Reason}; + Bin when is_binary(Bin) -> + {ok, Bin}; + DeepIoList -> + Bin = erlang:list_to_binary(DeepIoList), + {ok, Bin} + end; +encode_message(EncodingConfig, MegaMsg) + when is_record(MegaMsg, 'MegacoMessage') -> + {error, {bad_encoding_config, EncodingConfig}}; +encode_message(_EncodingConfig, _MegaMsg) -> + {error, bad_megaco_message}. + + +%%---------------------------------------------------------------------- +%% Convert a binary into a 'MegacoMessage' record +%% Return {ok, MegacoMessageRecord} | {error, Reason} +%% +%% See megaco_pretty_text_encoder:decode_message/2 +%% +%%---------------------------------------------------------------------- + + +%%---------------------------------------------------------------------- +%% Convert a transaction record into a deep io list +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- +encode_transaction(_EC, Trans) -> + case (catch enc_Transaction(Trans)) of + {'EXIT', Reason} -> + {error, Reason}; + Bin when is_binary(Bin) -> + {ok, Bin}; + DeepIoList -> + Bin = erlang:list_to_binary(DeepIoList), + {ok, Bin} + end. + +%%---------------------------------------------------------------------- +%% Convert a list of ActionRequest record's into a binary +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- +encode_action_requests(_EC, ActReqs) when is_list(ActReqs) -> + case (catch enc_ActionRequests(ActReqs)) of + {'EXIT', Reason} -> + {error, Reason}; + Bin when is_binary(Bin) -> + {ok, Bin}; + DeepIoList -> + Bin = erlang:list_to_binary(DeepIoList), + {ok, Bin} + end. + +%%---------------------------------------------------------------------- +%% Convert a ActionRequest record into a binary +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- +encode_action_request(_EC, ActReq) + when is_record(ActReq, 'ActionRequest') -> + case (catch enc_ActionRequest(ActReq)) of + {'EXIT', Reason} -> + {error, Reason}; + Bin when is_binary(Bin) -> + {ok, Bin}; + DeepIoList -> + Bin = erlang:list_to_binary(DeepIoList), + {ok, Bin} + end. + +%%---------------------------------------------------------------------- +%% Convert a CommandRequest record into a deep io list +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- +encode_command_request(_EC, CmdReq) + when is_record(CmdReq, 'CommandRequest') -> + case (catch enc_CommandRequest(CmdReq)) of + {'EXIT', Reason} -> + {error, Reason}; + Bin when is_binary(Bin) -> + {ok, Bin}; + DeepIoList -> + Bin = erlang:list_to_binary(DeepIoList), + {ok, Bin} + end. + +%%---------------------------------------------------------------------- +%% Convert a action reply into a deep io list +%% Return {ok, DeepIoList} | {error, Reason} +%%---------------------------------------------------------------------- +encode_action_reply(_EC, ActRep) + when is_record(ActRep, 'ActionReply') -> + case (catch enc_ActionReply(ActRep)) of + {'EXIT', Reason} -> + {error, Reason}; + Bin when is_binary(Bin) -> + {ok, Bin}; + DeepIoList -> + Bin = erlang:list_to_binary(DeepIoList), + {ok, Bin} + end. + + +%%---------------------------------------------------------------------- +%% A utility function to pretty print the tags found in a megaco message +%%---------------------------------------------------------------------- + +token_tag2string(addReq) -> ?CompactAddToken; +token_tag2string(addReply) -> ?CompactAddToken; +%% token_tag2string(X) -> ?CompactAndAUDITSelectToken; +token_tag2string(auditDescriptor) -> ?CompactAuditToken; +token_tag2string(auditCapRequest) -> ?CompactAuditCapToken; +token_tag2string(auditCapReply) -> ?CompactAuditCapToken; +token_tag2string(auditValueRequest) -> ?CompactAuditValueToken; +token_tag2string(auditValueReply) -> ?CompactAuditValueToken; +%% token_tag2string(X) -> ?CompactAuthToken; +token_tag2string(both) -> ?CompactBothToken; +token_tag2string(bothway) -> ?CompactBothwayToken; +token_tag2string(brief) -> ?CompactBriefToken; +%% token_tag2string(X) -> ?CompactBufferToken; +%% token_tag2string(X) -> ?CompactCtxToken; +%% token_tag2string(X) -> ?CompactContextAuditToken; +%% token_tag2string(X) -> ?CompactContextAttrToken; +%% token_tag2string(X) -> ?CompactContextListToken; +token_tag2string(digitMapDescriptor) -> ?CompactDigitMapToken; +token_tag2string(digitMapToken) -> ?CompactDigitMapToken; +%% token_tag2string(X) -> ?CompactDirectionToken; +%% token_tag2string(X) -> ?CompactDiscardToken; +%% token_tag2string(X) -> ?CompactDisconnectedToken; +%% token_tag2string(X) -> ?CompactDelayToken; +token_tag2string(duration) -> ?CompactDurationToken; +%% token_tag2string(X) -> ?CompactEmbedToken; +token_tag2string(emergencyAudit) -> ?CompactEmergencyToken; +%% token_tag2string(X) -> ?CompactEmergencyOffToken; +%% token_tag2string(X) -> ?CompactEmergencyValueToken; +token_tag2string(errorDescriptor) -> ?CompactErrorToken; +token_tag2string(eventBufferDescriptor) -> ?CompactEventBufferToken; +token_tag2string(eventBufferToken) -> ?CompactEventBufferToken; +token_tag2string(eventsDescriptor) -> ?CompactEventsToken; +token_tag2string(eventsToken) -> ?CompactEventsToken; +token_tag2string(external) -> ?CompactExternalToken; +%% token_tag2string(X) -> ?CompactFailoverToken; +%% token_tag2string(X) -> ?CompactForcedToken; +%% token_tag2string(X) -> ?CompactGracefulToken; +%% token_tag2string(X) -> ?CompactH221Token; +%% token_tag2string(X) -> ?CompactH223Token; +%% token_tag2string(X) -> ?CompactH226Token; +%% token_tag2string(X) -> ?CompactHandOffToken; +token_tag2string(iepsCallind) -> ?CompactIEPSToken; +%% token_tag2string(X) -> ?CompactImmAckRequiredToken; +token_tag2string(inactive) -> ?CompactInactiveToken; +token_tag2string(internal) -> ?CompactInternalToken; +%% token_tag2string(X) -> ?CompactIntsigDelayToken; +token_tag2string(onInterruptByEvent) -> ?CompactInterruptByEventToken; +token_tag2string(onInterruptByNewSignalDescr) -> ?CompactInterruptByNewSignalsDescrToken; +token_tag2string(isolate) -> ?CompactIsolateToken; +token_tag2string(inSvc) -> ?CompactInSvcToken; +token_tag2string(iteration) -> ?CompactIterationToken; +token_tag2string(keepActive) -> ?CompactKeepActiveToken; +token_tag2string(localDescriptor) -> ?CompactLocalToken; +token_tag2string(localControlDescriptor) -> ?CompactLocalControlToken; +token_tag2string(lockStep) -> ?CompactLockStepToken; +token_tag2string(loopBack) -> ?CompactLoopbackToken; +token_tag2string(mediaDescriptor) -> ?CompactMediaToken; +token_tag2string(mediaToken) -> ?CompactMediaToken; +%% token_tag2string(X) -> ?CompactMegacopToken; +%% token_tag2string(X) -> ?CompactMethodToken; +%% token_tag2string(X) -> ?CompactMgcIdToken; +%% token_tag2string(X) -> ?CompactModeToken; +token_tag2string(modReq) -> ?CompactModifyToken; +token_tag2string(modReply) -> ?CompactModifyToken; +token_tag2string(modemDescriptor) -> ?CompactModemToken; +token_tag2string(modemToken) -> ?CompactModemToken; +token_tag2string(moveReq) -> ?CompactMoveToken; +token_tag2string(moveReply) -> ?CompactMoveToken; +%% token_tag2string(X) -> ?CompactMtpToken; +token_tag2string(muxDescriptor) -> ?CompactMuxToken; +token_tag2string(muxToken) -> ?CompactMuxToken; +%% token_tag2string(X) -> ?CompactNeverNotifyToken; +token_tag2string(notifyReq) -> ?CompactNotifyToken; +%% token_tag2string(X) -> ?CompactNotifyCompletionToken; +%% token_tag2string(X) -> ?CompactNotifyImmediateToken; +%% token_tag2string(X) -> ?CompactNotifyRegulatedToken; +%% token_tag2string(X) -> ?CompactNx64kToken; +token_tag2string(observedEventsDescriptor) -> ?CompactObservedEventsToken; +token_tag2string(observedEventsToken) -> ?CompactObservedEventsToken; +token_tag2string(false) -> ?CompactOffToken; +token_tag2string(off) -> ?CompactOffToken; +token_tag2string(oneway) -> ?CompactOnewayToken; +token_tag2string(onewayboth) -> ?CompactOnewayBothToken; +token_tag2string(onewayexternal) -> ?CompactOnewayExternalToken; +token_tag2string(onOff) -> ?CompactOnOffToken; +%% token_tag2string(X) -> ?CompactOrAUDITselectToken; +token_tag2string(true) -> ?CompactOnToken; +token_tag2string(otherReason) -> ?CompactOtherReasonToken; +token_tag2string(outOfSvc) -> ?CompactOutOfSvcToken; +token_tag2string(packagesDescriptor) -> ?CompactPackagesToken; +token_tag2string(packagesToken) -> ?CompactPackagesToken; +%% token_tag2string(X) -> ?CompactPendingToken; +token_tag2string(priorityAudit) -> ?CompactPriorityToken; +%% token_tag2string(X) -> ?CompactProfileToken; +%% token_tag2string(X) -> ?CompactReasonToken; +token_tag2string(recvOnly) -> ?CompactRecvonlyToken; +%% token_tag2string(X) -> ?CompactReplyToken; +token_tag2string(resetEventsDescriptor) -> ?CompactResetEventsDescriptorToken; +%% token_tag2string(X) -> ?CompactRequestIDToken; +%% token_tag2string(X) -> ?CompactResponseAckToken; +%% token_tag2string(X) -> ?CompactRestartToken; +token_tag2string(remoteDescriptor) -> ?CompactRemoteToken; +%% token_tag2string(X) -> ?CompactReservedGroupToken; +%% token_tag2string(X) -> ?CompactReservedValueToken; +token_tag2string(sendOnly) -> ?CompactSendonlyToken; +token_tag2string(sendRecv) -> ?CompactSendrecvToken; +%% token_tag2string(X) -> ?CompactServicesToken; +%% token_tag2string(X) -> ?CompactServiceStatesToken; +token_tag2string(serviceChangeReq) -> ?CompactServiceChangeToken; +%% token_tag2string(X) -> ?CompactServiceChangeAddressToken; +token_tag2string(incomplete) -> ?CompactServiceChangeIncompleteToken; +%% token_tag2string(X) -> ?CompactSignalListToken; +token_tag2string(signalsDescriptor) -> ?CompactSignalsToken; +token_tag2string(signalsToken) -> ?CompactSignalsToken; +%% token_tag2string(X) -> ?CompactSignalTypeToken; +token_tag2string(statisticsDescriptor) -> ?CompactStatsToken; +token_tag2string(statsToken) -> ?CompactStatsToken; +%% token_tag2string(X) -> ?CompactStreamToken; +token_tag2string(subtractReq) -> ?CompactSubtractToken; +token_tag2string(subtractReply) -> ?CompactSubtractToken; +%% token_tag2string(X) -> ?CompactSynchISDNToken; +%% token_tag2string(X) -> ?CompactTerminationStateToken; +token_tag2string(test) -> ?CompactTestToken; +token_tag2string(timeOut) -> ?CompactTimeOutToken; +token_tag2string(onTimeOut) -> ?CompactTimeOutToken; +token_tag2string(topologyAudit) -> ?CompactTopologyToken; +%% token_tag2string(X) -> ?CompactTransToken; +%% token_tag2string(X) -> ?CompactV18Token; +%% token_tag2string(X) -> ?CompactV22Token; +%% token_tag2string(X) -> ?CompactV22bisToken; +%% token_tag2string(X) -> ?CompactV32Token; +%% token_tag2string(X) -> ?CompactV32bisToken; +%% token_tag2string(X) -> ?CompactV34Token; +%% token_tag2string(X) -> ?CompactV76Token; +%% token_tag2string(X) -> ?CompactV90Token; +%% token_tag2string(X) -> ?CompactV91Token; +%% token_tag2string(X) -> ?CompactVersionToken; +token_tag2string(_) -> []. + + +%%---------------------------------------------------------------------- +%% Define various macros used by the actual generator code +%%---------------------------------------------------------------------- + +-define(EQUAL, [?SpToken, ?EqualToken, ?SpToken]). +-define(COLON, [?ColonToken]). +-define(LBRKT, [?SpToken, ?LbrktToken, ?SpToken]). +-define(RBRKT, [?SpToken, ?RbrktToken, ?SpToken]). +-define(LSBRKT, [?SpToken, ?LsbrktToken, ?SpToken]). +-define(RSBRKT, [?SpToken, ?RsbrktToken, ?SpToken]). +-define(COMMA, [?CommaToken, ?SpToken]). +-define(DOT, [?DotToken]). +-define(SLASH, [?SlashToken]). +-define(DQUOTE, [?DoubleQuoteToken]). +-define(SP, [?SpToken]). +-define(HTAB, [?HtabToken]). +-define(CR, [?CrToken]). +-define(LF, [?LfToken]). +-define(LWSP, []). +-define(EOL, ?LF). +-define(WSP, ?SP). +-define(SEP, ?WSP). + +-define(INIT_INDENT, []). +-define(INC_INDENT(State), [?HtabToken | State]). +-define(INDENT(State), [?LfToken | State]). +-define(LBRKT_INDENT(State), [?SpToken, ?LbrktToken, ?INDENT(?INC_INDENT(State))]). +-define(RBRKT_INDENT(State), [?INDENT(State), ?RbrktToken]). +-define(LSBRKT_INDENT(State), [?SpToken, ?LsbrktToken, ?INDENT(?INC_INDENT(State))]). +-define(RSBRKT_INDENT(State), [?INDENT(State), ?RsbrktToken]). +-define(COMMA_INDENT(State), [?CommaToken, ?INDENT(State)]). +-define(SEP_INDENT(_State), [?LfToken]). + +%%---------------------------------------------------------------------- +%% Define token macros +%%---------------------------------------------------------------------- + +-define(AddToken , ?PrettyAddToken). +-define(AndAUDITSelectToken , ?PrettytAndAUDITSelectToken). +-define(AuditToken , ?PrettyAuditToken). +-define(AuditCapToken , ?PrettyAuditCapToken). +-define(AuditValueToken , ?PrettyAuditValueToken). +-define(AuthToken , ?PrettyAuthToken). +-define(BothToken , ?PrettyBothToken). +-define(BothwayToken , ?PrettyBothwayToken). +-define(BriefToken , ?PrettyBriefToken). +-define(BufferToken , ?PrettyBufferToken). +-define(CtxToken , ?PrettyCtxToken). +-define(ContextAuditToken , ?PrettyContextAuditToken). +-define(ContextAttrToken , ?PrettyContextAttrToken). +-define(ContextListToken , ?PrettyContextListToken). +-define(DigitMapToken , ?PrettyDigitMapToken). +-define(DirectionToken , ?PrettyDirectionToken). +-define(DiscardToken , ?PrettyDiscardToken). +-define(DisconnectedToken , ?PrettyDisconnectedToken). +-define(DelayToken , ?PrettyDelayToken). +-define(DeleteToken , ?PrettyDeleteToken). +-define(DurationToken , ?PrettyDurationToken). +-define(EmbedToken , ?PrettyEmbedToken). +-define(EmergencyToken , ?PrettyEmergencyToken). +-define(EmergencyOffToken , ?PrettyEmergencyOffToken). +-define(EmergencyValueToken , ?PrettyEmergencyValueToken). +-define(ErrorToken , ?PrettyErrorToken). +-define(EventBufferToken , ?PrettyEventBufferToken). +-define(EventsToken , ?PrettyEventsToken). +-define(ExternalToken , ?PrettyExternalToken). +-define(FailoverToken , ?PrettyFailoverToken). +-define(ForcedToken , ?PrettyForcedToken). +-define(GracefulToken , ?PrettyGracefulToken). +-define(H221Token , ?PrettyH221Token). +-define(H223Token , ?PrettyH223Token). +-define(H226Token , ?PrettyH226Token). +-define(HandOffToken , ?PrettyHandOffToken). +-define(IEPSToken , ?PrettyIEPSToken). +-define(ImmAckRequiredToken , ?PrettyImmAckRequiredToken). +-define(InactiveToken , ?PrettyInactiveToken). +-define(InternalToken , ?PrettyInternalToken). +-define(IntsigDelayToken , ?PrettyIntsigDelayToken). +-define(IsolateToken , ?PrettyIsolateToken). +-define(InSvcToken , ?PrettyInSvcToken). +-define(InterruptByEventToken , ?PrettyInterruptByEventToken). +-define(InterruptByNewSignalsDescrToken, ?PrettyInterruptByNewSignalsDescrToken). +-define(IterationToken , ?PrettyIterationToken). +-define(KeepActiveToken , ?PrettyKeepActiveToken). +-define(LocalToken , ?PrettyLocalToken). +-define(LocalControlToken , ?PrettyLocalControlToken). +-define(LockStepToken , ?PrettyLockStepToken). +-define(LoopbackToken , ?PrettyLoopbackToken). +-define(MediaToken , ?PrettyMediaToken). +-define(MegacopToken , ?PrettyMegacopToken). +-define(MessageSegmentToken , ?PrettyMessageSegmentToken). +-define(MethodToken , ?PrettyMethodToken). +-define(MgcIdToken , ?PrettyMgcIdToken). +-define(ModeToken , ?PrettyModeToken). +-define(ModifyToken , ?PrettyModifyToken). +-define(ModemToken , ?PrettyModemToken). +-define(MoveToken , ?PrettyMoveToken). +-define(MtpToken , ?PrettyMtpToken). +-define(MuxToken , ?PrettyMuxToken). +-define(NeverNotifyToken , ?PrettyNeverNotifyToken). +-define(NotifyToken , ?PrettyNotifyToken). +-define(NotifyCompletionToken , ?PrettyNotifyCompletionToken). +-define(NotifyImmediateToken , ?PrettyNotifyImmediateToken). +-define(NotifyRegulatedToken , ?PrettyNotifyRegulatedToken). +-define(Nx64kToken , ?PrettyNx64kToken). +-define(ObservedEventsToken , ?PrettyObservedEventsToken). +-define(OffToken , ?PrettyOffToken). +-define(OnewayToken , ?PrettyOnewayToken). +-define(OnewayBothToken , ?PrettyOnewayBothToken). +-define(OnewayExternalToken , ?PrettyOnewayExternalToken). +-define(OnOffToken , ?PrettyOnOffToken). +-define(OnToken , ?PrettyOnToken). +-define(OrAUDITselectToken , ?PrettyOrAUDITselectToken). +-define(OtherReasonToken , ?PrettyOtherReasonToken). +-define(OutOfSvcToken , ?PrettyOutOfSvcToken). +-define(PackagesToken , ?PrettyPackagesToken). +-define(PendingToken , ?PrettyPendingToken). +-define(PriorityToken , ?PrettyPriorityToken). +-define(ProfileToken , ?PrettyProfileToken). +-define(ReasonToken , ?PrettyReasonToken). +-define(RecvonlyToken , ?PrettyRecvonlyToken). +-define(ReplyToken , ?PrettyReplyToken). +-define(ResetEventsDescriptorToken , ?PrettyResetEventsDescriptorToken). +-define(ResponseAckToken , ?PrettyResponseAckToken). +-define(RestartToken , ?PrettyRestartToken). +-define(RemoteToken , ?PrettyRemoteToken). +-define(RequestIDToken , ?PrettyRequestIDToken). +-define(ReservedGroupToken , ?PrettyReservedGroupToken). +-define(ReservedValueToken , ?PrettyReservedValueToken). +-define(SegmentationCompleteToken , ?PrettySegmentationCompleteToken). +-define(SendonlyToken , ?PrettySendonlyToken). +-define(SendrecvToken , ?PrettySendrecvToken). +-define(ServicesToken , ?PrettyServicesToken). +-define(ServiceStatesToken , ?PrettyServiceStatesToken). +-define(ServiceChangeToken , ?PrettyServiceChangeToken). +-define(ServiceChangeAddressToken , ?PrettyServiceChangeAddressToken). +-define(ServiceChangeIncompleteToken , ?PrettyServiceChangeIncompleteToken). +-define(SignalListToken , ?PrettySignalListToken). +-define(SignalsToken , ?PrettySignalsToken). +-define(SignalTypeToken , ?PrettySignalTypeToken). +-define(StatsToken , ?PrettyStatsToken). +-define(StreamToken , ?PrettyStreamToken). +-define(SubtractToken , ?PrettySubtractToken). +-define(SynchISDNToken , ?PrettySynchISDNToken). +-define(TerminationStateToken , ?PrettyTerminationStateToken). +-define(TestToken , ?PrettyTestToken). +-define(TimeOutToken , ?PrettyTimeOutToken). +-define(TopologyToken , ?PrettyTopologyToken). +-define(TransToken , ?PrettyTransToken). +-define(V18Token , ?PrettyV18Token). +-define(V22Token , ?PrettyV22Token). +-define(V22bisToken , ?PrettyV22bisToken). +-define(V32Token , ?PrettyV32Token). +-define(V32bisToken , ?PrettyV32bisToken). +-define(V34Token , ?PrettyV34Token). +-define(V76Token , ?PrettyV76Token). +-define(V90Token , ?PrettyV90Token). +-define(V91Token , ?PrettyV91Token). +-define(VersionToken , ?PrettyVersionToken). + +%%---------------------------------------------------------------------- +%% Include the generator code +%%---------------------------------------------------------------------- + +-include("megaco_text_gen_v3.hrl"). + diff --git a/lib/megaco/src/text/megaco_text_gen_prev3a.hrl b/lib/megaco/src/text/megaco_text_gen_prev3a.hrl new file mode 100644 index 0000000000..b1ddb10a4e --- /dev/null +++ b/lib/megaco/src/text/megaco_text_gen_prev3a.hrl @@ -0,0 +1,2945 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2004-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 = Req, + transactionResult = Res, + %% These fields are actually not + %% supported in this implementation, + %% but because the messanger module + %% cannot see any diff between the + %% various v3 implementations... + segmentNumber = asn1_NOVALUE, + segmentationComplete = asn1_NOVALUE}, + 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(#'ActionRequest'{contextId = CID, + contextRequest = asn1_NOVALUE, + contextAttrAuditReq = asn1_NOVALUE, + commandRequests = CmdReqs}, State) -> + [ + ?CtxToken, + ?EQUAL, + enc_ContextID(CID, State), + ?LBRKT_INDENT(State), + enc_list([{CmdReqs, fun enc_CommandRequest/2}], + ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]; +enc_ActionRequest(#'ActionRequest'{contextId = CID, + contextRequest = CtxReq, + contextAttrAuditReq = asn1_NOVALUE, + commandRequests = CmdReqs}, State) -> + [ + ?CtxToken, + ?EQUAL, + enc_ContextID(CID, State), + ?LBRKT_INDENT(State), + enc_list([{[CtxReq], fun enc_ContextRequest/2}, + {CmdReqs, fun enc_CommandRequest/2}], + ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]; +enc_ActionRequest(#'ActionRequest'{contextId = CID, + contextRequest = CtxReq, + contextAttrAuditReq = CtxAAR, + commandRequests = CmdReqs}, State) -> + [ + ?CtxToken, + ?EQUAL, + enc_ContextID(CID, State), + ?LBRKT_INDENT(State), + enc_list([{[CtxReq], fun enc_ContextRequest/2}, + {[CtxAAR], fun enc_ContextAttrAuditRequest/2}, + {CmdReqs, fun enc_CommandRequest/2}], + ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]. + +%% OTP-5085 +enc_ActionReply(#'ActionReply'{contextId = Id, + errorDescriptor = ED, + contextReply = CtxRep, + commandReply = CmdRep}, + State) -> +% d("enc_ActionReply -> entry with" +% "~n Id: ~p" +% "~n ED: ~p" +% "~n CtxRep: ~p" +% "~n CmdRep: ~p", [Id, ED, CtxRep, CmdRep]), + [ + ?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, [], State) + when CtxRep =/= asn1_NOVALUE -> +% d("do_enc_ActionReply -> entry with" +% "~n CtxRep: ~p", [CtxRep]), + [ + enc_ContextRequest(CtxRep, ?INC_INDENT(State)) + ]; +do_enc_ActionReply(asn1_NOVALUE, CtxRep, CmdRep, State) + when CtxRep =/= asn1_NOVALUE, CmdRep =/= [] -> +% d("do_enc_ActionReply -> entry with" +% "~n CtxRep: ~p" +% "~n CmdRep: ~p", [CtxRep, CmdRep]), + [ + enc_ContextRequest(CtxRep, ?INC_INDENT(State)), + ?COMMA_INDENT(?INC_INDENT(State)), + enc_list([{CmdRep, fun enc_CommandReply/2}], + ?INC_INDENT(State)) + ]; +do_enc_ActionReply(asn1_NOVALUE, asn1_NOVALUE, CmdRep, State) + when CmdRep =/= [] -> +% d("do_enc_ActionReply -> entry with" +% "~n CmdRep: ~p", [CmdRep]), + [ + enc_list([{CmdRep, fun enc_CommandReply/2}], + ?INC_INDENT(State)) + ]; +do_enc_ActionReply(ED, CtxRep, [], State) + when (ED =/= asn1_NOVALUE) andalso (CtxRep =/= asn1_NOVALUE) -> +% d("do_enc_ActionReply -> entry with" +% "~n ED: ~p" +% "~n CtxRep: ~p", [ED, CtxRep]), + [ + enc_ContextRequest(CtxRep, ?INC_INDENT(State)), + ?COMMA_INDENT(?INC_INDENT(State)), + enc_list([{[ED], fun enc_ErrorDescriptor/2}], % Indention cosmetics + ?INC_INDENT(State)) + ]; +do_enc_ActionReply(ED, asn1_NOVALUE, CmdRep, State) + when (ED =/= asn1_NOVALUE) andalso (CmdRep =/= []) -> +% d("do_enc_ActionReply -> entry with" +% "~n ED: ~p" +% "~n CmdRep: ~p", [ED, CmdRep]), + [ + enc_list([{CmdRep, fun enc_CommandReply/2}, + {[ED], fun enc_ErrorDescriptor/2}], % Indention cosmetics + ?INC_INDENT(State)) + ]; +do_enc_ActionReply(ED, CtxRep, CmdRep, State) + when (ED =/= asn1_NOVALUE) andalso + (CtxRep =/= asn1_NOVALUE) andalso + (CmdRep =/= []) -> +% d("do_enc_ActionReply -> entry with" +% "~n ED: ~p" +% "~n CtxRep: ~p" +% "~n CmdRep: ~p", [ED, CtxRep, CmdRep]), + [ + enc_ContextRequest(CtxRep, ?INC_INDENT(State)), + ?COMMA_INDENT(?INC_INDENT(State)), + enc_list([{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 -> +% d("do_enc_ActionReply -> entry with" +% "~n ED: ~p", [ED]), + [ + enc_ErrorDescriptor(ED, ?INC_INDENT(State)) + ]. + + +enc_ContextRequest_priority(asn1_NOVALUE, _State) -> + {[], dummy}; +enc_ContextRequest_priority(Val, _State) -> + {[Val], fun(X,S) -> [?PriorityToken,?EQUAL,enc_UINT16(X, S)] end}. + +enc_ContextRequest_emergency(asn1_NOVALUE, _State) -> + {[], dummy}; +enc_ContextRequest_emergency(true, _State) -> + {[?EmergencyToken], fun(Elem, _) -> Elem end}; +enc_ContextRequest_emergency(false, _State) -> + {[?EmergencyOffToken], fun(Elem, _) -> Elem end}. + +enc_ContextRequest_topologyReq(asn1_NOVALUE, _State) -> + {[], dummy}; +enc_ContextRequest_topologyReq({'ContextRequest_topologyReq', + asn1_NOVALUE}, _State) -> + {[], dummy}; +enc_ContextRequest_topologyReq({'ContextRequest_topologyReq', + List}, _State) -> + {List, fun enc_TopologyRequest/2}; +enc_ContextRequest_topologyReq(List, _State) -> + {[List], fun enc_TopologyRequest/2}. + +enc_ContextRequest_iepsCallind(asn1_NOVALUE, _State) -> + {[], dummy}; +enc_ContextRequest_iepsCallind(false, _State) -> + {[], dummy}; +% enc_ContextRequest_iepsCallind(false, _State) -> +% {[?IEPS_XXXX_Token], fun(Elem, _) -> Elem end}; +enc_ContextRequest_iepsCallind(true, _State) -> + {[?IEPSToken], fun(Elem, _) -> Elem end}. + +enc_ContextRequest_contextProp(asn1_NOVALUE, _State) -> + {[], dummy}; +enc_ContextRequest_contextProp([], _State) -> + {[], dummy}; +enc_ContextRequest_contextProp([PP], _State) -> + {[PP], fun enc_PropertyParm/2}; +enc_ContextRequest_contextProp(PPs, _State) when is_list(PPs) -> + error({at_most_one_contextProp, PPs}). + +enc_ContextRequest(asn1_NOVALUE, _State) -> + []; +enc_ContextRequest(#'ContextRequest'{priority = asn1_NOVALUE, + emergency = asn1_NOVALUE, + topologyReq = asn1_NOVALUE, + iepsCallind = asn1_NOVALUE, + contextProp = asn1_NOVALUE}, _State) -> + []; +enc_ContextRequest(#'ContextRequest'{priority = asn1_NOVALUE, + emergency = asn1_NOVALUE, + topologyReq = [], + iepsCallind = asn1_NOVALUE, + contextProp = []}, _State) -> + []; +enc_ContextRequest(#'ContextRequest'{priority = Prio, + emergency = Em, + topologyReq = TR, + iepsCallind = Ieps, + contextProp = CP}, State) -> + [ + ?ContextAttrToken, + ?LBRKT_INDENT(State), + enc_list([enc_ContextRequest_priority(Prio, State), + enc_ContextRequest_emergency(Em, State), + enc_ContextRequest_topologyReq(TR, State), + enc_ContextRequest_iepsCallind(Ieps, State), + enc_ContextRequest_contextProp(CP, State)], + ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]. + +enc_ContextAttrAuditRequest( + #'ContextAttrAuditRequest'{topology = asn1_NOVALUE, + emergency = asn1_NOVALUE, + priority = asn1_NOVALUE, + iepsCallind = asn1_NOVALUE, + contextPropAud = asn1_NOVALUE}, _State) -> + []; +enc_ContextAttrAuditRequest( + #'ContextAttrAuditRequest'{topology = asn1_NOVALUE, + emergency = asn1_NOVALUE, + priority = asn1_NOVALUE, + iepsCallind = asn1_NOVALUE, + contextPropAud = []}, _State) -> + []; +enc_ContextAttrAuditRequest(CAAR, State) -> + [ + ?ContextAuditToken, + ?LBRKT_INDENT(State), + enc_IndAudContextAttrDescriptor(CAAR, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]. + +enc_IndAudContextAttrDescriptor( + #'ContextAttrAuditRequest'{topology = Top, + emergency = Em, + priority = Prio, + iepsCallind = Ieps, + contextPropAud = CPA}, State) -> + [ + ?ContextAttrToken, + ?LBRKT_INDENT(State), + enc_list([{[Top], fun('NULL', _) -> ?TopologyToken end}, + {[Em], fun('NULL', _) -> ?EmergencyToken end}, + {[Prio], fun('NULL', _) -> ?PriorityToken end}, + {[Ieps], fun('NULL', _) -> ?IEPSToken end}, + {CPA, fun enc_IndAudPropertyParm/2}], + ?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) -> +% d("enc_Command -> entry with" +% "~n Tag: ~p" +% "~n Val: ~p", [Tag, Val]), + 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) -> +% d("enc_CommandReply -> entry with" +% "~n Tag: ~p" +% "~n Val: ~p", [Tag, Val]), + 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}, State) -> + [ + enc_TerminationID(From, State), + ?COMMA_INDENT(State), + enc_TerminationID(To, State), + ?COMMA_INDENT(State), + enc_TopologyDirection(Dir, State) + ]. + +enc_TopologyDirection(bothway, _State) -> + ?BothwayToken; +enc_TopologyDirection(isolate, _State) -> + ?IsolateToken; +enc_TopologyDirection(oneway, _State) -> + ?OnewayToken; +enc_TopologyDirection(Top, _State) -> + error({illegal_TopologyDirection, Top}). + +enc_AmmRequest(Val, State) + when is_record(Val, 'AmmRequest') -> +% d("enc_AmmRequest -> entry with" +% "~n Val: ~p", [Val]), + [ + %% 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) -> +% d("enc_ammDescriptor -> entry with" +% "~n Tag: ~p" +% "~n Desc: ~p", [Tag, Desc]), + 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); + statisticsDescriptor -> enc_StatisticsDescriptor(Desc, State); + _ -> + error({invalid_ammDescriptor_tag, Tag}) + end. + +enc_AmmsReply(#'AmmsReply'{terminationID = ID, + terminationAudit = asn1_NOVALUE}, State) -> +% d("enc_AmmsReply(asn1_NOVALUE) -> entry with" +% "~n ID: ~p", [ID]), + [ + ?EQUAL, + enc_TerminationIDList1(ID, State) + ]; +enc_AmmsReply(#'AmmsReply'{terminationID = ID, + terminationAudit = []}, State) -> +% d("enc_AmmsReply([]) -> entry with" +% "~n ID: ~p", [ID]), + [ + ?EQUAL, + enc_TerminationIDList1(ID, State) + ]; +enc_AmmsReply(#'AmmsReply'{terminationID = ID, + terminationAudit = Res}, State) -> +% d("enc_AmmsReply -> entry with" +% "~n ID: ~p" +% "~n Res: ~p", [ID, Res]), + [ + ?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') -> +% d("enc_AuditRequest -> entry with" +% "~n Val: ~p", [Val]), + [ + %% 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) -> +% d("enc_AuditDescriptor(asn1_NOVALUE) -> entry"), + [ + ?AuditToken, + [?LBRKT, ?RBRKT] + ]; +enc_AuditDescriptor(#'AuditDescriptor'{auditToken = [], + auditPropertyToken = asn1_NOVALUE}, + _State) -> +% d("enc_AuditDescriptor([]) -> entry"), + [ + ?AuditToken, + [?LBRKT, ?RBRKT] + ]; +enc_AuditDescriptor(#'AuditDescriptor'{auditToken = List, + auditPropertyToken = asn1_NOVALUE}, + State) -> +% d("enc_AuditDescriptor -> entry with", +% "~n List: ~p", [List]), + [ + ?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) -> +% d("enc_AuditDescriptor -> entry with", +% "~n Prop: ~p", [Prop]), + [ + ?AuditToken, + [ + ?LBRKT_INDENT(State), + enc_auditPropertyToken(Prop, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ] + ]; +enc_AuditDescriptor(#'AuditDescriptor'{auditToken = List, + auditPropertyToken = Prop}, + State) -> +% d("enc_AuditDescriptor -> entry with", +% "~n List: ~p" +% "~n Prop: ~p", [List, Prop]), + [ + ?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) -> +% d("enc_auditPropertyToken -> entry with", +% "~n Param: ~p", [Param]), + [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 = Streams}, State) -> +% d("enc_IndAudMediaDescriptor -> entry with", +% "~n Streams: ~p", [Streams]), + [ + ?MediaToken, + ?LBRKT_INDENT(State), + enc_IndAudMediaDescriptor_streams(Streams, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]; +enc_IndAudMediaDescriptor(#'IndAudMediaDescriptor'{termStateDescr = TSD, + streams = asn1_NOVALUE}, + State) -> +% d("enc_IndAudMediaDescriptor -> entry with", +% "~n TSD: ~p", [TSD]), + [ + ?MediaToken, + ?LBRKT_INDENT(State), + enc_IndAudTerminationStateDescriptor(TSD, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]. + +enc_IndAudMediaDescriptor_streams({Tag, Val}, State) -> +% d("enc_IndAudMediaDescriptor_streams -> entry with", +% "~n Tag: ~p" +% "~n Val: ~p", [Tag, Val]), + 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) + ]. + +%% In text, localDescriptor and remoteDescriptor are not allowed!! +enc_IndAudStreamParms( + #'IndAudStreamParms'{localControlDescriptor = LCD, + localDescriptor = asn1_NOVALUE, + remoteDescriptor = asn1_NOVALUE, + statisticsDescriptor = SD}, State) -> +% d("enc_IndAudStreamParms -> entry with" +% "~n LCD: ~p" +% "~n SD: ~p", [LCD, SD]), + [ + enc_list([{[LCD], fun enc_IndAudLocalControlDescriptor/2}, + {[SD], fun enc_IndAudStatisticsDescriptor/2}], + ?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) -> +% d("enc_IndAudMediaDescriptor_multiStream -> entry with" +% "~n Val: ~p", [Val]), + [ + 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) -> +% d("enc_IndAudStreamDescriptor -> entry with" +% "~n SID: ~p" +% "~n Parms: ~p", [SID, Parms]), + [ + ?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) -> +% d("enc_IndAudStatisticsDescriptor -> entry with" +% "~n Name: ~p", [Name]), + [ + ?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) -> +% d("enc_TerminationAudit -> entry with" +% "~n Mand: ~p", [Mand]), + [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) -> +% d("enc_AuditReturnParameter -> entry with" +% "~n Tag: ~p" +% "~n Val: ~p", [Tag, Val]), + 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}, + {[Val#'StreamParms'.statisticsDescriptor], + fun enc_StatisticsDescriptor/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 + [ + ?EQUAL, + ?LSBRKT, + enc_Value(Low, State), + ?COLON, + enc_Value(High, State), + ?RSBRKT + ]; +enc_propertyParmValues(Values, {sublist, true}, State)-> + %% sublist (i.e. A AND B AND ...) + [ + ?EQUAL, + ?LSBRKT_INDENT(State), + enc_list([{Values, fun enc_Value/2}], ?INC_INDENT(State)), + ?RSBRKT_INDENT(State) + ]; +enc_propertyParmValues(Values, {sublist, false}, State) -> + %% alternatives (i.e. A OR B OR ...) + [ + ?EQUAL, + ?LBRKT_INDENT(State), + enc_list([{Values, fun enc_Value/2}], ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]; +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') -> + PkgdName = ?META_ENC(event, Val#'RequestedEvent'.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 =/= []) -> + [ + {[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 =:= []) -> + [ + {[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}) -> + [ + {[KA], fun enc_keepActive/2}, + {[EDM], fun enc_EventDM/2}, + {[{SE, SD}], fun enc_embedWithSig/2} + ]. + +enc_embedNoSig(#'SecondEventsDescriptor'{requestID = RID, + eventList = Evs}, State) -> + [ + ?EmbedToken, + ?LBRKT_INDENT(State), + enc_embedFirst(RID, Evs, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]. + +enc_embedWithSig({asn1_NOVALUE, SD}, State) -> + [ + ?EmbedToken, + ?LBRKT_INDENT(State), + enc_SignalsDescriptor(SD, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]; +enc_embedWithSig({#'SecondEventsDescriptor'{requestID = RID, + eventList = Evs}, SD}, State) -> + [ + ?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) -> + case Val of + true -> [?KeepActiveToken]; + false -> [] + end. + +enc_EventDM({'EventDM',Val}, State) -> + enc_EventDM(Val, State); +enc_EventDM({Tag, Val}, State) -> + 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) -> + 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') -> + [ + {[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) andalso (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) -> + [ + ?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) -> + 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}, + {[Val#'Signal'.direction], fun enc_SignalDirection/2}, + {[Val#'Signal'.requestID], fun enc_sigRequestID/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_SignalDirection({'SignalDirection', Val}, State) -> + enc_SignalDirection(Val, State); +enc_SignalDirection(Val, _State) -> + [ + ?DirectionToken, + ?EQUAL, + case Val of + internal -> ?InternalToken; + external -> ?ExternalToken; + both -> ?BothToken + end + ]. + +enc_sigRequestID(Val, State) -> + [ + ?RequestIDToken, + ?EQUAL, + enc_RequestID(Val, 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}, + {[Val#'ServiceChangeParm'.serviceChangeIncompleteFlag], + fun('NULL', _) -> ?ServiceChangeIncompleteToken end}], + ?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({invalid_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(get(dbg), F, A). + +%% d(true, F, A) -> +%% io:format("~p:" ++ F ++ "~n", [?MODULE | A]); +%% d(_, _, _) -> +%% ok. + + diff --git a/lib/megaco/src/text/megaco_text_gen_prev3b.hrl b/lib/megaco/src/text/megaco_text_gen_prev3b.hrl new file mode 100644 index 0000000000..8a4af877dc --- /dev/null +++ b/lib/megaco/src/text/megaco_text_gen_prev3b.hrl @@ -0,0 +1,2966 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2005-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 = Req, + transactionResult = Res, + %% These fields are actually not + %% supported in this implementation, + %% but because the messanger module + %% cannot see any diff between the + %% various v3 implementations... + segmentNumber = asn1_NOVALUE, + segmentationComplete = asn1_NOVALUE}, + 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(#'ActionRequest'{contextId = CID, + contextRequest = asn1_NOVALUE, + contextAttrAuditReq = asn1_NOVALUE, + commandRequests = CmdReqs}, State) -> + [ + ?CtxToken, + ?EQUAL, + enc_ContextID(CID, State), + ?LBRKT_INDENT(State), + enc_list([{CmdReqs, fun enc_CommandRequest/2}], + ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]; +enc_ActionRequest(#'ActionRequest'{contextId = CID, + contextRequest = CtxReq, + contextAttrAuditReq = asn1_NOVALUE, + commandRequests = CmdReqs}, State) -> + [ + ?CtxToken, + ?EQUAL, + enc_ContextID(CID, State), + ?LBRKT_INDENT(State), + enc_list([{[CtxReq], fun enc_ContextRequest/2}, + {CmdReqs, fun enc_CommandRequest/2}], + ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]; +enc_ActionRequest(#'ActionRequest'{contextId = CID, + contextRequest = CtxReq, + contextAttrAuditReq = CtxAAR, + commandRequests = CmdReqs}, State) -> + [ + ?CtxToken, + ?EQUAL, + enc_ContextID(CID, State), + ?LBRKT_INDENT(State), + enc_list([{[CtxReq], fun enc_ContextRequest/2}, + {[CtxAAR], fun enc_ContextAttrAuditRequest/2}, + {CmdReqs, fun enc_CommandRequest/2}], + ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]. + +%% OTP-5085 +enc_ActionReply(#'ActionReply'{contextId = Id, + errorDescriptor = ED, + contextReply = CtxRep, + commandReply = CmdRep}, + State) -> +%% d("enc_ActionReply -> entry with" +%% "~n Id: ~p" +%% "~n ED: ~p" +%% "~n CtxRep: ~p" +%% "~n CmdRep: ~p", [Id, ED, CtxRep, CmdRep]), + [ + ?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, [], State) + when (CtxRep =/= asn1_NOVALUE) -> +%% d("do_enc_ActionReply -> entry with" +%% "~n CtxRep: ~p", [CtxRep]), + [ + enc_ContextRequest(CtxRep, ?INC_INDENT(State)) + ]; +do_enc_ActionReply(asn1_NOVALUE, CtxRep, CmdRep, State) + when (CtxRep =/= asn1_NOVALUE) andalso (CmdRep =/= []) -> +%% d("do_enc_ActionReply -> entry with" +%% "~n CtxRep: ~p" +%% "~n CmdRep: ~p", [CtxRep, CmdRep]), + [ + enc_ContextRequest(CtxRep, ?INC_INDENT(State)), + ?COMMA_INDENT(?INC_INDENT(State)), + enc_list([{CmdRep, fun enc_CommandReply/2}], + ?INC_INDENT(State)) + ]; +do_enc_ActionReply(asn1_NOVALUE, asn1_NOVALUE, CmdRep, State) + when (CmdRep =/= []) -> +%% d("do_enc_ActionReply -> entry with" +%% "~n CmdRep: ~p", [CmdRep]), + [ + enc_list([{CmdRep, fun enc_CommandReply/2}], + ?INC_INDENT(State)) + ]; +do_enc_ActionReply(ED, CtxRep, [], State) + when (ED =/= asn1_NOVALUE) andalso (CtxRep =/= asn1_NOVALUE) -> +%% d("do_enc_ActionReply -> entry with" +%% "~n ED: ~p" +%% "~n CtxRep: ~p", [ED, CtxRep]), + [ + enc_ContextRequest(CtxRep, ?INC_INDENT(State)), + ?COMMA_INDENT(?INC_INDENT(State)), + enc_list([{[ED], fun enc_ErrorDescriptor/2}], % Indention cosmetics + ?INC_INDENT(State)) + ]; +do_enc_ActionReply(ED, asn1_NOVALUE, CmdRep, State) + when (ED =/= asn1_NOVALUE) andalso (CmdRep =/= []) -> +%% d("do_enc_ActionReply -> entry with" +%% "~n ED: ~p" +%% "~n CmdRep: ~p", [ED, CmdRep]), + [ + enc_list([{CmdRep, fun enc_CommandReply/2}, + {[ED], fun enc_ErrorDescriptor/2}], % Indention cosmetics + ?INC_INDENT(State)) + ]; +do_enc_ActionReply(ED, CtxRep, CmdRep, State) + when (ED =/= asn1_NOVALUE) andalso + (CtxRep =/= asn1_NOVALUE) andalso + (CmdRep =/= []) -> +%% d("do_enc_ActionReply -> entry with" +%% "~n ED: ~p" +%% "~n CtxRep: ~p" +%% "~n CmdRep: ~p", [ED, CtxRep, CmdRep]), + [ + enc_ContextRequest(CtxRep, ?INC_INDENT(State)), + ?COMMA_INDENT(?INC_INDENT(State)), + enc_list([{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 -> +%% d("do_enc_ActionReply -> entry with" +%% "~n ED: ~p", [ED]), + [ + enc_ErrorDescriptor(ED, ?INC_INDENT(State)) + ]. + + +enc_ContextRequest_priority(asn1_NOVALUE, _State) -> + {[], dummy}; +enc_ContextRequest_priority(Val, _State) -> + {[Val], fun(X,S) -> [?PriorityToken,?EQUAL,enc_UINT16(X, S)] end}. + +enc_ContextRequest_emergency(asn1_NOVALUE, _State) -> + {[], dummy}; +enc_ContextRequest_emergency(true, _State) -> + {[?EmergencyToken], fun(Elem, _) -> Elem end}; +enc_ContextRequest_emergency(false, _State) -> + {[?EmergencyOffToken], fun(Elem, _) -> Elem end}. + +enc_ContextRequest_topologyReq(asn1_NOVALUE, _State) -> + {[], dummy}; +enc_ContextRequest_topologyReq({'ContextRequest_topologyReq', + asn1_NOVALUE}, _State) -> + {[], dummy}; +enc_ContextRequest_topologyReq({'ContextRequest_topologyReq', + List}, _State) -> + {List, fun enc_TopologyRequest/2}; +enc_ContextRequest_topologyReq(List, _State) -> + {[List], fun enc_TopologyRequest/2}. + +enc_ContextRequest_iepscallind(asn1_NOVALUE, _State) -> + {[], dummy}; +enc_ContextRequest_iepscallind(Bool, _State) -> + {[Bool], fun enc_iepsValue/2}. + +enc_ContextRequest_contextProp(asn1_NOVALUE, _State) -> + {[], dummy}; +enc_ContextRequest_contextProp([], _State) -> + {[], dummy}; +enc_ContextRequest_contextProp(Props, _State) -> + {[Props], fun(Elem, S) -> enc_contextAttrDescriptor(Elem, contextProps, S) end}. + +enc_contextAttrDescriptor([Mand|Opt], contextProps, State) -> + [ + ?ContextAttrToken, + ?LBRKT_INDENT(State), + [enc_PropertyParm(Mand, State) | + [[?COMMA_INDENT(State), enc_PropertyParm(Val, State)] || Val <- Opt]], + ?RBRKT_INDENT(State) + ]. + +enc_ContextRequest(asn1_NOVALUE, _State) -> + []; +enc_ContextRequest(#'ContextRequest'{priority = asn1_NOVALUE, + emergency = asn1_NOVALUE, + topologyReq = asn1_NOVALUE, + iepscallind = asn1_NOVALUE, + contextProp = asn1_NOVALUE}, _State) -> + []; +enc_ContextRequest(#'ContextRequest'{priority = asn1_NOVALUE, + emergency = asn1_NOVALUE, + topologyReq = [], + iepscallind = asn1_NOVALUE, + contextProp = []}, _State) -> + []; +enc_ContextRequest(#'ContextRequest'{priority = Prio, + emergency = Em, + topologyReq = TR, + iepscallind = Ieps, + contextProp = CP}, State) -> + [ + enc_list([enc_ContextRequest_priority(Prio, State), + enc_ContextRequest_emergency(Em, State), + enc_ContextRequest_topologyReq(TR, State), + enc_ContextRequest_iepscallind(Ieps, State), + enc_ContextRequest_contextProp(CP, State)], + State) + ]. + +enc_ContextAttrAuditRequest( + #'ContextAttrAuditRequest'{topology = asn1_NOVALUE, + emergency = asn1_NOVALUE, + priority = asn1_NOVALUE, + iepscallind = asn1_NOVALUE, + contextPropAud = asn1_NOVALUE}, _State) -> + []; +enc_ContextAttrAuditRequest( + #'ContextAttrAuditRequest'{topology = asn1_NOVALUE, + emergency = asn1_NOVALUE, + priority = asn1_NOVALUE, + iepscallind = asn1_NOVALUE, + contextPropAud = []}, _State) -> + []; +enc_ContextAttrAuditRequest(CAAR, State) -> + [ + ?ContextAuditToken, + ?LBRKT_INDENT(State), + enc_IndAudContextAttrDescriptor(CAAR, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]. + +enc_IndAudContextAttrDescriptor( + #'ContextAttrAuditRequest'{topology = Top, + emergency = Em, + priority = Prio, + iepscallind = Ieps, + contextPropAud = CPA}, State) -> + [ + ?ContextAttrToken, + ?LBRKT_INDENT(State), + enc_list([{[Top], fun('NULL', _) -> ?TopologyToken end}, + {[Em], fun('NULL', _) -> ?EmergencyToken end}, + {[Prio], fun('NULL', _) -> ?PriorityToken end}, + {[Ieps], fun('NULL', _) -> ?IEPSToken end}, + {CPA, fun enc_IndAudPropertyParm/2}], + ?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) -> +% d("enc_Command -> entry with" +% "~n Tag: ~p" +% "~n Val: ~p", [Tag, Val]), + 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) -> +%% d("enc_CommandReply -> entry with" +%% "~n Tag: ~p" +%% "~n Val: ~p", [Tag, Val]), + 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}, State) -> + [ + enc_TerminationID(From, State), + ?COMMA_INDENT(State), + enc_TerminationID(To, State), + ?COMMA_INDENT(State), + enc_TopologyDirection(Dir, State) + ]. + +enc_TopologyDirection(bothway, _State) -> + ?BothwayToken; +enc_TopologyDirection(isolate, _State) -> + ?IsolateToken; +enc_TopologyDirection(oneway, _State) -> + ?OnewayToken; +enc_TopologyDirection(Top, _State) -> + error({illegal_TopologyDirection, Top}). + +enc_iepsValue(Val, _State) -> + [ + ?IEPSToken, + ?EQUAL, + case Val of + false -> ?OffToken; + true -> ?OnToken + end + ]. + + + +enc_AmmRequest(Val, State) + when is_record(Val, 'AmmRequest') -> +% d("enc_AmmRequest -> entry with" +% "~n Val: ~p", [Val]), + [ + %% 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) -> +% d("enc_ammDescriptor -> entry with" +% "~n Tag: ~p" +% "~n Desc: ~p", [Tag, Desc]), + 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); + statisticsDescriptor -> enc_StatisticsDescriptor(Desc, State); + _ -> + error({invalid_ammDescriptor_tag, Tag}) + end. + +enc_AmmsReply(#'AmmsReply'{terminationID = ID, + terminationAudit = asn1_NOVALUE}, State) -> +% d("enc_AmmsReply(asn1_NOVALUE) -> entry with" +% "~n ID: ~p", [ID]), + [ + ?EQUAL, + enc_TerminationIDList1(ID, State) + ]; +enc_AmmsReply(#'AmmsReply'{terminationID = ID, + terminationAudit = []}, State) -> +% d("enc_AmmsReply([]) -> entry with" +% "~n ID: ~p", [ID]), + [ + ?EQUAL, + enc_TerminationIDList1(ID, State) + ]; +enc_AmmsReply(#'AmmsReply'{terminationID = ID, + terminationAudit = Res}, State) -> +% d("enc_AmmsReply -> entry with" +% "~n ID: ~p" +% "~n Res: ~p", [ID, Res]), + [ + ?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') -> + %% d("enc_AuditRequest -> entry with" + %% "~n Val: ~p", [Val]), + [ + %% 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) -> +%% d("enc_AuditReply -> entry with" +%% "~n Tag: ~p" +%% "~n Val: ~p", [Tag, Val]), + case Tag of + contextAuditResult -> + %% d("enc_AuditReply -> contextAuditResult"), + [ + ?EQUAL, + ?CtxToken, + enc_TerminationIDListN(Val, State) + ]; + error -> + %% d("enc_AuditReply -> error"), + [ + ?EQUAL, + ?CtxToken, + ?LBRKT_INDENT(State), + enc_ErrorDescriptor(Val, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]; + auditResult when is_record(Val, 'AuditResult') -> + %% d("enc_AuditReply -> 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) -> +% d("enc_AuditDescriptor(asn1_NOVALUE) -> entry"), + [ + ?AuditToken, + [?LBRKT, ?RBRKT] + ]; +enc_AuditDescriptor(#'AuditDescriptor'{auditToken = [], + auditPropertyToken = asn1_NOVALUE}, + _State) -> +% d("enc_AuditDescriptor([]) -> entry"), + [ + ?AuditToken, + [?LBRKT, ?RBRKT] + ]; +enc_AuditDescriptor(#'AuditDescriptor'{auditToken = List, + auditPropertyToken = asn1_NOVALUE}, + State) -> +% d("enc_AuditDescriptor -> entry with", +% "~n List: ~p", [List]), + [ + ?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) -> +% d("enc_AuditDescriptor -> entry with", +% "~n Prop: ~p", [Prop]), + [ + ?AuditToken, + [ + ?LBRKT_INDENT(State), + enc_auditPropertyToken(Prop, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ] + ]; +enc_AuditDescriptor(#'AuditDescriptor'{auditToken = List, + auditPropertyToken = Prop}, + State) -> +% d("enc_AuditDescriptor -> entry with", +% "~n List: ~p" +% "~n Prop: ~p", [List, Prop]), + [ + ?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) -> +% d("enc_auditPropertyToken -> entry with", +% "~n Param: ~p", [Param]), + [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 = Streams}, State) -> +% d("enc_IndAudMediaDescriptor -> entry with", +% "~n Streams: ~p", [Streams]), + [ + ?MediaToken, + ?LBRKT_INDENT(State), + enc_IndAudMediaDescriptor_streams(Streams, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]; +enc_IndAudMediaDescriptor(#'IndAudMediaDescriptor'{termStateDescr = TSD, + streams = asn1_NOVALUE}, + State) -> +% d("enc_IndAudMediaDescriptor -> entry with", +% "~n TSD: ~p", [TSD]), + [ + ?MediaToken, + ?LBRKT_INDENT(State), + enc_IndAudTerminationStateDescriptor(TSD, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]. + +enc_IndAudMediaDescriptor_streams({Tag, Val}, State) -> +% d("enc_IndAudMediaDescriptor_streams -> entry with", +% "~n Tag: ~p" +% "~n Val: ~p", [Tag, Val]), + 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) + ]. + +%% In text, localDescriptor and remoteDescriptor are not allowed!! +enc_IndAudStreamParms( + #'IndAudStreamParms'{localControlDescriptor = LCD, + localDescriptor = asn1_NOVALUE, + remoteDescriptor = asn1_NOVALUE, + statisticsDescriptor = SD}, State) -> +% d("enc_IndAudStreamParms -> entry with" +% "~n LCD: ~p" +% "~n SD: ~p", [LCD, SD]), + [ + enc_list([{[LCD], fun enc_IndAudLocalControlDescriptor/2}, + {[SD], fun enc_IndAudStatisticsDescriptor/2}], + ?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) -> + %% d("enc_IndAudMediaDescriptor_multiStream -> entry with" + %% "~n Val: ~p", [Val]), + [ + enc_IndAudStreamDescriptor(Val, ?INC_INDENT(State)) + ]; +enc_IndAudMediaDescriptor_multiStream(Vals, State) when is_list(Vals) -> +%% d("enc_IndAudMediaDescriptor_multiStream -> entry with" +%% "~n Vals: ~p", [Vals]), + [ + enc_list([{Vals, fun enc_IndAudStreamDescriptor/2}], State) + ]; +enc_IndAudMediaDescriptor_multiStream(Val, _State) -> + error({invalid_IndAudMediaDescriptor_multiStream, Val}). + +enc_IndAudStreamDescriptor(#'IndAudStreamDescriptor'{streamID = SID, + streamParms = Parms}, + State) -> +%% d("enc_IndAudStreamDescriptor -> entry with" +%% "~n SID: ~p" +%% "~n Parms: ~p", [SID, Parms]), + [ + ?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) -> +% d("enc_IndAudStatisticsDescriptor -> entry with" +% "~n Name: ~p", [Name]), + [ + ?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) -> +% d("enc_TerminationAudit -> entry with" +% "~n Mand: ~p", [Mand]), + [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) -> +% d("enc_AuditReturnParameter -> entry with" +% "~n Tag: ~p" +% "~n Val: ~p", [Tag, Val]), + 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}, + {[Val#'StreamParms'.statisticsDescriptor], + fun enc_StatisticsDescriptor/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 + [ + ?EQUAL, + ?LSBRKT, + enc_Value(Low, State), + ?COLON, + enc_Value(High, State), + ?RSBRKT + ]; +enc_propertyParmValues(Values, {sublist, true}, State)-> + %% sublist (i.e. A AND B AND ...) + [ + ?EQUAL, + ?LSBRKT_INDENT(State), + enc_list([{Values, fun enc_Value/2}], ?INC_INDENT(State)), + ?RSBRKT_INDENT(State) + ]; +enc_propertyParmValues(Values, {sublist, false}, State) -> + %% alternatives (i.e. A OR B OR ...) + [ + ?EQUAL, + ?LBRKT_INDENT(State), + enc_list([{Values, fun enc_Value/2}], ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]; +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') -> + PkgdName = ?META_ENC(event, Val#'RequestedEvent'.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 =/= []) -> + [ + {[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 =:= []) -> + [ + {[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}) -> + [ + {[KA], fun enc_keepActive/2}, + {[EDM], fun enc_EventDM/2}, + {[{SE, SD}], fun enc_embedWithSig/2} + ]. + +enc_embedNoSig(#'SecondEventsDescriptor'{requestID = RID, + eventList = Evs}, State) -> + [ + ?EmbedToken, + ?LBRKT_INDENT(State), + enc_embedFirst(RID, Evs, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]. + +enc_embedWithSig({asn1_NOVALUE, SD}, State) -> + [ + ?EmbedToken, + ?LBRKT_INDENT(State), + enc_SignalsDescriptor(SD, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]; +enc_embedWithSig({#'SecondEventsDescriptor'{requestID = RID, + eventList = Evs}, SD}, State) -> + [ + ?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) -> + case Val of + true -> [?KeepActiveToken]; + false -> [] + end. + +enc_EventDM({'EventDM',Val}, State) -> + enc_EventDM(Val, State); +enc_EventDM({Tag, Val}, State) -> + 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) -> + 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') -> + [ + {[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) andalso (length(EventSpecs) >= 1) -> + [ + ?EventBufferToken, + ?LBRKT_INDENT(State), + enc_eventSpecs(EventSpecs, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]. + +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) -> + [ + ?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) -> + 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}, + {[Val#'Signal'.direction], fun enc_SignalDirection/2}, + {[Val#'Signal'.requestID], fun enc_sigRequestID/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_SignalDirection({'SignalDirection', Val}, State) -> + enc_SignalDirection(Val, State); +enc_SignalDirection(Val, _State) -> + [ + ?DirectionToken, + ?EQUAL, + case Val of + internal -> ?InternalToken; + external -> ?ExternalToken; + both -> ?BothToken + end + ]. + +enc_sigRequestID(Val, State) -> + [ + ?RequestIDToken, + ?EQUAL, + enc_RequestID(Val, 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}, + {[Val#'ServiceChangeParm'.serviceChangeIncompleteFlag], + fun('NULL', _) -> ?ServiceChangeIncompleteToken end}], + ?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({invalid_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(get(dbg), F, A). +%% +%% d(true, F, A) -> +%% io:format("~p:" ++ F ++ "~n", [?MODULE | A]); +%% d(_, _, _) -> +%% ok. +%% + diff --git a/lib/megaco/src/text/megaco_text_gen_prev3c.hrl b/lib/megaco/src/text/megaco_text_gen_prev3c.hrl new file mode 100644 index 0000000000..11db906846 --- /dev/null +++ b/lib/megaco/src/text/megaco_text_gen_prev3c.hrl @@ -0,0 +1,3443 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2005-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 V3 Megaco/H.248 text messages from internal form +%%---------------------------------------------------------------------- + +%% -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); +%% segmentReply -> +%% enc_SegmentReply(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%% , +%% segmentationNumber = SegNo, +%% segmentationComplete = SegCompl + }, + 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, + %% These fields are actually not + %% supported in this implementation, + %% but because the messanger module + %% cannot see any diff between the + %% various v3 implementations... + segmentNumber = asn1_NOVALUE, + segmentationComplete = asn1_NOVALUE + }, + 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(#'ActionRequest'{contextId = CID, + contextRequest = asn1_NOVALUE, + contextAttrAuditReq = asn1_NOVALUE, + commandRequests = CmdReqs}, State) -> + [ + ?CtxToken, + ?EQUAL, + enc_ContextID(CID, State), + ?LBRKT_INDENT(State), + enc_list([{CmdReqs, fun enc_CommandRequest/2}], + ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]; +enc_ActionRequest(#'ActionRequest'{contextId = CID, + contextRequest = CtxReq, + contextAttrAuditReq = asn1_NOVALUE, + commandRequests = CmdReqs}, State) -> + [ + ?CtxToken, + ?EQUAL, + enc_ContextID(CID, State), + ?LBRKT_INDENT(State), + enc_list([{[CtxReq], fun enc_ContextRequest/2}, + {CmdReqs, fun enc_CommandRequest/2}], + ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]; +enc_ActionRequest(#'ActionRequest'{contextId = CID, + contextRequest = CtxReq, + contextAttrAuditReq = CtxAAR, + commandRequests = CmdReqs}, State) -> + [ + ?CtxToken, + ?EQUAL, + enc_ContextID(CID, State), + ?LBRKT_INDENT(State), + enc_list([{[CtxReq], fun enc_ContextRequest/2}, + {[CtxAAR], fun enc_ContextAttrAuditRequest/2}, + {CmdReqs, fun enc_CommandRequest/2}], + ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]. + +%% OTP-5085 +enc_ActionReply(#'ActionReply'{contextId = Id, + errorDescriptor = asn1_NOVALUE, + contextReply = asn1_NOVALUE, + commandReply = []}, + State) -> +%% d("enc_ActionReply -> entry with" +%% "~n Id: ~p", [Id]), + [ + ?CtxToken, + ?EQUAL, + enc_ContextID(Id, State) + ]; +enc_ActionReply(#'ActionReply'{contextId = Id, + errorDescriptor = ED, + contextReply = CtxRep, + commandReply = CmdRep}, + State) -> +%% d("enc_ActionReply -> entry with" +%% "~n Id: ~p" +%% "~n ED: ~p" +%% "~n CtxRep: ~p" +%% "~n CmdRep: ~p", [Id, ED, CtxRep, CmdRep]), + [ + ?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, [], State) + when (CtxRep =/= asn1_NOVALUE) -> + [ + enc_ContextRequest(CtxRep, ?INC_INDENT(State)) + ]; +do_enc_ActionReply(asn1_NOVALUE, CtxRep, CmdRep, State) + when (CtxRep =/= asn1_NOVALUE) andalso (CmdRep =/= []) -> + [ + enc_ContextRequest(CtxRep, ?INC_INDENT(State)), + ?COMMA_INDENT(?INC_INDENT(State)), + enc_list([{CmdRep, fun enc_CommandReply/2}], + ?INC_INDENT(State)) + ]; +do_enc_ActionReply(asn1_NOVALUE, asn1_NOVALUE, CmdRep, State) + when (CmdRep =/= []) -> + [ + enc_list([{CmdRep, fun enc_CommandReply/2}], + ?INC_INDENT(State)) + ]; +do_enc_ActionReply(ED, CtxRep, [], State) + when (ED =/= asn1_NOVALUE) andalso (CtxRep =/= asn1_NOVALUE) -> + [ + enc_ContextRequest(CtxRep, ?INC_INDENT(State)), + ?COMMA_INDENT(?INC_INDENT(State)), + enc_list([{[ED], fun enc_ErrorDescriptor/2}], % Indention cosmetics + ?INC_INDENT(State)) + ]; +do_enc_ActionReply(ED, asn1_NOVALUE, CmdRep, State) + when (ED =/= asn1_NOVALUE) andalso (CmdRep =/= []) -> + [ + enc_list([{CmdRep, fun enc_CommandReply/2}, + {[ED], fun enc_ErrorDescriptor/2}], % Indention cosmetics + ?INC_INDENT(State)) + ]; +do_enc_ActionReply(ED, CtxRep, CmdRep, State) + when (ED =/= asn1_NOVALUE) andalso + (CtxRep =/= asn1_NOVALUE) andalso + (CmdRep =/= []) -> + [ + enc_ContextRequest(CtxRep, ?INC_INDENT(State)), + ?COMMA_INDENT(?INC_INDENT(State)), + enc_list([{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)) + ]. + + +enc_ContextRequest_priority(asn1_NOVALUE, _State) -> + {[], dummy}; +enc_ContextRequest_priority(Val, _State) -> + {[Val], fun(X,S) -> [?PriorityToken,?EQUAL,enc_UINT16(X, S)] end}. + +enc_ContextRequest_emergency(asn1_NOVALUE, _State) -> + {[], dummy}; +enc_ContextRequest_emergency(true, _State) -> + {[?EmergencyToken], fun(Elem, _) -> Elem end}; +enc_ContextRequest_emergency(false, _State) -> + {[?EmergencyOffToken], fun(Elem, _) -> Elem end}. + +enc_ContextRequest_topologyReq(asn1_NOVALUE, _State) -> + {[], dummy}; +enc_ContextRequest_topologyReq({'ContextRequest_topologyReq', + asn1_NOVALUE}, _State) -> + {[], dummy}; +enc_ContextRequest_topologyReq({'ContextRequest_topologyReq', + List}, _State) -> + {List, fun enc_TopologyRequest/2}; +enc_ContextRequest_topologyReq(List, _State) -> + {[List], fun enc_TopologyRequest/2}. + +enc_ContextRequest_iepscallind(asn1_NOVALUE, _State) -> + {[], dummy}; +enc_ContextRequest_iepscallind(Bool, _State) -> + {[Bool], fun enc_iepsValue/2}. + +enc_ContextRequest_contextProp(asn1_NOVALUE, _State) -> + {[], dummy}; +enc_ContextRequest_contextProp([], _State) -> + {[], dummy}; +enc_ContextRequest_contextProp(Props, _State) -> + {[Props], fun(Elem, S) -> enc_contextAttrDescriptor(Elem, contextProps, S) end}. + +enc_ContextRequest_contextList(asn1_NOVALUE, _State) -> + {[], dummy}; +enc_ContextRequest_contextList([], _State) -> + {[], dummy}; +enc_ContextRequest_contextList(Props, _State) -> + {[Props], fun(Elem, S) -> + enc_contextAttrDescriptor(Elem, contextList, S) + end}. + +enc_contextAttrDescriptor([Mand|Opt], contextProps, State) -> + [ + ?ContextAttrToken, + ?LBRKT_INDENT(State), + [enc_PropertyParm(Mand, State) | + [[?COMMA_INDENT(State), enc_PropertyParm(Val, State)] || Val <- Opt]], + ?RBRKT_INDENT(State) + ]; +enc_contextAttrDescriptor(CtxIdList, contextList, State) -> + [ + ?ContextAttrToken, + ?LBRKT_INDENT(State), + enc_contextIdList(CtxIdList, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]. + +enc_contextIdList([Mand|Opt], State) -> + State2 = ?INC_INDENT(State), + [ + ?ContextListToken, + ?EQUAL, + ?LBRKT_INDENT(State), + [enc_ContextID(Mand, State2) | + [[?COMMA_INDENT(State2), enc_ContextID(Val, State2)] || Val <- Opt]], + ?RBRKT_INDENT(State) + ]. + +enc_ContextRequest(asn1_NOVALUE, _State) -> + []; +enc_ContextRequest(#'ContextRequest'{priority = asn1_NOVALUE, + emergency = asn1_NOVALUE, + topologyReq = asn1_NOVALUE, + iepscallind = asn1_NOVALUE, + contextProp = asn1_NOVALUE, + contextList = asn1_NOVALUE}, _State) -> + []; +enc_ContextRequest(#'ContextRequest'{priority = asn1_NOVALUE, + emergency = asn1_NOVALUE, + topologyReq = [], + iepscallind = asn1_NOVALUE, + contextProp = [], + contextList = []}, _State) -> + []; +enc_ContextRequest(#'ContextRequest'{priority = Prio, + emergency = Em, + topologyReq = TR, + iepscallind = Ieps, + contextProp = CP, + contextList = CL}, State) -> + [ + enc_list([enc_ContextRequest_priority(Prio, State), + enc_ContextRequest_emergency(Em, State), + enc_ContextRequest_topologyReq(TR, State), + enc_ContextRequest_iepscallind(Ieps, State), + enc_ContextRequest_contextProp(CP, State), + enc_ContextRequest_contextList(CL, State)], + State) + ]. + + +%% -- contextAudit -- +%% contextAudit = ContextAuditToken LBRKT +%% (contextAuditProperties *(COMMA contextAuditProperties)) / +%% indAudcontextAttrDesscriptor +%% RBRKT +%% contextAuditProperties = +%% (TopologyToken / EmergencyToken / PriorityToken / +%% IEPSToken / pkgdName / contextAuditSelect) +%% contextAuditSelect = +%% priority / emergencyValue / iepsValue / +%% contextAttrDescriptor / auditSelectLogic +%% indAudcontextAttrDesscriptor = +%% ContextAttrToken LBRKT +%% (contextAuditProperties *(COMMA contextAuditProperties)) +%% RBRKT +%% +%% This could actually either be +%% a) a list of contextAuditProperties: +%% contextAuditProperties *(COMMA contextAuditProperties) +%% b) a indAudcontextAttrDescriptor +%% But since b) actually has the same content as a) with +%% the extra ContextAttrToken, there does not seem to be any +%% reason for using it. +enc_ContextAttrAuditRequest(asn1_NOVALUE, _State) -> + []; +enc_ContextAttrAuditRequest( + #'ContextAttrAuditRequest'{topology = asn1_NOVALUE, + emergency = asn1_NOVALUE, + priority = asn1_NOVALUE, + iepscallind = asn1_NOVALUE, + contextPropAud = asn1_NOVALUE, + selectpriority = asn1_NOVALUE, + selectemergency = asn1_NOVALUE, + selectiepscallind = asn1_NOVALUE, + selectLogic = asn1_NOVALUE}, _State) -> + []; +enc_ContextAttrAuditRequest( + #'ContextAttrAuditRequest'{topology = asn1_NOVALUE, + emergency = asn1_NOVALUE, + priority = asn1_NOVALUE, + iepscallind = asn1_NOVALUE, + contextPropAud = [], + selectpriority = asn1_NOVALUE, + selectemergency = asn1_NOVALUE, + selectiepscallind = asn1_NOVALUE, + selectLogic = asn1_NOVALUE}, _State) -> + []; +enc_ContextAttrAuditRequest( + #'ContextAttrAuditRequest'{topology = Top, + emergency = Em, + priority = Prio, + iepscallind = Ieps, + contextPropAud = CPA, + selectpriority = SPrio, + selectemergency = SEm, + selectiepscallind = SIeps, + selectLogic = SL}, State) -> + [ + ?ContextAuditToken, + ?LBRKT_INDENT(State), + enc_list([{[Top], fun('NULL', _) -> ?TopologyToken end}, + {[Em], fun('NULL', _) -> ?EmergencyToken end}, + {[Prio], fun('NULL', _) -> ?PriorityToken end}, + {[Ieps], fun('NULL', _) -> ?IEPSToken end}, + {CPA, fun enc_IndAudPropertyParm/2}, + enc_ContextAttrAuditRequest_selectpriority(SPrio, State), + enc_ContextAttrAuditRequest_selectemergency(SEm, State), + enc_ContextAttrAuditRequest_selectiepscallind(SIeps, State), + enc_ContextAttrAuditRequest_selectLogic(SL, State)], + ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]. + +enc_ContextAttrAuditRequest_selectpriority(asn1_NOVALUE, _State) -> + {[], dummy}; +enc_ContextAttrAuditRequest_selectpriority(SPrio, _State) -> + {[SPrio], fun(X,S) -> [?PriorityToken,?EQUAL,enc_UINT16(X, S)] end}. + +enc_ContextAttrAuditRequest_selectemergency(asn1_NOVALUE, _State) -> + {[], dummy}; +enc_ContextAttrAuditRequest_selectemergency(SEm, _State) -> + {[SEm], fun(X,S) -> enc_emergencyValue(X, S) end}. + +enc_ContextAttrAuditRequest_selectiepscallind(asn1_NOVALUE, _State) -> + {[], dummy}; +enc_ContextAttrAuditRequest_selectiepscallind(SEm, _State) -> + {[SEm], fun(X,S) -> enc_iepsValue(X, S) end}. + +enc_ContextAttrAuditRequest_selectLogic(asn1_NOVALUE, _State) -> + {[], dummy}; +enc_ContextAttrAuditRequest_selectLogic({andAUDITSelect, 'NULL'}, _State) -> + {[], dummy}; % This is default so, there is no reason to add it +enc_ContextAttrAuditRequest_selectLogic({orAUDITSelect, 'NULL'}, _State) -> + {[?OrAUDITselectToken], fun(Elem, _) -> Elem end}. + +enc_emergencyValue(true, _) -> + [?EmergencyValueToken,?EQUAL,?EmergencyToken]; +enc_emergencyValue(_, _) -> + [?EmergencyValueToken,?EQUAL,?EmergencyOffToken]. + + +%% enc_IndAudContextAttrDescriptor( +%% #'ContextAttrAuditRequest'{topology = Top, +%% emergency = Em, +%% priority = Prio, +%% iepscallind = Ieps, +%% contextPropAud = CPA, +%% selectpriority = SelPrio, +%% selectemergency = SelEm, +%% selectiepscallind = SelIeps, +%% selectLogic = SelLog}, State) -> +%% [ +%% ?ContextAttrToken, +%% ?LBRKT_INDENT(State), +%% enc_list([{[Top], fun('NULL', _) -> ?TopologyToken end}, +%% {[Em], fun('NULL', _) -> ?EmergencyToken end}, +%% {[Prio], fun('NULL', _) -> ?PriorityToken end}, +%% {[Ieps], fun('NULL', _) -> ?IEPSToken end}, +%% {CPA, fun enc_IndAudPropertyParm/2}], +%% ?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) -> +%% d("enc_Command -> entry with" +%% "~n Tag: ~p" +%% "~n Val: ~p", [Tag, Val]), + 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) -> +%% d("enc_CommandReply -> entry with" +%% "~n Tag: ~p" +%% "~n Val: ~p", [Tag, Val]), + 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 = TD, + streamID = asn1_NOVALUE, % OPTIONAL + topologyDirectionExtension = asn1_NOVALUE % OPTIONAL + }, State) -> + [ + enc_TerminationID(From, State), + ?COMMA_INDENT(State), + enc_TerminationID(To, State), + ?COMMA_INDENT(State), + enc_TopologyDirection(TD, State) + ]; +enc_TopologyRequest1( + #'TopologyRequest'{terminationFrom = From, + terminationTo = To, + topologyDirection = TD, + streamID = SID, % OPTIONAL + topologyDirectionExtension = asn1_NOVALUE}, % OPTIONAL + State) when (SID =/= asn1_NOVALUE) -> + [ + enc_TerminationID(From, State), + ?COMMA_INDENT(State), + enc_TerminationID(To, State), + ?COMMA_INDENT(State), + enc_TopologyDirection(TD, State), + ?COMMA_INDENT(State), + enc_StreamID(SID, State) + ]; +enc_TopologyRequest1( + #'TopologyRequest'{terminationFrom = From, + terminationTo = To, + topologyDirection = TD, + streamID = asn1_NOVALUE, % OPTIONAL + topologyDirectionExtension = TDE}, % OPTIONAL + State) when (TDE =/= asn1_NOVALUE) -> + [ + enc_TerminationID(From, State), + ?COMMA_INDENT(State), + enc_TerminationID(To, State), + ?COMMA_INDENT(State), + enc_TopologyDirection(TD, State), + ?COMMA_INDENT(State), + enc_TopologyDirectionExtension(TDE, State) + ]; +enc_TopologyRequest1( + #'TopologyRequest'{terminationFrom = From, + terminationTo = To, + topologyDirection = TD, + streamID = SID, % OPTIONAL + topologyDirectionExtension = TDE}, % OPTIONAL + State) when (SID =/= asn1_NOVALUE) andalso (TDE =/= asn1_NOVALUE) -> + [ + enc_TerminationID(From, State), + ?COMMA_INDENT(State), + enc_TerminationID(To, State), + ?COMMA_INDENT(State), + enc_TopologyDirection(TD, State), + ?COMMA_INDENT(State), + enc_StreamID(SID, State), + ?COMMA_INDENT(State), + enc_TopologyDirectionExtension(TDE, State) + ]. + +enc_TopologyDirection(bothway, _State) -> + ?BothwayToken; +enc_TopologyDirection(isolate, _State) -> + ?IsolateToken; +enc_TopologyDirection(oneway, _State) -> + ?OnewayToken. + +enc_TopologyDirectionExtension(onewayexternal, _State) -> + ?OnewayExternalToken; +enc_TopologyDirectionExtension(onewayboth, _State) -> + ?OnewayBothToken. + +enc_iepsValue(Val, _State) -> + [ + ?IEPSToken, + ?EQUAL, + case Val of + false -> ?OffToken; + true -> ?OnToken + end + ]. + + + +enc_AmmRequest(#'AmmRequest'{terminationID = TIDs, + descriptors = Ds}, State) -> + [ + %% Assume that Token is added elsewhere + ?EQUAL, + enc_termIDList(TIDs, State), + enc_opt_brackets( + enc_list([{Ds, 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); + statisticsDescriptor -> enc_StatisticsDescriptor(Desc, State); + _ -> + error({invalid_ammDescriptor_tag, Tag}) + end. + +enc_AmmsReply(#'AmmsReply'{terminationID = TIDs, + terminationAudit = asn1_NOVALUE}, State) -> + [ + ?EQUAL, + enc_termIDList(TIDs, State) + ]; +enc_AmmsReply(#'AmmsReply'{terminationID = TIDs, + terminationAudit = []}, State) -> + [ + ?EQUAL, + enc_termIDList(TIDs, State) + ]; +enc_AmmsReply(#'AmmsReply'{terminationID = TIDs, + terminationAudit = Res}, State) -> + [ + ?EQUAL, + enc_termIDList(TIDs, State), + case lists:flatten(enc_TerminationAudit(Res, ?INC_INDENT(State))) of + [] -> + []; + L -> + [ + ?LBRKT_INDENT(State), + L, + ?RBRKT_INDENT(State) + ] + end + ]. + +enc_SubtractRequest(#'SubtractRequest'{terminationID = TIDs, + auditDescriptor = asn1_NOVALUE}, + State) -> + [ + %% Assume that Token is added elsewhere + ?EQUAL, + enc_termIDList(TIDs, State) + ]; +enc_SubtractRequest(#'SubtractRequest'{terminationID = TIDs, + auditDescriptor = AD}, + State) -> + [ + %% Assume that Token is added elsewhere + ?EQUAL, + enc_termIDList(TIDs, State), + ?LBRKT_INDENT(State), + enc_AuditDescriptor(AD, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]. + +enc_AuditRequest(#'AuditRequest'{terminationID = TID, + auditDescriptor = asn1_NOVALUE, + terminationIDList = asn1_NOVALUE}, State) -> + [ + %% Assume that Token is added elsewhere + ?EQUAL, + enc_termIDList([TID], State) + ]; +enc_AuditRequest(#'AuditRequest'{terminationID = TID, + auditDescriptor = asn1_NOVALUE, + terminationIDList = [TID|_] = TIDList}, + State) -> + [ + %% Assume that Token is added elsewhere + ?EQUAL, + enc_termIDList(TIDList, State) + ]; +enc_AuditRequest(#'AuditRequest'{terminationID = TID, + auditDescriptor = asn1_NOVALUE, + terminationIDList = TIDList}, + _State) -> + error({invalid_terminationID, TID, TIDList}); +enc_AuditRequest(#'AuditRequest'{terminationID = TID, + auditDescriptor = AD, + terminationIDList = asn1_NOVALUE}, State) -> + [ + %% Assume that Token is added elsewhere + ?EQUAL, + enc_termIDList([TID], State), + ?LBRKT_INDENT(State), + enc_AuditDescriptor(AD, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]; +enc_AuditRequest(#'AuditRequest'{terminationID = TID, + auditDescriptor = AD, + terminationIDList = [TID|_] = TIDList}, + State) -> + [ + %% Assume that Token is added elsewhere + ?EQUAL, + enc_termIDList(TIDList, State), + ?LBRKT_INDENT(State), + enc_AuditDescriptor(AD, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]; +enc_AuditRequest(#'AuditRequest'{terminationID = TID, + auditDescriptor = _AD, + terminationIDList = TIDList}, + _State) -> + error({invalid_terminationID, TID, TIDList}). + +%% 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) -> +%% d("enc_AuditReply -> entry with" +%% "~n Tag: ~p" +%% "~n Val: ~p", [Tag, Val]), + case Tag of + contextAuditResult -> + [ + ?EQUAL, + ?CtxToken, + enc_TerminationIDList(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}); + auditResultTermList -> + enc_TermListAuditResult(Val, State); + _ -> + error({invalid_AuditReply_tag, Tag}) + end. + +%% This is actually the same as AuditResult with the exception +%% that instead of terminationID we have terminationIDList. +enc_TermListAuditResult( + #'TermListAuditResult'{terminationIDList = TIDList, + terminationAuditResult = asn1_NOVALUE}, State) -> +%% d("enc_TermListAuditResult -> entry with" +%% "~n TIDList: ~p", [TIDList]), + [ + ?EQUAL, + enc_termIDList(TIDList, State) + ]; +enc_TermListAuditResult( + #'TermListAuditResult'{terminationIDList = TIDList, + terminationAuditResult = []}, State) -> +%% d("enc_TermListAuditResult -> entry with" +%% "~n TIDList: ~p", [TIDList]), + [ + ?EQUAL, + enc_termIDList(TIDList, State) + ]; +enc_TermListAuditResult( + #'TermListAuditResult'{terminationIDList = TIDList, + terminationAuditResult = TAR}, State) -> +%% d("enc_TermListAuditResult -> entry with" +%% "~n TIDList: ~p" +%% "~n TAR: ~p", [TIDList, TAR]), + [ + ?EQUAL, + enc_termIDList(TIDList, State), + case lists:flatten(enc_TerminationAudit(TAR, ?INC_INDENT(State))) of + [] -> + []; + L -> + [ + ?LBRKT_INDENT(State), + L, + ?RBRKT_INDENT(State) + ] + end + ]. + +enc_auditOther(#'AuditResult'{terminationID = TID, + terminationAuditResult = asn1_NOVALUE}, State) -> + [ + ?EQUAL, + enc_termIDList([TID], State) + ]; +enc_auditOther(#'AuditResult'{terminationID = TID, + terminationAuditResult = []}, State) -> + [ + ?EQUAL, + enc_termIDList([TID], State) + ]; +enc_auditOther(#'AuditResult'{terminationID = TID, + terminationAuditResult = Res}, State) -> + [ + ?EQUAL, + enc_termIDList([TID], 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) -> +% d("enc_AuditDescriptor(asn1_NOVALUE) -> entry"), + [ + ?AuditToken, + [?LBRKT, ?RBRKT] + ]; +enc_AuditDescriptor(#'AuditDescriptor'{auditToken = [], + auditPropertyToken = asn1_NOVALUE}, + _State) -> +% d("enc_AuditDescriptor([]) -> entry"), + [ + ?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. + +enc_IndAudMediaDescriptor( + #'IndAudMediaDescriptor'{termStateDescr = asn1_NOVALUE, + streams = Streams}, State) -> + [ + ?MediaToken, + ?LBRKT_INDENT(State), + enc_IndAudMediaDescriptor_streams(Streams, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]; +enc_IndAudMediaDescriptor( + #'IndAudMediaDescriptor'{termStateDescr = TSD, + streams = asn1_NOVALUE}, State) -> + [ + ?MediaToken, + ?LBRKT_INDENT(State), + enc_IndAudTerminationStateDescriptor(TSD, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]; +enc_IndAudMediaDescriptor( + #'IndAudMediaDescriptor'{termStateDescr = TSD, + streams = Streams}, State) -> + [ + ?MediaToken, + ?LBRKT_INDENT(State), + enc_IndAudTerminationStateDescriptor(TSD, ?INC_INDENT(State)), + ?COMMA_INDENT(State), + enc_IndAudMediaDescriptor_streams(Streams, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]. + +enc_IndAudMediaDescriptor_streams({oneStream, Val}, State) -> + enc_IndAudStreamParms(Val, State); +enc_IndAudMediaDescriptor_streams({multiStream, Val}, State) -> + enc_IndAudMediaDescriptor_multiStream(Val, State); +enc_IndAudMediaDescriptor_streams({Tag, _Val}, _State) -> + error({invalid_IndAudMediaDescriptor_streams_tag, Tag}). + +enc_IndAudTerminationStateDescriptor( + #'IndAudTerminationStateDescriptor'{propertyParms = [], + eventBufferControl = asn1_NOVALUE, + serviceState = 'NULL', + serviceStateSel = asn1_NOVALUE}, + _State) -> + [ + ?TerminationStateToken, + ?LBRKT_INDENT(_State), + ?ServiceStatesToken, + ?RBRKT_INDENT(_State) + ]; +enc_IndAudTerminationStateDescriptor( + #'IndAudTerminationStateDescriptor'{propertyParms = [], + eventBufferControl = asn1_NOVALUE, + serviceState = asn1_NOVALUE, + serviceStateSel = SSS}, + State) when (SSS =/= asn1_NOVALUE) -> + [ + ?TerminationStateToken, + ?LBRKT_INDENT(State), + enc_serviceState(SSS, State), + ?RBRKT_INDENT(State) + ]; +enc_IndAudTerminationStateDescriptor( + #'IndAudTerminationStateDescriptor'{propertyParms = [], + eventBufferControl = 'NULL', + serviceState = asn1_NOVALUE, + serviceStateSel = asn1_NOVALUE}, + _State) -> + [ + ?TerminationStateToken, + ?LBRKT_INDENT(_State), + ?BufferToken, + ?RBRKT_INDENT(_State) + ]; +enc_IndAudTerminationStateDescriptor( + #'IndAudTerminationStateDescriptor'{propertyParms = [Parms], + eventBufferControl = asn1_NOVALUE, + serviceState = asn1_NOVALUE, + serviceStateSel = asn1_NOVALUE}, + State) -> + #'IndAudPropertyParm'{name = Name} = Parms, + [ + ?TerminationStateToken, + ?LBRKT_INDENT(State), + enc_PkgdName(Name, State), + ?RBRKT_INDENT(State) + ]. + +enc_IndAudStreamParms( + #'IndAudStreamParms'{localControlDescriptor = LCD, + localDescriptor = LD, + remoteDescriptor = RD, + statisticsDescriptor = SD}, State) -> + [ + enc_list([{[LCD], fun enc_IndAudLocalControlDescriptor/2}, + {[LD], fun enc_remoteDescriptor/2}, + {[RD], fun enc_localDescriptor/2}, + {[SD], fun enc_IndAudStatisticsDescriptor/2}], + ?INC_INDENT(State)) + ]. + +enc_IndAudLocalControlDescriptor( + #'IndAudLocalControlDescriptor'{streamMode = SM, + reserveValue = RV, + reserveGroup = RG, + propertyParms = PP, + streamModeSel = asn1_NOVALUE}, State) -> + [ + ?LocalControlToken, + ?LBRKT_INDENT(State), + enc_list([{[SM], fun('NULL', _) -> ?ModeToken end}, + {[RV], fun('NULL', _) -> ?ReservedValueToken end}, + {[RG], fun('NULL', _) -> ?ReservedGroupToken end}, + {PP, fun enc_IndAudPropertyParm/2}], + ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]; +enc_IndAudLocalControlDescriptor( + #'IndAudLocalControlDescriptor'{streamMode = asn1_NOVALUE, + reserveValue = RV, + reserveGroup = RG, + propertyParms = PP, + streamModeSel = SMS}, State) -> + [ + ?LocalControlToken, + ?LBRKT_INDENT(State), + enc_list([{[RV], fun('NULL', _) -> ?ReservedValueToken end}, + {[RG], fun('NULL', _) -> ?ReservedGroupToken end}, + { PP, fun enc_IndAudPropertyParm/2}, + {[SMS], fun enc_StreamMode/2}], + ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]. + +enc_IndAudPropertyParm(#'IndAudPropertyParm'{name = Name, propertyParms = PP}, + State) -> + [ + enc_list([{[Name], fun enc_PkgdName/2}, + {[PP], fun enc_PropertyParm/2}], State) + ]. + +enc_IndAudMediaDescriptor_multiStream(Val, State) when is_list(Val) -> + [ + enc_list([{Val, fun enc_IndAudStreamDescriptor/2}], State) + ]; +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( + #'IndAudEventBufferDescriptor'{eventName = EvName, + streamID = ID}, State) -> + [ + ?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({eventStream, ID}, State) -> + [ + ?LBRKT_INDENT(State), + enc_eventStream(ID, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]; +enc_IndAudEventBufferDescriptor_eventSpec(ID, State) -> + [ + ?LBRKT_INDENT(State), + enc_eventStream(ID, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]. + +enc_IndAudEventsDescriptor( + #'IndAudEventsDescriptor'{requestID = asn1_NOVALUE, + pkgdName = Name, + streamID = asn1_NOVALUE}, State) -> + [ + ?EventsToken, + ?LBRKT_INDENT(State), + enc_PkgdName(Name, State), + ?RBRKT_INDENT(State) + ]; +enc_IndAudEventsDescriptor( + #'IndAudEventsDescriptor'{requestID = RID, + pkgdName = Name, + streamID = asn1_NOVALUE}, State) -> + [ + ?EventsToken, + ?EQUAL, + enc_RequestID(RID, State), + ?LBRKT_INDENT(State), + enc_PkgdName(Name, State), + ?RBRKT_INDENT(State) + ]. + + +enc_IndAudSignalsDescriptor(asn1_NOVALUE, _State) -> + [ + ?SignalsToken, + ?LBRKT_INDENT(_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, + signalRequestID = asn1_NOVALUE}, State) -> + [ + enc_SignalName(SignalName, State) + ]; +enc_IndAudSignal(#'IndAudSignal'{signalName = SignalName, + streamID = SID, + signalRequestID = SRID}, State) -> + [ + enc_SignalName(SignalName, State), + ?LBRKT_INDENT(State), + enc_list([{[SID], fun enc_StreamID/2}, + {[SRID], fun enc_sigRequestID/2}], + State), + ?RBRKT_INDENT(State) + ]. + +enc_IndAudSeqSigList(#'IndAudSeqSigList'{id = ID, + signalList = asn1_NOVALUE}, + State) -> + [ + ?SignalListToken, + ?EQUAL, + enc_UINT16(ID, State) + ]; +enc_IndAudSeqSigList(#'IndAudSeqSigList'{id = ID, + signalList = SL}, + State) -> + [ + ?SignalListToken, + ?EQUAL, + enc_UINT16(ID, State), + ?LBRKT_INDENT(State), + enc_IndAudSignal(SL, ?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([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) -> +%% d("enc_AuditReturnParameter -> entry with" +%% "~n Tag: ~p" +%% "~n Val: ~p", [Tag, Val]), + 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) -> +%% d("enc_AuditReturnParameter -> entry with" +%% "~n List: ~p", [List]), + enc_list([{List, fun enc_auditReturnItem/2}], State). + + +enc_NotifyRequest(#'NotifyRequest'{terminationID = TIDs, + observedEventsDescriptor = OED, + errorDescriptor = asn1_NOVALUE}, + State) -> + [ + %% Assume that Token is added elsewhere + ?EQUAL, + enc_termIDList(TIDs, State), + ?LBRKT_INDENT(State), + enc_ObservedEventsDescriptor(OED, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]; +enc_NotifyRequest(#'NotifyRequest'{terminationID = TIDs, + observedEventsDescriptor = OED, + errorDescriptor = ED}, State) -> + [ + %% Assume that Token is added elsewhere + ?EQUAL, + enc_termIDList(TIDs, State), + ?LBRKT_INDENT(State), + enc_ObservedEventsDescriptor(OED, ?INC_INDENT(State)), + ?COMMA, + enc_ErrorDescriptor(ED, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]. + +enc_NotifyReply(#'NotifyReply'{terminationID = TIDs, + errorDescriptor = asn1_NOVALUE}, State) -> + [ + %% Assume that Token is added elsewhere + ?EQUAL, + enc_termIDList(TIDs, State) + ]; +enc_NotifyReply(#'NotifyReply'{terminationID = TIDs, + errorDescriptor = ED}, State) -> + [ + %% Assume that Token is added elsewhere + ?EQUAL, + enc_termIDList(TIDs, State), + ?LBRKT_INDENT(State), + enc_ErrorDescriptor(ED, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]. + +enc_ObservedEventsDescriptor( + #'ObservedEventsDescriptor'{requestId = RID, + observedEventLst = OEL}, State) -> + [ + ?ObservedEventsToken, + ?EQUAL, + enc_RequestID(RID, State), + ?LBRKT_INDENT(State), + enc_observedEvents(OEL, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]. + +enc_observedEvents([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(#'ObservedEvent'{eventName = EN, + streamID = SID, + eventParList = EPL, + timeNotation = asn1_NOVALUE}, State) -> + [ + ?LWSP, + enc_EventName(EN, State), + enc_opt_brackets( + enc_list([{[SID], fun enc_eventStream/2}, + { EPL, fun enc_eventOther/2}], + ?INC_INDENT(State)), + State) + ]; +enc_ObservedEvent(#'ObservedEvent'{eventName = EN, + streamID = SID, + eventParList = EPL, + timeNotation = TN}, State) -> + [ + enc_TimeNotation(TN, State), + ?LWSP, + ?COLON, + ?LWSP, + enc_EventName(EN, State), + enc_opt_brackets( + enc_list([{[SID], fun enc_eventStream/2}, + {EPL, 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( + #'ServiceChangeRequest'{terminationID = TIDs, + serviceChangeParms = Parms}, State) -> + [ + %% Assume that Token is added elsewhere + ?EQUAL, + enc_termIDList(TIDs, State), + ?LBRKT_INDENT(State), + enc_ServiceChangeParm(Parms, ?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( + #'ServiceChangeReply'{terminationID = TIDs, + serviceChangeResult = Res}, State) -> + [ + %% Assume that Token is added elsewhere + ?EQUAL, + enc_termIDList(TIDs, State), + enc_ServiceChangeResult(Res, State) + ]. + +enc_ServiceChangeResult({'ServiceChangeResult', Val}, State) -> + enc_ServiceChangeResult(Val, State); +enc_ServiceChangeResult({errorDescriptor, Val}, State) -> + [ + ?LBRKT_INDENT(State), + enc_ErrorDescriptor(Val, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]; +enc_ServiceChangeResult({serviceChangeResParms, Val}, State) -> + 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; +enc_ServiceChangeResult({Tag, _}, _State) -> + error({invalid_ServiceChangeResult_tag, Tag}). + +%% %% 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_TerminationIDList({'TerminationIDList',Val}, State) -> + enc_TerminationIDList(Val, State); +enc_TerminationIDList([TID], State) -> + [ + ?LBRKT_INDENT(State), + enc_TerminationID(TID, State), + ?RBRKT_INDENT(State) + ]; +enc_TerminationIDList(TIDs, State) -> + [ + ?LBRKT_INDENT(State), + enc_list([{TIDs, fun enc_TerminationID/2}], State), + ?RBRKT_INDENT(State) + ]. + +enc_termIDList({'TerminationIDList',Val}, State) -> + enc_termIDList(Val, State); +enc_termIDList([Singleton], State) -> + enc_TerminationID(Singleton, State); +enc_termIDList(TidList, State) + when is_list(TidList) andalso (length(TidList) > 1) -> +%% d("enc_termIDList -> entry with" +%% "~n TidList: ~p", [TidList]), + State2 = ?INC_INDENT(State), + [ + ?LSBRKT_INDENT(State), + enc_list([{TidList, fun enc_TerminationID/2}], State2), + ?RSBRKT_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(#'MediaDescriptor'{termStateDescr = TSD, + streams = Streams}, State) -> + [ + ?MediaToken, + ?LBRKT_INDENT(State), + enc_list([{[TSD], fun enc_TerminationStateDescriptor/2} | + decompose_streams(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}, + {[Val#'StreamParms'.statisticsDescriptor], + fun enc_StatisticsDescriptor/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') -> +%% d("enc_PropertyParm -> entry with" +%% "~n Val: ~p", [Val]), + 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) -> +%% d("enc_PropertyParmValues -> entry with" +%% "~n Single: ~p", [Single]), + [ + ?EqualToken, + enc_Value(Single, State) + ]; +enc_propertyParmValues([Single], {relation, Rel}, State) -> +%% d("enc_PropertyParmValues -> entry with" +%% "~n Single: ~p" +%% "~n Rel: ~p", [Single, Rel]), + 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 + [ + ?EQUAL, + ?LSBRKT, + enc_Value(Low, State), + ?COLON, + enc_Value(High, State), + ?RSBRKT + ]; +enc_propertyParmValues(Values, {sublist, true}, State)-> + %% sublist (i.e. A AND B AND ...) + [ + ?EQUAL, + ?LSBRKT_INDENT(State), + enc_list([{Values, fun enc_Value/2}], ?INC_INDENT(State)), + ?RSBRKT_INDENT(State) + ]; +enc_propertyParmValues(Values, {sublist, false}, State) -> + %% alternatives (i.e. A OR B OR ...) + [ + ?EQUAL, + ?LBRKT_INDENT(State), + enc_list([{Values, fun enc_Value/2}], ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]; +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_TerminationIDList(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(#'EventsDescriptor'{requestID = asn1_NOVALUE, + eventList = []}, _State) -> + [ + ?EventsToken + ]; +enc_EventsDescriptor(#'EventsDescriptor'{requestID = RID, + eventList = Evs}, State) + when (RID =/= asn1_NOVALUE) andalso (Evs =/= []) -> + [ + ?EventsToken, + ?EQUAL, + enc_RequestID(RID, State), + ?LBRKT_INDENT(State), + enc_list([{Evs, fun enc_RequestedEvent/2}], ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]; +enc_EventsDescriptor(#'EventsDescriptor'{requestID = RID, + eventList = Evs}, _State) -> + error({invalid_EventsDescriptor, RID, Evs}). + +enc_RequestedEvent(#'RequestedEvent'{pkgdName = N, + streamID = asn1_NOVALUE, + eventAction = asn1_NOVALUE, + evParList = []}, State) -> + PkgdName = ?META_ENC(event, N), + [ + enc_PkgdName(PkgdName, State) + ]; +enc_RequestedEvent(#'RequestedEvent'{pkgdName = N, + streamID = SID, + eventAction = EA, + evParList = EPL}, State) -> + PkgdName = ?META_ENC(event, N), + [ + enc_PkgdName(PkgdName, State), + ?LBRKT_INDENT(State), + enc_list([{[SID], fun enc_eventStream/2}, + {EPL, fun enc_eventOther/2} | + decompose_requestedActions(EA)], + ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]. + +decompose_requestedActions(asn1_NOVALUE) -> + []; +decompose_requestedActions( + #'RequestedActions'{keepActive = asn1_NOVALUE, + eventDM = asn1_NOVALUE, + secondEvent = asn1_NOVALUE, + signalsDescriptor = asn1_NOVALUE, + notifyBehaviour = asn1_NOVALUE, + resetEventsDescriptor = asn1_NOVALUE}) -> + []; + +%% +%% This in the ABNF: +%% at-most-once each of +%% - KeepActiveToken +%% - notifyBehaviour +%% - eventDM +%% - ResetEventsDescriptor +%% - 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, + notifyBehaviour = NB, + resetEventsDescriptor = RED}) + when (KA =/= true) andalso ((SD =/= asn1_NOVALUE) andalso (SD =/= [])) -> + [ + {[EDM], fun enc_EventDM/2}, + {[{SE, SD}], fun enc_embedWithSig/2}, + {[NB], fun enc_notifyBehaviour/2}, + {[RED], fun('NULL', _) -> ?ResetEventsDescriptorToken end} + ]; + +%% embedNoSig +decompose_requestedActions(#'RequestedActions'{keepActive = KA, + eventDM = EDM, + secondEvent = SE, + signalsDescriptor = SD, + notifyBehaviour = NB, + resetEventsDescriptor = RED}) + when (SD =:= asn1_NOVALUE) orelse (SD =:= []) -> + [ + {[KA], fun enc_keepActive/2}, + {[EDM], fun enc_EventDM/2}, + {[SE], fun enc_embedNoSig/2}, + {[NB], fun enc_notifyBehaviour/2}, + {[RED], fun('NULL', _) -> ?ResetEventsDescriptorToken end} + ]; + +%% Fallback, if everything else failes.... +decompose_requestedActions(#'RequestedActions'{keepActive = KA, + eventDM = EDM, + secondEvent = SE, + signalsDescriptor = SD, + notifyBehaviour = NB, + resetEventsDescriptor = RED}) -> + [ + {[KA], fun enc_keepActive/2}, + {[EDM], fun enc_EventDM/2}, + {[{SE, SD}], fun enc_embedWithSig/2}, + {[NB], fun enc_notifyBehaviour/2}, + {[RED], fun('NULL', _) -> ?ResetEventsDescriptorToken end} + ]. + + +enc_embedNoSig(#'SecondEventsDescriptor'{requestID = RID, + eventList = Evs}, State) -> + [ + ?EmbedToken, + ?LBRKT_INDENT(State), + enc_embedFirst(RID, Evs, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]. + +enc_embedWithSig({asn1_NOVALUE, SD}, State) -> + [ + ?EmbedToken, + ?LBRKT_INDENT(State), + enc_SignalsDescriptor(SD, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]; +enc_embedWithSig({#'SecondEventsDescriptor'{requestID = RID, + eventList = Evs}, SD}, State) -> + [ + ?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) -> + case Val of + true -> [?KeepActiveToken]; + false -> [] + end. + +enc_EventDM({'EventDM',Val}, State) -> + enc_EventDM(Val, State); +enc_EventDM({Tag, Val}, State) -> + 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_notifyBehaviour({notifyImmediate, 'NULL'}, _State) -> + [?NotifyImmediateToken]; +enc_notifyBehaviour({notifyRegulated, Val}, State) -> + enc_RegulatedEmbeddedDescriptor(Val, State); +enc_notifyBehaviour({neverNotify, 'NULL'}, _State) -> + [?NeverNotifyToken]; +enc_notifyBehaviour({Tag, Val}, _State) -> + error({invalid_notifyBehaviour, Tag, Val}). + +enc_RegulatedEmbeddedDescriptor( + #'RegulatedEmbeddedDescriptor'{secondEvent = asn1_NOVALUE, + signalsDescriptor = asn1_NOVALUE}, _State) -> + [ + ?NotifyRegulatedToken + ]; +enc_RegulatedEmbeddedDescriptor( + #'RegulatedEmbeddedDescriptor'{secondEvent = SE, + signalsDescriptor = asn1_NOVALUE}, State) -> + [ + ?NotifyRegulatedToken, + ?LBRKT_INDENT(State), + enc_embedNoSig(SE, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]; +enc_RegulatedEmbeddedDescriptor( + #'RegulatedEmbeddedDescriptor'{secondEvent = SE, + signalsDescriptor = SD}, State) -> + [ + ?NotifyRegulatedToken, + ?LBRKT_INDENT(State), + enc_embedWithSig({SE, SD}, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]; +enc_RegulatedEmbeddedDescriptor(Val, _State) -> + error({invalid_RegulatedEmbeddedDescriptor, Val}). + +enc_SecondRequestedEvent(#'SecondRequestedEvent'{pkgdName = N, + streamID = asn1_NOVALUE, + eventAction = asn1_NOVALUE, + evParList = []}, State) -> + PkgdName = ?META_ENC(event, N), + [ + enc_PkgdName(PkgdName, State) + ]; +enc_SecondRequestedEvent(#'SecondRequestedEvent'{pkgdName = N, + streamID = SID, + eventAction = EA, + evParList = EPL}, State) -> + PkgdName = ?META_ENC(event, N), + [ + enc_PkgdName(PkgdName, State), + ?LBRKT_INDENT(State), + enc_list([{[SID], fun enc_eventStream/2}, + {EPL, fun enc_eventOther/2} | + decompose_secondRequestedActions(EA)], + ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]. + +%% +%% This in the ABNF: +%% at-most-once each of +%% - KeepActiveToken +%% - notifyBehaviour +%% - eventDM +%% - ResetEventsDescriptor +%% - eventStream +%% KeepActiveToken and embedWithSig must not both be present +%% +decompose_secondRequestedActions(asn1_NOVALUE) -> + []; +decompose_secondRequestedActions( + #'SecondRequestedActions'{keepActive = asn1_NOVALUE, + eventDM = asn1_NOVALUE, + signalsDescriptor = asn1_NOVALUE, + notifyBehaviour = asn1_NOVALUE, + resetEventsDescriptor = asn1_NOVALUE}) -> + []; + +decompose_secondRequestedActions( + #'SecondRequestedActions'{keepActive = KA, + eventDM = EDM, + signalsDescriptor = SD, + notifyBehaviour = NB, + resetEventsDescriptor = RED}) + when (KA =/= true) andalso ((SD =/= asn1_NOVALUE) andalso (SD =/= [])) -> + [ + {[EDM], fun enc_EventDM/2}, + {[SD], fun enc_embedSig/2}, + {[NB], fun enc_notifyBehaviour/2}, + {[RED], fun('NULL', _) -> ?ResetEventsDescriptorToken end} + ]; +decompose_secondRequestedActions( + #'SecondRequestedActions'{keepActive = KA, + eventDM = EDM, + signalsDescriptor = SD, + notifyBehaviour = NB, + resetEventsDescriptor = RED}) + when (SD =:= asn1_NOVALUE) orelse (SD =:= []) -> + [ + {[KA], fun enc_keepActive/2}, + {[EDM], fun enc_EventDM/2}, + {[NB], fun enc_notifyBehaviour/2}, + {[RED], fun('NULL', _) -> ?ResetEventsDescriptorToken end} + ]; +decompose_secondRequestedActions(SRA) -> + error({invalid_SecondRequestedActions, SRA}). + +enc_embedSig(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(EvSpecs, State) + when is_list(EvSpecs) andalso (length(EvSpecs) >= 1) -> + [ + ?EventBufferToken, + ?LBRKT_INDENT(State), + enc_eventSpecs(EvSpecs, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]; +enc_EventBufferDescriptor(EvSpecs, _State) -> + error({bad_eventSpecs, EvSpecs}). + +enc_eventSpecs([Mand | Opt], State) -> + [enc_eventSpec(Mand, State), + [[?COMMA_INDENT(State), enc_eventSpec(Val, State)] || Val <- Opt]]. + +enc_eventSpec(#'EventSpec'{eventName = N, + streamID = asn1_NOVALUE, + eventParList = []}, State) -> + [ + enc_EventName(N, State) + ]; +enc_eventSpec(#'EventSpec'{eventName = N, + streamID = SID, + eventParList = EPL}, State) -> + [ + enc_EventName(N, State), + ?LBRKT_INDENT(State), + enc_list([{[SID], fun enc_eventStream/2}, {EPL, fun enc_eventOther/2}], + ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]. + +enc_SignalsDescriptor({'SignalsDescriptor',Val}, State) -> + enc_SignalsDescriptor(Val, State); +enc_SignalsDescriptor([], _State) -> + [ + ?SignalsToken + ]; +enc_SignalsDescriptor(SigRequests, State) when is_list(SigRequests) -> + [ + ?SignalsToken, + ?LBRKT_INDENT(State), + enc_list([{SigRequests, fun enc_SignalRequest/2}], ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]. + +enc_SignalRequest({'SignalRequest',Val}, State) -> + enc_SignalRequest(Val, State); +enc_SignalRequest({Tag, Val}, State) -> + 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(#'Signal'{signalName = SN, + streamID = SID, + sigType = ST, + duration = Du, + notifyCompletion = NC, + keepActive = KA, + sigParList = SPL, + direction = Di, + requestID = RID, + intersigDelay = ISD}, State) -> + [ + enc_SignalName(SN, State), + enc_opt_brackets( + enc_list([{[SID], fun enc_sigStream/2}, + {[ST], fun enc_sigSignalType/2}, + {[Du], fun enc_sigDuration/2}, + {[NC], fun enc_notifyCompletion/2}, + {[KA], fun enc_keepActive/2}, + {SPL, fun enc_sigOther/2}, + {[Di], fun enc_SignalDirection/2}, + {[RID], fun enc_sigRequestID/2}, + {[ISD], fun enc_sigIntsigDelay/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; + onIteration -> ?IterationToken + 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_SignalDirection({'SignalDirection', Val}, State) -> + enc_SignalDirection(Val, State); +enc_SignalDirection(Val, _State) -> + [ + ?DirectionToken, + ?EQUAL, + case Val of + internal -> ?InternalToken; + external -> ?ExternalToken; + both -> ?BothToken + end + ]. + +enc_sigRequestID(Val, State) -> + [ + ?RequestIDToken, + ?EQUAL, + enc_RequestID(Val, 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_sigIntsigDelay(Val, State) -> + [ + ?IntsigDelayToken, + ?EQUAL, + enc_UINT16(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}, + {[Val#'ServiceChangeParm'.serviceChangeIncompleteFlag], + fun('NULL', _) -> ?ServiceChangeIncompleteToken end}], + ?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; + _ -> + error({invalid_ServiceChangeMethod, Val}) + + end + ]. + +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 the string must contain at least one +%% BUGBUG: char. This violation of 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) -> +%% d("enc_Value -> entry with" +%% "~n String: ~p", [String]), + case quoted_string_count(String, 0, true, false) of + {_, 0, _} -> +%% d("enc_Value -> 0"), + [?DQUOTE, String, ?DQUOTE]; + {false, _, _} -> +%% d("enc_Value -> false"), + [?DQUOTE, String, ?DQUOTE]; + {true, _, _} -> +%% d("enc_Value -> true"), + [String] + end. + +%% needs_quoting(String) -> +%% case quoted_string_count(String, 0, true) of +%% {_, 0} -> +%% true; +%% {false, _} -> +%% true; +%% {true, _} -> +%% false +%% 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) -> +%% d("quoted_string_count -> entry with" +%% "~n H: ~p" +%% "~n Classified H: ~p" +%% "~n Count: ~p" +%% "~n IsSafe: ~p", [H, ?classify_char(H), Count, IsSafe]), + 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(asn1_NOVALUE, _State) -> +%% []; +%% enc_list([], _State) -> +%% []; +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({invalid_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(get(dbg), F, A). +%% d(true, F, A). + +%% d(true, F, A) -> +%% io:format("~p:" ++ F ++ "~n", [?MODULE | A]); +%% d(_, _, _) -> +%% ok. + + diff --git a/lib/megaco/src/text/megaco_text_gen_v1.hrl b/lib/megaco/src/text/megaco_text_gen_v1.hrl new file mode 100644 index 0000000000..b150c9ba58 --- /dev/null +++ b/lib/megaco/src/text/megaco_text_gen_v1.hrl @@ -0,0 +1,2404 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2000-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 Megaco/H.248 text messages from internal form +%%---------------------------------------------------------------------- + +-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), + ?INC_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) -> + [ + 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 -> {[], dummy}; + 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(Val, State) + when is_record(Val, 'TopologyRequest') -> + [ + fun(S) -> + [ + enc_TerminationID(Val#'TopologyRequest'.terminationFrom, S), + ?COMMA_INDENT(S), + enc_TerminationID(Val#'TopologyRequest'.terminationTo, S), + ?COMMA_INDENT(S), + case Val#'TopologyRequest'.topologyDirection of + bothway -> ?BothwayToken; + isolate -> ?IsolateToken; + oneway -> ?OnewayToken + end + ] + 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}, + _State) -> + [ + ?AuditToken, + [?LBRKT, ?RBRKT] + ]; +enc_AuditDescriptor(#'AuditDescriptor'{auditToken = []}, + _State) -> + [ + ?AuditToken, + [?LBRKT, ?RBRKT] + ]; +enc_AuditDescriptor(#'AuditDescriptor'{auditToken = List}, + State) -> + [ + ?AuditToken, + [ + ?LBRKT_INDENT(State), + enc_list([{List, fun enc_auditItem/2}], ?INC_INDENT(State)), + ?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. + +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({unknown_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 + 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') -> + PkgdName = ?META_ENC(event, Val#'RequestedEvent'.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 =:= []) -> + [ + {[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}) -> + [ + {[KA], fun enc_keepActive/2}, + {[EDM], fun enc_EventDM/2}, + {[{SE, SD}], fun enc_embedWithSig/2} + ]. + +enc_embedNoSig(#'SecondEventsDescriptor'{requestID = RID, + eventList = Evs}, State) -> + [ + ?EmbedToken, + ?LBRKT_INDENT(State), + enc_embedFirst(RID, Evs, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]. + +enc_embedWithSig({asn1_NOVALUE, SD}, State) -> + [ + ?EmbedToken, + ?LBRKT_INDENT(State), + enc_SignalsDescriptor(SD, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]; +enc_embedWithSig({#'SecondEventsDescriptor'{requestID = RID, + eventList = Evs}, SD}, State) -> + [ + ?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) -> + case Val of + true -> [?KeepActiveToken]; + false -> [] + end. + +enc_EventDM({'EventDM',Val}, State) -> + enc_EventDM(Val, State); +enc_EventDM({Tag, Val}, State) -> + 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 =/= []) -> + [ + ?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) -> + [ + ?EventsToken + ]. + +enc_SecondRequestedEvent(#'SecondRequestedEvent'{pkgdName = N, + streamID = SID, + evParList = EPL, + eventAction = EA}, State) -> + 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') -> + [ + {[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) andalso (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) -> + [ + ?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) -> + 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(#'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_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 = []}) -> + 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), + %% 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}], + ?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, 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(get(dbg), F, A). +% d(true, F, A). + +% d(true, F, A) -> +% io:format("DBG:~p:" ++ F ++ "~n", [?MODULE|A]); +% d(_, _, _) -> +% ok. 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. + + diff --git a/lib/megaco/src/text/megaco_text_gen_v3.hrl b/lib/megaco/src/text/megaco_text_gen_v3.hrl new file mode 100644 index 0000000000..1c19a4aa8b --- /dev/null +++ b/lib/megaco/src/text/megaco_text_gen_v3.hrl @@ -0,0 +1,3457 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2005-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 V3 Megaco/H.248 text messages from internal form +%%---------------------------------------------------------------------- + +%% -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) and (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) and (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); + segmentReply -> + enc_SegmentReply(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, + segmentNumber = asn1_NOVALUE, + segmentationComplete = asn1_NOVALUE + }, + 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, + segmentNumber = asn1_NOVALUE, + segmentationComplete = asn1_NOVALUE + }, + 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(#'TransactionReply'{transactionId = Tid, + immAckRequired = Req, + transactionResult = Res, + segmentNumber = SegNo, + segmentationComplete = asn1_NOVALUE + }, + State) -> + [ + ?ReplyToken, + ?EQUAL, + enc_TransactionId(Tid, State), + ?SLASH, + enc_SegmentNumber(SegNo, State), + ?LBRKT_INDENT(State), + enc_immAckRequired(Req, State), + enc_TransactionReply_transactionResult(Res, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]; +enc_TransactionReply(#'TransactionReply'{transactionId = Tid, + immAckRequired = Req, + transactionResult = Res, + segmentNumber = SegNo, + segmentationComplete = 'NULL' + }, + State) -> + [ + ?ReplyToken, + ?EQUAL, + enc_TransactionId(Tid, State), + ?SLASH, + enc_SegmentNumber(SegNo, State), + ?SLASH, + ?SegmentationCompleteToken, + ?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_SegmentReply({'SegmentReply', SR}, State) -> + enc_SegmentReply(SR, State); +enc_SegmentReply(#'SegmentReply'{transactionId = TID, + segmentNumber = SegNo, + segmentationComplete = asn1_NOVALUE + }, State) -> + [ + ?MessageSegmentToken, + ?EQUAL, + enc_TransactionId(TID, State), + ?SLASH, + enc_SegmentNumber(SegNo, State) + ]; +enc_SegmentReply(#'SegmentReply'{transactionId = TID, + segmentNumber = SegNo, + segmentationComplete = 'NULL' + }, State) -> + [ + ?MessageSegmentToken, + ?EQUAL, + enc_TransactionId(TID, State), + ?SLASH, + enc_SegmentNumber(SegNo, State), + ?SLASH, + ?SegmentationCompleteToken + ]; +enc_SegmentReply(Bin, _State) when is_binary(Bin) -> + [Bin]. + +enc_SegmentNumber({'SegmentNumber', SN}, State) -> + enc_SegmentNumber(SN, State); +enc_SegmentNumber(SN, State) -> + enc_UINT16(SN, State). + +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(#'ActionRequest'{contextId = CID, + contextRequest = asn1_NOVALUE, + contextAttrAuditReq = asn1_NOVALUE, + commandRequests = CmdReqs}, State) -> + [ + ?CtxToken, + ?EQUAL, + enc_ContextID(CID, State), + ?LBRKT_INDENT(State), + enc_list([{CmdReqs, fun enc_CommandRequest/2}], + ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]; +enc_ActionRequest(#'ActionRequest'{contextId = CID, + contextRequest = CtxReq, + contextAttrAuditReq = asn1_NOVALUE, + commandRequests = CmdReqs}, State) -> + [ + ?CtxToken, + ?EQUAL, + enc_ContextID(CID, State), + ?LBRKT_INDENT(State), + enc_list([{[CtxReq], fun enc_ContextRequest/2}, + {CmdReqs, fun enc_CommandRequest/2}], + ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]; +enc_ActionRequest(#'ActionRequest'{contextId = CID, + contextRequest = CtxReq, + contextAttrAuditReq = CtxAAR, + commandRequests = CmdReqs}, State) -> + [ + ?CtxToken, + ?EQUAL, + enc_ContextID(CID, State), + ?LBRKT_INDENT(State), + enc_list([{[CtxReq], fun enc_ContextRequest/2}, + {[CtxAAR], fun enc_ContextAttrAuditRequest/2}, + {CmdReqs, fun enc_CommandRequest/2}], + ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]. + +enc_ActionReply(Bin, _State) when is_binary(Bin) -> + [Bin]; % Already encoded... +%% OTP-5085 +enc_ActionReply(#'ActionReply'{contextId = Id, + errorDescriptor = asn1_NOVALUE, + contextReply = asn1_NOVALUE, + commandReply = []}, + State) -> +%% d("enc_ActionReply -> entry with" +%% "~n Id: ~p", [Id]), + [ + ?CtxToken, + ?EQUAL, + enc_ContextID(Id, State) + ]; +enc_ActionReply(#'ActionReply'{contextId = Id, + errorDescriptor = ED, + contextReply = CtxRep, + commandReply = CmdRep}, + State) -> +%% d("enc_ActionReply -> entry with" +%% "~n Id: ~p" +%% "~n ED: ~p" +%% "~n CtxRep: ~p" +%% "~n CmdRep: ~p", [Id, ED, CtxRep, CmdRep]), + [ + ?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, [], State) + when CtxRep =/= asn1_NOVALUE -> + [ + enc_ContextRequest(CtxRep, ?INC_INDENT(State)) + ]; +do_enc_ActionReply(asn1_NOVALUE, CtxRep, CmdRep, State) + when (CtxRep =/= asn1_NOVALUE) and (CmdRep =/= []) -> + [ + enc_ContextRequest(CtxRep, ?INC_INDENT(State)), + ?COMMA_INDENT(?INC_INDENT(State)), + enc_list([{CmdRep, fun enc_CommandReply/2}], + ?INC_INDENT(State)) + ]; +do_enc_ActionReply(asn1_NOVALUE, asn1_NOVALUE, CmdRep, State) + when CmdRep =/= [] -> + [ + enc_list([{CmdRep, fun enc_CommandReply/2}], + ?INC_INDENT(State)) + ]; +do_enc_ActionReply(ED, CtxRep, [], State) + when (ED =/= asn1_NOVALUE) and (CtxRep =/= asn1_NOVALUE) -> + [ + enc_ContextRequest(CtxRep, ?INC_INDENT(State)), + ?COMMA_INDENT(?INC_INDENT(State)), + enc_list([{[ED], fun enc_ErrorDescriptor/2}], % Indention cosmetics + ?INC_INDENT(State)) + ]; +do_enc_ActionReply(ED, asn1_NOVALUE, CmdRep, State) + when (ED =/= asn1_NOVALUE) and (CmdRep =/= []) -> + [ + enc_list([{CmdRep, fun enc_CommandReply/2}, + {[ED], fun enc_ErrorDescriptor/2}], % Indention cosmetics + ?INC_INDENT(State)) + ]; +do_enc_ActionReply(ED, CtxRep, CmdRep, State) + when (ED =/= asn1_NOVALUE) and + (CtxRep =/= asn1_NOVALUE) and + (CmdRep =/= []) -> + [ + enc_ContextRequest(CtxRep, ?INC_INDENT(State)), + ?COMMA_INDENT(?INC_INDENT(State)), + enc_list([{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)) + ]. + + +enc_ContextRequest_priority(asn1_NOVALUE, _State) -> + {[], dummy}; +enc_ContextRequest_priority(Val, _State) -> + {[Val], fun(X,S) -> [?PriorityToken,?EQUAL,enc_UINT16(X, S)] end}. + +enc_ContextRequest_emergency(asn1_NOVALUE, _State) -> + {[], dummy}; +enc_ContextRequest_emergency(true, _State) -> + {[?EmergencyToken], fun(Elem, _) -> Elem end}; +enc_ContextRequest_emergency(false, _State) -> + {[?EmergencyOffToken], fun(Elem, _) -> Elem end}. + +enc_ContextRequest_topologyReq(asn1_NOVALUE, _State) -> + {[], dummy}; +enc_ContextRequest_topologyReq({'ContextRequest_topologyReq', + asn1_NOVALUE}, _State) -> + {[], dummy}; +enc_ContextRequest_topologyReq({'ContextRequest_topologyReq', + List}, _State) -> + {List, fun enc_TopologyRequest/2}; +enc_ContextRequest_topologyReq(List, _State) -> + {[List], fun enc_TopologyRequest/2}. + +enc_ContextRequest_iepscallind(asn1_NOVALUE, _State) -> + {[], dummy}; +enc_ContextRequest_iepscallind(Bool, _State) -> + {[Bool], fun enc_iepsValue/2}. + +enc_ContextRequest_contextProp(asn1_NOVALUE, _State) -> + {[], dummy}; +enc_ContextRequest_contextProp([], _State) -> + {[], dummy}; +enc_ContextRequest_contextProp(Props, _State) -> + {[Props], fun(Elem, S) -> enc_contextAttrDescriptor(Elem, contextProps, S) end}. + +enc_ContextRequest_contextList(asn1_NOVALUE, _State) -> + {[], dummy}; +enc_ContextRequest_contextList([], _State) -> + {[], dummy}; +enc_ContextRequest_contextList(Props, _State) -> + {[Props], fun(Elem, S) -> + enc_contextAttrDescriptor(Elem, contextList, S) + end}. + +enc_contextAttrDescriptor([Mand|Opt], contextProps, State) -> + [ + ?ContextAttrToken, + ?LBRKT_INDENT(State), + [enc_PropertyParm(Mand, State) | + [[?COMMA_INDENT(State), enc_PropertyParm(Val, State)] || Val <- Opt]], + ?RBRKT_INDENT(State) + ]; +enc_contextAttrDescriptor(CtxIdList, contextList, State) -> + [ + ?ContextAttrToken, + ?LBRKT_INDENT(State), + enc_contextIdList(CtxIdList, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]. + +enc_contextIdList([Mand|Opt], State) -> + State2 = ?INC_INDENT(State), + [ + ?ContextListToken, + ?EQUAL, + ?LBRKT_INDENT(State), + [enc_ContextID(Mand, State2) | + [[?COMMA_INDENT(State2), enc_ContextID(Val, State2)] || Val <- Opt]], + ?RBRKT_INDENT(State) + ]. + +enc_ContextRequest(asn1_NOVALUE, _State) -> + []; +enc_ContextRequest(#'ContextRequest'{priority = asn1_NOVALUE, + emergency = asn1_NOVALUE, + topologyReq = asn1_NOVALUE, + iepscallind = asn1_NOVALUE, + contextProp = asn1_NOVALUE, + contextList = asn1_NOVALUE}, _State) -> + []; +enc_ContextRequest(#'ContextRequest'{priority = asn1_NOVALUE, + emergency = asn1_NOVALUE, + topologyReq = [], + iepscallind = asn1_NOVALUE, + contextProp = [], + contextList = []}, _State) -> + []; +enc_ContextRequest(#'ContextRequest'{priority = Prio, + emergency = Em, + topologyReq = TR, + iepscallind = Ieps, + contextProp = CP, + contextList = CL}, State) -> + [ + enc_list([enc_ContextRequest_priority(Prio, State), + enc_ContextRequest_emergency(Em, State), + enc_ContextRequest_topologyReq(TR, State), + enc_ContextRequest_iepscallind(Ieps, State), + enc_ContextRequest_contextProp(CP, State), + enc_ContextRequest_contextList(CL, State)], + State) + ]. + + +%% -- contextAudit -- +%% contextAudit = ContextAuditToken LBRKT +%% (contextAuditProperties *(COMMA contextAuditProperties)) / +%% indAudcontextAttrDesscriptor +%% RBRKT +%% contextAuditProperties = +%% (TopologyToken / EmergencyToken / PriorityToken / +%% IEPSToken / pkgdName / contextAuditSelect) +%% contextAuditSelect = +%% priority / emergencyValue / iepsValue / +%% contextAttrDescriptor / auditSelectLogic +%% indAudcontextAttrDesscriptor = +%% ContextAttrToken LBRKT +%% (contextAuditProperties *(COMMA contextAuditProperties)) +%% RBRKT +%% +%% This could actually either be +%% a) a list of contextAuditProperties: +%% contextAuditProperties *(COMMA contextAuditProperties) +%% b) a indAudcontextAttrDescriptor +%% But since b) actually has the same content as a) with +%% the extra ContextAttrToken, there does not seem to be any +%% reason for using it. +enc_ContextAttrAuditRequest(asn1_NOVALUE, _State) -> + []; +enc_ContextAttrAuditRequest( + #'ContextAttrAuditRequest'{topology = asn1_NOVALUE, + emergency = asn1_NOVALUE, + priority = asn1_NOVALUE, + iepscallind = asn1_NOVALUE, + contextPropAud = asn1_NOVALUE, + selectpriority = asn1_NOVALUE, + selectemergency = asn1_NOVALUE, + selectiepscallind = asn1_NOVALUE, + selectLogic = asn1_NOVALUE}, _State) -> + []; +enc_ContextAttrAuditRequest( + #'ContextAttrAuditRequest'{topology = asn1_NOVALUE, + emergency = asn1_NOVALUE, + priority = asn1_NOVALUE, + iepscallind = asn1_NOVALUE, + contextPropAud = [], + selectpriority = asn1_NOVALUE, + selectemergency = asn1_NOVALUE, + selectiepscallind = asn1_NOVALUE, + selectLogic = asn1_NOVALUE}, _State) -> + []; +enc_ContextAttrAuditRequest( + #'ContextAttrAuditRequest'{topology = Top, + emergency = Em, + priority = Prio, + iepscallind = Ieps, + contextPropAud = CPA, + selectpriority = SPrio, + selectemergency = SEm, + selectiepscallind = SIeps, + selectLogic = SL}, State) -> + [ + ?ContextAuditToken, + ?LBRKT_INDENT(State), + enc_list([{[Top], fun('NULL', _) -> ?TopologyToken end}, + {[Em], fun('NULL', _) -> ?EmergencyToken end}, + {[Prio], fun('NULL', _) -> ?PriorityToken end}, + {[Ieps], fun('NULL', _) -> ?IEPSToken end}, + {CPA, fun enc_IndAudPropertyParm/2}, + enc_ContextAttrAuditRequest_selectpriority(SPrio, State), + enc_ContextAttrAuditRequest_selectemergency(SEm, State), + enc_ContextAttrAuditRequest_selectiepscallind(SIeps, State), + enc_ContextAttrAuditRequest_selectLogic(SL, State)], + ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]. + +enc_ContextAttrAuditRequest_selectpriority(asn1_NOVALUE, _State) -> + {[], dummy}; +enc_ContextAttrAuditRequest_selectpriority(SPrio, _State) -> + {[SPrio], fun(X,S) -> [?PriorityToken,?EQUAL,enc_UINT16(X, S)] end}. + +enc_ContextAttrAuditRequest_selectemergency(asn1_NOVALUE, _State) -> + {[], dummy}; +enc_ContextAttrAuditRequest_selectemergency(SEm, _State) -> + {[SEm], fun(X,S) -> enc_emergencyValue(X, S) end}. + +enc_ContextAttrAuditRequest_selectiepscallind(asn1_NOVALUE, _State) -> + {[], dummy}; +enc_ContextAttrAuditRequest_selectiepscallind(SEm, _State) -> + {[SEm], fun(X,S) -> enc_iepsValue(X, S) end}. + +enc_ContextAttrAuditRequest_selectLogic(asn1_NOVALUE, _State) -> + {[], dummy}; +enc_ContextAttrAuditRequest_selectLogic({andAUDITSelect, 'NULL'}, _State) -> + {[], dummy}; % This is default so, there is no reason to add it +enc_ContextAttrAuditRequest_selectLogic({orAUDITSelect, 'NULL'}, _State) -> + {[?OrAUDITselectToken], fun(Elem, _) -> Elem end}. + +enc_emergencyValue(true, _) -> + [?EmergencyValueToken,?EQUAL,?EmergencyToken]; +enc_emergencyValue(_, _) -> + [?EmergencyValueToken,?EQUAL,?EmergencyOffToken]. + + +%% enc_IndAudContextAttrDescriptor( +%% #'ContextAttrAuditRequest'{topology = Top, +%% emergency = Em, +%% priority = Prio, +%% iepscallind = Ieps, +%% contextPropAud = CPA, +%% selectpriority = SelPrio, +%% selectemergency = SelEm, +%% selectiepscallind = SelIeps, +%% selectLogic = SelLog}, State) -> +%% [ +%% ?ContextAttrToken, +%% ?LBRKT_INDENT(State), +%% enc_list([{[Top], fun('NULL', _) -> ?TopologyToken end}, +%% {[Em], fun('NULL', _) -> ?EmergencyToken end}, +%% {[Prio], fun('NULL', _) -> ?PriorityToken end}, +%% {[Ieps], fun('NULL', _) -> ?IEPSToken end}, +%% {CPA, fun enc_IndAudPropertyParm/2}], +%% ?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) -> +%% d("enc_Command -> entry with" +%% "~n Tag: ~p" +%% "~n Val: ~p", [Tag, Val]), + 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) -> +%% d("enc_CommandReply -> entry with" +%% "~n Tag: ~p" +%% "~n Val: ~p", [Tag, Val]), + 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 = TD, + streamID = asn1_NOVALUE, % OPTIONAL + topologyDirectionExtension = asn1_NOVALUE % OPTIONAL + }, State) -> + [ + enc_TerminationID(From, State), + ?COMMA_INDENT(State), + enc_TerminationID(To, State), + ?COMMA_INDENT(State), + enc_TopologyDirection(TD, State) + ]; +enc_TopologyRequest1( + #'TopologyRequest'{terminationFrom = From, + terminationTo = To, + topologyDirection = TD, + streamID = SID, % OPTIONAL + topologyDirectionExtension = asn1_NOVALUE}, % OPTIONAL + State) when (SID =/= asn1_NOVALUE) -> + [ + enc_TerminationID(From, State), + ?COMMA_INDENT(State), + enc_TerminationID(To, State), + ?COMMA_INDENT(State), + enc_TopologyDirection(TD, State), + ?COMMA_INDENT(State), + enc_StreamID(SID, State) + ]; +enc_TopologyRequest1( + #'TopologyRequest'{terminationFrom = From, + terminationTo = To, + topologyDirection = TD, + streamID = asn1_NOVALUE, % OPTIONAL + topologyDirectionExtension = TDE}, % OPTIONAL + State) when (TDE =/= asn1_NOVALUE) -> + [ + enc_TerminationID(From, State), + ?COMMA_INDENT(State), + enc_TerminationID(To, State), + ?COMMA_INDENT(State), + enc_TopologyDirection(TD, State), + ?COMMA_INDENT(State), + enc_TopologyDirectionExtension(TDE, State) + ]; +enc_TopologyRequest1( + #'TopologyRequest'{terminationFrom = From, + terminationTo = To, + topologyDirection = TD, + streamID = SID, % OPTIONAL + topologyDirectionExtension = TDE}, % OPTIONAL + State) when (SID =/= asn1_NOVALUE) and (TDE =/= asn1_NOVALUE) -> + [ + enc_TerminationID(From, State), + ?COMMA_INDENT(State), + enc_TerminationID(To, State), + ?COMMA_INDENT(State), + enc_TopologyDirection(TD, State), + ?COMMA_INDENT(State), + enc_StreamID(SID, State), + ?COMMA_INDENT(State), + enc_TopologyDirectionExtension(TDE, State) + ]. + +enc_TopologyDirection(bothway, _State) -> + ?BothwayToken; +enc_TopologyDirection(isolate, _State) -> + ?IsolateToken; +enc_TopologyDirection(oneway, _State) -> + ?OnewayToken. + +enc_TopologyDirectionExtension(onewayexternal, _State) -> + ?OnewayExternalToken; +enc_TopologyDirectionExtension(onewayboth, _State) -> + ?OnewayBothToken. + +enc_iepsValue(Val, _State) -> + [ + ?IEPSToken, + ?EQUAL, + case Val of + false -> ?OffToken; + true -> ?OnToken + end + ]. + + + +enc_AmmRequest(#'AmmRequest'{terminationID = TIDs, + descriptors = Ds}, State) -> + [ + %% Assume that Token is added elsewhere + ?EQUAL, + enc_termIDList(TIDs, State), + enc_opt_brackets( + enc_list([{Ds, 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); + statisticsDescriptor -> enc_StatisticsDescriptor(Desc, State); + _ -> + error({invalid_ammDescriptor_tag, Tag}) + end. + +enc_AmmsReply(#'AmmsReply'{terminationID = TIDs, + terminationAudit = asn1_NOVALUE}, State) -> + [ + ?EQUAL, + enc_termIDList(TIDs, State) + ]; +enc_AmmsReply(#'AmmsReply'{terminationID = TIDs, + terminationAudit = []}, State) -> + [ + ?EQUAL, + enc_termIDList(TIDs, State) + ]; +enc_AmmsReply(#'AmmsReply'{terminationID = TIDs, + terminationAudit = Res}, State) -> + [ + ?EQUAL, + enc_termIDList(TIDs, State), + case lists:flatten(enc_TerminationAudit(Res, ?INC_INDENT(State))) of + [] -> + []; + L -> + [ + ?LBRKT_INDENT(State), + L, + ?RBRKT_INDENT(State) + ] + end + ]. + +enc_SubtractRequest(#'SubtractRequest'{terminationID = TIDs, + auditDescriptor = asn1_NOVALUE}, + State) -> + [ + %% Assume that Token is added elsewhere + ?EQUAL, + enc_termIDList(TIDs, State) + ]; +enc_SubtractRequest(#'SubtractRequest'{terminationID = TIDs, + auditDescriptor = AD}, + State) -> + [ + %% Assume that Token is added elsewhere + ?EQUAL, + enc_termIDList(TIDs, State), + ?LBRKT_INDENT(State), + enc_AuditDescriptor(AD, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]. + +enc_AuditRequest(#'AuditRequest'{terminationID = TID, + auditDescriptor = asn1_NOVALUE, + terminationIDList = asn1_NOVALUE}, State) -> + [ + %% Assume that Token is added elsewhere + ?EQUAL, + enc_termIDList([TID], State) + ]; +enc_AuditRequest(#'AuditRequest'{terminationID = TID, + auditDescriptor = asn1_NOVALUE, + terminationIDList = [TID|_] = TIDList}, + State) -> + [ + %% Assume that Token is added elsewhere + ?EQUAL, + enc_termIDList(TIDList, State) + ]; +enc_AuditRequest(#'AuditRequest'{terminationID = TID, + auditDescriptor = asn1_NOVALUE, + terminationIDList = TIDList}, + _State) -> + error({invalid_terminationID, TID, TIDList}); +enc_AuditRequest(#'AuditRequest'{terminationID = TID, + auditDescriptor = AD, + terminationIDList = asn1_NOVALUE}, State) -> + [ + %% Assume that Token is added elsewhere + ?EQUAL, + enc_termIDList([TID], State), + ?LBRKT_INDENT(State), + enc_AuditDescriptor(AD, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]; +enc_AuditRequest(#'AuditRequest'{terminationID = TID, + auditDescriptor = AD, + terminationIDList = [TID|_] = TIDList}, + State) -> + [ + %% Assume that Token is added elsewhere + ?EQUAL, + enc_termIDList(TIDList, State), + ?LBRKT_INDENT(State), + enc_AuditDescriptor(AD, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]; +enc_AuditRequest(#'AuditRequest'{terminationID = TID, + auditDescriptor = _AD, + terminationIDList = TIDList}, + _State) -> + error({invalid_terminationID, TID, TIDList}). + +%% 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) -> +%% d("enc_AuditReply -> entry with" +%% "~n Tag: ~p" +%% "~n Val: ~p", [Tag, Val]), + case Tag of + contextAuditResult -> + [ + ?EQUAL, + ?CtxToken, + enc_TerminationIDList(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}); + auditResultTermList -> + enc_TermListAuditResult(Val, State); + _ -> + error({invalid_AuditReply_tag, Tag}) + end. + +%% This is actually the same as AuditResult with the exception +%% that instead of terminationID we have terminationIDList. +enc_TermListAuditResult( + #'TermListAuditResult'{terminationIDList = TIDList, + terminationAuditResult = asn1_NOVALUE}, State) -> +%% d("enc_TermListAuditResult -> entry with" +%% "~n TIDList: ~p", [TIDList]), + [ + ?EQUAL, + enc_termIDList(TIDList, State) + ]; +enc_TermListAuditResult( + #'TermListAuditResult'{terminationIDList = TIDList, + terminationAuditResult = []}, State) -> +%% d("enc_TermListAuditResult -> entry with" +%% "~n TIDList: ~p", [TIDList]), + [ + ?EQUAL, + enc_termIDList(TIDList, State) + ]; +enc_TermListAuditResult( + #'TermListAuditResult'{terminationIDList = TIDList, + terminationAuditResult = TAR}, State) -> +%% d("enc_TermListAuditResult -> entry with" +%% "~n TIDList: ~p" +%% "~n TAR: ~p", [TIDList, TAR]), + [ + ?EQUAL, + enc_termIDList(TIDList, State), + case lists:flatten(enc_TerminationAudit(TAR, ?INC_INDENT(State))) of + [] -> + []; + L -> + [ + ?LBRKT_INDENT(State), + L, + ?RBRKT_INDENT(State) + ] + end + ]. + +enc_auditOther(#'AuditResult'{terminationID = TID, + terminationAuditResult = asn1_NOVALUE}, State) -> + [ + ?EQUAL, + enc_termIDList([TID], State) + ]; +enc_auditOther(#'AuditResult'{terminationID = TID, + terminationAuditResult = []}, State) -> + [ + ?EQUAL, + enc_termIDList([TID], State) + ]; +enc_auditOther(#'AuditResult'{terminationID = TID, + terminationAuditResult = Res}, State) -> + [ + ?EQUAL, + enc_termIDList([TID], 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) -> +% d("enc_AuditDescriptor(asn1_NOVALUE) -> entry"), + [ + ?AuditToken, + [?LBRKT, ?RBRKT] + ]; +enc_AuditDescriptor(#'AuditDescriptor'{auditToken = [], + auditPropertyToken = asn1_NOVALUE}, + _State) -> +% d("enc_AuditDescriptor([]) -> entry"), + [ + ?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. + +enc_IndAudMediaDescriptor( + #'IndAudMediaDescriptor'{termStateDescr = asn1_NOVALUE, + streams = Streams}, State) -> + [ + ?MediaToken, + ?LBRKT_INDENT(State), + enc_IndAudMediaDescriptor_streams(Streams, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]; +enc_IndAudMediaDescriptor( + #'IndAudMediaDescriptor'{termStateDescr = TSD, + streams = asn1_NOVALUE}, State) -> + [ + ?MediaToken, + ?LBRKT_INDENT(State), + enc_IndAudTerminationStateDescriptor(TSD, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]; +enc_IndAudMediaDescriptor( + #'IndAudMediaDescriptor'{termStateDescr = TSD, + streams = Streams}, State) -> + [ + ?MediaToken, + ?LBRKT_INDENT(State), + enc_IndAudTerminationStateDescriptor(TSD, ?INC_INDENT(State)), + ?COMMA_INDENT(State), + enc_IndAudMediaDescriptor_streams(Streams, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]. + +enc_IndAudMediaDescriptor_streams({oneStream, Val}, State) -> + enc_IndAudStreamParms(Val, State); +enc_IndAudMediaDescriptor_streams({multiStream, Val}, State) -> + enc_IndAudMediaDescriptor_multiStream(Val, State); +enc_IndAudMediaDescriptor_streams({Tag, _Val}, _State) -> + error({invalid_IndAudMediaDescriptor_streams_tag, Tag}). + +enc_IndAudTerminationStateDescriptor( + #'IndAudTerminationStateDescriptor'{propertyParms = [], + eventBufferControl = asn1_NOVALUE, + serviceState = 'NULL', + serviceStateSel = asn1_NOVALUE}, + _State) -> + [ + ?TerminationStateToken, + ?LBRKT_INDENT(_State), + ?ServiceStatesToken, + ?RBRKT_INDENT(_State) + ]; +enc_IndAudTerminationStateDescriptor( + #'IndAudTerminationStateDescriptor'{propertyParms = [], + eventBufferControl = asn1_NOVALUE, + serviceState = asn1_NOVALUE, + serviceStateSel = SSS}, + State) when SSS =/= asn1_NOVALUE -> + [ + ?TerminationStateToken, + ?LBRKT_INDENT(State), + enc_serviceState(SSS, State), + ?RBRKT_INDENT(State) + ]; +enc_IndAudTerminationStateDescriptor( + #'IndAudTerminationStateDescriptor'{propertyParms = [], + eventBufferControl = 'NULL', + serviceState = asn1_NOVALUE, + serviceStateSel = asn1_NOVALUE}, + _State) -> + [ + ?TerminationStateToken, + ?LBRKT_INDENT(_State), + ?BufferToken, + ?RBRKT_INDENT(_State) + ]; +enc_IndAudTerminationStateDescriptor( + #'IndAudTerminationStateDescriptor'{propertyParms = [Parms], + eventBufferControl = asn1_NOVALUE, + serviceState = asn1_NOVALUE, + serviceStateSel = asn1_NOVALUE}, + State) -> + #'IndAudPropertyParm'{name = Name} = Parms, + [ + ?TerminationStateToken, + ?LBRKT_INDENT(State), + enc_PkgdName(Name, State), + ?RBRKT_INDENT(State) + ]. + +enc_IndAudStreamParms( + #'IndAudStreamParms'{localControlDescriptor = LCD, + localDescriptor = LD, + remoteDescriptor = RD, + statisticsDescriptor = SD}, State) -> + [ + enc_list([{[LCD], fun enc_IndAudLocalControlDescriptor/2}, + {[LD], fun enc_remoteDescriptor/2}, + {[RD], fun enc_localDescriptor/2}, + {[SD], fun enc_IndAudStatisticsDescriptor/2}], + ?INC_INDENT(State)) + ]. + +enc_IndAudLocalControlDescriptor( + #'IndAudLocalControlDescriptor'{streamMode = SM, + reserveValue = RV, + reserveGroup = RG, + propertyParms = PP, + streamModeSel = asn1_NOVALUE}, State) -> + [ + ?LocalControlToken, + ?LBRKT_INDENT(State), + enc_list([{[SM], fun('NULL', _) -> ?ModeToken end}, + {[RV], fun('NULL', _) -> ?ReservedValueToken end}, + {[RG], fun('NULL', _) -> ?ReservedGroupToken end}, + {PP, fun enc_IndAudPropertyParm/2}], + ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]; +enc_IndAudLocalControlDescriptor( + #'IndAudLocalControlDescriptor'{streamMode = asn1_NOVALUE, + reserveValue = RV, + reserveGroup = RG, + propertyParms = PP, + streamModeSel = SMS}, State) -> + [ + ?LocalControlToken, + ?LBRKT_INDENT(State), + enc_list([{[RV], fun('NULL', _) -> ?ReservedValueToken end}, + {[RG], fun('NULL', _) -> ?ReservedGroupToken end}, + { PP, fun enc_IndAudPropertyParm/2}, + {[SMS], fun enc_StreamMode/2}], + ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]. + +enc_IndAudPropertyParm(#'IndAudPropertyParm'{name = Name, propertyParms = PP}, + State) -> + [ + enc_list([{[Name], fun enc_PkgdName/2}, + {[PP], fun enc_PropertyParm/2}], State) + ]. + +enc_IndAudMediaDescriptor_multiStream(Val, State) when is_list(Val) -> + [ + enc_list([{Val, fun enc_IndAudStreamDescriptor/2}], State) + ]; +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( + #'IndAudEventBufferDescriptor'{eventName = EvName, + streamID = ID}, State) -> + [ + ?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({eventStream, ID}, State) -> + [ + ?LBRKT_INDENT(State), + enc_eventStream(ID, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]; +enc_IndAudEventBufferDescriptor_eventSpec(ID, State) -> + [ + ?LBRKT_INDENT(State), + enc_eventStream(ID, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]. + +enc_IndAudEventsDescriptor( + #'IndAudEventsDescriptor'{requestID = asn1_NOVALUE, + pkgdName = Name, + streamID = asn1_NOVALUE}, State) -> + [ + ?EventsToken, + ?LBRKT_INDENT(State), + enc_PkgdName(Name, State), + ?RBRKT_INDENT(State) + ]; +enc_IndAudEventsDescriptor( + #'IndAudEventsDescriptor'{requestID = RID, + pkgdName = Name, + streamID = asn1_NOVALUE}, State) -> + [ + ?EventsToken, + ?EQUAL, + enc_RequestID(RID, State), + ?LBRKT_INDENT(State), + enc_PkgdName(Name, State), + ?RBRKT_INDENT(State) + ]. + + +enc_IndAudSignalsDescriptor(asn1_NOVALUE, _State) -> + [ + ?SignalsToken, + ?LBRKT_INDENT(_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, + signalRequestID = asn1_NOVALUE}, State) -> + [ + enc_SignalName(SignalName, State) + ]; +enc_IndAudSignal(#'IndAudSignal'{signalName = SignalName, + streamID = SID, + signalRequestID = SRID}, State) -> + [ + enc_SignalName(SignalName, State), + ?LBRKT_INDENT(State), + enc_list([{[SID], fun enc_StreamID/2}, + {[SRID], fun enc_sigRequestID/2}], + State), + ?RBRKT_INDENT(State) + ]. + +enc_IndAudSeqSigList(#'IndAudSeqSigList'{id = ID, + signalList = asn1_NOVALUE}, + State) -> + [ + ?SignalListToken, + ?EQUAL, + enc_UINT16(ID, State) + ]; +enc_IndAudSeqSigList(#'IndAudSeqSigList'{id = ID, + signalList = SL}, + State) -> + [ + ?SignalListToken, + ?EQUAL, + enc_UINT16(ID, State), + ?LBRKT_INDENT(State), + enc_IndAudSignal(SL, ?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([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) -> +%% d("enc_AuditReturnParameter -> entry with" +%% "~n Tag: ~p" +%% "~n Val: ~p", [Tag, Val]), + 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) -> +%% d("enc_AuditReturnParameter -> entry with" +%% "~n List: ~p", [List]), + enc_list([{List, fun enc_auditReturnItem/2}], State). + + +enc_NotifyRequest(#'NotifyRequest'{terminationID = TIDs, + observedEventsDescriptor = OED, + errorDescriptor = asn1_NOVALUE}, + State) -> + [ + %% Assume that Token is added elsewhere + ?EQUAL, + enc_termIDList(TIDs, State), + ?LBRKT_INDENT(State), + enc_ObservedEventsDescriptor(OED, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]; +enc_NotifyRequest(#'NotifyRequest'{terminationID = TIDs, + observedEventsDescriptor = OED, + errorDescriptor = ED}, State) -> + [ + %% Assume that Token is added elsewhere + ?EQUAL, + enc_termIDList(TIDs, State), + ?LBRKT_INDENT(State), + enc_ObservedEventsDescriptor(OED, ?INC_INDENT(State)), + ?COMMA, + enc_ErrorDescriptor(ED, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]. + +enc_NotifyReply(#'NotifyReply'{terminationID = TIDs, + errorDescriptor = asn1_NOVALUE}, State) -> + [ + %% Assume that Token is added elsewhere + ?EQUAL, + enc_termIDList(TIDs, State) + ]; +enc_NotifyReply(#'NotifyReply'{terminationID = TIDs, + errorDescriptor = ED}, State) -> + [ + %% Assume that Token is added elsewhere + ?EQUAL, + enc_termIDList(TIDs, State), + ?LBRKT_INDENT(State), + enc_ErrorDescriptor(ED, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]. + +enc_ObservedEventsDescriptor( + #'ObservedEventsDescriptor'{requestId = RID, + observedEventLst = OEL}, State) -> + [ + ?ObservedEventsToken, + ?EQUAL, + enc_RequestID(RID, State), + ?LBRKT_INDENT(State), + enc_observedEvents(OEL, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]. + +enc_observedEvents([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(#'ObservedEvent'{eventName = EN, + streamID = SID, + eventParList = EPL, + timeNotation = asn1_NOVALUE}, State) -> + [ + ?LWSP, + enc_EventName(EN, State), + enc_opt_brackets( + enc_list([{[SID], fun enc_eventStream/2}, + { EPL, fun enc_eventOther/2}], + ?INC_INDENT(State)), + State) + ]; +enc_ObservedEvent(#'ObservedEvent'{eventName = EN, + streamID = SID, + eventParList = EPL, + timeNotation = TN}, State) -> + [ + enc_TimeNotation(TN, State), + ?LWSP, + ?COLON, + ?LWSP, + enc_EventName(EN, State), + enc_opt_brackets( + enc_list([{[SID], fun enc_eventStream/2}, + {EPL, 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( + #'ServiceChangeRequest'{terminationID = TIDs, + serviceChangeParms = Parms}, State) -> + [ + %% Assume that Token is added elsewhere + ?EQUAL, + enc_termIDList(TIDs, State), + ?LBRKT_INDENT(State), + enc_ServiceChangeParm(Parms, ?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( + #'ServiceChangeReply'{terminationID = TIDs, + serviceChangeResult = Res}, State) -> + [ + %% Assume that Token is added elsewhere + ?EQUAL, + enc_termIDList(TIDs, State), + enc_ServiceChangeResult(Res, State) + ]. + +enc_ServiceChangeResult({'ServiceChangeResult', Val}, State) -> + enc_ServiceChangeResult(Val, State); +enc_ServiceChangeResult({errorDescriptor, Val}, State) -> + [ + ?LBRKT_INDENT(State), + enc_ErrorDescriptor(Val, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]; +enc_ServiceChangeResult({serviceChangeResParms, Val}, State) -> + 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; +enc_ServiceChangeResult({Tag, _}, _State) -> + error({invalid_ServiceChangeResult_tag, Tag}). + +%% 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_TerminationIDList({'TerminationIDList',Val}, State) -> + enc_TerminationIDList(Val, State); +enc_TerminationIDList([TID], State) -> + [ + ?LBRKT_INDENT(State), + enc_TerminationID(TID, State), + ?RBRKT_INDENT(State) + ]; +enc_TerminationIDList(TIDs, State) -> + [ + ?LBRKT_INDENT(State), + enc_list([{TIDs, fun enc_TerminationID/2}], State), + ?RBRKT_INDENT(State) + ]. + +enc_termIDList({'TerminationIDList',Val}, State) -> + enc_termIDList(Val, State); +enc_termIDList([Singleton], State) -> + enc_TerminationID(Singleton, State); +enc_termIDList(TidList, State) + when is_list(TidList) and (length(TidList) > 1) -> +%% d("enc_termIDList -> entry with" +%% "~n TidList: ~p", [TidList]), + State2 = ?INC_INDENT(State), + [ + ?LSBRKT_INDENT(State), + enc_list([{TidList, fun enc_TerminationID/2}], State2), + ?RSBRKT_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(#'MediaDescriptor'{termStateDescr = TSD, + streams = Streams}, State) -> + [ + ?MediaToken, + ?LBRKT_INDENT(State), + enc_list([{[TSD], fun enc_TerminationStateDescriptor/2} | + decompose_streams(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}, + {[Val#'StreamParms'.statisticsDescriptor], + fun enc_StatisticsDescriptor/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') and (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 + [ + ?EQUAL, + ?LSBRKT, + enc_Value(Low, State), + ?COLON, + enc_Value(High, State), + ?RSBRKT + ]; +enc_propertyParmValues(Values, {sublist, true}, State)-> + %% sublist (i.e. A AND B AND ...) + [ + ?EQUAL, + ?LSBRKT_INDENT(State), + enc_list([{Values, fun enc_Value/2}], ?INC_INDENT(State)), + ?RSBRKT_INDENT(State) + ]; +enc_propertyParmValues(Values, {sublist, false}, State) -> + %% alternatives (i.e. A OR B OR ...) + [ + ?EQUAL, + ?LBRKT_INDENT(State), + enc_list([{Values, fun enc_Value/2}], ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]; +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_TerminationIDList(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(#'EventsDescriptor'{requestID = asn1_NOVALUE, + eventList = []}, _State) -> + [ + ?EventsToken + ]; +enc_EventsDescriptor(#'EventsDescriptor'{requestID = RID, + eventList = Evs}, State) + when (RID =/= asn1_NOVALUE) and (Evs =/= []) -> + [ + ?EventsToken, + ?EQUAL, + enc_RequestID(RID, State), + ?LBRKT_INDENT(State), + enc_list([{Evs, fun enc_RequestedEvent/2}], ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]; +enc_EventsDescriptor(#'EventsDescriptor'{requestID = RID, + eventList = Evs}, _State) -> + error({invalid_EventsDescriptor, RID, Evs}). + +enc_RequestedEvent(#'RequestedEvent'{pkgdName = N, + streamID = asn1_NOVALUE, + eventAction = asn1_NOVALUE, + evParList = []}, State) -> + PkgdName = ?META_ENC(event, N), + [ + enc_PkgdName(PkgdName, State) + ]; +enc_RequestedEvent(#'RequestedEvent'{pkgdName = N, + streamID = SID, + eventAction = EA, + evParList = EPL}, State) -> + PkgdName = ?META_ENC(event, N), + [ + enc_PkgdName(PkgdName, State), + ?LBRKT_INDENT(State), + enc_list([{[SID], fun enc_eventStream/2}, + {EPL, fun enc_eventOther/2} | + decompose_requestedActions(EA)], + ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]. + +decompose_requestedActions(asn1_NOVALUE) -> + []; +decompose_requestedActions( + #'RequestedActions'{keepActive = asn1_NOVALUE, + eventDM = asn1_NOVALUE, + secondEvent = asn1_NOVALUE, + signalsDescriptor = asn1_NOVALUE, + notifyBehaviour = asn1_NOVALUE, + resetEventsDescriptor = asn1_NOVALUE}) -> + []; + +%% +%% This in the ABNF: +%% at-most-once each of +%% - KeepActiveToken +%% - notifyBehaviour +%% - eventDM +%% - ResetEventsDescriptor +%% - 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, + notifyBehaviour = NB, + resetEventsDescriptor = RED}) + when (KA =/= true) and ((SD =/= asn1_NOVALUE) and (SD =/= [])) -> + [ + {[EDM], fun enc_EventDM/2}, + {[{SE, SD}], fun enc_embedWithSig/2}, + {[NB], fun enc_notifyBehaviour/2}, + {[RED], fun('NULL', _) -> ?ResetEventsDescriptorToken end} + ]; + +%% embedNoSig +decompose_requestedActions(#'RequestedActions'{keepActive = KA, + eventDM = EDM, + secondEvent = SE, + signalsDescriptor = SD, + notifyBehaviour = NB, + resetEventsDescriptor = RED}) + when (SD == asn1_NOVALUE) or (SD == []) -> + [ + {[KA], fun enc_keepActive/2}, + {[EDM], fun enc_EventDM/2}, + {[SE], fun enc_embedNoSig/2}, + {[NB], fun enc_notifyBehaviour/2}, + {[RED], fun('NULL', _) -> ?ResetEventsDescriptorToken end} + ]; + +%% Fallback, if everything else failes.... +decompose_requestedActions(#'RequestedActions'{keepActive = KA, + eventDM = EDM, + secondEvent = SE, + signalsDescriptor = SD, + notifyBehaviour = NB, + resetEventsDescriptor = RED}) -> + [ + {[KA], fun enc_keepActive/2}, + {[EDM], fun enc_EventDM/2}, + {[{SE, SD}], fun enc_embedWithSig/2}, + {[NB], fun enc_notifyBehaviour/2}, + {[RED], fun('NULL', _) -> ?ResetEventsDescriptorToken end} + ]. + + +enc_embedNoSig(#'SecondEventsDescriptor'{requestID = RID, + eventList = Evs}, State) -> + [ + ?EmbedToken, + ?LBRKT_INDENT(State), + enc_embedFirst(RID, Evs, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]. + +enc_embedWithSig({asn1_NOVALUE, SD}, State) -> + [ + ?EmbedToken, + ?LBRKT_INDENT(State), + enc_SignalsDescriptor(SD, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]; +enc_embedWithSig({#'SecondEventsDescriptor'{requestID = RID, + eventList = Evs}, SD}, State) -> + [ + ?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) -> + case Val of + true -> [?KeepActiveToken]; + false -> [] + end. + +enc_EventDM({'EventDM',Val}, State) -> + enc_EventDM(Val, State); +enc_EventDM({Tag, Val}, State) -> + 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) and (is_list(Evs) and (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_notifyBehaviour({notifyImmediate, 'NULL'}, _State) -> + [?NotifyImmediateToken]; +enc_notifyBehaviour({notifyRegulated, Val}, State) -> + enc_RegulatedEmbeddedDescriptor(Val, State); +enc_notifyBehaviour({neverNotify, 'NULL'}, _State) -> + [?NeverNotifyToken]; +enc_notifyBehaviour({Tag, Val}, _State) -> + error({invalid_notifyBehaviour, Tag, Val}). + +enc_RegulatedEmbeddedDescriptor( + #'RegulatedEmbeddedDescriptor'{secondEvent = asn1_NOVALUE, + signalsDescriptor = asn1_NOVALUE}, _State) -> + [ + ?NotifyRegulatedToken + ]; +enc_RegulatedEmbeddedDescriptor( + #'RegulatedEmbeddedDescriptor'{secondEvent = SE, + signalsDescriptor = asn1_NOVALUE}, State) -> + [ + ?NotifyRegulatedToken, + ?LBRKT_INDENT(State), + enc_embedNoSig(SE, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]; +enc_RegulatedEmbeddedDescriptor( + #'RegulatedEmbeddedDescriptor'{secondEvent = SE, + signalsDescriptor = SD}, State) -> + [ + ?NotifyRegulatedToken, + ?LBRKT_INDENT(State), + enc_embedWithSig({SE, SD}, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]; +enc_RegulatedEmbeddedDescriptor(Val, _State) -> + error({invalid_RegulatedEmbeddedDescriptor, Val}). + +enc_SecondRequestedEvent(#'SecondRequestedEvent'{pkgdName = N, + streamID = asn1_NOVALUE, + eventAction = asn1_NOVALUE, + evParList = []}, State) -> + PkgdName = ?META_ENC(event, N), + [ + enc_PkgdName(PkgdName, State) + ]; +enc_SecondRequestedEvent(#'SecondRequestedEvent'{pkgdName = N, + streamID = SID, + eventAction = EA, + evParList = EPL}, State) -> + PkgdName = ?META_ENC(event, N), + [ + enc_PkgdName(PkgdName, State), + ?LBRKT_INDENT(State), + enc_list([{[SID], fun enc_eventStream/2}, + {EPL, fun enc_eventOther/2} | + decompose_secondRequestedActions(EA)], + ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]. + +%% +%% This in the ABNF: +%% at-most-once each of +%% - KeepActiveToken +%% - notifyBehaviour +%% - eventDM +%% - ResetEventsDescriptor +%% - eventStream +%% KeepActiveToken and embedWithSig must not both be present +%% +decompose_secondRequestedActions(asn1_NOVALUE) -> + []; +decompose_secondRequestedActions( + #'SecondRequestedActions'{keepActive = asn1_NOVALUE, + eventDM = asn1_NOVALUE, + signalsDescriptor = asn1_NOVALUE, + notifyBehaviour = asn1_NOVALUE, + resetEventsDescriptor = asn1_NOVALUE}) -> + []; + +decompose_secondRequestedActions( + #'SecondRequestedActions'{keepActive = KA, + eventDM = EDM, + signalsDescriptor = SD, + notifyBehaviour = NB, + resetEventsDescriptor = RED}) + when (KA =/= true) and ((SD =/= asn1_NOVALUE) and (SD =/= [])) -> + [ + {[EDM], fun enc_EventDM/2}, + {[SD], fun enc_embedSig/2}, + {[NB], fun enc_notifyBehaviour/2}, + {[RED], fun('NULL', _) -> ?ResetEventsDescriptorToken end} + ]; +decompose_secondRequestedActions( + #'SecondRequestedActions'{keepActive = KA, + eventDM = EDM, + signalsDescriptor = SD, + notifyBehaviour = NB, + resetEventsDescriptor = RED}) + when (SD == asn1_NOVALUE) or (SD == []) -> + [ + {[KA], fun enc_keepActive/2}, + {[EDM], fun enc_EventDM/2}, + {[NB], fun enc_notifyBehaviour/2}, + {[RED], fun('NULL', _) -> ?ResetEventsDescriptorToken end} + ]; +decompose_secondRequestedActions(SRA) -> + error({invalid_SecondRequestedActions, SRA}). + +enc_embedSig(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(EvSpecs, State) + when is_list(EvSpecs) andalso (length(EvSpecs) >= 1) -> + [ + ?EventBufferToken, + ?LBRKT_INDENT(State), + enc_eventSpecs(EvSpecs, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]; +enc_EventBufferDescriptor(EvSpecs, _State) -> + error({bad_eventSpecs, EvSpecs}). + +enc_eventSpecs([Mand | Opt], State) -> + [enc_eventSpec(Mand, State), + [[?COMMA_INDENT(State), enc_eventSpec(Val, State)] || Val <- Opt]]. + +enc_eventSpec(#'EventSpec'{eventName = N, + streamID = asn1_NOVALUE, + eventParList = []}, State) -> + [ + enc_EventName(N, State) + ]; +enc_eventSpec(#'EventSpec'{eventName = N, + streamID = SID, + eventParList = EPL}, State) -> + [ + enc_EventName(N, State), + ?LBRKT_INDENT(State), + enc_list([{[SID], fun enc_eventStream/2}, {EPL, fun enc_eventOther/2}], + ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]. + +enc_SignalsDescriptor({'SignalsDescriptor',Val}, State) -> + enc_SignalsDescriptor(Val, State); +enc_SignalsDescriptor([], _State) -> + [ + ?SignalsToken + ]; +enc_SignalsDescriptor(SigRequests, State) when is_list(SigRequests) -> + [ + ?SignalsToken, + ?LBRKT_INDENT(State), + enc_list([{SigRequests, fun enc_SignalRequest/2}], ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]. + +enc_SignalRequest({'SignalRequest',Val}, State) -> + enc_SignalRequest(Val, State); +enc_SignalRequest({Tag, Val}, State) -> + 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(#'Signal'{signalName = SN, + streamID = SID, + sigType = ST, + duration = Du, + notifyCompletion = NC, + keepActive = KA, + sigParList = SPL, + direction = Di, + requestID = RID, + intersigDelay = ISD}, State) -> + [ + enc_SignalName(SN, State), + enc_opt_brackets( + enc_list([{[SID], fun enc_sigStream/2}, + {[ST], fun enc_sigSignalType/2}, + {[Du], fun enc_sigDuration/2}, + {[NC], fun enc_notifyCompletion/2}, + {[KA], fun enc_keepActive/2}, + {SPL, fun enc_sigOther/2}, + {[Di], fun enc_SignalDirection/2}, + {[RID], fun enc_sigRequestID/2}, + {[ISD], fun enc_sigIntsigDelay/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; + onIteration -> ?IterationToken + 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_SignalDirection({'SignalDirection', Val}, State) -> + enc_SignalDirection(Val, State); +enc_SignalDirection(Val, _State) -> + [ + ?DirectionToken, + ?EQUAL, + case Val of + internal -> ?InternalToken; + external -> ?ExternalToken; + both -> ?BothToken + end + ]. + +enc_sigRequestID(Val, State) -> + [ + ?RequestIDToken, + ?EQUAL, + enc_RequestID(Val, 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_sigIntsigDelay(Val, State) -> + [ + ?IntsigDelayToken, + ?EQUAL, + enc_UINT16(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 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 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}, + State) + when (Value =/= asn1_NOVALUE) -> + [ + ?DigitMapToken, + ?EQUAL, + ?LBRKT_INDENT(State), + enc_DigitMapValue(Value, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]; +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) -> + [ + ?DigitMapToken, + ?EQUAL, + enc_DigitMapName(Name, State), + ?LBRKT_INDENT(State), + enc_DigitMapValue(Value, ?INC_INDENT(State)), + ?RBRKT_INDENT(State) + ]; +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). + +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}, + {[Val#'ServiceChangeParm'.serviceChangeIncompleteFlag], + fun('NULL', _) -> ?ServiceChangeIncompleteToken end}], + ?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; + _ -> + error({invalid_ServiceChangeMethod, Val}) + + end + ]. + +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) and (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) and (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) and (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({invalid_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) and 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(get(dbg), F, A). + +%% d(true, F, A) -> +%% io:format("~p:" ++ F ++"~n", [?MODULE | A]); +%% d(_, _, _) -> +%% ok. + + diff --git a/lib/megaco/src/text/megaco_text_mini_decoder.erl b/lib/megaco/src/text/megaco_text_mini_decoder.erl new file mode 100644 index 0000000000..6e1bf9295a --- /dev/null +++ b/lib/megaco/src/text/megaco_text_mini_decoder.erl @@ -0,0 +1,88 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2004-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 PRETTY Megaco/H.248 text messages from internal form +%%---------------------------------------------------------------------- + +-module(megaco_text_mini_decoder). + +-export([decode_message/2]). + +-include("megaco_text_tokens.hrl"). +-include_lib("megaco/src/engine/megaco_message_internal.hrl"). + + +%%---------------------------------------------------------------------- +%% Convert a binary into a mini 'MegacoMessage' record +%% Return {ok, MegacoMessageRecord} | {error, Reason} +%%---------------------------------------------------------------------- + +decode_message(_, Bin) when is_binary(Bin) -> + case megaco_text_scanner:scan(Bin) of + {ok, Tokens, _Vsn, _LastLine} -> + decode_message(Tokens); + + {error, Reason, Line} -> + parse_error(Reason, Line, []) + end; +decode_message(_EC, _BadBin) -> + {error, bad_binary}. + + +decode_message(Tokens0) -> + Tokens = strip(Tokens0, []), + case (catch megaco_text_mini_parser:parse(Tokens)) of + {ok, MegacoMessage} -> + {ok, MegacoMessage}; + {error, Reason} -> + parse_error(Reason, Tokens); + + %% OTP-4007 + {'EXIT', Reason} -> + parse_error(Reason, Tokens) + end. + +strip([], Tokens) -> + lists:reverse(Tokens); +strip([{'TransToken', _Line, _Text}|_], Acc) -> + strip_finish(Acc); +strip([{'ReplyToken', _Line, _Text}|_], Acc) -> + strip_finish(Acc); +strip([{'PendingToken', _Line, _Text}|_], Acc) -> + strip_finish(Acc); +strip([{'ResponseAckToken', _Line, _Text}|_], Acc) -> + strip_finish(Acc); +strip([{'ErrorToken', _Line, _Text}|_], Acc) -> + strip_finish(Acc); +strip([H|T], Acc) -> + strip(T, [H|Acc]). + +strip_finish(RevTokens) -> + lists:reverse([{endOfMessage, 1, endOfMessage}|RevTokens]). + + +parse_error(Reason, Tokens) -> + {error, [{reason, Reason}, {token, Tokens}]}. + +parse_error(Reason, Line, Tokens) -> + {error, [{reason, Reason, Line}, {token, Tokens}]}. + + diff --git a/lib/megaco/src/text/megaco_text_mini_parser.hrl b/lib/megaco/src/text/megaco_text_mini_parser.hrl new file mode 100644 index 0000000000..bb6ee43247 --- /dev/null +++ b/lib/megaco/src/text/megaco_text_mini_parser.hrl @@ -0,0 +1,1246 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2004-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 : Define semantic text parser actions +%%---------------------------------------------------------------------- + + +-include_lib("megaco/include/megaco.hrl"). +-include_lib("megaco/include/megaco_message_v2.hrl"). +-include("megaco_text_tokens.hrl"). + +-define(d(F,A), io:format("DBG:"++F++"~n",A)). + +make_safe_token({_TokenTag, Line, Text}) -> + {safeToken, Line, Text}. + +% ensure_value({safeToken, _Line, Text}) -> +% ensure_value(Text); +% ensure_value({'QuotedChars', _Line, Text}) -> +% ensure_value(Text); +% ensure_value(Text) when list(Text) -> +% Text. %% BUGBUG: ensure length + +% %% NAME = ALPHA *63(ALPHA / DIGIT / "_" ) +% ensure_NAME({_TokenTag, _Line, Text}) -> +% Text. %% BUGBUG: ensure length and chars + +% ensure_requestID({safeToken, _Line, "*"}) -> +% ?megaco_all_request_id; +% ensure_requestID(RequestId) -> +% ensure_uint32(RequestId). + +% ensure_streamID(StreamId) -> +% ensure_uint16(StreamId). + +ensure_auth_header(SpiToken, SnToken, AdToken) -> + Spi = ensure_hex(SpiToken, 8, 8), + Sn = ensure_hex(SnToken, 8, 8), + Ad = ensure_hex(AdToken, 24, 64), + #'AuthenticationHeader'{secParmIndex = Spi, seqNum = Sn, ad = Ad}. + +%% ContextID = (UINT32 / "*" / "-" / "$") +% ensure_contextID({_TokenTag, _Line, Text}) -> +% case Text of +% "*" -> ?megaco_all_context_id; +% "-" -> ?megaco_null_context_id; +% "\$" -> ?megaco_choose_context_id; +% Int -> ensure_uint32(Int) +% end. + +ensure_domainAddress([{_T, _L, _A} = Addr0], Port) -> + Addr = ensure_ip4addr(Addr0), + {ip4Address, #'IP4Address'{address = Addr, portNumber = Port}}; +ensure_domainAddress([colon,colon], Port) -> + Addr = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + {ip6Address, #'IP6Address'{address = Addr, portNumber = Port}}; +ensure_domainAddress(Addr0, Port) -> + Addr = ensure_ip6addr(Addr0), + {ip6Address, #'IP6Address'{address = Addr, portNumber = Port}}. + + +ensure_ip4addr({TokenTag, Line, Addr}) -> + case string:tokens(Addr, [$.]) of + [T1, T2, T3, T4] -> + A1 = ensure_uint({TokenTag, Line, T1}, 0, 255), + A2 = ensure_uint({TokenTag, Line, T2}, 0, 255), + A3 = ensure_uint({TokenTag, Line, T3}, 0, 255), + A4 = ensure_uint({TokenTag, Line, T4}, 0, 255), + [A1, A2, A3, A4]; + _ -> + return_error(Line, {bad_IP4address, Addr}) + end. + + +ensure_ip6addr([colon,colon|T]) -> + [H1|T1] = lists:reverse(T), + case do_ensure_ip6addr(T1, true, [ensure_hex4_or_ip4addr(H1)], 1) of + {true, A} when length(A) == 16 -> + A; + {true, B} when length(B) < 16 -> + lists:duplicate(16 - length(B), 0) ++ B; + {true, C} -> + throw({error, {?MODULE, {bad_mid_ip6addr_length, C}}}) + end; +ensure_ip6addr(L) -> + case lists:reverse(L) of + [colon, colon| T] -> + case do_ensure_ip6addr(T, true, [], 1) of + {true, A} when length(A) == 16 -> + A; + {true, B} when length(B) < 16 -> + B ++ lists:duplicate(16 - length(B), 0); + {true, C} -> + throw({error, {?MODULE, {bad_mid_ip6addr_length, C}}}) + end; + [H|L1] -> % A (last element) could be an ip4 address + case do_ensure_ip6addr(L1,false,[ensure_hex4_or_ip4addr(H)],1) of + {false, A} when length(A) == 16 -> + A; + %% allow a pad even if the address is full (i.e. 16) + {true, B} when length(B) =< 17 -> + do_ensure_ip6addr_padding(B, 0); + {Pad, C} -> + throw({error, {?MODULE, {bad_mid_ip6addr_length, Pad, C}}}) + end + + end. + + +do_ensure_ip6addr([], Pad, Acc, _) -> + {Pad, lists:flatten(Acc)}; +do_ensure_ip6addr([colon,colon|T], false, Acc, Line) -> + do_ensure_ip6addr(T, true, [pad|Acc], Line); +do_ensure_ip6addr([colon,colon|T], true, Acc, Line) -> + return_error(Line, {bad_mid_duplicate_padding, T, Acc}); +do_ensure_ip6addr([colon|T], Pad, Acc, Line) -> + do_ensure_ip6addr(T, Pad, Acc, Line); +do_ensure_ip6addr([{_, Line, _} = A|T], Pad, Acc, _) -> + do_ensure_ip6addr(T, Pad, [ensure_hex4(A)|Acc], Line). + +do_ensure_ip6addr_padding([], _) -> + []; +do_ensure_ip6addr_padding([pad|T], N) -> + lists:duplicate(16 - (N + length(T)), 0) ++ T; +do_ensure_ip6addr_padding([H|T], N) -> + [H|do_ensure_ip6addr_padding(T, N+1)]. + +ensure_hex4_or_ip4addr({TokenTag, Line, Addr} = V) -> + case string:tokens(Addr, [$.]) of + [T1, T2, T3, T4] -> + A1 = ensure_uint({TokenTag, Line, T1}, 0, 255), + A2 = ensure_uint({TokenTag, Line, T2}, 0, 255), + A3 = ensure_uint({TokenTag, Line, T3}, 0, 255), + A4 = ensure_uint({TokenTag, Line, T4}, 0, 255), + [A1, A2, A3, A4]; + _ -> + ensure_hex4(V) + %% %% BMK BMK BMK + %% %% Here we should test for hexseq + %% return_error(Line, {bad_IP4address, Addr}) + end. + +ensure_hex4({_TokenTag, Line, Hex4}) + when (length(Hex4) =< 4) andalso (length(Hex4) > 0) -> + case (catch do_ensure_hex4(Hex4)) of + IL when is_list(IL) andalso (length(IL) =:= 2) -> + IL; + Error -> + return_error(Line, {bad_hex4, Hex4, Error}) + end. + +do_ensure_hex4([_H1, _H2, _H3, _H4] = H) -> + hex_to_int(H, []); +do_ensure_hex4([H2, H3, H4]) -> + hex_to_int([$0, H2, H3, H4], []); +do_ensure_hex4([H3, H4]) -> + hex_to_int([$0, $0, H3, H4], []); +do_ensure_hex4([H4]) -> + hex_to_int([$0, $0, $0, H4], []). + +ensure_domainName({_TokenTag, _Line, Name}, Port) -> + %% BUGBUG: validate name + {domainName, #'DomainName'{name = Name, portNumber = Port}}. + +%% extensionParameter= "X" ("-" / "+") 1*6(ALPHA / DIGIT) +% ensure_extensionParameter({_TokenTag, Line, Text}) -> +% case Text of +% [X, S | _Chars] -> +% if +% X /= $X, X /= $x, +% S /= $+, S /= $- -> +% return_error(Line, {bad_extension_parameter, Text}); +% true -> +% {extension_parameter, Text} +% end; +% _ -> +% return_error(Line, {bad_extension_parameter, Text}) +% end. + +ensure_message(MegacopToken, MID) -> + #'ServiceChangeProfile'{profileName = Name, + version = Version} = + ensure_profile(MegacopToken), + case Name of + "megaco" -> + #'Message'{version = Version, mId = MID}; + [$!] -> + #'Message'{version = Version, mId = MID} + end. + + +%% modemType = (V32bisToken / V22bisToken / V18Token / +%% V22Token / V32Token / V34Token / V90Token / +%% V91Token / SynchISDNToken / extensionParameter) +% ensure_modemType({_TokenTag, _Line, Text} = Token) -> +% case Text of +% "v32b" -> v32bis; +% "v22b" -> v22bis; +% "v18" -> v18; +% "v22" -> v22; +% "v32" -> v32; +% "v34" -> v34; +% "v90" -> v90; +% "v91" -> v91; +% "synchisdn" -> synchISDN; +% "sn" -> synchISDN; +% [$x | _] -> ensure_extensionParameter(Token) +% end. + +%% An mtp address is five octets long +ensure_mtpAddress({_TokenTag, _Line, Addr}) -> + %% BUGBUG: validate address + {mtpAddress, Addr}. + +%% MuxType = ( H221Token / H223Token / H226Token / V76Token / extensionParameter ) +% ensure_muxType({_TokenTag, _Line, Text} = Token) -> +% case Text of +% "h221" -> h221; +% "h223" -> h223; +% "h226" -> h226; +% "v76" -> v76; +% "nx64k" -> nx64k; % v2 +% [$x | _] -> ensure_extensionParameter(Token) +% end. + +%% packagesItem = NAME "-" UINT16 +%% NAME = ALPHA *63(ALPHA / DIGIT / "_" ) +% ensure_packagesItem({TokenTag, Line, Text}) -> +% case string:tokens(Text, [$-]) of +% [Name, Version] -> +% #'PackagesItem'{packageName = ensure_NAME({TokenTag, Line, Name}), +% packageVersion = ensure_uint({TokenTag, Line, Version}, 0, 99)}; +% _ -> +% return_error(Line, {bad_PackagesItem, Text}) +% end. + +%% pkgdName = (PackageName / "*") SLASH (ItemID / "*" ) +%% PackageName = NAME +%% ItemID = NAME +% ensure_pkgdName({TokenTag, Line, Text}) -> +% case string:tokens(Text, [$/]) of +% [Name, Item] -> +% ensure_name_or_star({TokenTag, Line, Name}), +% ensure_name_or_star({TokenTag, Line, Item}), +% Text; +% _ -> +% return_error(Line, {bad_pkgdName, Text}) +% end. + +% ensure_name_or_star({_, _, Name}) when Name == "*" -> +% Name; +% ensure_name_or_star(Name) -> +% ensure_NAME(Name). + + + +%% v2 - start + +% merge_indAudMediaDescriptor({termStateDescr, Val}) -> +% #'IndAudMediaDescriptor'{termStateDescr = Val}; +% merge_indAudMediaDescriptor({streamParm, Val}) -> +% #'IndAudMediaDescriptor'{streams = {oneStream, Val}}; +% merge_indAudMediaDescriptor({streamDescr, Val}) -> +% #'IndAudMediaDescriptor'{streams = {multiStream, [Val]}}. + +% merge_indAudLocalControlDescriptor(Parms) -> +% do_merge_indAudLocalControlDescriptor(Parms, +% #'IndAudLocalControlDescriptor'{}). + +% do_merge_indAudLocalControlDescriptor([Parm | Parms], Desc) -> +% case Parm of +% modeToken when Desc#'IndAudLocalControlDescriptor'.streamMode == asn1_NOVALUE -> +% Desc2 = Desc#'IndAudLocalControlDescriptor'{streamMode = 'NULL'}, +% do_merge_indAudLocalControlDescriptor(Parms, Desc2); +% reservedGroupToken when Desc#'IndAudLocalControlDescriptor'.reserveGroup == asn1_NOVALUE -> +% Desc2 = Desc#'IndAudLocalControlDescriptor'{reserveGroup = 'NULL'}, +% do_merge_indAudLocalControlDescriptor(Parms, Desc2); +% reservedValueToken when Desc#'IndAudLocalControlDescriptor'.reserveValue == asn1_NOVALUE -> +% Desc2 = Desc#'IndAudLocalControlDescriptor'{reserveValue = 'NULL'}, +% do_merge_indAudLocalControlDescriptor(Parms, Desc2); +% {pkgdName, Val} when Desc#'IndAudLocalControlDescriptor'.propertyParms == asn1_NOVALUE -> +% PropParms = [#'IndAudPropertyParm'{name = Val}], +% Desc2 = Desc#'IndAudLocalControlDescriptor'{propertyParms = PropParms}, +% do_merge_indAudLocalControlDescriptor(Parms, Desc2); +% {pkgdName, Val} when list(Desc#'IndAudLocalControlDescriptor'.propertyParms) -> +% PropParms = Desc#'IndAudLocalControlDescriptor'.propertyParms, +% PropParms2 = [#'IndAudPropertyParm'{name = Val} | PropParms], +% Desc2 = Desc#'IndAudLocalControlDescriptor'{propertyParms = PropParms2}, +% do_merge_indAudLocalControlDescriptor(Parms, Desc2) +% end; +% do_merge_indAudLocalControlDescriptor([], Desc) -> +% case Desc#'IndAudLocalControlDescriptor'.propertyParms of +% [_ | _] = PropParms -> % List has more then one element +% PropParms2= lists:reverse(PropParms), +% Desc#'IndAudLocalControlDescriptor'{propertyParms = PropParms2}; +% _ -> +% Desc +% end. + +% ensure_indAudLocalParm(Token) -> +% case Token of +% {safeToken, _Line, "mode"} -> modeToken; +% {safeToken, _Line, "mo"} -> modeToken; +% {safeToken, _Line, "reservedgroup"} -> reservedGroupToken; +% {safeToken, _Line, "rg"} -> reservedGroupToken; +% {safeToken, _Line, "reservedvalue"} -> reservedValueToken; +% {safeToken, _Line, "rv"} -> reservedValueToken; +% PkgdName -> {pkgdName, +% ensure_pkgdName(PkgdName)} +% end. + +% merge_indAudTerminationStateDescriptor({pkgdName, Val}) -> +% PropParm = #'IndAudPropertyParm'{name = Val}, +% #'IndAudTerminationStateDescriptor'{propertyParms = [PropParm]}; +% merge_indAudTerminationStateDescriptor(serviceStatesToken) -> +% #'IndAudTerminationStateDescriptor'{serviceState = 'NULL'}; +% merge_indAudTerminationStateDescriptor(bufferToken) -> +% #'IndAudTerminationStateDescriptor'{eventBufferControl = 'NULL'}. + + +% merge_indAudEventBufferDescriptor(EventName, SpecParams) -> +% IAEBD = #'IndAudEventBufferDescriptor'{eventName = EventName}, +% do_merge_indAudEventBufferDescriptor(SpecParams, IAEBD). + +% do_merge_indAudEventBufferDescriptor(asn1_NOVALUE, IAEBD) -> +% IAEBD; +% do_merge_indAudEventBufferDescriptor({streamID, StreamID}, IAEBD) -> +% IAEBD#'IndAudEventBufferDescriptor'{streamID = StreamID}; +% do_merge_indAudEventBufferDescriptor({eventParameterName, _Name} = EPN, +% IAEBD) -> +% %% BUGBUG BUGBUG BUGBUG +% %% This is an ugly hack to allow the eventParamName which only +% %% exists in the text encoding... +% IAEBD#'IndAudEventBufferDescriptor'{streamID = EPN}. + + +% ensure_indAudSignalListParm(SIG) when record(SIG, 'Signal') -> +% ensure_indAudSignal(SIG). + +% ensure_indAudSignal(#'Signal'{signalName = SignalName, +% streamID = asn1_NOVALUE, +% sigType = asn1_NOVALUE, +% duration = asn1_NOVALUE, +% notifyCompletion = asn1_NOVALUE, +% keepActive = asn1_NOVALUE, +% sigParList = []}) -> +% #'IndAudSignal'{signalName = SignalName}. + + +% ensure_IADMD({_TokenTag, _Line, +% #'DigitMapDescriptor'{digitMapName = Name, +% digitMapValue = asn1_NOVALUE}}) -> +% #'IndAudDigitMapDescriptor'{digitMapName = Name}. + + +% merge_indAudPackagesDescriptor(#'PackagesItem'{packageName = N, +% packageVersion = V}) -> +% #'IndAudPackagesDescriptor'{packageName = N, +% packageVersion = V}. + + +% ensure_indAudTerminationStateParm(Token) -> +% case Token of +% {safeToken, _Line, "servicestates"} -> serviceStatesToken; +% {safeToken, _Line, "si"} -> serviceStatesToken; +% {safeToken, _Line, "buffer"} -> bufferToken; +% {safeToken, _Line, "bf"} -> bufferToken; +% PkgdName -> {pkgdName, +% ensure_pkgdName(PkgdName)} +% end. + + +% %% Types modified by v2: + +% merge_auditDescriptor([]) -> +% #'AuditDescriptor'{}; +% merge_auditDescriptor(Tokens) when list(Tokens) -> +% case lists:keysearch(terminationAudit, 1, Tokens) of +% {value, {terminationAudit, TA}} -> +% case lists:keydelete(terminationAudit, 1, Tokens) of +% [] -> +% #'AuditDescriptor'{auditPropertyToken = TA}; +% AuditTokens -> +% #'AuditDescriptor'{auditToken = AuditTokens, +% auditPropertyToken = TA} +% end; +% false -> +% #'AuditDescriptor'{auditToken = Tokens} +% end; +% merge_auditDescriptor(_) -> +% #'AuditDescriptor'{}. + + +% %% v2 - end + + + +% merge_ServiceChangeParm(Parms) -> +% Required = [serviceChangeReason, serviceChangeMethod], +% merge_ServiceChangeParm(Parms, #'ServiceChangeParm'{}, Required). + +% merge_ServiceChangeParm([], SCP, []) -> +% SCP; + +% merge_ServiceChangeParm([], _SCP, Required) -> +% exit({missing_required_serviceChangeParm, Required}); + +% merge_ServiceChangeParm([{address, Val}|Parms], SCP0, Req) +% when SCP0#'ServiceChangeParm'.serviceChangeAddress == asn1_NOVALUE, +% SCP0#'ServiceChangeParm'.serviceChangeMgcId == asn1_NOVALUE -> +% SCP = SCP0#'ServiceChangeParm'{serviceChangeAddress = Val}, +% merge_ServiceChangeParm(Parms, SCP, Req); +% merge_ServiceChangeParm([{address, Val}|_Parms], SCP0, _Req) +% when SCP0#'ServiceChangeParm'.serviceChangeAddress == asn1_NOVALUE -> +% MgcId = SCP0#'ServiceChangeParm'.serviceChangeMgcId, +% exit({not_both_address_mgcid_serviceChangeParm, Val, MgcId}); + +% merge_ServiceChangeParm([{mgc_id, Val}|Parms], SCP0, Req) +% when SCP0#'ServiceChangeParm'.serviceChangeMgcId == asn1_NOVALUE, +% SCP0#'ServiceChangeParm'.serviceChangeAddress == asn1_NOVALUE -> +% SCP = SCP0#'ServiceChangeParm'{serviceChangeMgcId = Val}, +% merge_ServiceChangeParm(Parms, SCP, Req); +% merge_ServiceChangeParm([{mgc_id, Val}|_Parms], SCP0, _Req) +% when SCP0#'ServiceChangeParm'.serviceChangeMgcId == asn1_NOVALUE -> +% Addr = SCP0#'ServiceChangeParm'.serviceChangeAddress, +% exit({not_both_address_mgcid_serviceChangeParm, Val, Addr}); + +% merge_ServiceChangeParm([{profile, Val}|Parms], SCP0, Req) +% when SCP0#'ServiceChangeParm'.serviceChangeProfile == asn1_NOVALUE -> +% SCP = SCP0#'ServiceChangeParm'{serviceChangeProfile = Val}, +% merge_ServiceChangeParm(Parms, SCP, Req); + +% merge_ServiceChangeParm([{version, Val}|Parms], SCP0, Req) +% when SCP0#'ServiceChangeParm'.serviceChangeVersion == asn1_NOVALUE -> +% SCP = SCP0#'ServiceChangeParm'{serviceChangeVersion = Val}, +% merge_ServiceChangeParm(Parms, SCP, Req); + +% %% REQUIRED (i.e. no default value) +% merge_ServiceChangeParm([{reason, Val}|Parms], SCP0, Req0) +% when SCP0#'ServiceChangeParm'.serviceChangeReason == undefined -> +% SCP = SCP0#'ServiceChangeParm'{serviceChangeReason = Val}, +% Req = lists:delete(serviceChangeReason, Req0), +% merge_ServiceChangeParm(Parms, SCP, Req); + +% merge_ServiceChangeParm([{delay, Val}|Parms], SCP0, Req) +% when SCP0#'ServiceChangeParm'.serviceChangeDelay == asn1_NOVALUE -> +% SCP = SCP0#'ServiceChangeParm'{serviceChangeDelay = Val}, +% merge_ServiceChangeParm(Parms, SCP, Req); + +% %% REQUIRED (i.e. no default value) +% merge_ServiceChangeParm([{method, Val}|Parms], SCP0, Req0) +% when SCP0#'ServiceChangeParm'.serviceChangeMethod == undefined -> +% SCP = SCP0#'ServiceChangeParm'{serviceChangeMethod = Val}, +% Req = lists:delete(serviceChangeMethod, Req0), +% merge_ServiceChangeParm(Parms, SCP, Req); + +% merge_ServiceChangeParm([{time_stamp, Val}|Parms], SCP0, Req) +% when SCP0#'ServiceChangeParm'.timeStamp == asn1_NOVALUE -> +% SCP = SCP0#'ServiceChangeParm'{timeStamp = Val}, +% merge_ServiceChangeParm(Parms, SCP, Req); + +% merge_ServiceChangeParm([{extension, _Val}|Parms], SCP0, Req) -> +% merge_ServiceChangeParm(Parms, SCP0, Req); + +% merge_ServiceChangeParm([{audit_item, Val}|Parms], SCP0, Req) +% when SCP0#'ServiceChangeParm'.serviceChangeInfo == asn1_NOVALUE -> +% SCI = #'AuditDescriptor'{auditToken = [Val]}, +% SCP = SCP0#'ServiceChangeParm'{serviceChangeInfo = SCI}, +% merge_ServiceChangeParm(Parms, SCP, Req); + +% merge_ServiceChangeParm([{Tag, Val}|_Parms], SCP, _Req) -> +% Val2 = +% case Tag of +% address -> +% SCP#'ServiceChangeParm'.serviceChangeAddress; +% mgc_id -> +% SCP#'ServiceChangeParm'.serviceChangeMgcId; +% profile -> +% SCP#'ServiceChangeParm'.serviceChangeProfile; +% version -> +% SCP#'ServiceChangeParm'.serviceChangeVersion; +% reason -> +% SCP#'ServiceChangeParm'.serviceChangeReason; +% delay -> +% SCP#'ServiceChangeParm'.serviceChangeDelay; +% method -> +% SCP#'ServiceChangeParm'.serviceChangeMethod; +% time_stamp -> +% SCP#'ServiceChangeParm'.timeStamp; +% audit_item -> +% SCP#'ServiceChangeParm'.serviceChangeInfo +% end, +% exit({at_most_once_serviceChangeParm, {Tag, Val, Val2}}). + + +% merge_ServiceChangeResParm(Parms) -> +% merge_ServiceChangeResParm(Parms, #'ServiceChangeResParm'{}). + +% merge_ServiceChangeResParm([], SCRP) -> +% SCRP; +% merge_ServiceChangeResParm([{address, Val}|Parms], SCRP0) +% when SCRP0#'ServiceChangeResParm'.serviceChangeAddress == asn1_NOVALUE, +% SCRP0#'ServiceChangeResParm'.serviceChangeMgcId == asn1_NOVALUE -> +% SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeAddress = Val}, +% merge_ServiceChangeResParm(Parms, SCRP); +% merge_ServiceChangeResParm([{address, Val}|_Parms], SCRP0) +% when SCRP0#'ServiceChangeResParm'.serviceChangeAddress == asn1_NOVALUE -> +% MgcId = SCRP0#'ServiceChangeResParm'.serviceChangeMgcId, +% exit({not_both_address_mgcid_servChgReplyParm, Val, MgcId}); + +% merge_ServiceChangeResParm([{mgc_id, Val}|Parms], SCRP0) +% when SCRP0#'ServiceChangeResParm'.serviceChangeMgcId == asn1_NOVALUE, +% SCRP0#'ServiceChangeResParm'.serviceChangeAddress == asn1_NOVALUE -> +% SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeMgcId = Val}, +% merge_ServiceChangeResParm(Parms, SCRP); +% merge_ServiceChangeResParm([{mgc_id, Val}|_Parms], SCRP0) +% when SCRP0#'ServiceChangeResParm'.serviceChangeMgcId == asn1_NOVALUE -> +% Addr = SCRP0#'ServiceChangeResParm'.serviceChangeAddress, +% exit({not_both_address_mgcid_servChgReplyParm, Val, Addr}); + +% merge_ServiceChangeResParm([{profile, Val}|Parms], SCRP0) +% when SCRP0#'ServiceChangeResParm'.serviceChangeProfile == asn1_NOVALUE -> +% SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeProfile = Val}, +% merge_ServiceChangeResParm(Parms, SCRP); + +% merge_ServiceChangeResParm([{version, Val}|Parms], SCRP0) +% when SCRP0#'ServiceChangeResParm'.serviceChangeVersion == asn1_NOVALUE -> +% SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeVersion = Val}, +% merge_ServiceChangeResParm(Parms, SCRP); + +% merge_ServiceChangeResParm([{time_stamp, Val}|Parms], SCRP0) +% when SCRP0#'ServiceChangeResParm'.timeStamp == asn1_NOVALUE -> +% SCRP = SCRP0#'ServiceChangeResParm'{timeStamp = Val}, +% merge_ServiceChangeResParm(Parms, SCRP); + +% merge_ServiceChangeResParm([{Tag, Val}|_Parms], SCRP) -> +% Val2 = +% case Tag of +% address -> SCRP#'ServiceChangeResParm'.serviceChangeAddress; +% mgc_id -> SCRP#'ServiceChangeResParm'.serviceChangeMgcId; +% profile -> SCRP#'ServiceChangeResParm'.serviceChangeProfile; +% version -> SCRP#'ServiceChangeResParm'.serviceChangeVersion; +% time_stamp -> SCRP#'ServiceChangeResParm'.timeStamp +% end, +% exit({at_most_once_servChgReplyParm, {Tag, Val, Val2}}). + + +% ensure_serviceChangeMethod({safeToken, _Line, "fl"}) -> +% failover; +% ensure_serviceChangeMethod({safeToken, _Line, "failover"}) -> +% failover; +% ensure_serviceChangeMethod({safeToken, _Line, "fo"}) -> +% forced; +% ensure_serviceChangeMethod({safeToken, _Line, "forced"}) -> +% forced; +% ensure_serviceChangeMethod({safeToken, _Line, "gr"}) -> +% graceful; +% ensure_serviceChangeMethod({safeToken, _Line, "graceful"}) -> +% graceful; +% ensure_serviceChangeMethod({safeToken, _Line, "rs"}) -> +% restart; +% ensure_serviceChangeMethod({safeToken, _Line, "restart"}) -> +% restart; +% ensure_serviceChangeMethod({safeToken, _Line, "dc"}) -> +% disconnected; +% ensure_serviceChangeMethod({safeToken, _Line, "disconnected"}) -> +% disconnected; +% ensure_serviceChangeMethod({safeToken, _Line, "ho"}) -> +% handOff; +% ensure_serviceChangeMethod({safeToken, _Line, "handoff"}) -> +% handOff; +% ensure_serviceChangeMethod({safeToken, Line, Text}) -> +% return_error(Line, {bad_serviceChangeMethod, Text}). + + +ensure_profile({_TokenTag, Line, Text}) -> + case string:tokens(Text, [$/]) of + [Name, Version] -> + Version2 = ensure_version(Version), + #'ServiceChangeProfile'{profileName = Name, version = Version2}; + _ -> + return_error(Line, {bad_profile, Text}) + end. + +ensure_version(Version) -> + ensure_uint(Version, 0, 99). + +% merge_signalRequest(SignalName, PropertyParms) -> +% Sig = #'Signal'{signalName = SignalName}, +% SPL = [], +% do_merge_signalRequest(Sig, PropertyParms, SPL). + +% do_merge_signalRequest(Sig, [H | T], SPL) -> +% case H of +% {stream, StreamId} when Sig#'Signal'.streamID == asn1_NOVALUE -> +% do_merge_signalRequest(Sig#'Signal'{streamID = StreamId}, T, SPL); +% {signal_type, SigType} when Sig#'Signal'.sigType == asn1_NOVALUE -> +% do_merge_signalRequest(Sig#'Signal'{sigType = SigType}, T, SPL); +% {duration, Duration} when Sig#'Signal'.duration == asn1_NOVALUE -> +% do_merge_signalRequest(Sig#'Signal'{duration = Duration}, T, SPL); +% {notify_completion, NC} when Sig#'Signal'.notifyCompletion == asn1_NOVALUE -> +% do_merge_signalRequest(Sig#'Signal'{notifyCompletion = NC}, T, SPL); +% keepActive when Sig#'Signal'.keepActive == asn1_NOVALUE-> +% do_merge_signalRequest(Sig#'Signal'{keepActive = true}, T, SPL); +% {other, Name, PP} -> +% SP = #'SigParameter'{sigParameterName = Name, +% value = PP#'PropertyParm'.value, +% extraInfo = PP#'PropertyParm'.extraInfo}, +% do_merge_signalRequest(Sig, T, [SP | SPL]); +% _ -> +% return_error(0, {bad_sigParm, H}) +% end; +% do_merge_signalRequest(Sig, [], SPL) -> +% Sig#'Signal'{sigParList = lists:reverse(SPL)} . + +% %% eventStream = StreamToken EQUAL StreamID +% %% eventOther = eventParameterName parmValue +% select_stream_or_other("st", #'PropertyParm'{value = [Value]}) -> +% {stream, ensure_uint16(Value)}; +% select_stream_or_other("st", Value) -> +% {stream, ensure_uint16(Value)}; +% select_stream_or_other("stream", #'PropertyParm'{value = [Value]}) -> +% {stream, ensure_uint16(Value)}; +% select_stream_or_other("stream", Value) -> +% {stream, ensure_uint16(Value)}; +% select_stream_or_other(Name, #'PropertyParm'{value = Value}) -> +% EP = #'EventParameter'{eventParameterName = Name, +% value = Value}, +% {other, EP}. + +% ensure_eventDM({_TokenTag, Line, DMD}) +% when record(DMD, 'DigitMapDescriptor') -> +% Name = DMD#'DigitMapDescriptor'.digitMapName, +% Val = DMD#'DigitMapDescriptor'.digitMapValue, +% if +% Name == asn1_NOVALUE, Val /= asn1_NOVALUE -> +% {'DigitMapValue', Start, Short, Long, Duration, Body} = Val, +% DMV = #'DigitMapValue'{startTimer = Start, +% shortTimer = Short, +% longTimer = Long, +% digitMapBody = Body, +% durationTimer = Duration}, +% {eventDM, {digitMapValue, DMV}}; +% Name /= asn1_NOVALUE, Val == asn1_NOVALUE -> +% {eventDM, {digitMapName, Name}}; +% true -> +% return_error(Line, {bad_eventDM, DMD}) +% end. + +% ensure_DMD({_TokenTag, _Line, DMD}) +% when record(DMD, 'DigitMapDescriptor') -> +% Val2 = +% case DMD#'DigitMapDescriptor'.digitMapValue of +% %% Note that the values of the digitMapBody and durationTimers +% %% are swapped by the scanner (this is done because of a +% %% problem in the flex scanner). +% #'DigitMapValue'{durationTimer = Body, +% digitMapBody = Duration} = DMV -> +% %% Convert to version 1 DigitMapValue +% DMV#'DigitMapValue'{digitMapBody = Body, +% durationTimer = Duration}; +% Other -> +% Other +% end, +% DMD#'DigitMapDescriptor'{digitMapValue = Val2}. + + +% merge_observed_event(ObservedEvents, EventName, TimeStamp) -> +% StreamId = asn1_NOVALUE, +% EPL = [], +% do_merge_observed_event(ObservedEvents, EventName, TimeStamp, StreamId, EPL). + +% do_merge_observed_event([{stream, StreamID} | T], EventName, TimeStamp, asn1_NOVALUE, EPL) -> +% do_merge_observed_event(T, EventName, TimeStamp, StreamID, EPL); +% do_merge_observed_event([{other, PP} | T], EventName, TimeStamp, StreamID, EPL) -> +% do_merge_observed_event(T, EventName, TimeStamp, StreamID, [PP | EPL]); +% do_merge_observed_event([], EventName, TimeStamp, StreamID, EPL) -> +% #'ObservedEvent'{eventName = EventName, +% timeNotation = TimeStamp, +% streamID = StreamID, +% eventParList = lists:reverse(EPL)}. + +% merge_eventSpec(OE) when record(OE, 'ObservedEvent'), +% OE#'ObservedEvent'.timeNotation == asn1_NOVALUE -> +% #'EventSpec'{eventName = OE#'ObservedEvent'.eventName, +% streamID = OE#'ObservedEvent'.streamID, +% eventParList = OE#'ObservedEvent'.eventParList}; +% merge_eventSpec(OE) -> +% return_error(0, {bad_event_spec, OE}). + +% merge_eventParameters(Params) -> +% StreamId = asn1_NOVALUE, +% EPL = [], +% RA = #'RequestedActions'{}, +% HasA = no, +% do_merge_eventParameters(Params, StreamId, EPL, RA, HasA) . + +% do_merge_eventParameters([H | T], StreamId, EPL, RA, HasA) -> +% case H of +% keepActive when RA#'RequestedActions'.keepActive == asn1_NOVALUE -> +% RA2 = RA#'RequestedActions'{keepActive = true}, +% do_merge_eventParameters(T, StreamId, EPL, RA2, yes); +% {embed, SD, SED} when RA#'RequestedActions'.signalsDescriptor == asn1_NOVALUE -> +% RA2 = RA#'RequestedActions'{signalsDescriptor = SD, +% secondEvent = SED}, +% do_merge_eventParameters(T, StreamId, EPL, RA2, yes); +% {eventDM, DM} when RA#'RequestedActions'.eventDM == asn1_NOVALUE -> +% RA2 = RA#'RequestedActions'{eventDM = DM}, +% do_merge_eventParameters(T, StreamId, EPL, RA2, yes); +% {stream, NewStreamId} when StreamId == asn1_NOVALUE -> +% do_merge_eventParameters(T, NewStreamId, EPL, RA, HasA); +% {other, PP} when record(PP, 'PropertyParm') -> +% EP = #'EventParameter'{eventParameterName = PP#'PropertyParm'.name, +% value = PP#'PropertyParm'.value, +% extraInfo = PP#'PropertyParm'.extraInfo}, +% do_merge_eventParameters(T, StreamId, [EP | EPL], RA, HasA); +% {other, EP} when record(EP, 'EventParameter') -> +% do_merge_eventParameters(T, StreamId, [EP | EPL], RA, HasA); +% _ -> +% return_error(0, {bad_eventParameter, H}) +% end; +% do_merge_eventParameters([], StreamId, EPL, RA, yes) -> +% #'RequestedEvent'{streamID = StreamId, +% eventAction = RA, +% evParList = lists:reverse(EPL)}; +% do_merge_eventParameters([], StreamId, EPL, _RA, no) -> +% #'RequestedEvent'{streamID = StreamId, +% eventAction = asn1_NOVALUE, +% evParList = lists:reverse(EPL)}. + +% merge_secondEventParameters(Params) -> +% StreamId = asn1_NOVALUE, +% EPL = [], +% SRA = #'SecondRequestedActions'{}, +% HasA = no, +% do_merge_secondEventParameters(Params, StreamId, EPL, SRA, HasA) . + +% do_merge_secondEventParameters([H | T], StreamId, EPL, SRA, HasA) -> +% case H of +% keepActive when SRA#'SecondRequestedActions'.keepActive == asn1_NOVALUE -> +% SRA2 = SRA#'SecondRequestedActions'{keepActive = true}, +% do_merge_secondEventParameters(T, StreamId, EPL, SRA2, yes); +% {second_embed, SD} when SRA#'SecondRequestedActions'.signalsDescriptor == asn1_NOVALUE -> +% SRA2 = SRA#'SecondRequestedActions'{signalsDescriptor = SD}, +% do_merge_secondEventParameters(T, StreamId, EPL, SRA2, yes); +% {eventDM, DM} when SRA#'SecondRequestedActions'.eventDM == asn1_NOVALUE -> +% SRA2 = SRA#'SecondRequestedActions'{eventDM = DM}, +% do_merge_secondEventParameters(T, StreamId, EPL, SRA2, yes); +% {stream, NewStreamId} when StreamId == asn1_NOVALUE -> +% do_merge_secondEventParameters(T, NewStreamId, EPL, SRA, HasA); +% {other, PP} when record(PP, 'PropertyParm') -> +% EP = #'EventParameter'{eventParameterName = PP#'PropertyParm'.name, +% value = PP#'PropertyParm'.value, +% extraInfo = PP#'PropertyParm'.extraInfo}, +% do_merge_secondEventParameters(T, StreamId, [EP | EPL], SRA, HasA); +% {other, EP} when record(EP, 'EventParameter') -> +% do_merge_secondEventParameters(T, StreamId, [EP | EPL], SRA, HasA); +% _ -> +% return_error(0, {bad_secondEventParameter, H}) +% end; +% do_merge_secondEventParameters([], StreamId, EPL, SRA, yes) -> +% #'SecondRequestedEvent'{streamID = StreamId, +% eventAction = SRA, +% evParList = lists:reverse(EPL)}; +% do_merge_secondEventParameters([], StreamId, EPL, _SRA, no) -> +% #'SecondRequestedEvent'{streamID = StreamId, +% eventAction = asn1_NOVALUE, +% evParList = lists:reverse(EPL)}. + +% %% terminationID = "ROOT" / pathName / "$" / "*" +% %% Total length of pathName must not exceed 64 chars. +% %% pathName = ["*"] NAME *("/" / "*"/ ALPHA / DIGIT /"_" / "$" ) +% %% ["@" pathDomainName ] +% %% ABNF allows two or more consecutive "." although it is meaningless +% %% in a path domain name. +% %% pathDomainName = (ALPHA / DIGIT / "*" ) +% %% *63(ALPHA / DIGIT / "-" / "*" / ".") +% ensure_terminationID({safeToken, _Line, LowerText}) -> +% %% terminationID = "ROOT" / pathName / "$" / "*" +% decode_term_id(LowerText, false, [], []). + +% decode_term_id([H | T], Wild, Id, Component) -> +% case H of +% $/ -> decode_term_id(T, Wild, [lists:reverse(Component) | Id], []); +% $* -> decode_term_id(T, true, Id, [?megaco_all | Component]); +% $$ -> decode_term_id(T, true, Id, [?megaco_choose | Component]); +% _ -> decode_term_id(T, Wild, Id, [H | Component]) +% end; +% decode_term_id([], Wild, Id, Component) -> +% Id2 = [lists:reverse(Component) | Id], +% #megaco_term_id{contains_wildcards = Wild, id = lists:reverse(Id2)}. + +ensure_pathName({_TokenTag, _Line, Text}) -> + Text. %% BUGBUG: ensure values + +%% TimeStamp = Date "T" Time ; per ISO 8601:1988 +%% Date = 8(DIGIT) ; Date = yyyymmdd +%% Time = 8(DIGIT) ; Time = hhmmssss +% ensure_timeStamp({'TimeStampToken', Line, Text}) -> +% case string:tokens(Text, [$T, $t]) of +% [Date, Time] -> +% #'TimeNotation'{date = Date, time = Time}; +% _ -> +% return_error(Line, {bad_timeStamp, Text}) +% end. + +% ensure_transactionID(TransId) -> +% ensure_uint32(TransId). + +% %% transactionAck = transactionID / (transactionID "-" transactionID) +% ensure_transactionAck({safeToken, _Line, Text}) -> +% case string:tokens(Text, [$-]) of +% [Id] -> +% #'TransactionAck'{firstAck = ensure_transactionID(Id)}; +% [Id, Id2] -> +% #'TransactionAck'{firstAck = ensure_transactionID(Id), +% lastAck = ensure_transactionID(Id2)} +% end. + +% merge_action_requests(CtxId, Items) -> +% CtxReq = #'ContextRequest'{}, +% CtxAuditReq = asn1_NOVALUE, +% CmdReq = [], +% TopReq = [], +% do_merge_action_requests(CtxId, CtxReq, CtxAuditReq, CmdReq, TopReq, Items). + +% do_merge_action_requests(CtxId, CtxReq, CtxAuditReq, CmdReq, TopReq, [H | T]) -> +% case H of +% _ when record(H, 'CommandRequest') -> +% do_merge_action_requests(CtxId, CtxReq, CtxAuditReq, [H | CmdReq], TopReq, T); + +% {priority, Int} when CtxReq#'ContextRequest'.priority == asn1_NOVALUE -> +% CtxReq2 = CtxReq#'ContextRequest'{priority = Int}, +% do_merge_action_requests(CtxId, CtxReq2, CtxAuditReq, CmdReq, +% TopReq, T); +% {emergency, Bool} when CtxReq#'ContextRequest'.emergency == asn1_NOVALUE -> +% CtxReq2 = CtxReq#'ContextRequest'{emergency = Bool}, +% do_merge_action_requests(CtxId, CtxReq2, CtxAuditReq, CmdReq, +% TopReq, T); +% {topology, Desc} -> +% TopReq2 = Desc ++ TopReq, %% OTP-4088 +% do_merge_action_requests(CtxId, CtxReq, CtxAuditReq, CmdReq, +% TopReq2, T); + +% {contextAudit, CAs} -> +% CtxAuditReq2 = merge_context_attr_audit_request(CtxAuditReq, CAs), +% do_merge_action_requests(CtxId, CtxReq, CtxAuditReq2, CmdReq, +% TopReq, T) + +% end; +% do_merge_action_requests(CtxId, CtxReq, CtxAuditReq, CmdReq, TopReq, []) -> +% #'ActionRequest'{contextId = CtxId, +% contextRequest = strip_contextRequest(CtxReq, TopReq), +% contextAttrAuditReq = strip_contextAttrAuditRequest(CtxAuditReq), +% commandRequests = lists:reverse(CmdReq)}. + + +% merge_context_attr_audit_request(asn1_NOVALUE, CAs) -> +% merge_context_attr_audit_request(#'ContextAttrAuditRequest'{}, CAs); +% merge_context_attr_audit_request(CAAR, [H|T]) -> +% CAAR2 = +% case H of +% priorityAudit when CAAR#'ContextAttrAuditRequest'.priority == asn1_NOVALUE -> +% CAAR#'ContextAttrAuditRequest'{priority = 'NULL'}; + +% priorityAudit -> +% Prio = CAAR#'ContextAttrAuditRequest'.priority, +% exit({only_once, priorityAudit, Prio}); + +% emergencyAudit when CAAR#'ContextAttrAuditRequest'.emergency == asn1_NOVALUE -> +% CAAR#'ContextAttrAuditRequest'{emergency = 'NULL'}; + +% emergencyAudit -> +% Em = CAAR#'ContextAttrAuditRequest'.emergency, +% exit({only_once, emergencyAudit, Em}); + +% topologyAudit when CAAR#'ContextAttrAuditRequest'.topology == asn1_NOVALUE -> +% CAAR#'ContextAttrAuditRequest'{topology = 'NULL'}; + +% topologyAudit -> +% Top = CAAR#'ContextAttrAuditRequest'.topology, +% exit({only_once, topologyAudit, Top}) + +% end, +% merge_context_attr_audit_request(CAAR2, T); +% merge_context_attr_audit_request(CAAR, []) -> +% CAAR. + +% %% OTP-5085: +% %% In order to solve a problem in the parser, the error descriptor +% %% has been put last in the non-empty commandReplyList, if it is not +% %% asn1_NOVALUE +% merge_action_reply(ReplyList) -> +% CtxReq = #'ContextRequest'{}, +% TopReq = [], +% CmdList = [], +% case lists:reverse(ReplyList) of +% [ED|RL2] when record(ED, 'ErrorDescriptor') -> +% AR = do_merge_action_reply(lists:reverse(RL2), +% CtxReq, TopReq, CmdList), +% AR#'ActionReply'{errorDescriptor = ED}; +% _ -> +% do_merge_action_reply(ReplyList, CtxReq, TopReq, CmdList) +% end. + +% do_merge_action_reply([H | T], CtxReq, TopReq, CmdList) -> +% case H of +% {command, Cmd} -> +% do_merge_action_reply(T, CtxReq, TopReq, [Cmd | CmdList]); +% {context, Ctx} -> +% case Ctx of +% {priority, Int} when CtxReq#'ContextRequest'.priority == asn1_NOVALUE -> +% CtxReq2 = CtxReq#'ContextRequest'{priority = Int}, +% do_merge_action_reply(T, CtxReq2, TopReq, CmdList); +% {emergency, Bool} when CtxReq#'ContextRequest'.emergency == asn1_NOVALUE -> +% CtxReq2 = CtxReq#'ContextRequest'{emergency = Bool}, +% do_merge_action_reply(T, CtxReq2, TopReq, CmdList); +% {topology, Desc} -> +% TopReq2 = Desc ++ TopReq, %% OTP-4088 +% do_merge_action_reply(T, CtxReq, TopReq2, CmdList) +% end +% end; +% do_merge_action_reply([], CtxReq, TopReq, CmdList) -> +% #'ActionReply'{contextReply = strip_contextRequest(CtxReq, TopReq), +% commandReply = lists:reverse(CmdList)}. + +% strip_contextRequest(R, TopReq) +% when R#'ContextRequest'.priority == asn1_NOVALUE, +% R#'ContextRequest'.emergency == asn1_NOVALUE, +% TopReq == [] -> +% asn1_NOVALUE; +% strip_contextRequest(R, []) -> +% R#'ContextRequest'{topologyReq = asn1_NOVALUE}; +% strip_contextRequest(R, TopReq) -> +% R#'ContextRequest'{topologyReq = TopReq}. %% OTP-4088 + + +% strip_contextAttrAuditRequest(R) +% when R#'ContextAttrAuditRequest'.priority == asn1_NOVALUE, +% R#'ContextAttrAuditRequest'.emergency == asn1_NOVALUE, +% R#'ContextAttrAuditRequest'.topology == asn1_NOVALUE -> +% asn1_NOVALUE; +% strip_contextAttrAuditRequest(R) -> +% R. + +% make_commandRequest({CmdTag, {_TokenTag, _Line, Text}}, Cmd) -> +% Req = #'CommandRequest'{command = {CmdTag, Cmd}}, +% case Text of +% [$w, $- | _] -> +% Req#'CommandRequest'{wildcardReturn = 'NULL'}; +% [$o, $-, $w, $- | _] -> +% Req#'CommandRequest'{optional = 'NULL', wildcardReturn = 'NULL'}; +% [$o, $- | _] -> +% Req#'CommandRequest'{optional = 'NULL'}; +% _ -> +% Req +% end. + +% merge_terminationAudit(AuditReturnParameters) -> +% lists:reverse(do_merge_terminationAudit(AuditReturnParameters, [], [])). + +% do_merge_terminationAudit([H| T], ARPs, AuditItems) -> +% case H of +% {auditReturnItem, AuditItem} -> +% do_merge_terminationAudit(T, ARPs, [AuditItem | AuditItems]); +% AuditReturnParameter -> +% do_merge_terminationAudit(T, [AuditReturnParameter | ARPs], AuditItems) +% end; +% do_merge_terminationAudit([], AuditReturnParameters, []) -> +% AuditReturnParameters; +% do_merge_terminationAudit([], AuditReturnParameters, AuditItems) -> +% AuditDescriptor = #'AuditDescriptor'{auditToken = AuditItems}, +% AuditReturnParameter = {emptyDescriptors, AuditDescriptor}, +% [AuditReturnParameter | AuditReturnParameters]. + +% merge_mediaDescriptor(MediaParms) -> +% do_merge_mediaDescriptor(MediaParms, asn1_NOVALUE, [], []). + +% do_merge_mediaDescriptor([H | T], TS, One, Multi) -> +% case H of +% {streamParm, Parm} when Multi == [] -> +% do_merge_mediaDescriptor(T, TS, [Parm | One], Multi); +% {streamDescriptor, Desc} when One == [] -> +% do_merge_mediaDescriptor(T, TS, One, [Desc | Multi]); +% {termState, TS2} when TS == asn1_NOVALUE -> +% do_merge_mediaDescriptor(T, TS2, One, Multi); +% _ -> +% return_error(0, {bad_merge_mediaDescriptor, [H, TS, One, Multi]}) +% end; +% do_merge_mediaDescriptor([], TS, One, Multi) -> +% if +% One == [], Multi == [] -> +% #'MediaDescriptor'{streams = asn1_NOVALUE, +% termStateDescr = TS}; +% One /= [], Multi == [] -> +% #'MediaDescriptor'{streams = {oneStream, merge_streamParms(One)}, +% termStateDescr = TS}; +% One == [], Multi /= [] -> +% #'MediaDescriptor'{streams = {multiStream, lists:reverse(Multi)}, +% termStateDescr = TS} +% end. + +% merge_streamParms(TaggedStreamParms) -> +% SP = #'StreamParms'{}, +% do_merge_streamParms(TaggedStreamParms, SP). + +% do_merge_streamParms([{Tag, D} | T] = All, SP) -> +% case Tag of +% local when SP#'StreamParms'.localDescriptor == asn1_NOVALUE -> +% do_merge_streamParms(T, SP#'StreamParms'{localDescriptor = D}); +% remote when SP#'StreamParms'.remoteDescriptor == asn1_NOVALUE -> +% do_merge_streamParms(T, SP#'StreamParms'{remoteDescriptor = D}); +% control -> +% LCD = +% case SP#'StreamParms'.localControlDescriptor of +% asn1_NOVALUE -> +% #'LocalControlDescriptor'{propertyParms = []}; +% PrevLCD -> +% PrevLCD +% end, +% LCD2 = do_merge_control_streamParms(D, LCD), +% do_merge_streamParms(T, SP#'StreamParms'{localControlDescriptor = LCD2}); +% _ -> +% return_error(0, {do_merge_streamParms, [All, SP]}) +% end; +% do_merge_streamParms([], SP) when record(SP#'StreamParms'.localControlDescriptor, 'LocalControlDescriptor') -> +% LCD = SP#'StreamParms'.localControlDescriptor, +% PP = LCD#'LocalControlDescriptor'.propertyParms, +% LCD2 = LCD#'LocalControlDescriptor'{propertyParms = lists:reverse(PP)}, +% SP#'StreamParms'{localControlDescriptor = LCD2}; +% do_merge_streamParms([], SP) -> +% SP. + + +% do_merge_control_streamParms([{SubTag, SD} | T] = All, LCD) -> +% case SubTag of +% group when LCD#'LocalControlDescriptor'.reserveGroup == asn1_NOVALUE -> +% LCD2 = LCD#'LocalControlDescriptor'{reserveGroup = SD}, +% do_merge_control_streamParms(T, LCD2); +% value when LCD#'LocalControlDescriptor'.reserveValue == asn1_NOVALUE -> +% LCD2 = LCD#'LocalControlDescriptor'{reserveValue = SD}, +% do_merge_control_streamParms(T, LCD2); +% mode when LCD#'LocalControlDescriptor'.streamMode == asn1_NOVALUE -> +% LCD2 = LCD#'LocalControlDescriptor'{streamMode = SD}, +% do_merge_control_streamParms(T, LCD2); +% prop -> +% PP = LCD#'LocalControlDescriptor'.propertyParms, +% LCD2 = LCD#'LocalControlDescriptor'{propertyParms = [SD | PP]}, +% do_merge_control_streamParms(T, LCD2); +% _ -> +% return_error(0, {do_merge_control_streamParms, [All, LCD]}) +% end; +% do_merge_control_streamParms([], LCD) -> +% LCD. + +% merge_terminationStateDescriptor(Parms) -> +% TSD = #'TerminationStateDescriptor'{propertyParms = []}, +% do_merge_terminationStateDescriptor(Parms, TSD). + +% do_merge_terminationStateDescriptor([{Tag, Val} | T], TSD) -> +% case Tag of +% serviceState when TSD#'TerminationStateDescriptor'.serviceState == asn1_NOVALUE -> +% TSD2 = TSD#'TerminationStateDescriptor'{serviceState = Val}, +% do_merge_terminationStateDescriptor(T, TSD2); +% eventBufferControl when TSD#'TerminationStateDescriptor'.eventBufferControl == asn1_NOVALUE-> +% TSD2 = TSD#'TerminationStateDescriptor'{eventBufferControl = Val}, +% do_merge_terminationStateDescriptor(T, TSD2); +% propertyParm -> +% PP = TSD#'TerminationStateDescriptor'.propertyParms, +% TSD2 = TSD#'TerminationStateDescriptor'{propertyParms = [Val | PP]}, +% do_merge_terminationStateDescriptor(T, TSD2) +% end; +% do_merge_terminationStateDescriptor([], TSD) -> +% PP = TSD#'TerminationStateDescriptor'.propertyParms, +% TSD#'TerminationStateDescriptor'{propertyParms = lists:reverse(PP)}. + +% ensure_prop_groups({_TokenTag, _Line, Text}) -> +% Group = [], +% Groups = [], +% parse_prop_name(Text, Group, Groups). + +% parse_prop_name([Char | Rest] = All, Group, Groups) -> +% case ?classify_char(Char) of +% white_space -> +% parse_prop_name(Rest, Group, Groups); +% end_of_line -> +% parse_prop_name(Rest, Group, Groups); +% _ -> +% Name = [], +% do_parse_prop_name(All, Name, Group, Groups) +% end; +% parse_prop_name([] = All, Group, Groups) -> +% Name = [], +% do_parse_prop_name(All, Name, Group, Groups). + +% do_parse_prop_name([Char | Rest], Name, Group, Groups) -> +% case ?classify_char(Char) of +% safe_char -> +% do_parse_prop_name(Rest, [Char | Name], Group, Groups); +% rest_char when Char == $=, Name /= [] -> +% %% Now we have a complete name +% if +% Name == "v", Group /= [] -> +% %% v= is a property group delimiter, +% %% lets create yet another property group. +% Groups2 = [lists:reverse(Group) | Groups], +% Group2 = [], +% parse_prop_value(Rest, Name, Group2, Groups2); +% true -> +% %% Use current property group +% parse_prop_value(Rest, Name, Group, Groups) +% end; +% _ -> +% return_error(0, {bad_prop_name, lists:reverse(Name), Char}) +% end; +% do_parse_prop_name([], [], [], Groups) -> +% lists:reverse(Groups); +% do_parse_prop_name([], [], Group, Groups) -> +% Group2 = lists:reverse(Group), +% lists:reverse([Group2 | Groups]); +% do_parse_prop_name([], Name, Group, Groups) when Name /= [] -> +% %% Assume end of line +% Value = [], +% PP = make_prop_parm(Name, Value), +% Group2 = lists:reverse([PP | Group]), +% lists:reverse([Group2 | Groups]). + +% parse_prop_value(Chars, Name, Group, Groups) -> +% Value = [], +% do_parse_prop_value(Chars, Name, Value, Group, Groups). + +% do_parse_prop_value([Char | Rest], Name, Value, Group, Groups) -> +% case ?classify_char(Char) of +% end_of_line -> +% %% Now we have a complete "name=value" pair +% PP = make_prop_parm(Name, Value), +% parse_prop_name(Rest, [PP | Group], Groups); +% _ -> +% do_parse_prop_value(Rest, Name, [Char | Value], Group, Groups) +% end; +% do_parse_prop_value([], Name, Value, Group, Groups) -> +% %% Assume end of line +% PP = make_prop_parm(Name, Value), +% Group2 = lists:reverse([PP | Group]), +% lists:reverse([Group2 | Groups]). + +% make_prop_parm(Name, Value) -> +% #'PropertyParm'{name = lists:reverse(Name), +% value = [lists:reverse(Value)]}. + +ensure_uint({_TokenTag, Line, Val}, Min, Max) when is_integer(Val) -> + if + is_integer(Min) andalso (Val >= Min) -> + if + is_integer(Max) andalso (Val =< Max) -> + Val; + Max =:= infinity -> + Val; + true -> + return_error(Line, {too_large_integer, Val, Max}) + end; + true -> + return_error(Line, {too_small_integer, Val, Min}) + end; +ensure_uint({TokenTag, Line, Text}, Min, Max) -> + case catch list_to_integer(Text) of + {'EXIT', _} -> + return_error(Line, {not_an_integer, Text}); + Val when is_integer(Val) -> + ensure_uint({TokenTag, Line, Val}, Min, Max) + end; +ensure_uint(Val, Min, Max) -> + ensure_uint({uint, 0, Val}, Min, Max). + +ensure_uint16(Int) -> + ensure_uint(Int, 0, 65535). + +% ensure_uint32(Int) -> +% ensure_uint(Int, 0, 4294967295) . + +%% OTP-4710 +ensure_hex({_TokenTag, _Line, [$0, $x |Chars]}, Min, Max) -> + ensure_uint(length(Chars), Min, Max), + hex_to_int(Chars, []); +ensure_hex({_TokenTag, _Line, [$0, $X |Chars]}, Min, Max) -> + ensure_uint(length(Chars), Min, Max), + hex_to_int(Chars, []); +ensure_hex([$0, $x |Chars], Min, Max) -> + ensure_uint(length(Chars), Min, Max), + hex_to_int(Chars, []); +ensure_hex([$0, $X |Chars], Min, Max) -> + ensure_uint(length(Chars), Min, Max), + hex_to_int(Chars, []). + +%% OTP-4710 +hex_to_int([], Acc) -> + lists:reverse(Acc); +hex_to_int([Char1,Char2|Tail], Acc) -> + Int1 = hchar_to_int(Char1), + Int2 = hchar_to_int(Char2), + Val = Int2 bor (Int1 bsl 4), + hex_to_int(Tail, [Val| Acc]); +hex_to_int([Char], Acc) -> + Int = hchar_to_int(Char), + lists:reverse([Int|Acc]). + +hchar_to_int(Char) when $0 =< Char, Char =< $9 -> + Char - $0; +hchar_to_int(Char) when $A =< Char, Char =< $F -> + Char - $A + 10; % OTP-4710 +hchar_to_int(Char) when $a =< Char, Char =< $f -> + Char - $a + 10. % OTP-4710 + +% value_of({_TokenTag, _Line, Text}) -> +% Text. + + +% d(F) -> +% d(F, []). + +% d(F, A) -> +% d(get(dbg), F, A). + +% d(true, F, A) -> +% io:format("~p:" ++ F ++ "~n", [?MODULE|A]); +% d(_, _, _) -> +% ok. + diff --git a/lib/megaco/src/text/megaco_text_mini_parser.yrl b/lib/megaco/src/text/megaco_text_mini_parser.yrl new file mode 100644 index 0000000000..50e31b9eb4 --- /dev/null +++ b/lib/megaco/src/text/megaco_text_mini_parser.yrl @@ -0,0 +1,398 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2004-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: YECC grammar for mini text decoding of Megaco/H.248 +%%---------------------------------------------------------------------- + +%%---------------------------------------------------------------------- +%% Annex B TEXT ENCODING OF THE PROTOCOL (NORMATIVE) +%% +%% B.1 Coding of wildcards +%% +%% In a text encoding of the protocol, while TerminationIDs are +%% arbitrary, by judicious choice of names, the wildcard character, "*" +%% may be made more useful. When the wildcard character is encountered, +%% it will "match" all TerminationIDs having the same previous and +%% following characters (if appropriate). For example, if there were +%% TerminationIDs of R13/3/1, R13/3/2 and R13/3/3, the TerminationID +%% R13/3/* would match all of them. There are some circumstances where +%% ALL Terminations must be referred to. The TerminationID "*" suffices, +%% and is referred to as ALL. The CHOOSE TerminationID "$" may be used to +%% signal to the MG that it has to create an ephemeral Termination or +%% select an idle physical Termination. +%% +%% B.2 ABNF specification +%% +%% The protocol syntax is presented in ABNF according to RFC2234. The +%% protocol is not case sensitive. Identifiers are not case sensitive. +%%---------------------------------------------------------------------- + +Expect 1. + + +%%---------------------------------------------------------------------- +%% Non-terminals +%%---------------------------------------------------------------------- + +Nonterminals + + authenticationHeader + daddr + deviceName + domainAddress + domainName + mId + megacoMessage + message + mtpAddress + optSep + pathName + portNumber + safeToken + safeToken2 +. + +%%---------------------------------------------------------------------- +%% Terminals +%%---------------------------------------------------------------------- + +Terminals + + %% 'AddToken' + %% 'AndAUDITselectToken' + 'AuditCapToken' + 'AuditToken' + 'AuditValueToken' + 'AuthToken' + %% 'BothToken' + %% 'BothwayToken' + 'BriefToken' + %% 'BufferToken' + 'COLON' + %% 'ContextAttrToken' + 'ContextAuditToken' + %% 'ContextListToken' + 'CtxToken' + 'DelayToken' + %% 'DigitMapToken' + %% 'DigitMapDescriptorToken' + 'DirectionToken' + 'DiscardToken' + 'DisconnectedToken' + 'DurationToken' + 'EQUAL' + 'EmbedToken' + %% 'EmergencyToken' + %% 'EmergencyOffToken' + %% 'EmergencyValueToken' + 'ErrorToken' + %% 'EventBufferToken' + %% 'EventsToken' + %% 'ExternalToken' + 'FailoverToken' + 'ForcedToken' + 'GREATER' + 'GracefulToken' + 'H221Token' + 'H223Token' + 'H226Token' + 'HandOffToken' + %% 'IEPSToken' + 'ImmAckRequiredToken' + 'InSvcToken' + 'InactiveToken' + %% 'InternalToken' + 'InterruptByEventToken' + 'InterruptByNewSignalsDescrToken' + %% 'IntsigDelayToken' + %% 'IsolateToken' + %% 'IterationToken' + 'KeepActiveToken' + 'LESSER' + 'LSBRKT' + 'LocalControlToken' + %% 'LocalDescriptorToken' + 'LockStepToken' + 'LoopbackToken' + %% 'MediaToken' + %% 'MessageSegmentToken' + 'MethodToken' + 'MgcIdToken' + %% 'ModeToken' + %% 'ModemToken' + %% 'ModifyToken' + %% 'MoveToken' + 'MtpAddressToken' + %% 'MuxToken' + %% 'NeverNotifyToken' + 'NotifyCompletionToken' + %% 'NotifyImmediateToken' + %% 'NotifyRegulatedToken' + 'NotifyToken' + 'Nx64Token' + %% 'ObservedEventsToken' + 'OffToken' + 'OnToken' + 'OnOffToken' + %% 'OnewayToken' + %% 'OnewayExternalToken' + %% 'OnewayBothToken' + %% 'OrAUDITselectToken' + 'OtherReasonToken' + 'OutOfSvcToken' + %% 'PackagesToken' + 'PendingToken' + %% 'PriorityToken' + 'ProfileToken' + %% 'QuotedChars' + 'RSBRKT' + 'ReasonToken' + 'RecvonlyToken' + %% 'RemoteDescriptorToken' + 'ReplyToken' + 'RequestIDToken' + %% 'ReservedGroupToken' + %% 'ReservedValueToken' + %% 'ResetEventsDescriptorToken' + 'ResponseAckToken' + 'RestartToken' + 'SEP' + 'SafeChars' + 'SendonlyToken' + 'SendrecvToken' + 'ServiceChangeAddressToken' + 'ServiceChangeToken' + %% 'ServiceChangeIncompleteToken' + %% 'ServiceStatesToken' + 'ServicesToken' + 'SignalListToken' + 'SignalTypeToken' + %% 'SignalsToken' + %% 'StatsToken' + 'StreamToken' + %% 'SubtractToken' + 'SynchISDNToken' + 'TerminationStateToken' + 'TestToken' + 'TimeOutToken' + %% 'TimeStampToken' + %% 'TopologyToken' + 'TransToken' + 'V18Token' + 'V22Token' + 'V22bisToken' + 'V32Token' + 'V32bisToken' + 'V34Token' + 'V76Token' + 'V90Token' + 'V91Token' + 'VersionToken' + endOfMessage + +. + +%%---------------------------------------------------------------------- +%% Root symbol +%%---------------------------------------------------------------------- + +Rootsymbol megacoMessage. + +%%---------------------------------------------------------------------- +%% The grammar +%%---------------------------------------------------------------------- + +%% megacoMessage = LWSP [authenticationHeader SEP ] message +%% authenticationHeader = AuthToken EQUAL SecurityParmIndex COLON +%% SequenceNum COLON AuthData +%% +%% SecurityParmIndex = "0x" 8(HEXDIG) +%% SequenceNum = "0x" 8(HEXDIG) +%% AuthData = "0x" 24*64(HEXDIG) +%% message = MegacopToken SLASH version SEP mId SEP messageBody +%% version = 1*2(DIGIT) . + +megacoMessage -> optSep authenticationHeader message endOfMessage + : #'MegacoMessage'{authHeader = '$2', mess = '$3'} . + +optSep -> 'SEP' : sep . +optSep -> '$empty' : no_sep . + +authenticationHeader -> 'AuthToken' 'EQUAL' safeToken 'COLON' + safeToken 'COLON' safeToken optSep + : ensure_auth_header('$3', '$5', '$7') . +authenticationHeader -> '$empty' : asn1_NOVALUE . + +message -> safeToken mId : ensure_message('$1', '$2') . + +mId -> domainName : '$1' . +mId -> domainAddress : '$1' . +mId -> optSep mtpAddress optSep : '$2' . +mId -> optSep deviceName optSep : '$2' . + +domainName -> 'LESSER' safeToken 'GREATER' 'COLON' portNumber optSep + : ensure_domainName('$2', '$5') . +domainName -> 'LESSER' safeToken 'GREATER' + : ensure_domainName('$2', asn1_NOVALUE) . + +deviceName -> pathName : {deviceName, '$1'} . + +domainAddress -> 'LSBRKT' daddr 'RSBRKT' 'COLON' portNumber optSep + : ensure_domainAddress('$2', '$5') . +domainAddress -> 'LSBRKT' daddr 'RSBRKT' + : ensure_domainAddress('$2', asn1_NOVALUE) . + +daddr -> '$empty' : [] . +daddr -> 'COLON' daddr : [colon| '$2'] . +daddr -> safeToken daddr : ['$1'| '$2'] . + +portNumber -> safeToken : ensure_uint16('$1') . + +mtpAddress -> 'MtpAddressToken' : ensure_mtpAddress('$1') . + +pathName -> safeToken : ensure_pathName('$1') . + +safeToken -> safeToken2 : make_safe_token('$1') . + +%% safeToken2 -> 'AddToken' : '$1' . +safeToken2 -> 'AuditToken' : '$1' . +safeToken2 -> 'AuditCapToken' : '$1' . +safeToken2 -> 'AuditValueToken' : '$1' . +safeToken2 -> 'AuthToken' : '$1' . +%% safeToken2 -> 'BothToken' : '$1' . % v3 +%% safeToken2 -> 'BothwayToken' : '$1' . +safeToken2 -> 'BriefToken' : '$1' . +%% safeToken2 -> 'BufferToken' : '$1' . +safeToken2 -> 'CtxToken' : '$1' . +%% safeToken2 -> 'ContextAttrToken' : '$1' . % v3 +safeToken2 -> 'ContextAuditToken' : '$1' . +%% safeToken2 -> 'ContextListToken' : '$1' . % v3 +%% safeToken2 -> 'DigitMapToken' : '$1' . +%% safeToken2 -> 'DigitMapDescriptorToken' : '$1' . +safeToken2 -> 'DirectionToken' : '$1' . % v3 +safeToken2 -> 'DiscardToken' : '$1' . +safeToken2 -> 'DisconnectedToken' : '$1' . +safeToken2 -> 'DelayToken' : '$1' . +safeToken2 -> 'DurationToken' : '$1' . +safeToken2 -> 'EmbedToken' : '$1' . +%% safeToken2 -> 'EmergencyToken' : '$1' . +%% safeToken2 -> 'EmergencyOffToken' : '$1' . +safeToken2 -> 'ErrorToken' : '$1' . +%% safeToken2 -> 'EventBufferToken' : '$1' . +%% safeToken2 -> 'EventsToken' : '$1' . +%% safeToken2 -> 'ExternalToken' : '$1' . % v3 +safeToken2 -> 'FailoverToken' : '$1' . +safeToken2 -> 'ForcedToken' : '$1' . +safeToken2 -> 'GracefulToken' : '$1' . +safeToken2 -> 'H221Token' : '$1' . +safeToken2 -> 'H223Token' : '$1' . +safeToken2 -> 'H226Token' : '$1' . +safeToken2 -> 'HandOffToken' : '$1' . +%% safeToken2 -> 'IEPSToken' : '$1' . % v3 +safeToken2 -> 'ImmAckRequiredToken' : '$1' . +safeToken2 -> 'InactiveToken' : '$1' . +%% safeToken2 -> 'InternalToken' : '$1' . % v3 +safeToken2 -> 'InterruptByEventToken' : '$1' . +safeToken2 -> 'InterruptByNewSignalsDescrToken' : '$1' . +%% safeToken2 -> 'IsolateToken' : '$1' . +safeToken2 -> 'InSvcToken' : '$1' . +safeToken2 -> 'KeepActiveToken' : '$1' . +%% safeToken2 -> 'LocalToken' : '$1' . +%% safeToken2 -> 'LocalDescriptorToken' : '$1' . +safeToken2 -> 'LocalControlToken' : '$1' . +safeToken2 -> 'LoopbackToken' : '$1' . +safeToken2 -> 'LockStepToken' : '$1' . +%% safeToken2 -> 'MediaToken' : '$1' . +%% safeToken2 -> 'MegacopToken' : '$1' . +safeToken2 -> 'MethodToken' : '$1' . +safeToken2 -> 'MgcIdToken' : '$1' . +%% safeToken2 -> 'ModeToken' : '$1' . +%% safeToken2 -> 'ModifyToken' : '$1' . +%% safeToken2 -> 'ModemToken' : '$1' . +%% safeToken2 -> 'MoveToken' : '$1' . +%% safeToken2 -> 'MtpToken' : '$1' . +%% safeToken2 -> 'MtpAddressToken' : '$1' . +%% safeToken2 -> 'MuxToken' : '$1' . +safeToken2 -> 'NotifyToken' : '$1' . +safeToken2 -> 'NotifyCompletionToken' : '$1' . +safeToken2 -> 'Nx64Token' : '$1' . +%% safeToken2 -> 'ObservedEventsToken' : '$1' . +%% safeToken2 -> 'OnewayToken' : '$1' . +%% safeToken2 -> 'OnewayExternalToken' : '$1' . +%% safeToken2 -> 'OnewayBothToken' : '$1' . +safeToken2 -> 'OffToken' : '$1' . +safeToken2 -> 'OnToken' : '$1' . +safeToken2 -> 'OnOffToken' : '$1' . +safeToken2 -> 'OutOfSvcToken' : '$1' . +safeToken2 -> 'OtherReasonToken' : '$1' . +%% safeToken2 -> 'PackagesToken' : '$1' . +safeToken2 -> 'PendingToken' : '$1' . +%% safeToken2 -> 'PriorityToken' : '$1' . +safeToken2 -> 'ProfileToken' : '$1' . +safeToken2 -> 'ReasonToken' : '$1' . +safeToken2 -> 'RecvonlyToken' : '$1' . +safeToken2 -> 'ReplyToken' : '$1' . +safeToken2 -> 'RequestIDToken' : '$1' . +safeToken2 -> 'ResponseAckToken' : '$1' . +safeToken2 -> 'SafeChars' : '$1' . +safeToken2 -> 'RestartToken' : '$1' . +%% safeToken2 -> 'RemoteToken' : '$1' . +%% safeToken2 -> 'RemoteDescriptorToken' : '$1' . +%% safeToken2 -> 'ReservedGroupToken' : '$1' . +%% safeToken2 -> 'ReservedValueToken' : '$1' . +safeToken2 -> 'SendonlyToken' : '$1' . +safeToken2 -> 'SendrecvToken' : '$1' . +safeToken2 -> 'ServicesToken' : '$1' . +%% safeToken2 -> 'ServiceStatesToken' : '$1' . +safeToken2 -> 'ServiceChangeToken' : '$1' . +%% safeToken2 -> 'ServiceChangeIncompleteToken' : '$1' . +safeToken2 -> 'ServiceChangeAddressToken' : '$1' . +safeToken2 -> 'SignalListToken' : '$1' . +%% safeToken2 -> 'SignalsToken' : '$1' . +safeToken2 -> 'SignalTypeToken' : '$1' . +%% safeToken2 -> 'StatsToken' : '$1' . +safeToken2 -> 'StreamToken' : '$1' . +%% safeToken2 -> 'SubtractToken' : '$1' . +safeToken2 -> 'SynchISDNToken' : '$1' . +safeToken2 -> 'TerminationStateToken' : '$1' . +safeToken2 -> 'TestToken' : '$1' . +safeToken2 -> 'TimeOutToken' : '$1' . +%% safeToken2 -> 'TopologyToken' : '$1' . +safeToken2 -> 'TransToken' : '$1' . +safeToken2 -> 'V18Token' : '$1' . +safeToken2 -> 'V22Token' : '$1' . +safeToken2 -> 'V22bisToken' : '$1' . +safeToken2 -> 'V32Token' : '$1' . +safeToken2 -> 'V32bisToken' : '$1' . +safeToken2 -> 'V34Token' : '$1' . +safeToken2 -> 'V76Token' : '$1' . +safeToken2 -> 'V90Token' : '$1' . +safeToken2 -> 'V91Token' : '$1' . +safeToken2 -> 'VersionToken' : '$1' . + +Erlang code. + +%% The following directive is needed for (significantly) faster compilation +%% of the generated .erl file by the HiPE compiler. Please do not remove. +-compile([{hipe,[{regalloc,linear_scan}]}]). + +-include("megaco_text_mini_parser.hrl"). + diff --git a/lib/megaco/src/text/megaco_text_parser_prev3a.hrl b/lib/megaco/src/text/megaco_text_parser_prev3a.hrl new file mode 100644 index 0000000000..7faf46afc8 --- /dev/null +++ b/lib/megaco/src/text/megaco_text_parser_prev3a.hrl @@ -0,0 +1,1670 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2004-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 : Define semantic text parser actions +%%---------------------------------------------------------------------- + + +-include_lib("megaco/include/megaco.hrl"). +-include_lib("megaco/include/megaco_message_prev3a.hrl"). +-define(encoder_version_pre_prev3c,true). +-include("megaco_text_tokens.hrl"). + +-ifdef(megaco_parser_inline). +-compile({inline,[{make_safe_token,1}]}). +-endif. +make_safe_token(Token) -> + {_TokenTag, Line, Text} = Token, + {safeToken, Line, Text}. + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_value,1}]}). +-endif. +ensure_value(Token) -> + case Token of + {safeToken, _Line, Text} when is_list(Text) -> + Text; % We really should ensure length + {'QuotedChars', _Line, Text} when is_list(Text) -> + Text; % We really should ensure length + Text when is_list(Text) -> + Text % We really should ensure length + end. + +%% NAME = ALPHA *63(ALPHA / DIGIT / "_" ) +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_NAME,1}]}). +-endif. +ensure_NAME(Token) -> + {_TokenTag, _Line, Text} = Token, + Text. % We really should ensure length and chars + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_requestID,1}]}). +-endif. +ensure_requestID(Token) -> + case Token of + {safeToken, _Line, "*"} -> + ?megaco_all_request_id; + _ -> + ensure_uint32(Token) + end. + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_streamID,1}]}). +-endif. +ensure_streamID(StreamId) -> + ensure_uint16(StreamId). + +ensure_auth_header(SpiToken, SnToken, AdToken) -> + Spi = ensure_hex(SpiToken, 8, 8), + Sn = ensure_hex(SnToken, 8, 8), + Ad = ensure_hex(AdToken, 24, 64), + #'AuthenticationHeader'{secParmIndex = Spi, seqNum = Sn, ad = Ad}. + +%% The values 0x0, 0xFFFFFFFE and 0xFFFFFFFF are reserved. +%% ContextID = (UINT32 / "*" / "-" / "$") +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_contextID,1}]}). +-endif. +ensure_contextID(Token) -> + {_TokenTag, Line, Text} = Token, + case Text of + "*" -> ?megaco_all_context_id; + "-" -> ?megaco_null_context_id; + "\$" -> ?megaco_choose_context_id; + Int -> + CID = ensure_uint32(Int), + if + (CID =/= 0) andalso + (CID =/= 16#FFFFFFFE) andalso + (CID =/= 16#FFFFFFFF) -> + CID; + true -> + return_error(Line, {bad_ContextID, CID}) + end + end. + +ensure_domainAddress([{_T, _L, _A} = Addr0], Port) -> + Addr = ensure_ip4addr(Addr0), + {ip4Address, #'IP4Address'{address = Addr, portNumber = Port}}; +ensure_domainAddress([colon,colon], Port) -> + Addr = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + {ip6Address, #'IP6Address'{address = Addr, portNumber = Port}}; +ensure_domainAddress(Addr0, Port) -> + Addr = ensure_ip6addr(Addr0), + {ip6Address, #'IP6Address'{address = Addr, portNumber = Port}}. + + +ensure_ip4addr(Token) -> + {_TokenTag, Line, Addr} = Token, +%% case string:tokens(Addr, [$.]) of +%% [T1, T2, T3, T4] -> + case split_ip4addr_text(Addr, []) of + [T1, T2, T3, T4] -> + %% We optimize by sending only the text part (Addr) of + %% the token to the function. + %% If something is wrong, then we do not get a proper + %% position and therefor we catch and issue the + %% the error again (with the proper line number). + case (catch [ + ensure_uint(T1, 0, 255), + ensure_uint(T2, 0, 255), + ensure_uint(T3, 0, 255), + ensure_uint(T4, 0, 255) + ]) of + A when is_list(A) -> + A; + _ -> + return_error(Line, {bad_IP4address, Addr}) + end; + _ -> + return_error(Line, {bad_IP4address, Addr}) + end. + +split_ip4addr_text([], Acc) -> + [ lists:reverse(Acc) ]; +split_ip4addr_text([$. | Rest], Acc) -> + [ lists:reverse(Acc) | split_ip4addr_text(Rest, []) ]; +split_ip4addr_text([H | T], Acc) -> + split_ip4addr_text(T, [H | Acc]). + + +ensure_ip6addr([colon,colon|T]) -> + [H1|T1] = lists:reverse(T), + case do_ensure_ip6addr(T1, true, [ensure_hex4_or_ip4addr(H1)], 1) of + {true, A} when length(A) == 16 -> + A; + {true, B} when length(B) < 16 -> + lists:duplicate(16 - length(B), 0) ++ B; + {true, C} -> + throw({error, {?MODULE, {bad_mid_ip6addr_length, C}}}) + end; +ensure_ip6addr(L) -> + case lists:reverse(L) of + [colon, colon| T] -> + case do_ensure_ip6addr(T, true, [], 1) of + {true, A} when length(A) == 16 -> + A; + {true, B} when length(B) < 16 -> + B ++ lists:duplicate(16 - length(B), 0); + {true, C} -> + throw({error, {?MODULE, {bad_mid_ip6addr_length, C}}}) + end; + [H|L1] -> % A (last element) could be an ip4 address + case do_ensure_ip6addr(L1,false,[ensure_hex4_or_ip4addr(H)],1) of + {false, A} when length(A) == 16 -> + A; + %% allow a pad even if the address is full (i.e. 16) + {true, B} when length(B) =< 17 -> + do_ensure_ip6addr_padding(B, 0); + {Pad, C} -> + throw({error, {?MODULE, {bad_mid_ip6addr_length, Pad, C}}}) + end + + end. + + +do_ensure_ip6addr([], Pad, Acc, _) -> + {Pad, lists:flatten(Acc)}; +do_ensure_ip6addr([colon,colon|T], false, Acc, Line) -> + do_ensure_ip6addr(T, true, [pad|Acc], Line); +do_ensure_ip6addr([colon,colon|T], true, Acc, Line) -> + return_error(Line, {bad_mid_duplicate_padding, T, Acc}); +do_ensure_ip6addr([colon|T], Pad, Acc, Line) -> + do_ensure_ip6addr(T, Pad, Acc, Line); +do_ensure_ip6addr([{_, Line, _} = A|T], Pad, Acc, _) -> + do_ensure_ip6addr(T, Pad, [ensure_hex4(A)|Acc], Line). + +do_ensure_ip6addr_padding([], _) -> + []; +do_ensure_ip6addr_padding([pad|T], N) -> + lists:duplicate(16 - (N + length(T)), 0) ++ T; +do_ensure_ip6addr_padding([H|T], N) -> + [H|do_ensure_ip6addr_padding(T, N+1)]. + +ensure_hex4_or_ip4addr({TokenTag, Line, Addr} = V) -> + case string:tokens(Addr, [$.]) of + [T1, T2, T3, T4] -> + A1 = ensure_uint({TokenTag, Line, T1}, 0, 255), + A2 = ensure_uint({TokenTag, Line, T2}, 0, 255), + A3 = ensure_uint({TokenTag, Line, T3}, 0, 255), + A4 = ensure_uint({TokenTag, Line, T4}, 0, 255), + [A1, A2, A3, A4]; + _ -> + ensure_hex4(V) + %% %% BMK BMK BMK + %% %% Here we should test for hexseq + %% return_error(Line, {bad_IP4address, Addr}) + end. + +ensure_hex4({_TokenTag, Line, Hex4}) + when length(Hex4) =< 4, length(Hex4) > 0 -> + case (catch do_ensure_hex4(Hex4)) of + IL when is_list(IL) andalso (length(IL) =:= 2) -> + IL; + Error -> + return_error(Line, {bad_hex4, Hex4, Error}) + end. + +do_ensure_hex4([_H1, _H2, _H3, _H4] = H) -> + hex_to_int(H, []); +do_ensure_hex4([H2, H3, H4]) -> + hex_to_int([$0, H2, H3, H4], []); +do_ensure_hex4([H3, H4]) -> + hex_to_int([$0, $0, H3, H4], []); +do_ensure_hex4([H4]) -> + hex_to_int([$0, $0, $0, H4], []). + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_domainName,2}]}). +-endif. +ensure_domainName(Token, Port) -> + {_TokenTag, _Line, Name} = Token, + %% BUGBUG: validate name + {domainName, #'DomainName'{name = Name, portNumber = Port}}. + +%% extensionParameter= "X" ("-" / "+") 1*6(ALPHA / DIGIT) +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_extensionParameter,1}]}). +-endif. +ensure_extensionParameter(Token) -> + {_TokenTag, Line, Text} = Token, + case Text of + [X, S | _Chars] -> + if + X /= $X, X /= $x, + S /= $+, S /= $- -> + return_error(Line, {bad_extension_parameter, Text}); + true -> + {extension_parameter, Text} + end; + _ -> + return_error(Line, {bad_extension_parameter, Text}) + end. + +ensure_message(MegacopToken, MID, Body) -> +%% #'ServiceChangeProfile'{profileName = Name, +%% version = Version} = +%% ensure_profile(MegacopToken), +%% case Name of +%% "megaco" -> +%% #'Message'{version = Version, mId = MID, messageBody = Body}; +%% [$!] -> +%% #'Message'{version = Version, mId = MID, messageBody = Body} +%% end. + {_TokenTag, Line, Text} = MegacopToken, + case split_Megacop(Text, []) of + {Name, Version} -> + Version2 = ensure_version(Version), + case Name of + "megaco" -> + #'Message'{version = Version2, + mId = MID, + messageBody = Body}; + [$!] -> + #'Message'{version = Version2, + mId = MID, + messageBody = Body} + end; + _ -> + return_error(Line, {bad_name_or_version, Text}) + end. + +split_Megacop([], _) -> + error; +split_Megacop([$/ | Version], Acc) -> + {lists:reverse(Acc), Version}; +split_Megacop([H | T], Acc) -> + split_Megacop(T, [H | Acc]). + + +%% Corr1: +%% As of corr 1 ModemDescriptor has been deprecated. +%% and since this functon is only used when creating +%% a ModemDescriptor, iit is removed. +%% modemType = (V32bisToken / V22bisToken / V18Token / +%% V22Token / V32Token / V34Token / V90Token / +%% V91Token / SynchISDNToken / extensionParameter) +%% ensure_modemType({_TokenTag, _Line, Text} = Token) -> +%% case Text of +%% "v32b" -> v32bis; +%% "v22b" -> v22bis; +%% "v18" -> v18; +%% "v22" -> v22; +%% "v32" -> v32; +%% "v34" -> v34; +%% "v90" -> v90; +%% "v91" -> v91; +%% "synchisdn" -> synchISDN; +%% "sn" -> synchISDN; +%% [$x | _] -> ensure_extensionParameter(Token) +%% end. + +%% An mtp address is five octets long +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_mtpAddress,1}]}). +-endif. +ensure_mtpAddress(Token) -> + {_TokenTag, _Line, Addr} = Token, + %% BUGBUG: validate address + {mtpAddress, Addr}. + +%% MuxType = ( H221Token / H223Token / H226Token / V76Token / extensionParameter ) +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_muxType,1}]}). +-endif. +ensure_muxType(Token) -> + {_TokenTag, _Line, Text} = Token, + case Text of + "h221" -> h221; + "h223" -> h223; + "h226" -> h226; + "v76" -> v76; + "nx64k" -> nx64k; % v2 + [$x | _] -> ensure_extensionParameter(Token) + end. + +%% packagesItem = NAME "-" UINT16 +%% NAME = ALPHA *63(ALPHA / DIGIT / "_" ) +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_packagesItem,1}]}). +-endif. +ensure_packagesItem(Token) -> + {_TokenTag, Line, Text} = Token, + case split_packagesItem(Text, []) of + {Name, Version} -> + %% As we don't ensure length of the names, there is no point + %% in doing the ensure_NAME thing... + #'PackagesItem'{packageName = Name, + packageVersion = ensure_uint(Version, 0, 99)}; + _ -> + return_error(Line, {bad_PackagesItem, Text}) + end. + +split_packagesItem([], _) -> + error; +split_packagesItem([$- | Version], Acc) -> + {lists:reverse(Acc), Version}; +split_packagesItem([H|T], Acc) -> + split_packagesItem(T, [H|Acc]). + + +%% pkgdName = (PackageName / "*") SLASH (ItemID / "*" ) +%% PackageName = NAME +%% ItemID = NAME +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_pkgdName,1}]}). +-endif. +ensure_pkgdName(Token) -> + {_TokenTag, Line, Text} = Token, + case ensure_pkgdName(Text, []) of + ok -> + %% As we don't really do any checks on the strings + %% (length or content) there is really no point in + %% "ensuring" the name and item part of the + %% package name + %% ensure_name_or_star(Name), + %% ensure_name_or_star(Item), + Text; + _ -> + return_error(Line, {bad_pkgdName, Text}) + end. + +ensure_pkgdName([], _) -> + error; +ensure_pkgdName([$/ | T], Acc) + when ((length(T) > 0) andalso (length(Acc) > 0)) -> + ok; +ensure_pkgdName([H | T], Acc) -> + ensure_pkgdName(T, [H | Acc]). + + +%% -compile({inline,[{ensure_name_or_star,1}]}). +%% ensure_name_or_star(Val) -> +%% %% case Token of +%% %% {_, _, Name} when Name =:= "*" -> +%% %% Name; +%% %% _ -> +%% %% ensure_NAME(Token) +%% %% end. +%% if +%% Val =:= "*" -> +%% Val; +%% true -> +%% %% as we don't really validate the text part of the token(s), +%% %% we can just return the value assuming it to be correct... +%% Val +%% end. + + +%% v2 - start + +merge_indAudMediaDescriptor({termStateDescr, Val}) -> + #'IndAudMediaDescriptor'{termStateDescr = Val}; +merge_indAudMediaDescriptor({streamParm, Val}) -> + #'IndAudMediaDescriptor'{streams = {oneStream, Val}}; +merge_indAudMediaDescriptor({streamDescr, Val}) -> + #'IndAudMediaDescriptor'{streams = {multiStream, [Val]}}. + +-ifdef(megaco_parser_inline). +-compile({inline, [{merge_indAudLocalControlDescriptor,1}]}). +-endif. +merge_indAudLocalControlDescriptor(Parms) -> + do_merge_indAudLocalControlDescriptor(Parms, + #'IndAudLocalControlDescriptor'{}). + +do_merge_indAudLocalControlDescriptor([Parm | Parms], Desc) -> + case Parm of + modeToken when Desc#'IndAudLocalControlDescriptor'.streamMode =:= asn1_NOVALUE -> + Desc2 = Desc#'IndAudLocalControlDescriptor'{streamMode = 'NULL'}, + do_merge_indAudLocalControlDescriptor(Parms, Desc2); + reservedGroupToken when Desc#'IndAudLocalControlDescriptor'.reserveGroup =:= asn1_NOVALUE -> + Desc2 = Desc#'IndAudLocalControlDescriptor'{reserveGroup = 'NULL'}, + do_merge_indAudLocalControlDescriptor(Parms, Desc2); + reservedValueToken when Desc#'IndAudLocalControlDescriptor'.reserveValue =:= asn1_NOVALUE -> + Desc2 = Desc#'IndAudLocalControlDescriptor'{reserveValue = 'NULL'}, + do_merge_indAudLocalControlDescriptor(Parms, Desc2); + {pkgdName, Val} when Desc#'IndAudLocalControlDescriptor'.propertyParms =:= asn1_NOVALUE -> + PropParms = [#'IndAudPropertyParm'{name = Val}], + Desc2 = Desc#'IndAudLocalControlDescriptor'{propertyParms = PropParms}, + do_merge_indAudLocalControlDescriptor(Parms, Desc2); + {pkgdName, Val} when is_list(Desc#'IndAudLocalControlDescriptor'.propertyParms) -> + PropParms = Desc#'IndAudLocalControlDescriptor'.propertyParms, + PropParms2 = [#'IndAudPropertyParm'{name = Val} | PropParms], + Desc2 = Desc#'IndAudLocalControlDescriptor'{propertyParms = PropParms2}, + do_merge_indAudLocalControlDescriptor(Parms, Desc2) + end; +do_merge_indAudLocalControlDescriptor([], Desc) -> + case Desc#'IndAudLocalControlDescriptor'.propertyParms of + [_ | _] = PropParms -> % List has more then one element + PropParms2= lists:reverse(PropParms), + Desc#'IndAudLocalControlDescriptor'{propertyParms = PropParms2}; + _ -> + Desc + end. + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_indAudLocalParm,1}]}). +-endif. +ensure_indAudLocalParm(Token) -> + case Token of + {safeToken, _Line, "mode"} -> modeToken; + {safeToken, _Line, "mo"} -> modeToken; + {safeToken, _Line, "reservedgroup"} -> reservedGroupToken; + {safeToken, _Line, "rg"} -> reservedGroupToken; + {safeToken, _Line, "reservedvalue"} -> reservedValueToken; + {safeToken, _Line, "rv"} -> reservedValueToken; + PkgdName -> {pkgdName, + ensure_pkgdName(PkgdName)} + end. + +merge_indAudTerminationStateDescriptor({pkgdName, Val}) -> + PropParm = #'IndAudPropertyParm'{name = Val}, + #'IndAudTerminationStateDescriptor'{propertyParms = [PropParm]}; +merge_indAudTerminationStateDescriptor(serviceStatesToken) -> + #'IndAudTerminationStateDescriptor'{serviceState = 'NULL'}; +merge_indAudTerminationStateDescriptor(bufferToken) -> + #'IndAudTerminationStateDescriptor'{eventBufferControl = 'NULL'}. + + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_indAudEventBufferDescriptor,2}]}). +-endif. +merge_indAudEventBufferDescriptor(EventName, SpecParams) -> + IAEBD = #'IndAudEventBufferDescriptor'{eventName = EventName}, + do_merge_indAudEventBufferDescriptor(SpecParams, IAEBD). + +do_merge_indAudEventBufferDescriptor(asn1_NOVALUE, IAEBD) -> + IAEBD; +do_merge_indAudEventBufferDescriptor({streamID, StreamID}, IAEBD) -> + IAEBD#'IndAudEventBufferDescriptor'{streamID = StreamID}; +do_merge_indAudEventBufferDescriptor({eventParameterName, _Name} = EPN, + IAEBD) -> + %% BUGBUG BUGBUG BUGBUG + %% This is an ugly hack to allow the eventParamName which only + %% exists in the text encoding... + IAEBD#'IndAudEventBufferDescriptor'{streamID = EPN}. + + +ensure_indAudSignalListParm(SIG) when is_record(SIG, 'Signal') -> + ensure_indAudSignal(SIG). + +ensure_indAudSignal(#'Signal'{signalName = SignalName, + streamID = asn1_NOVALUE, + sigType = asn1_NOVALUE, + duration = asn1_NOVALUE, + notifyCompletion = asn1_NOVALUE, + keepActive = asn1_NOVALUE, + sigParList = []}) -> + #'IndAudSignal'{signalName = SignalName}. + + +ensure_IADMD({_TokenTag, _Line, + #'DigitMapDescriptor'{digitMapName = Name, + digitMapValue = asn1_NOVALUE}}) -> + #'IndAudDigitMapDescriptor'{digitMapName = Name}. + + +merge_indAudPackagesDescriptor(#'PackagesItem'{packageName = N, + packageVersion = V}) -> + #'IndAudPackagesDescriptor'{packageName = N, + packageVersion = V}. + + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_indAudTerminationStateParm,1}]}). +-endif. +ensure_indAudTerminationStateParm(Token) -> + case Token of + {safeToken, _Line, "servicestates"} -> serviceStatesToken; + {safeToken, _Line, "si"} -> serviceStatesToken; + {safeToken, _Line, "buffer"} -> bufferToken; + {safeToken, _Line, "bf"} -> bufferToken; + PkgdName -> {pkgdName, + ensure_pkgdName(PkgdName)} + end. + + +%% Types modified by v2: + +merge_auditDescriptor([]) -> + #'AuditDescriptor'{}; +merge_auditDescriptor(Tokens) when is_list(Tokens) -> + case lists:keysearch(terminationAudit, 1, Tokens) of + {value, {terminationAudit, TA}} -> + case lists:keydelete(terminationAudit, 1, Tokens) of + [] -> + #'AuditDescriptor'{auditPropertyToken = TA}; + AuditTokens -> + #'AuditDescriptor'{auditToken = AuditTokens, + auditPropertyToken = TA} + end; + false -> + #'AuditDescriptor'{auditToken = Tokens} + end; +merge_auditDescriptor(_) -> + #'AuditDescriptor'{}. + + +%% v2 - end + + + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_ServiceChangeParm,1}]}). +-endif. +merge_ServiceChangeParm(Parms) -> + Required = [serviceChangeReason, serviceChangeMethod], + merge_ServiceChangeParm(Parms, #'ServiceChangeParm'{}, Required). + +merge_ServiceChangeParm([], SCP, []) -> + SCP; + +merge_ServiceChangeParm([], _SCP, Required) -> + exit({missing_required_serviceChangeParm, Required}); + +merge_ServiceChangeParm([{address, Val}|Parms], SCP0, Req) + when (SCP0#'ServiceChangeParm'.serviceChangeAddress == asn1_NOVALUE) andalso + (SCP0#'ServiceChangeParm'.serviceChangeMgcId == asn1_NOVALUE) -> + SCP = SCP0#'ServiceChangeParm'{serviceChangeAddress = Val}, + merge_ServiceChangeParm(Parms, SCP, Req); +merge_ServiceChangeParm([{address, Val}|_Parms], SCP0, _Req) + when SCP0#'ServiceChangeParm'.serviceChangeAddress == asn1_NOVALUE -> + MgcId = SCP0#'ServiceChangeParm'.serviceChangeMgcId, + exit({not_both_address_mgcid_serviceChangeParm, Val, MgcId}); + +merge_ServiceChangeParm([{mgc_id, Val}|Parms], SCP0, Req) + when (SCP0#'ServiceChangeParm'.serviceChangeMgcId == asn1_NOVALUE) andalso + (SCP0#'ServiceChangeParm'.serviceChangeAddress == asn1_NOVALUE) -> + SCP = SCP0#'ServiceChangeParm'{serviceChangeMgcId = Val}, + merge_ServiceChangeParm(Parms, SCP, Req); +merge_ServiceChangeParm([{mgc_id, Val}|_Parms], SCP0, _Req) + when SCP0#'ServiceChangeParm'.serviceChangeMgcId == asn1_NOVALUE -> + Addr = SCP0#'ServiceChangeParm'.serviceChangeAddress, + exit({not_both_address_mgcid_serviceChangeParm, Val, Addr}); + +merge_ServiceChangeParm([{profile, Val}|Parms], SCP0, Req) + when SCP0#'ServiceChangeParm'.serviceChangeProfile == asn1_NOVALUE -> + SCP = SCP0#'ServiceChangeParm'{serviceChangeProfile = Val}, + merge_ServiceChangeParm(Parms, SCP, Req); + +merge_ServiceChangeParm([{version, Val}|Parms], SCP0, Req) + when SCP0#'ServiceChangeParm'.serviceChangeVersion == asn1_NOVALUE -> + SCP = SCP0#'ServiceChangeParm'{serviceChangeVersion = Val}, + merge_ServiceChangeParm(Parms, SCP, Req); + +%% REQUIRED (i.e. no default value) +merge_ServiceChangeParm([{reason, Val}|Parms], SCP0, Req0) + when SCP0#'ServiceChangeParm'.serviceChangeReason == undefined -> + SCP = SCP0#'ServiceChangeParm'{serviceChangeReason = Val}, + Req = lists:delete(serviceChangeReason, Req0), + merge_ServiceChangeParm(Parms, SCP, Req); + +merge_ServiceChangeParm([{delay, Val}|Parms], SCP0, Req) + when SCP0#'ServiceChangeParm'.serviceChangeDelay == asn1_NOVALUE -> + SCP = SCP0#'ServiceChangeParm'{serviceChangeDelay = Val}, + merge_ServiceChangeParm(Parms, SCP, Req); + +%% REQUIRED (i.e. no default value) +merge_ServiceChangeParm([{method, Val}|Parms], SCP0, Req0) + when SCP0#'ServiceChangeParm'.serviceChangeMethod == undefined -> + SCP = SCP0#'ServiceChangeParm'{serviceChangeMethod = Val}, + Req = lists:delete(serviceChangeMethod, Req0), + merge_ServiceChangeParm(Parms, SCP, Req); + +merge_ServiceChangeParm([{time_stamp, Val}|Parms], SCP0, Req) + when SCP0#'ServiceChangeParm'.timeStamp == asn1_NOVALUE -> + SCP = SCP0#'ServiceChangeParm'{timeStamp = Val}, + merge_ServiceChangeParm(Parms, SCP, Req); + +merge_ServiceChangeParm([{extension, _Val}|Parms], SCP0, Req) -> + merge_ServiceChangeParm(Parms, SCP0, Req); + +merge_ServiceChangeParm([{audit_item, Val}|Parms], SCP0, Req) + when (SCP0#'ServiceChangeParm'.serviceChangeInfo == asn1_NOVALUE) andalso + is_atom(Val) -> + SCI = #'AuditDescriptor'{auditToken = [Val]}, + SCP = SCP0#'ServiceChangeParm'{serviceChangeInfo = SCI}, + merge_ServiceChangeParm(Parms, SCP, Req); +merge_ServiceChangeParm([{audit_item, Val}|Parms], SCP0, Req) + when (SCP0#'ServiceChangeParm'.serviceChangeInfo == asn1_NOVALUE) andalso + is_tuple(Val) -> + SCI = #'AuditDescriptor'{auditPropertyToken = [Val]}, + SCP = SCP0#'ServiceChangeParm'{serviceChangeInfo = SCI}, + merge_ServiceChangeParm(Parms, SCP, Req); +merge_ServiceChangeParm([{audit_item, Val}|Parms], SCP0, Req) + when is_record(SCP0#'ServiceChangeParm'.serviceChangeInfo, 'AuditDescriptor') andalso + is_atom(Val) -> + SCI0 = SCP0#'ServiceChangeParm'.serviceChangeInfo, + L = SCI0#'AuditDescriptor'.auditToken, + SCI = SCI0#'AuditDescriptor'{auditToken = [Val|L]}, + SCP = SCP0#'ServiceChangeParm'{serviceChangeInfo = SCI}, + merge_ServiceChangeParm(Parms, SCP, Req); +merge_ServiceChangeParm([{audit_item, Val}|Parms], SCP0, Req) + when is_record(SCP0#'ServiceChangeParm'.serviceChangeInfo, 'AuditDescriptor') andalso + is_tuple(Val) -> + SCI0 = SCP0#'ServiceChangeParm'.serviceChangeInfo, + L = SCI0#'AuditDescriptor'.auditPropertyToken, + SCI = SCI0#'AuditDescriptor'{auditPropertyToken = [Val|L]}, + SCP = SCP0#'ServiceChangeParm'{serviceChangeInfo = SCI}, + merge_ServiceChangeParm(Parms, SCP, Req); + +merge_ServiceChangeParm([incomplete|Parms], SCP0, Req) + when SCP0#'ServiceChangeParm'.serviceChangeIncompleteFlag == asn1_NOVALUE -> + SCP = SCP0#'ServiceChangeParm'{serviceChangeIncompleteFlag = 'NULL'}, + merge_ServiceChangeParm(Parms, SCP, Req); + +merge_ServiceChangeParm([{Tag, Val}|_Parms], SCP, _Req) -> + Val2 = + case Tag of + address -> + SCP#'ServiceChangeParm'.serviceChangeAddress; + mgc_id -> + SCP#'ServiceChangeParm'.serviceChangeMgcId; + profile -> + SCP#'ServiceChangeParm'.serviceChangeProfile; + version -> + SCP#'ServiceChangeParm'.serviceChangeVersion; + reason -> + SCP#'ServiceChangeParm'.serviceChangeReason; + delay -> + SCP#'ServiceChangeParm'.serviceChangeDelay; + method -> + SCP#'ServiceChangeParm'.serviceChangeMethod; + time_stamp -> + SCP#'ServiceChangeParm'.timeStamp; + audit_item -> + SCP#'ServiceChangeParm'.serviceChangeInfo + end, + exit({at_most_once_serviceChangeParm, {Tag, Val, Val2}}); +merge_ServiceChangeParm([Parm|_Parms], SCP, _Req) -> + Parm2 = + case Parm of + incomplete -> + SCP#'ServiceChangeParm'.serviceChangeIncompleteFlag + end, + exit({at_most_once_serviceChangeParm, {Parm, Parm2}}). + + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_ServiceChangeResParm,1}]}). +-endif. +merge_ServiceChangeResParm(Parms) -> + merge_ServiceChangeResParm(Parms, #'ServiceChangeResParm'{}). + +merge_ServiceChangeResParm([], SCRP) -> + SCRP; +merge_ServiceChangeResParm([{address, Val}|Parms], SCRP0) + when SCRP0#'ServiceChangeResParm'.serviceChangeAddress == asn1_NOVALUE, + SCRP0#'ServiceChangeResParm'.serviceChangeMgcId == asn1_NOVALUE -> + SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeAddress = Val}, + merge_ServiceChangeResParm(Parms, SCRP); +merge_ServiceChangeResParm([{address, Val}|_Parms], SCRP0) + when SCRP0#'ServiceChangeResParm'.serviceChangeAddress == asn1_NOVALUE -> + MgcId = SCRP0#'ServiceChangeResParm'.serviceChangeMgcId, + exit({not_both_address_mgcid_servChgReplyParm, Val, MgcId}); + +merge_ServiceChangeResParm([{mgc_id, Val}|Parms], SCRP0) + when SCRP0#'ServiceChangeResParm'.serviceChangeMgcId == asn1_NOVALUE, + SCRP0#'ServiceChangeResParm'.serviceChangeAddress == asn1_NOVALUE -> + SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeMgcId = Val}, + merge_ServiceChangeResParm(Parms, SCRP); +merge_ServiceChangeResParm([{mgc_id, Val}|_Parms], SCRP0) + when SCRP0#'ServiceChangeResParm'.serviceChangeMgcId == asn1_NOVALUE -> + Addr = SCRP0#'ServiceChangeResParm'.serviceChangeAddress, + exit({not_both_address_mgcid_servChgReplyParm, Val, Addr}); + +merge_ServiceChangeResParm([{profile, Val}|Parms], SCRP0) + when SCRP0#'ServiceChangeResParm'.serviceChangeProfile == asn1_NOVALUE -> + SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeProfile = Val}, + merge_ServiceChangeResParm(Parms, SCRP); + +merge_ServiceChangeResParm([{version, Val}|Parms], SCRP0) + when SCRP0#'ServiceChangeResParm'.serviceChangeVersion == asn1_NOVALUE -> + SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeVersion = Val}, + merge_ServiceChangeResParm(Parms, SCRP); + +merge_ServiceChangeResParm([{time_stamp, Val}|Parms], SCRP0) + when SCRP0#'ServiceChangeResParm'.timeStamp == asn1_NOVALUE -> + SCRP = SCRP0#'ServiceChangeResParm'{timeStamp = Val}, + merge_ServiceChangeResParm(Parms, SCRP); + +merge_ServiceChangeResParm([{Tag, Val}|_Parms], SCRP) -> + Val2 = + case Tag of + address -> SCRP#'ServiceChangeResParm'.serviceChangeAddress; + mgc_id -> SCRP#'ServiceChangeResParm'.serviceChangeMgcId; + profile -> SCRP#'ServiceChangeResParm'.serviceChangeProfile; + version -> SCRP#'ServiceChangeResParm'.serviceChangeVersion; + time_stamp -> SCRP#'ServiceChangeResParm'.timeStamp + end, + exit({at_most_once_servChgReplyParm, {Tag, Val, Val2}}). + + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_serviceChangeMethod,1}]}). +-endif. +ensure_serviceChangeMethod(Token) -> + case Token of + {safeToken, _Line, "fl"} -> + failover; + {safeToken, _Line, "failover"} -> + failover; + {safeToken, _Line, "fo"} -> + forced; + {safeToken, _Line, "forced"} -> + forced; + {safeToken, _Line, "gr"} -> + graceful; + {safeToken, _Line, "graceful"} -> + graceful; + {safeToken, _Line, "rs"} -> + restart; + {safeToken, _Line, "restart"} -> + restart; + {safeToken, _Line, "dc"} -> + disconnected; + {safeToken, _Line, "disconnected"} -> + disconnected; + {safeToken, _Line, "ho"} -> + handOff; + {safeToken, _Line, "handoff"} -> + handOff; + {safeToken, Line, Text} -> + return_error(Line, {bad_serviceChangeMethod, Text}) + end. + + +ensure_profile({_TokenTag, Line, Text}) -> + case string:tokens(Text, [$/]) of + [Name, Version] -> + Version2 = ensure_version(Version), + #'ServiceChangeProfile'{profileName = Name, version = Version2}; + _ -> + return_error(Line, {bad_profile, Text}) + end. + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_version,1}]}). +-endif. +ensure_version(Version) -> + ensure_uint(Version, 0, 99). + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_signalRequest,2}]}). +-endif. +merge_signalRequest(SignalName, PropertyParms) -> + Sig = #'Signal'{signalName = SignalName}, + SPL = [], + do_merge_signalRequest(Sig, PropertyParms, SPL). + +do_merge_signalRequest(Sig, [H | T], SPL) -> + case H of + {stream, SID} when Sig#'Signal'.streamID == asn1_NOVALUE -> + do_merge_signalRequest(Sig#'Signal'{streamID = SID}, T, SPL); + {signal_type, SigType} when Sig#'Signal'.sigType == asn1_NOVALUE -> + do_merge_signalRequest(Sig#'Signal'{sigType = SigType}, T, SPL); + {duration, Duration} when Sig#'Signal'.duration == asn1_NOVALUE -> + do_merge_signalRequest(Sig#'Signal'{duration = Duration}, T, SPL); + {notify_completion, NC} when Sig#'Signal'.notifyCompletion == asn1_NOVALUE -> + do_merge_signalRequest(Sig#'Signal'{notifyCompletion = NC}, T, SPL); + keepActive when Sig#'Signal'.keepActive == asn1_NOVALUE-> + do_merge_signalRequest(Sig#'Signal'{keepActive = true}, T, SPL); + {other, Name, PP} -> + SP = #'SigParameter'{sigParameterName = Name, + value = PP#'PropertyParm'.value, + extraInfo = PP#'PropertyParm'.extraInfo}, + do_merge_signalRequest(Sig, T, [SP | SPL]); + {direction, Dir} when Sig#'Signal'.direction == asn1_NOVALUE-> + do_merge_signalRequest(Sig#'Signal'{direction = Dir}, T, SPL); + {requestId, RID} when Sig#'Signal'.requestID == asn1_NOVALUE-> + do_merge_signalRequest(Sig#'Signal'{requestID = RID}, T, SPL); + _ -> + return_error(0, {bad_sigParm, H}) + end; +do_merge_signalRequest(Sig, [], SPL) -> + Sig#'Signal'{sigParList = lists:reverse(SPL)} . + +%% eventStream = StreamToken EQUAL StreamID +%% eventOther = eventParameterName parmValue +-ifdef(megaco_parser_inline). +-compile({inline,[{select_stream_or_other,2}]}). +-endif. +select_stream_or_other(EventParameterName, ParmValue) -> + if + (EventParameterName =:= "st") orelse + (EventParameterName =:= "stream") -> + case ParmValue of + #'PropertyParm'{value = [Value]} -> + {stream, ensure_uint16(Value)}; + _ -> + {stream, ensure_uint16(ParmValue)} + end; + true -> + #'PropertyParm'{value = Value} = ParmValue, + EP = #'EventParameter'{eventParameterName = EventParameterName, + value = Value}, + {other, EP} + end. + +%% select_stream_or_other("st", #'PropertyParm'{value = [Value]}) -> +%% {stream, ensure_uint16(Value)}; +%% select_stream_or_other("st", Value) -> +%% {stream, ensure_uint16(Value)}; +%% select_stream_or_other("stream", #'PropertyParm'{value = [Value]}) -> +%% {stream, ensure_uint16(Value)}; +%% select_stream_or_other("stream", Value) -> +%% {stream, ensure_uint16(Value)}; +%% select_stream_or_other(Name, #'PropertyParm'{value = Value}) -> +%% EP = #'EventParameter'{eventParameterName = Name, +%% value = Value}, +%% {other, EP}. + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_eventDM,1}]}). +-endif. +ensure_eventDM(Token) -> + {_TokenTag, Line, DMD} = Token, + if + is_record(DMD, 'DigitMapDescriptor') -> + Name = DMD#'DigitMapDescriptor'.digitMapName, + Val = DMD#'DigitMapDescriptor'.digitMapValue, + if + (Name =:= asn1_NOVALUE) andalso (Val =/= asn1_NOVALUE) -> + {'DigitMapValue', Start, Short, Long, Duration, Body} = Val, + DMV = #'DigitMapValue'{startTimer = Start, + shortTimer = Short, + longTimer = Long, + digitMapBody = Body, + durationTimer = Duration}, + {eventDM, {digitMapValue, DMV}}; + (Name =/= asn1_NOVALUE) andalso (Val =:= asn1_NOVALUE) -> + {eventDM, {digitMapName, Name}}; + true -> + return_error(Line, {bad_eventDM, DMD}) + end; + true -> + return_error(Line, {bad_eventDM, DMD}) + end. + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_DMD,1}]}). +-endif. +ensure_DMD(Token) -> + {_TokenTag, Line, DMD} = Token, + if + is_record(DMD, 'DigitMapDescriptor') -> + Val2 = + case DMD#'DigitMapDescriptor'.digitMapValue of + %% Note that the values of the digitMapBody and + %% durationTimers are swapped by the scanner + %% (this is done because of a problem in the flex scanner). + #'DigitMapValue'{startTimer = asn1_NOVALUE, + shortTimer = asn1_NOVALUE, + longTimer = asn1_NOVALUE, + durationTimer = [], + digitMapBody = asn1_NOVALUE} -> + asn1_NOVALUE; + #'DigitMapValue'{durationTimer = Body, + digitMapBody = Duration} = DMV -> + %% Convert to version 1 DigitMapValue + DMV#'DigitMapValue'{digitMapBody = Body, + durationTimer = Duration}; + Other -> + Other + end, + DMD#'DigitMapDescriptor'{digitMapValue = Val2}; + true -> + return_error(Line, {bad_DigitMapDescriptor, DMD}) + end. + + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_observed_event,3}]}). +-endif. +merge_observed_event(ObservedEvents, EventName, TimeStamp) -> + StreamId = asn1_NOVALUE, + EPL = [], + do_merge_observed_event(ObservedEvents, EventName, TimeStamp, StreamId, EPL). + +do_merge_observed_event([{stream, StreamID} | T], EventName, TimeStamp, asn1_NOVALUE, EPL) -> + do_merge_observed_event(T, EventName, TimeStamp, StreamID, EPL); +do_merge_observed_event([{other, PP} | T], EventName, TimeStamp, StreamID, EPL) -> + do_merge_observed_event(T, EventName, TimeStamp, StreamID, [PP | EPL]); +do_merge_observed_event([], EventName, TimeStamp, StreamID, EPL) -> + #'ObservedEvent'{eventName = EventName, + timeNotation = TimeStamp, + streamID = StreamID, + eventParList = lists:reverse(EPL)}. + +merge_eventSpec(OE) + when is_record(OE, 'ObservedEvent') andalso + (OE#'ObservedEvent'.timeNotation == asn1_NOVALUE) -> + #'EventSpec'{eventName = OE#'ObservedEvent'.eventName, + streamID = OE#'ObservedEvent'.streamID, + eventParList = OE#'ObservedEvent'.eventParList}; +merge_eventSpec(OE) -> + return_error(0, {bad_event_spec, OE}). + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_eventParameters,1}]}). +-endif. +merge_eventParameters(Params) -> + StreamId = asn1_NOVALUE, + EPL = [], + RA = #'RequestedActions'{}, + HasA = no, + do_merge_eventParameters(Params, StreamId, EPL, RA, HasA) . + +do_merge_eventParameters([H | T], StreamId, EPL, RA, HasA) -> + case H of + keepActive when RA#'RequestedActions'.keepActive == asn1_NOVALUE -> + RA2 = RA#'RequestedActions'{keepActive = true}, + do_merge_eventParameters(T, StreamId, EPL, RA2, yes); + {embed, SD, SED} when RA#'RequestedActions'.signalsDescriptor == asn1_NOVALUE -> + RA2 = RA#'RequestedActions'{signalsDescriptor = SD, + secondEvent = SED}, + do_merge_eventParameters(T, StreamId, EPL, RA2, yes); + {eventDM, DM} when RA#'RequestedActions'.eventDM == asn1_NOVALUE -> + RA2 = RA#'RequestedActions'{eventDM = DM}, + do_merge_eventParameters(T, StreamId, EPL, RA2, yes); + {stream, NewStreamId} when StreamId == asn1_NOVALUE -> + do_merge_eventParameters(T, NewStreamId, EPL, RA, HasA); + {other, PP} when is_record(PP, 'PropertyParm') -> + EP = #'EventParameter'{eventParameterName = PP#'PropertyParm'.name, + value = PP#'PropertyParm'.value, + extraInfo = PP#'PropertyParm'.extraInfo}, + do_merge_eventParameters(T, StreamId, [EP | EPL], RA, HasA); + {other, EP} when is_record(EP, 'EventParameter') -> + do_merge_eventParameters(T, StreamId, [EP | EPL], RA, HasA); + _ -> + return_error(0, {bad_eventParameter, H}) + end; +do_merge_eventParameters([], StreamId, EPL, RA, yes) -> + #'RequestedEvent'{streamID = StreamId, + eventAction = RA, + evParList = lists:reverse(EPL)}; +do_merge_eventParameters([], StreamId, EPL, _RA, no) -> + #'RequestedEvent'{streamID = StreamId, + eventAction = asn1_NOVALUE, + evParList = lists:reverse(EPL)}. + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_secondEventParameters,1}]}). +-endif. +merge_secondEventParameters(Params) -> + StreamId = asn1_NOVALUE, + EPL = [], + SRA = #'SecondRequestedActions'{}, + HasA = no, + do_merge_secondEventParameters(Params, StreamId, EPL, SRA, HasA) . + +do_merge_secondEventParameters([H | T], StreamId, EPL, SRA, HasA) -> + case H of + keepActive when SRA#'SecondRequestedActions'.keepActive =:= asn1_NOVALUE -> + SRA2 = SRA#'SecondRequestedActions'{keepActive = true}, + do_merge_secondEventParameters(T, StreamId, EPL, SRA2, yes); + {second_embed, SD} when SRA#'SecondRequestedActions'.signalsDescriptor =:= asn1_NOVALUE -> + SRA2 = SRA#'SecondRequestedActions'{signalsDescriptor = SD}, + do_merge_secondEventParameters(T, StreamId, EPL, SRA2, yes); + {eventDM, DM} when SRA#'SecondRequestedActions'.eventDM =:= asn1_NOVALUE -> + SRA2 = SRA#'SecondRequestedActions'{eventDM = DM}, + do_merge_secondEventParameters(T, StreamId, EPL, SRA2, yes); + {stream, NewStreamId} when StreamId =:= asn1_NOVALUE -> + do_merge_secondEventParameters(T, NewStreamId, EPL, SRA, HasA); + {other, PP} when is_record(PP, 'PropertyParm') -> + EP = #'EventParameter'{eventParameterName = PP#'PropertyParm'.name, + value = PP#'PropertyParm'.value, + extraInfo = PP#'PropertyParm'.extraInfo}, + do_merge_secondEventParameters(T, StreamId, [EP | EPL], SRA, HasA); + {other, EP} when is_record(EP, 'EventParameter') -> + do_merge_secondEventParameters(T, StreamId, [EP | EPL], SRA, HasA); + _ -> + return_error(0, {bad_secondEventParameter, H}) + end; +do_merge_secondEventParameters([], StreamId, EPL, SRA, yes) -> + #'SecondRequestedEvent'{streamID = StreamId, + eventAction = SRA, + evParList = lists:reverse(EPL)}; +do_merge_secondEventParameters([], StreamId, EPL, _SRA, no) -> + #'SecondRequestedEvent'{streamID = StreamId, + eventAction = asn1_NOVALUE, + evParList = lists:reverse(EPL)}. + +%% terminationID = "ROOT" / pathName / "$" / "*" +%% Total length of pathName must not exceed 64 chars. +%% pathName = ["*"] NAME *("/" / "*"/ ALPHA / DIGIT /"_" / "$" ) +%% ["@" pathDomainName ] +%% ABNF allows two or more consecutive "." although it is meaningless +%% in a path domain name. +%% pathDomainName = (ALPHA / DIGIT / "*" ) +%% *63(ALPHA / DIGIT / "-" / "*" / ".") +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_terminationID,1}]}). +-endif. +ensure_terminationID(Token) -> + {safeToken, _Line, LowerText} = Token, + %% terminationID = "ROOT" / pathName / "$" / "*" + decode_term_id(LowerText, false, [], []). + +decode_term_id([H | T], Wild, Id, Component) -> + case H of + $/ -> decode_term_id(T, Wild, [lists:reverse(Component) | Id], []); + $* -> decode_term_id(T, true, Id, [?megaco_all | Component]); + $$ -> decode_term_id(T, true, Id, [?megaco_choose | Component]); + _ -> decode_term_id(T, Wild, Id, [H | Component]) + end; +decode_term_id([], Wild, Id, Component) -> + Id2 = [lists:reverse(Component) | Id], + #megaco_term_id{contains_wildcards = Wild, id = lists:reverse(Id2)}. + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_pathName,1}]}). +-endif. +ensure_pathName(Token) -> + {_TokenTag, _Line, Text} = Token, + Text. %% BUGBUG: ensure values + +%% TimeStamp = Date "T" Time ; per ISO 8601:1988 +%% Date = 8(DIGIT) ; Date = yyyymmdd +%% Time = 8(DIGIT) ; Time = hhmmssss +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_timeStamp,1}]}). +-endif. +ensure_timeStamp(Token) -> + {'TimeStampToken', Line, Text} = Token, + case string:tokens(Text, [$T, $t]) of + [Date, Time] -> + #'TimeNotation'{date = Date, time = Time}; + _ -> + return_error(Line, {bad_timeStamp, Text}) + end. + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_transactionID,1}]}). +-endif. +ensure_transactionID(TransId) -> + ensure_uint32(TransId). + +%% transactionAck = transactionID / (transactionID "-" transactionID) +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_transactionAck,1}]}). +-endif. +ensure_transactionAck(Tokens) -> + {safeToken, _Line, Text} = Tokens, + ensure_transactionAck2(Text, []). + +ensure_transactionAck2([], Acc) -> + Id = lists:reverse(Acc), + #'TransactionAck'{firstAck = ensure_transactionID(Id)}; +ensure_transactionAck2([$- | Id2], Acc) -> + Id1 = lists:reverse(Acc), + #'TransactionAck'{firstAck = ensure_transactionID(Id1), + lastAck = ensure_transactionID(Id2)}; +ensure_transactionAck2([H|T], Acc) -> + ensure_transactionAck2(T, [H|Acc]). + + +merge_context_request(CR, []) -> + CR; +merge_context_request(CR, [H|T]) -> + case H of + {priority, Int} when CR#'ContextRequest'.priority == asn1_NOVALUE -> + merge_context_request(CR#'ContextRequest'{priority = Int}, T); + + {emergency, Bool} when CR#'ContextRequest'.emergency == asn1_NOVALUE -> + merge_context_request(CR#'ContextRequest'{emergency = Bool}, T); + + {topology, Desc} when CR#'ContextRequest'.topologyReq == asn1_NOVALUE -> + merge_context_request(CR#'ContextRequest'{topologyReq = Desc}, T); + + {iepsCallind, Ind} when CR#'ContextRequest'.iepsCallind == asn1_NOVALUE -> + merge_context_request(CR#'ContextRequest'{iepsCallind = Ind}, T); + + {prop, Prop} when CR#'ContextRequest'.contextProp == asn1_NOVALUE -> + merge_context_request(CR#'ContextRequest'{contextProp = [Prop]}, T); + {Tag, Val} -> + Val2 = + case Tag of + priority -> CR#'ContextRequest'.priority; + emergency -> CR#'ContextRequest'.emergency; + topology -> CR#'ContextRequest'.topologyReq; + iepsCallind -> CR#'ContextRequest'.iepsCallind; + prop -> CR#'ContextRequest'.contextProp + end, + exit({at_most_once_contextProperty, {Tag, Val, Val2}}) + end. + + +merge_context_attr_audit_request(CAAR, []) -> + CAAR; +merge_context_attr_audit_request(CAAR, [H|T]) -> + case H of + priorityAudit when CAAR#'ContextAttrAuditRequest'.priority == asn1_NOVALUE -> + CAAR2 = CAAR#'ContextAttrAuditRequest'{priority = 'NULL'}, + merge_context_attr_audit_request(CAAR2, T); + + emergencyAudit when CAAR#'ContextAttrAuditRequest'.emergency == asn1_NOVALUE -> + CAAR2 = CAAR#'ContextAttrAuditRequest'{emergency = 'NULL'}, + merge_context_attr_audit_request(CAAR2, T); + + topologyAudit when CAAR#'ContextAttrAuditRequest'.topology == asn1_NOVALUE -> + CAAR2 = CAAR#'ContextAttrAuditRequest'{topology = 'NULL'}, + merge_context_attr_audit_request(CAAR2, T); + + iepsCallind when CAAR#'ContextAttrAuditRequest'.iepsCallind == asn1_NOVALUE -> + CAAR2 = CAAR#'ContextAttrAuditRequest'{iepsCallind = 'NULL'}, + merge_context_attr_audit_request(CAAR2, T); + + {prop, Name} when CAAR#'ContextAttrAuditRequest'.contextPropAud == asn1_NOVALUE -> + CPA = [#'IndAudPropertyParm'{name = Name}], + CAAR2 = CAAR#'ContextAttrAuditRequest'{contextPropAud = CPA}, + merge_context_attr_audit_request(CAAR2, T); + + {prop, Name} -> + CPA = CAAR#'ContextAttrAuditRequest'.contextPropAud, + CPA2 = [#'IndAudPropertyParm'{name = Name}|CPA], + CAAR2 = CAAR#'ContextAttrAuditRequest'{contextPropAud = CPA2}, + merge_context_attr_audit_request(CAAR2, T) + + end. + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_action_request,2}]}). +-endif. +merge_action_request(CtxId, Items) -> + do_merge_action_request(Items, [], asn1_NOVALUE, asn1_NOVALUE, CtxId). + +do_merge_action_request([H|T], CmdReqs, CtxReq, CtxAuditReq, CtxId) -> + case H of + {commandRequest, CmdReq} -> + do_merge_action_request(T, [CmdReq|CmdReqs], + CtxReq, CtxAuditReq, CtxId); + + {contextProps, ContextReq} when CtxReq == asn1_NOVALUE -> + do_merge_action_request(T, CmdReqs, + ContextReq, CtxAuditReq, CtxId); + + {contextAudit, ContextAuditReq} when CtxAuditReq == asn1_NOVALUE -> + do_merge_action_request(T, CmdReqs, + CtxReq, ContextAuditReq, CtxId) + end; +do_merge_action_request([], CmdReqs, CtxReq, CtxAuditReq, CtxId) -> + #'ActionRequest'{contextId = CtxId, + contextRequest = strip_ContextRequest(CtxReq), + contextAttrAuditReq = strip_ContextAttrAuditRequest(CtxAuditReq), + commandRequests = lists:reverse(CmdReqs)}. + + +%% OTP-5085: +%% In order to solve a problem in the parser, the error descriptor +%% has been put last in the non-empty commandReplyList, if it is not +%% asn1_NOVALUE +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_action_reply,1}]}). +-endif. +merge_action_reply(Items) -> + do_merge_action_reply(Items, asn1_NOVALUE, asn1_NOVALUE, []). + +do_merge_action_reply([], Err, Ctx, Cmds) -> + #'ActionReply'{errorDescriptor = Err, + contextReply = strip_ContextRequest(Ctx), + commandReply = lists:reverse(Cmds)}; +do_merge_action_reply([H|T], Err0, Ctx0, Cmds) -> + case H of + {error, Err1} when Err0 == asn1_NOVALUE -> + do_merge_action_reply(T, Err1, Ctx0, Cmds); + {command, Cmd} -> + do_merge_action_reply(T, Err0, Ctx0, [Cmd | Cmds]); + {context, Ctx1} when Ctx0 == asn1_NOVALUE -> + do_merge_action_reply(T, Err0, Ctx1, Cmds) + end. + +strip_ContextRequest(#'ContextRequest'{priority = asn1_NOVALUE, + emergency = asn1_NOVALUE, + topologyReq = asn1_NOVALUE, + iepsCallind = asn1_NOVALUE, + contextProp = asn1_NOVALUE}) -> + asn1_NOVALUE; +strip_ContextRequest(#'ContextRequest'{priority = asn1_NOVALUE, + emergency = asn1_NOVALUE, + topologyReq = asn1_NOVALUE, + iepsCallind = asn1_NOVALUE, + contextProp = []}) -> + asn1_NOVALUE; +strip_ContextRequest(asn1_NOVALUE) -> + asn1_NOVALUE; +strip_ContextRequest(R) -> + R. + +strip_ContextAttrAuditRequest(asn1_NOVALUE) -> + asn1_NOVALUE; +strip_ContextAttrAuditRequest( + #'ContextAttrAuditRequest'{priority = asn1_NOVALUE, + emergency = asn1_NOVALUE, + topology = asn1_NOVALUE, + iepsCallind = asn1_NOVALUE, + contextPropAud = asn1_NOVALUE}) -> + asn1_NOVALUE; +strip_ContextAttrAuditRequest( + #'ContextAttrAuditRequest'{priority = asn1_NOVALUE, + emergency = asn1_NOVALUE, + topology = asn1_NOVALUE, + iepsCallind = asn1_NOVALUE, + contextPropAud = []}) -> + asn1_NOVALUE; +strip_ContextAttrAuditRequest(R) -> + R. + +merge_AmmRequest_descriptors([], Acc) -> + lists:reverse(Acc); +merge_AmmRequest_descriptors([{_, deprecated}|Descs], Acc) -> + merge_AmmRequest_descriptors(Descs, Acc); +merge_AmmRequest_descriptors([Desc|Descs], Acc) -> + merge_AmmRequest_descriptors(Descs, [Desc|Acc]). + +make_commandRequest({CmdTag, {_TokenTag, _Line, Text}}, Cmd) -> + Req = #'CommandRequest'{command = {CmdTag, Cmd}}, + case Text of + [$w, $- | _] -> + Req#'CommandRequest'{wildcardReturn = 'NULL'}; + [$o, $-, $w, $- | _] -> + Req#'CommandRequest'{optional = 'NULL', wildcardReturn = 'NULL'}; + [$o, $- | _] -> + Req#'CommandRequest'{optional = 'NULL'}; + _ -> + Req + end. + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_terminationAudit,1}]}). +-endif. +merge_terminationAudit(AuditReturnParameters) -> + lists:reverse(do_merge_terminationAudit(AuditReturnParameters, [], [])). + +do_merge_terminationAudit([H| T], ARPs, AuditItems) -> + case H of + {auditReturnItem, AuditItem} -> + do_merge_terminationAudit(T, ARPs, [AuditItem | AuditItems]); + AuditReturnParameter -> + do_merge_terminationAudit(T, [AuditReturnParameter | ARPs], AuditItems) + end; +do_merge_terminationAudit([], AuditReturnParameters, []) -> + AuditReturnParameters; +do_merge_terminationAudit([], AuditReturnParameters, AuditItems) -> + AuditDescriptor = #'AuditDescriptor'{auditToken = AuditItems}, + AuditReturnParameter = {emptyDescriptors, AuditDescriptor}, + [AuditReturnParameter | AuditReturnParameters]. + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_mediaDescriptor,1}]}). +-endif. +merge_mediaDescriptor(MediaParms) -> + do_merge_mediaDescriptor(MediaParms, asn1_NOVALUE, [], []). + +do_merge_mediaDescriptor([H | T], TS, One, Multi) -> + case H of + {streamParm, Parm} when Multi =:= [] -> + do_merge_mediaDescriptor(T, TS, [Parm | One], Multi); + {streamDescriptor, Desc} when One =:= [] -> + do_merge_mediaDescriptor(T, TS, One, [Desc | Multi]); + {termState, TS2} when TS =:= asn1_NOVALUE -> + do_merge_mediaDescriptor(T, TS2, One, Multi); + _ -> + return_error(0, {bad_merge_mediaDescriptor, [H, TS, One, Multi]}) + end; +do_merge_mediaDescriptor([], TS, One, Multi) -> + if + (One =:= []) -> + if (Multi =:= []) -> + #'MediaDescriptor'{streams = asn1_NOVALUE, + termStateDescr = TS}; + true -> % (Multi =/= []) + Streams = {multiStream, lists:reverse(Multi)}, + #'MediaDescriptor'{streams = Streams, + termStateDescr = TS} + end; + true -> % (One =/= []) + if + (Multi =:= []) -> + Streams = {oneStream, merge_streamParms(One)}, + #'MediaDescriptor'{streams = Streams, + termStateDescr = TS}; + true -> % (Multi =/= []) + return_error(0, + {bad_merge_mediaDescriptor, [TS, One, Multi]}) + end + end. + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_streamParms,1}]}). +-endif. +merge_streamParms(TaggedStreamParms) -> + SP = #'StreamParms'{}, + do_merge_streamParms(TaggedStreamParms, SP). + +do_merge_streamParms([{Tag, D} | T] = All, SP) -> + case Tag of + local when SP#'StreamParms'.localDescriptor =:= asn1_NOVALUE -> + do_merge_streamParms(T, SP#'StreamParms'{localDescriptor = D}); + remote when SP#'StreamParms'.remoteDescriptor =:= asn1_NOVALUE -> + do_merge_streamParms(T, SP#'StreamParms'{remoteDescriptor = D}); + control -> + LCD = + case SP#'StreamParms'.localControlDescriptor of + asn1_NOVALUE -> + #'LocalControlDescriptor'{propertyParms = []}; + PrevLCD -> + PrevLCD + end, + LCD2 = do_merge_control_streamParms(D, LCD), + do_merge_streamParms(T, SP#'StreamParms'{localControlDescriptor = LCD2}); + statistics when SP#'StreamParms'.statisticsDescriptor =:= asn1_NOVALUE -> + do_merge_streamParms(T, SP#'StreamParms'{statisticsDescriptor = D}); + _ -> + return_error(0, {do_merge_streamParms, [All, SP]}) + end; +do_merge_streamParms([], SP) + when is_record(SP#'StreamParms'.localControlDescriptor, + 'LocalControlDescriptor') -> + LCD = SP#'StreamParms'.localControlDescriptor, + PP = LCD#'LocalControlDescriptor'.propertyParms, + LCD2 = LCD#'LocalControlDescriptor'{propertyParms = lists:reverse(PP)}, + SP#'StreamParms'{localControlDescriptor = LCD2}; +do_merge_streamParms([], SP) -> + SP. + + +do_merge_control_streamParms([{SubTag, SD} | T] = All, LCD) -> + case SubTag of + group when LCD#'LocalControlDescriptor'.reserveGroup =:= asn1_NOVALUE -> + LCD2 = LCD#'LocalControlDescriptor'{reserveGroup = SD}, + do_merge_control_streamParms(T, LCD2); + value when LCD#'LocalControlDescriptor'.reserveValue =:= asn1_NOVALUE -> + LCD2 = LCD#'LocalControlDescriptor'{reserveValue = SD}, + do_merge_control_streamParms(T, LCD2); + mode when LCD#'LocalControlDescriptor'.streamMode =:= asn1_NOVALUE -> + LCD2 = LCD#'LocalControlDescriptor'{streamMode = SD}, + do_merge_control_streamParms(T, LCD2); + prop -> + PP = LCD#'LocalControlDescriptor'.propertyParms, + LCD2 = LCD#'LocalControlDescriptor'{propertyParms = [SD | PP]}, + do_merge_control_streamParms(T, LCD2); + _ -> + return_error(0, {do_merge_control_streamParms, [All, LCD]}) + end; +do_merge_control_streamParms([], LCD) -> + LCD. + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_terminationStateDescriptor,1}]}). +-endif. +merge_terminationStateDescriptor(Parms) -> + TSD = #'TerminationStateDescriptor'{propertyParms = []}, + do_merge_terminationStateDescriptor(Parms, TSD). + +do_merge_terminationStateDescriptor([{Tag, Val} | T], TSD) -> + case Tag of + serviceState when TSD#'TerminationStateDescriptor'.serviceState =:= asn1_NOVALUE -> + TSD2 = TSD#'TerminationStateDescriptor'{serviceState = Val}, + do_merge_terminationStateDescriptor(T, TSD2); + eventBufferControl when TSD#'TerminationStateDescriptor'.eventBufferControl =:= asn1_NOVALUE-> + TSD2 = TSD#'TerminationStateDescriptor'{eventBufferControl = Val}, + do_merge_terminationStateDescriptor(T, TSD2); + propertyParm -> + PP = TSD#'TerminationStateDescriptor'.propertyParms, + TSD2 = TSD#'TerminationStateDescriptor'{propertyParms = [Val | PP]}, + do_merge_terminationStateDescriptor(T, TSD2) + end; +do_merge_terminationStateDescriptor([], TSD) -> + PP = TSD#'TerminationStateDescriptor'.propertyParms, + TSD#'TerminationStateDescriptor'{propertyParms = lists:reverse(PP)}. + +-ifdef(megaco_nscanner_props). + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_prop_groups,1}]}). +-endif. +ensure_prop_groups(Token) -> + {_TokenTag, _Line, Text} = Token, + Group = [], + parse_prop_name(Text, Group). + +parse_prop_name([Char | Rest] = All, Group) -> + if + ?white_space(Char) -> + parse_prop_name(Rest, Group); + ?end_of_line(Char) -> + parse_prop_name(Rest, Group); + true -> + Name = [], + do_parse_prop_name(All, Name, Group) + end; +parse_prop_name([] = All, Group) -> + Name = [], + do_parse_prop_name(All, Name, Group). + +do_parse_prop_name([Char | Rest], Name, Group) + when (Char =:= $=) andalso (Name =/= []) -> + %% Now we have a complete name + if + (Name =:= "v") andalso (Group =/= []) -> + %% v= is a property group delimiter, + %% lets create yet another property group. + NewGroup = [], + [lists:reverse(Group) | parse_prop_value(Rest, Name, NewGroup)]; + true -> + %% Use current property group + parse_prop_value(Rest, Name, Group) + end; +do_parse_prop_name([Char | Rest], Name, Group) -> + case ?classify_char4(Char) of + safe_char_upper -> + do_parse_prop_name(Rest, [Char | Name], Group); + safe_char -> + do_parse_prop_name(Rest, [Char | Name], Group); + _ -> + return_error(0, {bad_prop_name, lists:reverse(Name), Char}) + end; +do_parse_prop_name([], [], []) -> + []; +do_parse_prop_name([], [], Group) -> + [lists:reverse(Group)]; +do_parse_prop_name([], Name, Group) when Name =/= [] -> + %% Assume end of line + Value = [], + PP = make_prop_parm(Name, Value), + Group2 = lists:reverse([PP | Group]), + [Group2]. + +-ifdef(megaco_parser_inline). +-compile({inline,[{parse_prop_value,3}]}). +-endif. +parse_prop_value(Chars, Name, Group) -> + Value = [], + do_parse_prop_value(Chars, Name, Value, Group). + +do_parse_prop_value([Char | Rest], Name, Value, Group) -> + if + ?end_of_line(Char) -> + %% Now we have a complete "name=value" pair + PP = make_prop_parm(Name, Value), + parse_prop_name(Rest, [PP | Group]); + true -> + do_parse_prop_value(Rest, Name, [Char | Value], Group) + end; +do_parse_prop_value([], Name, Value, Group) -> + %% Assume end of line + PP = make_prop_parm(Name, Value), + Group2 = lists:reverse([PP | Group]), + [Group2]. + +-ifdef(megaco_parser_inline). +-compile({inline,[{make_prop_parm,2}]}). +-endif. +make_prop_parm(Name, Value) -> + #'PropertyParm'{name = lists:reverse(Name), + value = [lists:reverse(Value)]}. + +-else. % -ifdef(megaco_nscanner_props). + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_prop_groups,1}]}). +-endif. +ensure_prop_groups(Token) -> + {_TokenTag, _Line, Groups} = Token, + Groups. + +%% do_ensure_prop_groups(Groups) when is_list(Groups) -> +%% [ensure_prop_group(Group) || Group <- Groups]; +%% do_ensure_prop_groups(BadGroups) -> +%% throw({error, {?MODULE, {bad_property_groups, BadGroups}}}). + +%% -ifdef(megaco_parser_inline). +%% -compile({inline,[{ensure_prop_group,1}]}). +%% -endif. +%% ensure_prop_group(Group) when is_list(Group) -> +%% [ensure_prop_parm(PropParm) || PropParm <- Group]; +%% ensure_prop_group(BadGroup) -> +%% throw({error, {?MODULE, {bad_property_group, BadGroup}}}). + +%% -ifdef(megaco_parser_inline). +%% -compile({inline,[{ensure_prop_parm,1}]}). +%% -endif. +%% ensure_prop_parm(#property_parm{name = Name, +%% value = Value}) -> +%% #'PropertyParm'{name = Name, +%% value = Value}; +%% ensure_prop_parm(PP) when is_record(PP, 'PropertyParm') -> +%% PP; +%% ensure_prop_parm(BadPropParm) -> +%% throw({error, {?MODULE, {bad_property_parm, BadPropParm}}}). + +-endif. % -ifdef(megaco_nscanner_props). + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_uint,3}]}). +-endif. +ensure_uint(Token, Min, Max) -> + case Token of + {_TokenTag, Line, Val} when is_integer(Val) -> + ensure_uint(Val, Min, Max, Line); + {_TokenTag, Line, Text} -> + case (catch list_to_integer(Text)) of + {'EXIT', _} -> + return_error(Line, {not_an_integer, Text}); + Val when is_integer(Val) -> + ensure_uint(Val, Min, Max, Line) + end; + Val when is_integer(Val) -> + ensure_uint(Val, Min, Max, 0); + Text -> + case (catch list_to_integer(Text)) of + {'EXIT', _} -> + return_error(0, {not_an_integer, Text}); + Val when is_integer(Val) -> + ensure_uint(Val, Min, Max, 0) + end + end. + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_uint,4}]}). +-endif. +ensure_uint(Val, Min, Max, Line) -> + if + is_integer(Min) andalso (Val >= Min) -> + if + is_integer(Max) andalso (Val =< Max) -> + Val; + Max =:= infinity -> + Val; + true -> + return_error(Line, {too_large_integer, Val, Max}) + end; + true -> + return_error(Line, {too_small_integer, Val, Min}) + end. + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_uint16,1}]}). +-endif. +ensure_uint16(Int) -> + ensure_uint(Int, 0, 65535). + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_uint32,1}]}). +-endif. +ensure_uint32(Int) -> + ensure_uint(Int, 0, 4294967295) . + +%% OTP-4710 +ensure_hex({_TokenTag, _Line, [$0, $x |Chars]}, Min, Max) -> + ensure_uint(length(Chars), Min, Max), + hex_to_int(Chars, []); +ensure_hex({_TokenTag, _Line, [$0, $X |Chars]}, Min, Max) -> + ensure_uint(length(Chars), Min, Max), + hex_to_int(Chars, []); +ensure_hex([$0, $x |Chars], Min, Max) -> + ensure_uint(length(Chars), Min, Max), + hex_to_int(Chars, []); +ensure_hex([$0, $X |Chars], Min, Max) -> + ensure_uint(length(Chars), Min, Max), + hex_to_int(Chars, []). + +%% OTP-4710 +hex_to_int([], Acc) -> + lists:reverse(Acc); +hex_to_int([Char1,Char2|Tail], Acc) -> + Int1 = hchar_to_int(Char1), + Int2 = hchar_to_int(Char2), + Val = Int2 bor (Int1 bsl 4), + hex_to_int(Tail, [Val| Acc]); +hex_to_int([Char], Acc) -> + Int = hchar_to_int(Char), + lists:reverse([Int|Acc]). + +hchar_to_int(Char) when ($0 =< Char) andalso (Char =< $9) -> + Char - $0; +hchar_to_int(Char) when ($A =< Char) andalso (Char =< $F) -> + Char - $A + 10; % OTP-4710 +hchar_to_int(Char) when ($a =< Char) andalso (Char =< $f) -> + Char - $a + 10. % OTP-4710 + +-ifdef(megaco_parser_inline). +-compile({inline,[{value_of,1}]}). +-endif. +value_of(Token) -> + {_TokenTag, _Line, Text} = Token, + Text. + + +%% ------------------------------------------------------------------- + +% d(F) -> +% d(F,[]). +% d(F, A) -> +% d(get(dbg), F, A). + +% d(true, F, A) -> +% io:format("DBG:~w:" ++ F ++ "~n", [?MODULE | A]); +% d(_, _, _) -> +% ok. + diff --git a/lib/megaco/src/text/megaco_text_parser_prev3a.yrl b/lib/megaco/src/text/megaco_text_parser_prev3a.yrl new file mode 100644 index 0000000000..b8c39a5f33 --- /dev/null +++ b/lib/megaco/src/text/megaco_text_parser_prev3a.yrl @@ -0,0 +1,1591 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2004-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: YECC grammar for text encoding of Megaco/H.248 +%%---------------------------------------------------------------------- + +%%---------------------------------------------------------------------- +%% Annex B TEXT ENCODING OF THE PROTOCOL (NORMATIVE) +%% +%% B.1 Coding of wildcards +%% +%% In a text encoding of the protocol, while TerminationIDs are +%% arbitrary, by judicious choice of names, the wildcard character, "*" +%% may be made more useful. When the wildcard character is encountered, +%% it will "match" all TerminationIDs having the same previous and +%% following characters (if appropriate). For example, if there were +%% TerminationIDs of R13/3/1, R13/3/2 and R13/3/3, the TerminationID +%% R13/3/* would match all of them. There are some circumstances where +%% ALL Terminations must be referred to. The TerminationID "*" suffices, +%% and is referred to as ALL. The CHOOSE TerminationID "$" may be used to +%% signal to the MG that it has to create an ephemeral Termination or +%% select an idle physical Termination. +%% +%% B.2 ABNF specification +%% +%% The protocol syntax is presented in ABNF according to RFC2234. The +%% protocol is not case sensitive. Identifiers are not case sensitive. +%% +%% NOTE 1 - This syntax specification does not enforce all restrictions +%% on element inclusions and values. Some additional +%% restrictions are stated in comments and other restrictions +%% appear in the text of this Recommendation. These additional +%% restrictions are part of the protocol even though not +%% enforced by this Recommendation. +%% NOTE 2 - The syntax is context-dependent. For example, "Add" can be +%% the AddToken or a NAME depending on the context in which it +%% occurs. +%% +%% Everything in the ABNF and text encoding is case insensitive. This +%% includes TerminationIDs, digitmap Ids etc. SDP is case sensitive as +%% per RFC 2327. +%% +%%---------------------------------------------------------------------- + +%%---------------------------------------------------------------------- +%% Number of expected shift/reduce warnings +%% This is ugly but... +%%---------------------------------------------------------------------- + +Expect 118. + + +%%---------------------------------------------------------------------- +%% Non-terminals +%%---------------------------------------------------------------------- + +Nonterminals + + actionReply + actionReplyBody + actionReplyList + actionRequest + actionRequestBody + actionRequestItem + actionRequestItems + actionRequestList + alternativeValue + ammParameter + ammParameters + ammRequest + ammRequestBody + ammToken + ammsReply + ammsReplyBody + ammsToken + auditDescriptor + auditDescriptorBody + auditItem + auditItemList + auditOther + auditReply + auditRequest + auditReturnItem + auditReturnParameter + auditReturnParameterList + authenticationHeader + commandReplyList + commandReplys %% v3 + commandRequest + contextAttrDescriptor %% v3 + contextAttrDescProp %% v3 + contextAttrDescProps %% v3 + contextAudit + contextAuditProperties + contextAuditProperty + contextID + contextProperties %% v3 + contextProperty + contextTerminationAudit + daddr + deviceName + digitMapDescriptor + direction %% v3 + domainAddress + domainName + embedFirst + embedNoSig + embedSig + embedWithSig + errorCode + errorDescriptor + errorText + eventBufferControl + eventBufferControlState + eventBufferDescriptor + eventDM + eventParameter + eventParameterName + eventParameters + eventSpec + eventSpecList + eventStream + eventStreamOrOther + eventsDescriptor + extension + extensionParameter + + %% v2 - start + indAudauditReturnParameter + indAuddigitMapDescriptor + indAudeventBufferDescriptor + indAudeventSpec + indAudeventSpecParameter + %% indAudeventSpecParameterList + indAudeventsDescriptor + indAudlocalControlDescriptor + indAudlocalParm + indAudlocalParmList + indAudmediaDescriptor + indAudmediaParm + %% indAudmediaParmList + indAudpackagesDescriptor + indAudrequestedEvent + indAudsignalsDescriptor + indAudsignalList + %% indAudsignalListParm + indAudsignalParm + %% indAudsignalRequest + indAudstreamDescriptor + indAudstreamParm + indAudstatisticsDescriptor + indAudterminationAudit + indAudterminationAuditList + indAudterminationStateDescriptor + indAudterminationStateParm + %% indAudterminationStateParmList + optIndAudeventSpecParameter + optIndAudsignalParm + %% v2 - end + + indAudcontextAttrDescriptor %% v3 + + localControlDescriptor + localParm + localParmList + mId + mediaDescriptor + mediaParm + mediaParmList + megacoMessage + message + messageBody + modemDescriptor % Deprecated as of Corr 1 + modemType % Deprecated as of Corr 1 + modemTypeList % Deprecated as of Corr 1 + mtpAddress + muxDescriptor + muxType + notificationReason + notificationReasons + notifyReply + notifyReplyBody + notifyRequest + notifyRequestBody + observedEvent + observedEventBody + observedEventParameter + observedEventParameters + % observedEventTimeStamp + observedEvents + observedEventsDescriptor + onOrOff + optAuditDescriptor + optImmAckRequired + optPropertyParms + optSep + packagesDescriptor + packagesItem + packagesItems + %% parmName + parmValue + pathName + pkgdName + portNumber + priority + propertyParm + propertyParms + requestID + requestedEvent + requestedEventBody + requestedEvents + safeToken + safeToken2 + secondEventParameter + secondEventParameters + secondRequestedEvent + secondRequestedEventBody + secondRequestedEvents + servChgReplyParm + servChgReplyParms + serviceChangeAddress + serviceChangeDelay + serviceChangeDescriptor + serviceChangeMethod + serviceChangeMgcId + serviceChangeParm + serviceChangeParms + serviceChangeProfile + serviceChangeReason + serviceChangeReply + serviceChangeReplyBody + serviceChangeReplyDescriptor + serviceChangeRequest + serviceChangeVersion + serviceState + serviceStates + sigParameter + sigParameters + signalList + signalListId + signalListParm + signalListParms + signalName + signalParm + signalParms + signalRequest + signalsDescriptor + signalType + statisticsDescriptor + statisticsParameter + statisticsParameters + streamDescriptor + streamID + streamModes + streamParm + streamParmList + subtractRequest + terminationA + terminationAudit + terminationB + terminationID + terminationIDList + terminationIDListRepeat + terminationStateDescriptor + terminationStateParm + terminationStateParms + timeStamp + topologyDescriptor + topologyDirection + topologyTriple + topologyTripleList + transactionAck + transactionAckList + transactionID + transactionItem + transactionList + transactionPending + transactionReply + transactionReplyBody + transactionRequest + transactionResponseAck + value + valueList + +. + +%%---------------------------------------------------------------------- +%% Terminals +%%---------------------------------------------------------------------- + +Terminals + + 'AddToken' + 'AuditCapToken' + 'AuditToken' + 'AuditValueToken' + 'AuthToken' + 'BothToken' %% v3 + 'BothwayToken' + 'BriefToken' + 'BufferToken' + 'COLON' + 'COMMA' + 'ContextAttrToken' %% v3 + 'ContextAuditToken' + 'CtxToken' + 'DelayToken' + 'DigitMapToken' + 'DigitMapDescriptorToken' + 'DirectionToken' %% v3 + 'DiscardToken' + 'DisconnectedToken' + 'DurationToken' + 'EQUAL' + 'EmbedToken' + 'EmergencyToken' + 'EmergencyOffToken' + 'ErrorToken' + 'EventBufferToken' + 'EventsToken' + 'ExternalToken' %% v3 + 'FailoverToken' + 'ForcedToken' + 'GREATER' + 'GracefulToken' + 'H221Token' + 'H223Token' + 'H226Token' + 'HandOffToken' + 'IEPSToken' %% v3 + 'ImmAckRequiredToken' + 'InSvcToken' + 'InactiveToken' + 'InternalToken' %% v3 + 'InterruptByEventToken' + 'InterruptByNewSignalsDescrToken' + 'IsolateToken' + 'KeepActiveToken' + 'LBRKT' + 'LESSER' + 'LSBRKT' + 'LocalControlToken' + 'LocalDescriptorToken' + 'LockStepToken' + 'LoopbackToken' + 'MediaToken' + %% 'MegacopToken' + 'MethodToken' + 'MgcIdToken' + 'ModeToken' + 'ModemToken' + 'ModifyToken' + 'MoveToken' + 'MtpAddressToken' + 'MuxToken' + 'NEQUAL' + 'NotifyCompletionToken' + 'NotifyToken' + 'Nx64kToken' %% v2 + 'ObservedEventsToken' + 'OffToken' + 'OnToken' + 'OnOffToken' + 'OnewayToken' + 'OtherReasonToken' + 'OutOfSvcToken' + 'PackagesToken' + 'PendingToken' + 'PriorityToken' + 'ProfileToken' + 'QuotedChars' + 'RBRKT' + 'RSBRKT' + 'ReasonToken' + 'RecvonlyToken' + 'RemoteDescriptorToken' + 'ReplyToken' + 'RequestIDToken' %% v3 + 'ReservedGroupToken' + 'ReservedValueToken' + 'ResponseAckToken' + 'RestartToken' + 'SEP' + 'SafeChars' + 'SendonlyToken' + 'SendrecvToken' + 'ServiceChangeAddressToken' + 'ServiceChangeToken' + 'ServiceChangeIncompleteToken' + 'ServiceStatesToken' + 'ServicesToken' + 'SignalListToken' + 'SignalTypeToken' + 'SignalsToken' + 'StatsToken' + 'StreamToken' + 'SubtractToken' + 'SynchISDNToken' + 'TerminationStateToken' + 'TestToken' + 'TimeOutToken' + 'TimeStampToken' + 'TopologyToken' + 'TransToken' + 'V18Token' + 'V22Token' + 'V22bisToken' + 'V32Token' + 'V32bisToken' + 'V34Token' + 'V76Token' + 'V90Token' + 'V91Token' + 'VersionToken' + 'AndAUDITSelectToken' %% OTP-7534: v3-fix + 'ContextListToken' %% OTP-7534: v3-fix + 'EmergencyValueToken' %% OTP-7534: v3-fix + 'IntsigDelayToken' %% OTP-7534: v3-fix + 'IterationToken' %% OTP-7534: v3-fix + 'MessageSegmentToken' %% OTP-7534: v3-fix + 'NeverNotifyToken' %% OTP-7534: v3-fix + 'NotifyImmediateToken' %% OTP-7534: v3-fix + 'NotifyRegulatedToken' %% OTP-7534: v3-fix + 'OnewayBothToken' %% OTP-7534: v3-fix + 'OnewayExternalToken' %% OTP-7534: v3-fix + 'OrAUDITselectToken' %% OTP-7534: v3-fix + 'ResetEventsDescriptorToken' %% OTP-7534: v3-fix + 'SegmentationCompleteToken' %% OTP-7534: v3-fix + endOfMessage + +. + +%%---------------------------------------------------------------------- +%% Root symbol +%%---------------------------------------------------------------------- + +Rootsymbol megacoMessage. + +%%---------------------------------------------------------------------- +%% The grammar +%%---------------------------------------------------------------------- + +%% megacoMessage = LWSP [authenticationHeader SEP ] message +%% authenticationHeader = AuthToken EQUAL SecurityParmIndex COLON +%% SequenceNum COLON AuthData +%% +%% SecurityParmIndex = "0x" 8(HEXDIG) +%% SequenceNum = "0x" 8(HEXDIG) +%% AuthData = "0x" 24*64(HEXDIG) +%% message = MegacopToken SLASH version SEP mId SEP messageBody +%% version = 1*2(DIGIT) . + +megacoMessage -> optSep authenticationHeader message endOfMessage + : #'MegacoMessage'{authHeader = '$2', mess = '$3'} . + +optSep -> 'SEP' : sep . +optSep -> '$empty' : no_sep . + +authenticationHeader -> 'AuthToken' 'EQUAL' safeToken 'COLON' + safeToken 'COLON' safeToken optSep + : ensure_auth_header('$3', '$5', '$7') . +authenticationHeader -> '$empty' : asn1_NOVALUE . + +message -> safeToken mId messageBody : ensure_message('$1', '$2', '$3') . + +messageBody -> errorDescriptor : {messageError, '$1'} . +messageBody -> transactionList : {transactions, '$1'} . + +transactionList -> transactionItem : ['$1'] . +transactionList -> transactionItem transactionList : ['$1' | '$2'] . + +transactionItem -> transactionRequest : {transactionRequest, '$1'} . +transactionItem -> transactionReply : {transactionReply, '$1'}. +transactionItem -> transactionPending : {transactionPending, '$1'} . +transactionItem -> transactionResponseAck : {transactionResponseAck, '$1'} . + +transactionResponseAck -> 'ResponseAckToken' + 'LBRKT' transactionAck transactionAckList 'RBRKT' : ['$3' | '$4'] . + +transactionAckList -> 'COMMA' transactionAck transactionAckList : ['$2' | '$3'] . +transactionAckList -> '$empty' : [] . + +transactionAck -> safeToken : ensure_transactionAck('$1') . + +transactionPending -> 'PendingToken' 'EQUAL' transactionID 'LBRKT' 'RBRKT' + : #'TransactionPending'{transactionId = ensure_transactionID('$3') } . + +transactionRequest -> 'TransToken' + 'LBRKT' actionRequest actionRequestList 'RBRKT' + : #'TransactionRequest'{transactionId = asn1_NOVALUE, + actions = ['$3' | '$4']} . +transactionRequest -> 'TransToken' 'EQUAL' + 'LBRKT' actionRequest actionRequestList 'RBRKT' + : #'TransactionRequest'{transactionId = asn1_NOVALUE, + actions = ['$4' | '$5']} . +transactionRequest -> 'TransToken' 'EQUAL' transactionID + 'LBRKT' actionRequest actionRequestList 'RBRKT' + : #'TransactionRequest'{transactionId = ensure_transactionID('$3'), + actions = ['$5' | '$6']} . + +actionRequestList -> 'COMMA' actionRequest actionRequestList : ['$2' | '$3'] . +actionRequestList -> '$empty' : [] . + +actionRequest -> 'CtxToken' 'EQUAL' contextID + 'LBRKT' actionRequestBody 'RBRKT' + : merge_action_request('$3', '$5') . + +actionRequestBody -> actionRequestItem actionRequestItems : ['$1' | '$2'] . + +actionRequestItems -> 'COMMA' actionRequestItem actionRequestItems + : ['$2' | '$3'] . +actionRequestItems -> '$empty' : [] . + +actionRequestItem -> contextProperties : {contextProps, '$1'} . +actionRequestItem -> contextAudit : {contextAudit, '$1'} . +actionRequestItem -> commandRequest : {commandRequest, '$1'} . + +contextProperties -> contextAttrDescriptor : + merge_context_request(#'ContextRequest'{}, '$1') . + +contextAttrDescriptor -> 'ContextAttrToken' + 'LBRKT' contextAttrDescProp + contextAttrDescProps 'RBRKT' + : ['$3' | '$4'] . + +contextAttrDescProp -> contextProperty : '$1' . + +contextAttrDescProps -> 'COMMA' contextAttrDescProp contextAttrDescProps + : ['$2' | '$3'] . +contextAttrDescProps -> '$empty' : [] . + +%% at-most-once +contextProperty -> topologyDescriptor : {topology, '$1'}. +contextProperty -> priority : {priority, '$1'}. +contextProperty -> 'EmergencyToken' : {emergency, true}. +contextProperty -> 'EmergencyOffToken' : {emergency, false}. +contextProperty -> 'IEPSToken' : {iepsCallind, true} . % BMK BMK +contextProperty -> propertyParm : {prop, '$1'} . + +contextAudit -> 'ContextAuditToken' 'LBRKT' indAudcontextAttrDescriptor 'RBRKT' + : merge_context_attr_audit_request( + #'ContextAttrAuditRequest'{}, '$3') . + +indAudcontextAttrDescriptor -> 'ContextAttrToken' + 'LBRKT' contextAuditProperty + contextAuditProperties 'RBRKT' + : ['$3' | '$4'] . + +contextAuditProperties -> 'COMMA' contextAuditProperty contextAuditProperties + : ['$2' | '$3'] . +contextAuditProperties -> '$empty' : [] . + +%% at-most-once . +contextAuditProperty -> 'TopologyToken' : topologyAudit . +contextAuditProperty -> 'EmergencyToken' : emergencyAudit . +contextAuditProperty -> 'PriorityToken' : priorityAudit . +contextAuditProperty -> 'IEPSToken' : iepsCallind . +contextAuditProperty -> pkgdName : {prop, '$1'} . + +commandRequest -> ammRequest : '$1'. +commandRequest -> subtractRequest : '$1'. +commandRequest -> auditRequest : '$1'. +commandRequest -> notifyRequest : '$1'. +commandRequest -> serviceChangeRequest : '$1'. + +transactionReply -> 'ReplyToken' 'EQUAL' transactionID + 'LBRKT' + optImmAckRequired transactionReplyBody + 'RBRKT' + : #'TransactionReply'{transactionId = '$3', + immAckRequired = '$5', + transactionResult = '$6'} . + +optImmAckRequired -> 'ImmAckRequiredToken' 'COMMA' : 'NULL' . +optImmAckRequired -> '$empty' : asn1_NOVALUE . + +transactionReplyBody -> errorDescriptor : {transactionError, '$1'} . +transactionReplyBody -> actionReply actionReplyList : {actionReplies, ['$1' | '$2']} . + +actionReplyList -> 'COMMA' actionReply actionReplyList : ['$2' | '$3'] . +actionReplyList -> '$empty' : [] . + +actionReply -> 'CtxToken' 'EQUAL' contextID + 'LBRKT' actionReplyBody 'RBRKT' : + setelement(#'ActionReply'.contextId, '$5', '$3') . + +actionReplyBody -> errorDescriptor : + #'ActionReply'{errorDescriptor = '$1'} . +actionReplyBody -> commandReplys commandReplyList : + merge_action_reply(['$1' | '$2']) . + +%% OTP-5085 +%% This ugly thing is to fool the parser. The errorDescriptor does not +%% realy belong here. The merge_action_reply will remove it and put it +%% in it's right place later. +commandReplyList -> 'COMMA' errorDescriptor : + [{error, '$2'}] . +commandReplyList -> 'COMMA' commandReplys commandReplyList : + ['$2' | '$3'] . +commandReplyList -> '$empty' : [] . + +commandReplys -> serviceChangeReply : {command, '$1'} . +commandReplys -> auditReply : {command, '$1'} . +commandReplys -> ammsReply : {command, '$1'} . +commandReplys -> notifyReply : {command, '$1'} . +commandReplys -> contextProperties : {context, '$1'} . + +%Add Move and Modify have the same request parameter +ammRequest -> ammToken 'EQUAL' terminationID ammRequestBody : + Descs = merge_AmmRequest_descriptors('$4', []), + make_commandRequest('$1', + #'AmmRequest'{terminationID = ['$3'], + descriptors = Descs}) . + +ammToken -> 'AddToken' : {addReq, '$1'} . +ammToken -> 'MoveToken' : {moveReq, '$1'} . +ammToken -> 'ModifyToken' : {modReq, '$1'} . + +ammRequestBody -> 'LBRKT' ammParameter ammParameters 'RBRKT' : ['$2' | '$3'] . +ammRequestBody -> '$empty' : [] . + +ammParameters -> 'COMMA' ammParameter ammParameters : ['$2' | '$3'] . +ammParameters -> '$empty' : [] . + +%at-most-once +ammParameter -> mediaDescriptor : {mediaDescriptor, '$1'}. +ammParameter -> modemDescriptor : {modemDescriptor, deprecated}. +ammParameter -> muxDescriptor : {muxDescriptor, '$1'}. +ammParameter -> eventsDescriptor : {eventsDescriptor, '$1'}. +ammParameter -> eventBufferDescriptor : {eventBufferDescriptor, '$1'}. +ammParameter -> signalsDescriptor : {signalsDescriptor, '$1'}. +ammParameter -> digitMapDescriptor : {digitMapDescriptor, '$1'}. +ammParameter -> auditDescriptor : {auditDescriptor, '$1'}. +ammParameter -> statisticsDescriptor : {statisticsDescriptor, '$1'}. + +ammsReply -> ammsToken 'EQUAL' terminationID ammsReplyBody + : {'$1', #'AmmsReply'{terminationID = ['$3'], + terminationAudit = '$4'}} . + +ammsToken -> 'AddToken' : addReply . +ammsToken -> 'MoveToken' : moveReply . +ammsToken -> 'ModifyToken' : modReply . +ammsToken -> 'SubtractToken' : subtractReply . + +ammsReplyBody -> 'LBRKT' terminationAudit 'RBRKT' : '$2' . +ammsReplyBody -> '$empty' : asn1_NOVALUE . + +subtractRequest -> 'SubtractToken' 'EQUAL' terminationID + optAuditDescriptor + : make_commandRequest({subtractReq, '$1'}, + #'SubtractRequest'{terminationID = ['$3'], + auditDescriptor = '$4'}) . + + +optAuditDescriptor -> 'LBRKT' auditDescriptor 'RBRKT' : '$2'. +optAuditDescriptor -> '$empty' : asn1_NOVALUE . + +auditRequest -> 'AuditValueToken' 'EQUAL' + terminationID optAuditDescriptor : + make_commandRequest({auditValueRequest, '$1'}, + #'AuditRequest'{terminationID = '$3', + auditDescriptor = '$4'}) . +auditRequest -> 'AuditCapToken' 'EQUAL' + terminationID optAuditDescriptor : + make_commandRequest({auditCapRequest, '$1'}, + #'AuditRequest'{terminationID = '$3', + auditDescriptor = '$4'}) . + +auditReply -> 'AuditValueToken' 'EQUAL' 'CtxToken' contextTerminationAudit + : {auditValueReply, '$4'} . +auditReply -> 'AuditCapToken' 'EQUAL' 'CtxToken' contextTerminationAudit + : {auditCapReply, '$4'} . +auditReply -> 'AuditValueToken' 'EQUAL' auditOther + : {auditValueReply, '$3'} . +auditReply -> 'AuditCapToken' 'EQUAL' auditOther + : {auditCapReply, '$3'} . + +contextTerminationAudit -> terminationIDList : {contextAuditResult, '$1'} . +contextTerminationAudit -> 'LBRKT' errorDescriptor 'RBRKT' : {contextAuditResult, '$2'} . + +auditOther -> terminationID : + {auditResult, + #'AuditResult'{terminationID = '$1', + terminationAuditResult = []}} . +auditOther -> terminationID 'LBRKT' terminationAudit 'RBRKT' : + {auditResult, + #'AuditResult'{terminationID = '$1', + terminationAuditResult = '$3'}} . + + +terminationAudit -> auditReturnParameter auditReturnParameterList : + merge_terminationAudit(['$1' |'$2' ]) . + +auditReturnParameterList -> 'COMMA' auditReturnParameter auditReturnParameterList : ['$2' | '$3'] . +auditReturnParameterList -> '$empty' : [] . + +auditReturnParameter -> mediaDescriptor : {mediaDescriptor, '$1'} . +auditReturnParameter -> modemDescriptor. +auditReturnParameter -> muxDescriptor : {muxDescriptor, '$1'} . +auditReturnParameter -> eventsDescriptor : {eventsDescriptor, '$1'} . +auditReturnParameter -> signalsDescriptor : {signalsDescriptor, '$1'} . +auditReturnParameter -> digitMapDescriptor : {digitMapDescriptor, '$1'} . +auditReturnParameter -> observedEventsDescriptor : {observedEventsDescriptor, '$1'} . +auditReturnParameter -> eventBufferDescriptor : {eventBufferDescriptor, '$1'} . +auditReturnParameter -> statisticsDescriptor : {statisticsDescriptor, '$1'} . +auditReturnParameter -> packagesDescriptor : {packagesDescriptor, '$1'} . +auditReturnParameter -> errorDescriptor : {errorDescriptor, '$1'} . +auditReturnParameter -> auditReturnItem : {auditReturnItem, '$1'} . + +auditDescriptor -> 'AuditToken' 'LBRKT' auditDescriptorBody 'RBRKT' : + merge_auditDescriptor('$3') . + +auditDescriptorBody -> auditItem auditItemList : ['$1' | '$2']. +auditDescriptorBody -> '$empty' : asn1_NOVALUE . + +auditItemList -> 'COMMA' auditItem auditItemList : ['$2' | '$3'] . +auditItemList -> '$empty' : [] . + +%% IGv11 - begin +%% +auditReturnItem -> 'MuxToken' : muxToken . +auditReturnItem -> 'ModemToken' : modemToken . +auditReturnItem -> 'MediaToken' : mediaToken . +auditReturnItem -> 'DigitMapToken' : digitMapToken . +auditReturnItem -> 'StatsToken' : statsToken . +auditReturnItem -> 'ObservedEventsToken' : observedEventsToken . +auditReturnItem -> 'PackagesToken' : packagesToken . + +%% at-most-once, and DigitMapToken and PackagesToken are not allowed +%% in AuditCapabilities command +auditItem -> auditReturnItem : '$1' . +auditItem -> 'SignalsToken' : signalsToken. +auditItem -> 'EventBufferToken' : eventBufferToken. +auditItem -> 'EventsToken' : eventsToken . +auditItem -> indAudterminationAudit : {terminationAudit, '$1'} . % v2 +%% +%% IGv11 - end + + +%% v2 - start +%% +indAudterminationAudit -> indAudauditReturnParameter + indAudterminationAuditList + : ['$1' | '$2'] . + +indAudterminationAuditList -> 'COMMA' indAudauditReturnParameter + indAudterminationAuditList + : ['$2' | '$3'] . +indAudterminationAuditList -> '$empty' : [] . + +indAudauditReturnParameter -> indAudmediaDescriptor + : {indAudMediaDescriptor, '$1'} . +indAudauditReturnParameter -> indAudeventsDescriptor + : {indAudEventsDescriptor, '$1'} . +indAudauditReturnParameter -> indAudsignalsDescriptor + : {indAudSignalsDescriptor, '$1'} . +indAudauditReturnParameter -> indAuddigitMapDescriptor + : {indAudDigitMapDescriptor, '$1'} . +indAudauditReturnParameter -> indAudeventBufferDescriptor + : {indAudEventBufferDescriptor, '$1'} . +indAudauditReturnParameter -> indAudstatisticsDescriptor + : {indAudStatisticsDescriptor, '$1'} . +indAudauditReturnParameter -> indAudpackagesDescriptor + : {indAudPackagesDescriptor, '$1'} . + + +indAudmediaDescriptor -> 'MediaToken' 'LBRKT' + indAudmediaParm 'RBRKT' + : merge_indAudMediaDescriptor('$3') . + +%% at-most-once per item +%% and either streamParm or streamDescriptor but not both +%% <rambling> +%% This is solved in another way in text than in binary :( +%% Instead of having a list of indAudmediaParm we put this +%% stuff in the indAudterminationAuditList with several +%% indAudmediaDescriptor's. +%% </rambling> +%% + +indAudmediaParm -> indAudstreamParm : {streamParm, '$1'} . +indAudmediaParm -> indAudstreamDescriptor : {streamDescr, '$1'} . +indAudmediaParm -> indAudterminationStateDescriptor : {termStateDescr, '$1'} . + +%% at-most-once +indAudstreamParm -> indAudlocalControlDescriptor + : #'IndAudStreamParms'{localControlDescriptor = '$1'} . +indAudstreamParm -> indAudstatisticsDescriptor + : #'IndAudStreamParms'{statisticsDescriptor = '$1'} . + +indAudstreamDescriptor -> 'StreamToken' 'EQUAL' streamID + 'LBRKT' indAudstreamParm 'RBRKT' + : #'IndAudStreamDescriptor'{streamID = '$3', + streamParms = '$5'} . + + +indAudlocalControlDescriptor -> 'LocalControlToken' + 'LBRKT' indAudlocalParm indAudlocalParmList 'RBRKT' : + merge_indAudLocalControlDescriptor(['$3'| '$4']) . + +indAudlocalParmList -> 'COMMA' indAudlocalParm indAudlocalParmList : ['$2'| '$3'] . +indAudlocalParmList -> '$empty' : [] . + +%% at-most-once per item +%% +indAudlocalParm -> safeToken : ensure_indAudLocalParm('$1') . + +indAudterminationStateDescriptor -> 'TerminationStateToken' + 'LBRKT' indAudterminationStateParm 'RBRKT' + : + merge_indAudTerminationStateDescriptor('$3') . + +%% at-most-once per item +%% + +indAudterminationStateParm -> safeToken : + ensure_indAudTerminationStateParm('$1') . + +indAudeventBufferDescriptor -> 'EventBufferToken' + 'LBRKT' indAudeventSpec 'RBRKT' : '$3' . + +indAudeventSpec -> pkgdName optIndAudeventSpecParameter + : merge_indAudEventBufferDescriptor('$1','$2') . + +optIndAudeventSpecParameter -> 'LBRKT' indAudeventSpecParameter 'RBRKT' + : '$2' . +optIndAudeventSpecParameter -> '$empty' : asn1_NOVALUE . + + +indAudeventSpecParameter -> eventStream : {streamID, '$1'} . +indAudeventSpecParameter -> eventParameterName : {eventParameterName, '$1'} . + +indAudeventsDescriptor -> 'EventsToken' 'EQUAL' requestID + 'LBRKT' indAudrequestedEvent 'RBRKT' + : #'IndAudEventsDescriptor'{requestID = '$3', + pkgdName = '$5'} . + +indAudrequestedEvent -> pkgdName : '$1' . + + +indAudsignalsDescriptor -> 'SignalsToken' optIndAudsignalParm : '$2' . + + +optIndAudsignalParm -> 'LBRKT' 'RBRKT' : asn1_NOVALUE . +optIndAudsignalParm -> 'LBRKT' indAudsignalParm 'RBRKT' : '$2' . + +indAudsignalParm -> indAudsignalList : {seqSigList, '$1'} . +indAudsignalParm -> signalRequest : {signal, ensure_indAudSignal('$1')} . + +indAudsignalList -> 'SignalListToken' 'EQUAL' signalListId + 'LBRKT' signalListParm 'RBRKT' : + #'IndAudSeqSigList'{id = ensure_uint16('$3'), + signalList = + ensure_indAudSignalListParm('$5')} . + + +%% The DigitMapDescriptorToken is specially treated by the scanner +indAuddigitMapDescriptor -> 'DigitMapDescriptorToken' : + ensure_IADMD('$1') . + +indAudstatisticsDescriptor -> 'StatsToken' 'LBRKT' pkgdName 'RBRKT' : + #'IndAudStatisticsDescriptor'{statName = '$3'} . + +indAudpackagesDescriptor -> 'PackagesToken' 'LBRKT' packagesItem 'RBRKT' + : merge_indAudPackagesDescriptor('$3') . + +eventStream -> 'StreamToken' 'EQUAL' streamID : '$3' . + + +%% +%% v2 - end + +notifyRequest -> 'NotifyToken' 'EQUAL' terminationID + 'LBRKT' notifyRequestBody 'RBRKT' + : make_commandRequest({notifyReq, '$1'}, + setelement(#'NotifyRequest'.terminationID, '$5', ['$3'])) . + +notifyRequestBody -> observedEventsDescriptor + : #'NotifyRequest'{observedEventsDescriptor = '$1'}. +notifyRequestBody -> errorDescriptor + : #'NotifyRequest'{errorDescriptor = '$1'}. + +notifyReply -> 'NotifyToken' 'EQUAL' terminationID notifyReplyBody + : {notifyReply, + #'NotifyReply'{terminationID = ['$3'], + errorDescriptor = '$4'}} . + +notifyReplyBody -> 'LBRKT' errorDescriptor 'RBRKT' : '$2'. +notifyReplyBody -> '$empty' : asn1_NOVALUE . + +serviceChangeRequest -> 'ServiceChangeToken' 'EQUAL' terminationID + 'LBRKT' serviceChangeDescriptor 'RBRKT' + : make_commandRequest({serviceChangeReq, '$1'}, + #'ServiceChangeRequest'{terminationID = ['$3'], + serviceChangeParms = '$5'}) . + +serviceChangeReply -> 'ServiceChangeToken' 'EQUAL' terminationID serviceChangeReplyBody + : {serviceChangeReply, + #'ServiceChangeReply'{terminationID = ['$3'], + serviceChangeResult = '$4'}} . + +serviceChangeReplyBody -> 'LBRKT' errorDescriptor 'RBRKT' + : {errorDescriptor, '$2'} . +serviceChangeReplyBody -> 'LBRKT' serviceChangeReplyDescriptor 'RBRKT' + : {serviceChangeResParms, '$2'} . +serviceChangeReplyBody -> '$empty' : {serviceChangeResParms, #'ServiceChangeResParm'{}}. + +errorDescriptor -> 'ErrorToken' 'EQUAL' errorCode 'LBRKT' errorText 'RBRKT' + : #'ErrorDescriptor'{errorCode = '$3', + errorText = '$5'} . + +errorCode -> safeToken : ensure_uint('$1', 0, 999) . + +errorText -> 'QuotedChars' : value_of('$1') . +errorText -> '$empty' : asn1_NOVALUE . + +transactionID -> safeToken : ensure_uint32('$1') . + +mId -> domainName : '$1' . +mId -> domainAddress : '$1' . +mId -> optSep mtpAddress optSep : '$2' . +mId -> optSep deviceName optSep : '$2' . + +domainName -> 'LESSER' safeToken 'GREATER' 'COLON' portNumber optSep + : ensure_domainName('$2', '$5') . +domainName -> 'LESSER' safeToken 'GREATER' + : ensure_domainName('$2', asn1_NOVALUE) . + +deviceName -> pathName : {deviceName, '$1'} . + +%% '-' is used for NULL context +contextID -> safeToken : ensure_contextID('$1') . + +domainAddress -> 'LSBRKT' daddr 'RSBRKT' 'COLON' portNumber optSep + : ensure_domainAddress('$2', '$5') . +domainAddress -> 'LSBRKT' daddr 'RSBRKT' + : ensure_domainAddress('$2', asn1_NOVALUE) . + +daddr -> '$empty' : [] . +daddr -> 'COLON' daddr : [colon| '$2'] . +daddr -> safeToken daddr : ['$1'| '$2'] . + + +portNumber -> safeToken : ensure_uint16('$1') . + +mtpAddress -> 'MtpAddressToken' : ensure_mtpAddress('$1') . + +%% terminationIDList -> LBRKT terminationID *(COMMA terminationID) RBRKT . + +terminationIDList -> 'LBRKT' terminationID terminationIDListRepeat 'RBRKT' + : ['$2' | '$3'] . + +terminationIDListRepeat -> 'COMMA' terminationID terminationIDListRepeat + : ['$2'| '$3'] . +terminationIDListRepeat -> '$empty' : [] . + + +pathName -> safeToken : ensure_pathName('$1') . + +terminationID -> safeToken : ensure_terminationID('$1') . + +mediaDescriptor -> 'MediaToken' 'LBRKT' mediaParm mediaParmList 'RBRKT' + : merge_mediaDescriptor(['$3' | '$4']) . + +mediaParmList -> 'COMMA' mediaParm mediaParmList : ['$2' | '$3'] . +mediaParmList -> '$empty' : [] . + + +%% at-most-once per item +%% using either streamParms or streamDescriptors but not both +mediaParm -> streamParm + : {streamParm, '$1'} . +mediaParm -> streamDescriptor + : {streamDescriptor, '$1'} . +mediaParm -> terminationStateDescriptor + : {termState, '$1'} . + +%% at-most-onc . +%% Specially treated by the scanner. +streamParm -> 'LocalDescriptorToken' : + PGs = ensure_prop_groups('$1'), + {local, #'LocalRemoteDescriptor'{propGrps = PGs} } . +streamParm -> 'RemoteDescriptorToken' : + PGs = ensure_prop_groups('$1'), + {remote, #'LocalRemoteDescriptor'{propGrps = PGs}} . +streamParm -> localControlDescriptor : {control, '$1'} . +streamParm -> statisticsDescriptor : {statistics, '$1'} . + +streamDescriptor -> 'StreamToken' 'EQUAL' streamID + 'LBRKT' streamParm streamParmList 'RBRKT' + : #'StreamDescriptor'{streamID = '$3', + streamParms = merge_streamParms(['$5' | '$6'])} . + +streamParmList -> 'COMMA' streamParm streamParmList : ['$2' | '$3'] . +streamParmList -> '$empty' : [] . + +localControlDescriptor -> 'LocalControlToken' 'LBRKT' localParm localParmList 'RBRKT' + : ['$3' | '$4'] . + +localParmList -> 'COMMA' localParm localParmList : ['$2' | '$3'] . +localParmList -> '$empty': [] . + +terminationStateDescriptor -> 'TerminationStateToken' + 'LBRKT' terminationStateParm + terminationStateParms 'RBRKT' + : merge_terminationStateDescriptor(['$3' | '$4']) . + +terminationStateParms -> 'COMMA' terminationStateParm terminationStateParms : ['$2' | '$3'] . +terminationStateParms -> '$empty' : [] . + +%% at-most-once per item except for propertyParm +localParm -> 'ReservedGroupToken' 'EQUAL' onOrOff : {group, '$3'} . +localParm -> 'ReservedValueToken' 'EQUAL' onOrOff : {value, '$3'} . +localParm -> 'ModeToken' 'EQUAL' streamModes : {mode, '$3'} . +localParm -> propertyParm : {prop, '$1'} . + +onOrOff -> 'OnToken' : true . +onOrOff -> 'OffToken' : false . + +%% at-most-once +streamModes -> 'SendonlyToken' : sendOnly . +streamModes -> 'RecvonlyToken' : recvOnly . +streamModes -> 'SendrecvToken' : sendRecv . +streamModes -> 'InactiveToken' : inactive . +streamModes -> 'LoopbackToken' : loopBack . + +propertyParm -> pkgdName parmValue : + setelement(#'PropertyParm'.name, '$2', '$1') . + +parmValue -> 'EQUAL' alternativeValue : + '$2' . + +parmValue -> 'NEQUAL' value : + #'PropertyParm'{value = ['$2'], + extraInfo = {relation, unequalTo}} . +parmValue -> 'LESSER' value : + #'PropertyParm'{value = ['$2'], + extraInfo = {relation, smallerThan}} . +parmValue -> 'GREATER' value : + #'PropertyParm'{value = ['$2'], + extraInfo = {relation, greaterThan}} . + +%% OTP-4013 +%% alternativeValue = ( VALUE / +%% LSBRKT VALUE *(COMMA VALUE) RSBRKT / +%% LSBRKT VALUE COLON VALUE RSBRKT ) / +%% LBRKT VALUE *(COMMA VALUE) RBRKT +alternativeValue -> 'LBRKT' value valueList 'RBRKT' + : #'PropertyParm'{value = ['$2' | '$3'], + extraInfo = {sublist, false}}. % OR + +alternativeValue -> 'LSBRKT' value 'COLON' value 'RSBRKT' + : #'PropertyParm'{value = ['$2', '$4'], + extraInfo = {range, true}}. + +alternativeValue -> 'LSBRKT' value valueList 'RSBRKT' + : #'PropertyParm'{value = ['$2' | '$3'], + extraInfo = {sublist, true}}. % AND + +alternativeValue -> value : + #'PropertyParm'{value = ['$1']} . + +valueList -> 'COMMA' value valueList : ['$2' | '$3'] . +valueList -> '$empty' : [] . + + +eventBufferDescriptor -> 'EventBufferToken' : [] . +eventBufferDescriptor -> 'EventBufferToken' 'LBRKT' eventSpec eventSpecList 'RBRKT' + : ['$3' | '$4'] . + +eventSpecList -> 'COMMA' eventSpec eventSpecList : ['$2' | '$3'] . +eventSpecList -> '$empty' : [] . + +eventSpec -> observedEvent : merge_eventSpec('$1') . + +%% at-most-once per item except for propertyParm +terminationStateParm -> serviceStates : {serviceState, '$1'} . +terminationStateParm -> eventBufferControl : {eventBufferControl, '$1'} . +terminationStateParm -> propertyParm : {propertyParm, '$1'} . + +serviceStates -> 'ServiceStatesToken' 'EQUAL' serviceState : '$3' . + +serviceState -> 'TestToken' : test . +serviceState -> 'OutOfSvcToken' : outOfSvc . +serviceState -> 'InSvcToken' : inSvc . + +eventBufferControl -> 'BufferToken' 'EQUAL' eventBufferControlState : '$3' . + +eventBufferControlState -> 'OffToken' : off . +eventBufferControlState -> 'LockStepToken' : lockStep . + +muxDescriptor -> 'MuxToken' 'EQUAL' muxType terminationIDList : + #'MuxDescriptor'{muxType = '$3', + termList = '$4'} . + +muxType -> safeToken : ensure_muxType('$1') . + +streamID -> safeToken : ensure_streamID('$1') . + +pkgdName -> safeToken : ensure_pkgdName('$1') . + +eventsDescriptor -> 'EventsToken' : + #'EventsDescriptor'{requestID = asn1_NOVALUE, + eventList = []} . +eventsDescriptor -> 'EventsToken' 'EQUAL' requestID + 'LBRKT' requestedEvent requestedEvents 'RBRKT' : + #'EventsDescriptor'{requestID = '$3', + eventList = ['$5' | '$6']} . + +requestedEvents -> 'COMMA' requestedEvent requestedEvents : ['$2' | '$3'] . +requestedEvents -> '$empty' : [] . + +requestedEvent -> pkgdName requestedEventBody : + setelement(#'RequestedEvent'.pkgdName, '$2', '$1') . + +requestedEventBody -> 'LBRKT' eventParameter eventParameters 'RBRKT' : + merge_eventParameters(['$2' | '$3']) . +requestedEventBody -> '$empty' : #'RequestedEvent'{evParList = []} . + +eventParameters -> 'COMMA' eventParameter eventParameters : + ['$2' | '$3'] . +eventParameters -> '$empty' : [] . + +%% at-most-once each of embedOrKeepActive , eventDM or eventStream +eventParameter -> 'KeepActiveToken' : keepActive . +eventParameter -> embedWithSig : '$1'. +eventParameter -> embedNoSig : '$1'. +eventParameter -> eventDM : '$1'. +eventParameter -> eventStreamOrOther : '$1'. + +embedWithSig -> 'EmbedToken' 'LBRKT' signalsDescriptor + 'COMMA' embedFirst 'RBRKT' + : {embed, '$3', '$5'} . +embedWithSig -> 'EmbedToken' 'LBRKT' signalsDescriptor 'RBRKT' + : {embed, '$3', asn1_NOVALUE} . + +embedNoSig -> 'EmbedToken' 'LBRKT' embedFirst 'RBRKT' + : {embed, asn1_NOVALUE, '$3'} . + +embedFirst -> 'EventsToken' : + #'SecondEventsDescriptor'{requestID = asn1_NOVALUE, + eventList = []} . +embedFirst -> 'EventsToken' 'EQUAL' requestID + 'LBRKT' secondRequestedEvent secondRequestedEvents 'RBRKT' : + #'SecondEventsDescriptor'{requestID = '$3', + eventList = ['$5' | '$6']} . + +secondRequestedEvents -> 'COMMA' secondRequestedEvent secondRequestedEvents : ['$2' | '$3'] . +secondRequestedEvents -> '$empty' : [] . + +%% at-most-once of each +secondRequestedEvent -> pkgdName secondRequestedEventBody + : setelement(#'SecondRequestedEvent'.pkgdName, '$2', '$1') . + +secondRequestedEventBody -> 'LBRKT' secondEventParameter secondEventParameters 'RBRKT' + : merge_secondEventParameters(['$2' | '$3']) . +secondRequestedEventBody -> '$empty' : #'SecondRequestedEvent'{evParList = []} . + +secondEventParameters -> 'COMMA' secondEventParameter secondEventParameters : ['$2' | '$3'] . +secondEventParameters -> '$empty' : [] . + +%% at-most-once each of embedOrKeepActive , eventDM or eventStream +secondEventParameter -> 'KeepActiveToken' : keepActive . +secondEventParameter -> embedSig : '$1' . +secondEventParameter -> eventDM : '$1' . +secondEventParameter -> eventStreamOrOther : '$1' . + +embedSig -> 'EmbedToken' 'LBRKT' signalsDescriptor 'RBRKT' + : {second_embed, '$3'} . + +eventStreamOrOther -> eventParameterName parmValue : + select_stream_or_other('$1', '$2') . + +eventParameterName -> safeToken : ensure_NAME('$1') . + +%% The DigitMapDescriptorToken is specially treated by the scanner +eventDM -> 'DigitMapDescriptorToken' : + ensure_eventDM('$1') . + +%% H248S-IG (IGv11) +signalsDescriptor -> 'SignalsToken' 'LBRKT' signalParm signalParms 'RBRKT' : + ['$3' | '$4'] . +signalsDescriptor -> 'SignalsToken' : [] . + +signalParms -> 'COMMA' signalParm signalParms : [ '$2' | '$3'] . +signalParms -> '$empty' : [] . + +signalParm -> signalList : {seqSigList, '$1'} . +signalParm -> signalRequest : {signal, '$1'} . + +signalRequest -> signalName 'LBRKT' sigParameter sigParameters 'RBRKT' + : merge_signalRequest('$1', ['$3' | '$4']). +signalRequest -> signalName : merge_signalRequest('$1', []). + +sigParameters -> 'COMMA' sigParameter sigParameters : ['$2' | '$3'] . +sigParameters -> '$empty' : [] . + +%% sigParameter = sigStream / sigSignalType / sigDuration / sigOther / +%% notifyCompletion / KeepActiveToken / +%% direction / sigRequestID +%% sigStream = StreamToken EQUAL StreamID +%% sigOther = sigParameterName parmValue +%% sigParameterName = NAME +%% sigSignalType = SignalTypeToken EQUAL signalType +%% signalType = (OnOffToken / TimeOutToken / BriefToken) +%% sigDuration = DurationToken EQUAL UINT16 +%% notifyCompletion = NotifyCompletionToken EQUAL (LBRKT +%% notificationReason *(COMMA notificationReason) +%% RBRKT) +%% +%% notificationReason = ( TimeOutToken / InterruptByEventToken / +%% InterruptByNewSignalsDescrToken / +%% OtherReasonToken ) +%% sigDirection = DirectionToken EQUAL direction +%% sigRequestID = RequestIDToken EQUAL RequestID + +sigParameter -> 'StreamToken' 'EQUAL' streamID : + {stream, '$3'}. +sigParameter -> 'SignalTypeToken' 'EQUAL' signalType : + {signal_type, '$3'} . +sigParameter -> 'DurationToken' 'EQUAL' safeToken : + {duration, ensure_uint16('$3')} . +sigParameter -> 'NotifyCompletionToken' 'EQUAL' + 'LBRKT' notificationReason notificationReasons 'RBRKT' : + {notify_completion, ['$4' | '$5']} . +sigParameter -> 'KeepActiveToken' : keepActive . +sigParameter -> 'DirectionToken' 'EQUAL' direction : {direction, '$3'} . +sigParameter -> 'RequestIDToken' 'EQUAL' requestID : {requestId, '$3'} . +sigParameter -> safeToken parmValue : + {other, ensure_NAME('$1'), '$2'}. + +signalType -> 'OnOffToken' : onOff. +signalType -> 'TimeOutToken' : timeOut. +signalType -> 'BriefToken' : brief. + +direction -> 'ExternalToken' : external . +direction -> 'InternalToken' : internal . +direction -> 'BothToken' : both . + +notificationReasons -> 'COMMA' notificationReason notificationReasons : ['$2' | '$3'] . +notificationReasons -> '$empty' : [] . + +notificationReason -> 'TimeOutToken' : onTimeOut . +notificationReason -> 'InterruptByEventToken' : onInterruptByEvent . +notificationReason -> 'InterruptByNewSignalsDescrToken' : onInterruptByNewSignalDescr . +notificationReason -> 'OtherReasonToken' : otherReason . + +signalList -> 'SignalListToken' 'EQUAL' signalListId + 'LBRKT' signalListParm signalListParms 'RBRKT' + : #'SeqSigList'{id = ensure_uint16('$3'), + signalList = ['$5' | '$6']} . + +signalListParms -> 'COMMA' signalListParm signalListParms : + ['$2' | '$3'] . +signalListParms -> '$empty' : [] . + +signalListId -> safeToken : ensure_uint16('$1') . + +%% exactly once signalType, +%% at most once duration and every signal parameter +signalListParm -> signalRequest : '$1'. + +signalName -> pkgdName : '$1'. + +observedEventsDescriptor -> 'ObservedEventsToken' 'EQUAL' requestID + 'LBRKT' observedEvent observedEvents 'RBRKT' + : #'ObservedEventsDescriptor'{requestId = '$3', + observedEventLst = ['$5' | '$6']} . + +observedEvents -> 'COMMA' observedEvent observedEvents : ['$2' | '$3'] . +observedEvents -> '$empty' : [] . + +%%time per event, because it might be buffered + +observedEvent -> timeStamp optSep 'COLON' optSep pkgdName observedEventBody : + merge_observed_event('$6', '$5', '$1') . +observedEvent -> optSep pkgdName observedEventBody : + merge_observed_event('$3', '$2', asn1_NOVALUE) . + +observedEventBody -> 'LBRKT' observedEventParameter + observedEventParameters 'RBRKT' + : ['$2' | '$3'] . +observedEventBody -> '$empty' : [] . + +observedEventParameters -> 'COMMA' observedEventParameter observedEventParameters : ['$2' | '$3'] . +observedEventParameters -> '$empty' : [] . + +%%at-most-once eventStream, every eventParameterName at most once +observedEventParameter -> eventStreamOrOther : '$1' . + +requestID -> safeToken : ensure_requestID('$1') . + +%% Deprecated as of Corr 1 +modemDescriptor -> 'ModemToken' 'EQUAL' modemType optPropertyParms . +modemDescriptor -> 'ModemToken' 'LSBRKT' modemType modemTypeList 'RSBRKT' + optPropertyParms. +modemTypeList -> 'COMMA' modemType modemTypeList. +modemTypeList -> '$empty'. +modemType -> safeToken. + +optPropertyParms -> 'LBRKT' propertyParm propertyParms 'RBRKT' : + ['$2' | '$3'] . +optPropertyParms -> '$empty' : [] . + +propertyParms -> 'COMMA' propertyParm propertyParms : ['$2' | '$3'] . +propertyParms -> '$empty' : [] . + +% parmName -> safeToken : ensure_NAME('$1') . + +%% The DigitMapDescriptorToken is specially treated by the scanner +digitMapDescriptor -> 'DigitMapDescriptorToken' : + ensure_DMD('$1') . + +%% each parameter at-most-once, except auditItem +%% at most one of either serviceChangeAddress or serviceChangeMgcId but +%% not both. serviceChangeMethod and serviceChangeReason are REQUIRED +serviceChangeDescriptor -> 'ServicesToken' + 'LBRKT' serviceChangeParm + serviceChangeParms 'RBRKT' : + merge_ServiceChangeParm(['$3' | '$4']) . + +serviceChangeParms -> 'COMMA' serviceChangeParm serviceChangeParms : + ['$2' | '$3'] . +serviceChangeParms -> '$empty' : [] . + +serviceChangeParm -> serviceChangeMethod : {method, '$1'} . +serviceChangeParm -> serviceChangeReason : {reason, '$1'} . +serviceChangeParm -> serviceChangeDelay : {delay, '$1'} . +serviceChangeParm -> serviceChangeAddress : {address, '$1'} . +serviceChangeParm -> serviceChangeProfile : {profile, '$1'} . +serviceChangeParm -> extension : {extension, '$1'} . +serviceChangeParm -> timeStamp : {time_stamp, '$1'} . +serviceChangeParm -> serviceChangeMgcId : {mgc_id, '$1'} . +serviceChangeParm -> serviceChangeVersion : {version, '$1'} . +serviceChangeParm -> 'ServiceChangeIncompleteToken' : incomplete . % v3 +serviceChangeParm -> auditItem : {audit_item, '$1'} . % v2 + +serviceChangeMethod -> 'MethodToken' 'EQUAL' safeToken : + ensure_serviceChangeMethod('$3') . + +serviceChangeReason -> 'ReasonToken' 'EQUAL' value : ['$3'] . + +serviceChangeDelay -> 'DelayToken' 'EQUAL' safeToken : ensure_uint32('$3'). + +serviceChangeAddress -> 'ServiceChangeAddressToken' 'EQUAL' mId : '$3' . +serviceChangeAddress -> 'ServiceChangeAddressToken' 'EQUAL' portNumber : + {portNumber, '$3'} . + +serviceChangeMgcId -> 'MgcIdToken' 'EQUAL' mId : '$3' . + +serviceChangeProfile -> 'ProfileToken' 'EQUAL' safeToken : ensure_profile('$3'). + +serviceChangeVersion -> 'VersionToken' 'EQUAL' safeToken : ensure_version('$3') . + +extension -> extensionParameter parmValue + : setelement(#'PropertyParm'.name, '$2', '$1') . + +%% at most once. Version is REQUIRED on first ServiceChange response +%% at most of either serviceChangeAddress or serviceChangeMgcId but not both +serviceChangeReplyDescriptor -> 'ServicesToken' + 'LBRKT' servChgReplyParm + servChgReplyParms 'RBRKT' : + merge_ServiceChangeResParm(['$3' | '$4']) . + +servChgReplyParms -> 'COMMA' servChgReplyParm servChgReplyParms : + ['$2' | '$3'] . +servChgReplyParms -> '$empty' : [] . + +servChgReplyParm -> serviceChangeAddress : {address, '$1'} . +servChgReplyParm -> serviceChangeMgcId : {mgc_id, '$1'} . +servChgReplyParm -> serviceChangeProfile : {profile, '$1'} . +servChgReplyParm -> serviceChangeVersion : {version, '$1'} . +servChgReplyParm -> timeStamp : {time_stamp,'$1'} . + +packagesDescriptor -> 'PackagesToken' 'LBRKT' packagesItem + packagesItems 'RBRKT' + : ['$3' | '$4'] . + +packagesItems -> 'COMMA' packagesItem packagesItems : ['$2' | '$3'] . +packagesItems -> '$empty' : [] . + +packagesItem -> safeToken : ensure_packagesItem('$1') . + +timeStamp -> TimeStampToken : ensure_timeStamp('$1') . + +statisticsDescriptor -> 'StatsToken' + 'LBRKT' statisticsParameter + statisticsParameters 'RBRKT' + : ['$3' | '$4'] . + +statisticsParameters -> 'COMMA' statisticsParameter statisticsParameters : ['$2' | '$3'] . +statisticsParameters -> '$empty' : [] . + +%%at-most-once per item +statisticsParameter -> pkgdName + : #'StatisticsParameter'{statName = '$1', + statValue = asn1_NOVALUE} . +statisticsParameter -> pkgdName 'EQUAL' value + : #'StatisticsParameter'{statName = '$1', + statValue = ['$3']} . + +topologyDescriptor -> 'TopologyToken' 'LBRKT' topologyTriple + topologyTripleList 'RBRKT' : ['$3' | '$4'] . + +terminationA -> terminationID : '$1' . + +terminationB -> terminationID : '$1' . + +topologyTriple -> terminationA 'COMMA' + terminationB 'COMMA' + topologyDirection : + #'TopologyRequest'{terminationFrom = '$1', + terminationTo = '$3', + topologyDirection = '$5'} . + +topologyTripleList -> '$empty' : [] . +topologyTripleList -> 'COMMA' topologyTriple topologyTripleList : + ['$2' | '$3'] . + +topologyDirection -> 'BothwayToken' : bothway . +topologyDirection -> 'IsolateToken' : isolate . +topologyDirection -> 'OnewayToken' : oneway . + +priority -> 'PriorityToken' 'EQUAL' safeToken : ensure_uint16('$3') . + +extensionParameter -> safeToken : ensure_extensionParameter('$1') . + +value -> 'QuotedChars' : ensure_value('$1') . +value -> safeToken : ensure_value('$1'). + +safeToken -> safeToken2 : make_safe_token('$1') . + +safeToken2 -> 'SafeChars' : '$1' . +%% BMK BMK safeToken2 -> 'AddToken' : '$1' . +safeToken2 -> 'AuditToken' : '$1' . +safeToken2 -> 'AuditCapToken' : '$1' . +safeToken2 -> 'AuditValueToken' : '$1' . +safeToken2 -> 'AuthToken' : '$1' . +safeToken2 -> 'BothToken' : '$1' . % v3 +safeToken2 -> 'BothwayToken' : '$1' . +safeToken2 -> 'BriefToken' : '$1' . +safeToken2 -> 'BufferToken' : '$1' . +safeToken2 -> 'CtxToken' : '$1' . +%% v3-safeToken2 -> 'ContextAttrToken' : '$1' . % v3 +safeToken2 -> 'ContextAuditToken' : '$1' . +%% v2-safeToken2 -> 'DigitMapToken' : '$1' . +%% safeToken2 -> 'DigitMapDescriptorToken' : '$1' . +%% v3- +safeToken2 -> 'DirectionToken' : '$1' . % v3 +safeToken2 -> 'DiscardToken' : '$1' . +safeToken2 -> 'DisconnectedToken' : '$1' . +safeToken2 -> 'DelayToken' : '$1' . +safeToken2 -> 'DurationToken' : '$1' . +safeToken2 -> 'EmbedToken' : '$1' . +%% BMK BMK safeToken2 -> 'EmergencyToken' : '$1' . +%% BMK BMK safeToken2 -> 'EmergencyOffToken' : '$1' . +safeToken2 -> 'ErrorToken' : '$1' . +%% v2-safeToken2 -> 'EventBufferToken' : '$1' . +%% v2-safeToken2 -> 'EventsToken' : '$1' . +%% v3-safeToken2 -> 'ExternalToken' : '$1' . % v3 +safeToken2 -> 'FailoverToken' : '$1' . +safeToken2 -> 'ForcedToken' : '$1' . +safeToken2 -> 'GracefulToken' : '$1' . +safeToken2 -> 'H221Token' : '$1' . +safeToken2 -> 'H223Token' : '$1' . +safeToken2 -> 'H226Token' : '$1' . +safeToken2 -> 'HandOffToken' : '$1' . +%% v3-safeToken2 -> 'IEPSToken' : '$1' . % v3 +safeToken2 -> 'ImmAckRequiredToken' : '$1' . +safeToken2 -> 'InactiveToken' : '$1' . +%% v3-safeToken2 -> 'InternalToken' : '$1' . % v3 +safeToken2 -> 'InterruptByEventToken' : '$1' . +safeToken2 -> 'InterruptByNewSignalsDescrToken' : '$1' . +safeToken2 -> 'IsolateToken' : '$1' . +safeToken2 -> 'InSvcToken' : '$1' . +safeToken2 -> 'KeepActiveToken' : '$1' . +%% safeToken2 -> 'LocalToken' : '$1' . +%% safeToken2 -> 'LocalDescriptorToken' : '$1' . +safeToken2 -> 'LocalControlToken' : '$1' . +safeToken2 -> 'LoopbackToken' : '$1' . +safeToken2 -> 'LockStepToken' : '$1' . +%% v2-safeToken2 -> 'MediaToken' : '$1' . +%% safeToken2 -> 'MegacopToken' : '$1' . +safeToken2 -> 'MethodToken' : '$1' . +safeToken2 -> 'MgcIdToken' : '$1' . +safeToken2 -> 'ModeToken' : '$1' . +%% BMK BMK safeToken2 -> 'ModifyToken' : '$1' . +%% v2-safeToken2 -> 'ModemToken' : '$1' . +%% BMK BMK safeToken2 -> 'MoveToken' : '$1' . +%% safeToken2 -> 'MtpToken' : '$1' . +%% safeToken2 -> 'MtpAddressToken' : '$1' . +%% v2-safeToken2 -> 'MuxToken' : '$1' . +safeToken2 -> 'NotifyToken' : '$1' . +safeToken2 -> 'NotifyCompletionToken' : '$1' . +safeToken2 -> 'Nx64kToken' : '$1' . +%% v2-safeToken2 -> 'ObservedEventsToken' : '$1' . +safeToken2 -> 'OnewayToken' : '$1' . +safeToken2 -> 'OffToken' : '$1' . +safeToken2 -> 'OnToken' : '$1' . +safeToken2 -> 'OnOffToken' : '$1' . +safeToken2 -> 'OutOfSvcToken' : '$1' . +safeToken2 -> 'OtherReasonToken' : '$1' . +%% v2-safeToken2 -> 'PackagesToken' : '$1' . +safeToken2 -> 'PendingToken' : '$1' . +%% BMK BMK safeToken2 -> 'PriorityToken' : '$1' . +safeToken2 -> 'ProfileToken' : '$1' . +safeToken2 -> 'ReasonToken' : '$1' . +safeToken2 -> 'RecvonlyToken' : '$1' . +safeToken2 -> 'ReplyToken' : '$1' . +%% v3- +safeToken2 -> 'RequestIDToken' : '$1' . % v3 +safeToken2 -> 'ResponseAckToken' : '$1' . +safeToken2 -> 'RestartToken' : '$1' . +%% safeToken2 -> 'RemoteToken' : '$1' . +%% safeToken2 -> 'RemoteDescriptorToken' : '$1' . +safeToken2 -> 'ReservedGroupToken' : '$1' . +safeToken2 -> 'ReservedValueToken' : '$1' . +safeToken2 -> 'SendonlyToken' : '$1' . +safeToken2 -> 'SendrecvToken' : '$1' . +safeToken2 -> 'ServicesToken' : '$1' . +safeToken2 -> 'ServiceStatesToken' : '$1' . +safeToken2 -> 'ServiceChangeToken' : '$1' . +%% v3-safeToken2 -> 'ServiceChangeIncompleteToken' : '$1' . % v3 +safeToken2 -> 'ServiceChangeAddressToken' : '$1' . +safeToken2 -> 'SignalListToken' : '$1' . +%% v2-safeToken2 -> 'SignalsToken' : '$1' . +safeToken2 -> 'SignalTypeToken' : '$1' . +%% v2-safeToken2 -> 'StatsToken' : '$1' . +safeToken2 -> 'StreamToken' : '$1' . +%% BMK BMK safeToken2 -> 'SubtractToken' : '$1' . +safeToken2 -> 'SynchISDNToken' : '$1' . +safeToken2 -> 'TerminationStateToken' : '$1' . +safeToken2 -> 'TestToken' : '$1' . +safeToken2 -> 'TimeOutToken' : '$1' . +%% BMK BMK safeToken2 -> 'TopologyToken' : '$1' . +safeToken2 -> 'TransToken' : '$1' . +safeToken2 -> 'V18Token' : '$1' . +safeToken2 -> 'V22Token' : '$1' . +safeToken2 -> 'V22bisToken' : '$1' . +safeToken2 -> 'V32Token' : '$1' . +safeToken2 -> 'V32bisToken' : '$1' . +safeToken2 -> 'V34Token' : '$1' . +safeToken2 -> 'V76Token' : '$1' . +safeToken2 -> 'V90Token' : '$1' . +safeToken2 -> 'V91Token' : '$1' . +safeToken2 -> 'VersionToken' : '$1' . +%% <OTP-7534> +safeToken2 -> 'AndAUDITSelectToken' : '$1' . % v3 +safeToken2 -> 'ContextListToken' : '$1' . % v3 +safeToken2 -> 'EmergencyValueToken' : '$1' . % v3 +safeToken2 -> 'IntsigDelayToken' : '$1' . % v3 +safeToken2 -> 'IterationToken' : '$1' . % v3 +safeToken2 -> 'MessageSegmentToken' : '$1' . % v3 +safeToken2 -> 'NeverNotifyToken' : '$1' . % v3 +safeToken2 -> 'NotifyImmediateToken' : '$1' . % v3 +safeToken2 -> 'NotifyRegulatedToken' : '$1' . % v3 +safeToken2 -> 'OnewayBothToken' : '$1' . % v3 +safeToken2 -> 'OnewayExternalToken' : '$1' . % v3 +safeToken2 -> 'OrAUDITselectToken' : '$1' . % v3 +safeToken2 -> 'ResetEventsDescriptorToken' : '$1' . % v3 +safeToken2 -> 'SegmentationCompleteToken' : '$1' . % v3 +%% </OTP-7534> + + +Erlang code. + +%% The following directive is needed for (significantly) faster compilation +%% of the generated .erl file by the HiPE compiler. Please do not remove. +-compile([{hipe,[{regalloc,linear_scan}]}]). + +-include("megaco_text_parser_prev3a.hrl"). + + diff --git a/lib/megaco/src/text/megaco_text_parser_prev3b.hrl b/lib/megaco/src/text/megaco_text_parser_prev3b.hrl new file mode 100644 index 0000000000..ba10dfb943 --- /dev/null +++ b/lib/megaco/src/text/megaco_text_parser_prev3b.hrl @@ -0,0 +1,1717 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2005-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 : Define semantic text parser actions +%%---------------------------------------------------------------------- + + +-include_lib("megaco/include/megaco.hrl"). +-include_lib("megaco/include/megaco_message_prev3b.hrl"). +-define(encoder_version_pre_prev3c,true). +-include("megaco_text_tokens.hrl"). + +-ifdef(megaco_parser_inline). +-compile({inline,[{make_safe_token,1}]}). +-endif. +make_safe_token(Token) -> + {_TokenTag, Line, Text} = Token, + {safeToken, Line, Text}. + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_value,1}]}). +-endif. +ensure_value(Token) -> + case Token of + {safeToken, _Line, Text} when is_list(Text) -> + Text; % We really should ensure length + {'QuotedChars', _Line, Text} when is_list(Text) -> + Text; % We really should ensure length + Text when is_list(Text) -> + Text % We really should ensure length + end. + +%% NAME = ALPHA *63(ALPHA / DIGIT / "_" ) +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_NAME,1}]}). +-endif. +ensure_NAME(Token) -> + {_TokenTag, _Line, Text} = Token, + Text. %% BUGBUG: ensure length and chars + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_requestID,1}]}). +-endif. +ensure_requestID(Token) -> + case Token of + {safeToken, _Line, "*"} -> + ?megaco_all_request_id; + _ -> + ensure_uint32(Token) + end. + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_streamID,1}]}). +-endif. +ensure_streamID(StreamId) -> + ensure_uint16(StreamId). + +ensure_auth_header(SpiToken, SnToken, AdToken) -> + Spi = ensure_hex(SpiToken, 8, 8), + Sn = ensure_hex(SnToken, 8, 8), + Ad = ensure_hex(AdToken, 24, 64), + #'AuthenticationHeader'{secParmIndex = Spi, seqNum = Sn, ad = Ad}. + +%% The values 0x0, 0xFFFFFFFE and 0xFFFFFFFF are reserved. +%% ContextID = (UINT32 / "*" / "-" / "$") +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_contextID,1}]}). +-endif. +ensure_contextID(Token) -> + {_TokenTag, Line, Text} = Token, + case Text of + "*" -> ?megaco_all_context_id; + "-" -> ?megaco_null_context_id; + "\$" -> ?megaco_choose_context_id; + Int -> + CID = ensure_uint32(Int), + if + (CID =/= 0) andalso + (CID =/= 16#FFFFFFFE) andalso + (CID =/= 16#FFFFFFFF) -> + CID; + true -> + return_error(Line, {bad_ContextID, CID}) + end + end. + +ensure_domainAddress([{_T, _L, _A} = Addr0], Port) -> + Addr = ensure_ip4addr(Addr0), + {ip4Address, #'IP4Address'{address = Addr, portNumber = Port}}; +ensure_domainAddress([colon,colon], Port) -> + Addr = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + {ip6Address, #'IP6Address'{address = Addr, portNumber = Port}}; +ensure_domainAddress(Addr0, Port) -> + Addr = ensure_ip6addr(Addr0), + {ip6Address, #'IP6Address'{address = Addr, portNumber = Port}}. + + +ensure_ip4addr(Token) -> + {_TokenTag, Line, Addr} = Token, +%% case string:tokens(Addr, [$.]) of +%% [T1, T2, T3, T4] -> + case split_ip4addr_text(Addr, []) of + [T1, T2, T3, T4] -> + %% We optimize by sending only the text part (Addr) of + %% the token to the function. + %% If something is wrong, then we do not get a proper + %% position and therefor we catch and issue the + %% the error again (with the proper line number). + case (catch [ + ensure_uint(T1, 0, 255), + ensure_uint(T2, 0, 255), + ensure_uint(T3, 0, 255), + ensure_uint(T4, 0, 255) + ]) of + A when is_list(A) -> + A; + _ -> + return_error(Line, {bad_IP4address, Addr}) + end; + _ -> + return_error(Line, {bad_IP4address, Addr}) + end. + +split_ip4addr_text([], Acc) -> + [ lists:reverse(Acc) ]; +split_ip4addr_text([$. | Rest], Acc) -> + [ lists:reverse(Acc) | split_ip4addr_text(Rest, []) ]; +split_ip4addr_text([H | T], Acc) -> + split_ip4addr_text(T, [H | Acc]). + + +ensure_ip6addr([colon,colon|T]) -> + [H1|T1] = lists:reverse(T), + case do_ensure_ip6addr(T1, true, [ensure_hex4_or_ip4addr(H1)], 1) of + {true, A} when length(A) == 16 -> + A; + {true, B} when length(B) < 16 -> + lists:duplicate(16 - length(B), 0) ++ B; + {true, C} -> + throw({error, {?MODULE, {bad_mid_ip6addr_length, C}}}) + end; +ensure_ip6addr(L) -> + case lists:reverse(L) of + [colon, colon| T] -> + case do_ensure_ip6addr(T, true, [], 1) of + {true, A} when length(A) == 16 -> + A; + {true, B} when length(B) < 16 -> + B ++ lists:duplicate(16 - length(B), 0); + {true, C} -> + throw({error, {?MODULE, {bad_mid_ip6addr_length, C}}}) + end; + [H|L1] -> % A (last element) could be an ip4 address + case do_ensure_ip6addr(L1,false,[ensure_hex4_or_ip4addr(H)],1) of + {false, A} when length(A) == 16 -> + A; + %% allow a pad even if the address is full (i.e. 16) + {true, B} when length(B) =< 17 -> + do_ensure_ip6addr_padding(B, 0); + {Pad, C} -> + throw({error, {?MODULE, {bad_mid_ip6addr_length, Pad, C}}}) + end + + end. + + +do_ensure_ip6addr([], Pad, Acc, _) -> + {Pad, lists:flatten(Acc)}; +do_ensure_ip6addr([colon,colon|T], false, Acc, Line) -> + do_ensure_ip6addr(T, true, [pad|Acc], Line); +do_ensure_ip6addr([colon,colon|T], true, Acc, Line) -> + return_error(Line, {bad_mid_duplicate_padding, T, Acc}); +do_ensure_ip6addr([colon|T], Pad, Acc, Line) -> + do_ensure_ip6addr(T, Pad, Acc, Line); +do_ensure_ip6addr([{_, Line, _} = A|T], Pad, Acc, _) -> + do_ensure_ip6addr(T, Pad, [ensure_hex4(A)|Acc], Line). + +do_ensure_ip6addr_padding([], _) -> + []; +do_ensure_ip6addr_padding([pad|T], N) -> + lists:duplicate(16 - (N + length(T)), 0) ++ T; +do_ensure_ip6addr_padding([H|T], N) -> + [H|do_ensure_ip6addr_padding(T, N+1)]. + +ensure_hex4_or_ip4addr({TokenTag, Line, Addr} = V) -> + case string:tokens(Addr, [$.]) of + [T1, T2, T3, T4] -> + A1 = ensure_uint({TokenTag, Line, T1}, 0, 255), + A2 = ensure_uint({TokenTag, Line, T2}, 0, 255), + A3 = ensure_uint({TokenTag, Line, T3}, 0, 255), + A4 = ensure_uint({TokenTag, Line, T4}, 0, 255), + [A1, A2, A3, A4]; + _ -> + ensure_hex4(V) + %% %% BMK BMK BMK + %% %% Here we should test for hexseq + %% return_error(Line, {bad_IP4address, Addr}) + end. + +ensure_hex4({_TokenTag, Line, Hex4}) + when length(Hex4) =< 4, length(Hex4) > 0 -> + case (catch do_ensure_hex4(Hex4)) of + IL when is_list(IL) andalso (length(IL) =:= 2) -> + IL; + Error -> + return_error(Line, {bad_hex4, Hex4, Error}) + end. + +do_ensure_hex4([_H1, _H2, _H3, _H4] = H) -> + hex_to_int(H, []); +do_ensure_hex4([H2, H3, H4]) -> + hex_to_int([$0, H2, H3, H4], []); +do_ensure_hex4([H3, H4]) -> + hex_to_int([$0, $0, H3, H4], []); +do_ensure_hex4([H4]) -> + hex_to_int([$0, $0, $0, H4], []). + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_domainName,2}]}). +-endif. +ensure_domainName(Token, Port) -> + {_TokenTag, _Line, Name} = Token, + %% BUGBUG: validate name + {domainName, #'DomainName'{name = Name, portNumber = Port}}. + +%% extensionParameter= "X" ("-" / "+") 1*6(ALPHA / DIGIT) +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_extensionParameter,1}]}). +-endif. +ensure_extensionParameter(Token) -> + {_TokenTag, Line, Text} = Token, + case Text of + [X, S | _Chars] -> + if + X /= $X, X /= $x, + S /= $+, S /= $- -> + return_error(Line, {bad_extension_parameter, Text}); + true -> + {extension_parameter, Text} + end; + _ -> + return_error(Line, {bad_extension_parameter, Text}) + end. + +ensure_message(MegacopToken, MID, Body) -> +%% #'ServiceChangeProfile'{profileName = Name, +%% version = Version} = +%% ensure_profile(MegacopToken), +%% case Name of +%% "megaco" -> +%% #'Message'{version = Version, mId = MID, messageBody = Body}; +%% [$!] -> +%% #'Message'{version = Version, mId = MID, messageBody = Body} +%% end. + {_TokenTag, Line, Text} = MegacopToken, + case split_Megacop(Text, []) of + {Name, Version} -> + Version2 = ensure_version(Version), + case Name of + "megaco" -> + #'Message'{version = Version2, + mId = MID, + messageBody = Body}; + [$!] -> + #'Message'{version = Version2, + mId = MID, + messageBody = Body} + end; + _ -> + return_error(Line, {bad_name_or_version, Text}) + end. + +split_Megacop([], _) -> + error; +split_Megacop([$/ | Version], Acc) -> + {lists:reverse(Acc), Version}; +split_Megacop([H | T], Acc) -> + split_Megacop(T, [H | Acc]). + + +%% Corr1: +%% As of corr 1 ModemDescriptor has been deprecated. +%% and since this functon is only used when creating +%% a ModemDescriptor, iit is removed. +%% modemType = (V32bisToken / V22bisToken / V18Token / +%% V22Token / V32Token / V34Token / V90Token / +%% V91Token / SynchISDNToken / extensionParameter) +%% ensure_modemType({_TokenTag, _Line, Text} = Token) -> +%% case Text of +%% "v32b" -> v32bis; +%% "v22b" -> v22bis; +%% "v18" -> v18; +%% "v22" -> v22; +%% "v32" -> v32; +%% "v34" -> v34; +%% "v90" -> v90; +%% "v91" -> v91; +%% "synchisdn" -> synchISDN; +%% "sn" -> synchISDN; +%% [$x | _] -> ensure_extensionParameter(Token) +%% end. + +%% An mtp address is five octets long +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_mtpAddress,1}]}). +-endif. +ensure_mtpAddress(Token) -> + {_TokenTag, _Line, Addr} = Token, + %% BUGBUG: validate address + {mtpAddress, Addr}. + +%% MuxType = ( H221Token / H223Token / H226Token / V76Token / extensionParameter ) +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_muxType,1}]}). +-endif. +ensure_muxType(Token) -> + {_TokenTag, _Line, Text} = Token, + case Text of + "h221" -> h221; + "h223" -> h223; + "h226" -> h226; + "v76" -> v76; + "nx64k" -> nx64k; % v2 + [$x | _] -> ensure_extensionParameter(Token) + end. + +%% packagesItem = NAME "-" UINT16 +%% NAME = ALPHA *63(ALPHA / DIGIT / "_" ) +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_packagesItem,1}]}). +-endif. +ensure_packagesItem(Token) -> + {_TokenTag, Line, Text} = Token, + case split_packagesItem(Text, []) of + {Name, Version} -> + %% As we don't ensure length of the names, there is no point + %% in doing the ensure_NAME thing... + #'PackagesItem'{packageName = Name, + packageVersion = ensure_uint(Version, 0, 99)}; + _ -> + return_error(Line, {bad_PackagesItem, Text}) + end. + +split_packagesItem([], _) -> + error; +split_packagesItem([$- | Version], Acc) -> + {lists:reverse(Acc), Version}; +split_packagesItem([H|T], Acc) -> + split_packagesItem(T, [H|Acc]). + + +%% pkgdName = (PackageName / "*") SLASH (ItemID / "*" ) +%% PackageName = NAME +%% ItemID = NAME +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_pkgdName,1}]}). +-endif. +ensure_pkgdName(Token) -> + {_TokenTag, Line, Text} = Token, + case ensure_pkgdName(Text, []) of + ok -> + %% As we don't really do any checks on the strings + %% (length or content) there is really no point in + %% "ensuring" the name and item part of the + %% package name + %% ensure_name_or_star(Name), + %% ensure_name_or_star(Item), + Text; + _ -> + return_error(Line, {bad_pkgdName, Text}) + end. + +ensure_pkgdName([], _) -> + error; +ensure_pkgdName([$/ | T], Acc) + when ((length(T) > 0) andalso (length(Acc) > 0)) -> + ok; +ensure_pkgdName([H | T], Acc) -> + ensure_pkgdName(T, [H | Acc]). + + +%% -compile({inline,[{ensure_name_or_star,1}]}). +%% ensure_name_or_star(Val) -> +%% %% case Token of +%% %% {_, _, Name} when Name =:= "*" -> +%% %% Name; +%% %% _ -> +%% %% ensure_NAME(Token) +%% %% end. +%% if +%% Val =:= "*" -> +%% Val; +%% true -> +%% %% as we don't really validate the text part of the token(s), +%% %% we can just return the value assuming it to be correct... +%% Val +%% end. + + +%% v2 - start + +merge_indAudMediaDescriptor_streams(asn1_NOVALUE, []) -> + asn1_NOVALUE; +merge_indAudMediaDescriptor_streams(Stream, []) + when is_record(Stream, 'IndAudStreamParms') -> + {oneStream, Stream}; +merge_indAudMediaDescriptor_streams(asn1_NOVALUE, MStreams) -> + {multiStream, lists:reverse(MStreams)}; +merge_indAudMediaDescriptor_streams(Stream, MStreams) -> + return_error(0, + {invalid_indAudMediaDescriptor_streams, {Stream, MStreams}}). + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_indAudMediaDescriptor,1}]}). +-endif. +merge_indAudMediaDescriptor(Vals) -> + merge_indAudMediaDescriptor(Vals, asn1_NOVALUE, asn1_NOVALUE, []). + +merge_indAudMediaDescriptor([], TSD, OneStream, MultiStreams) -> + Streams = merge_indAudMediaDescriptor_streams(OneStream, MultiStreams), + #'IndAudMediaDescriptor'{termStateDescr = TSD, + streams = Streams}; + +merge_indAudMediaDescriptor([{termStateDescr, H}|T], asn1_NOVALUE, OS, MS) -> + merge_indAudMediaDescriptor(T, H, OS, MS); +merge_indAudMediaDescriptor([{streamDescr, Val}|T], TSD, asn1_NOVALUE, MS) -> + merge_indAudMediaDescriptor(T, TSD, asn1_NOVALUE, [Val|MS]); +merge_indAudMediaDescriptor([{streamParm, Val}|T], TSD, asn1_NOVALUE, []) -> + merge_indAudMediaDescriptor(T, TSD, Val, []); +merge_indAudMediaDescriptor(Vals, TSD, OneStream, MultiStream) -> + return_error(0, {invalid_indAudMediaDescriptor, + {Vals, TSD, OneStream, MultiStream}}). + + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_indAudLocalControlDescriptor,1}]}). +-endif. +merge_indAudLocalControlDescriptor(Parms) -> + do_merge_indAudLocalControlDescriptor(Parms, + #'IndAudLocalControlDescriptor'{}). + +do_merge_indAudLocalControlDescriptor([Parm | Parms], Desc) -> + case Parm of + modeToken when Desc#'IndAudLocalControlDescriptor'.streamMode =:= asn1_NOVALUE -> + Desc2 = Desc#'IndAudLocalControlDescriptor'{streamMode = 'NULL'}, + do_merge_indAudLocalControlDescriptor(Parms, Desc2); + reservedGroupToken when Desc#'IndAudLocalControlDescriptor'.reserveGroup =:= asn1_NOVALUE -> + Desc2 = Desc#'IndAudLocalControlDescriptor'{reserveGroup = 'NULL'}, + do_merge_indAudLocalControlDescriptor(Parms, Desc2); + reservedValueToken when Desc#'IndAudLocalControlDescriptor'.reserveValue =:= asn1_NOVALUE -> + Desc2 = Desc#'IndAudLocalControlDescriptor'{reserveValue = 'NULL'}, + do_merge_indAudLocalControlDescriptor(Parms, Desc2); + {pkgdName, Val} when Desc#'IndAudLocalControlDescriptor'.propertyParms =:= asn1_NOVALUE -> + PropParms = [#'IndAudPropertyParm'{name = Val}], + Desc2 = Desc#'IndAudLocalControlDescriptor'{propertyParms = PropParms}, + do_merge_indAudLocalControlDescriptor(Parms, Desc2); + {pkgdName, Val} when is_list(Desc#'IndAudLocalControlDescriptor'.propertyParms) -> + PropParms = Desc#'IndAudLocalControlDescriptor'.propertyParms, + PropParms2 = [#'IndAudPropertyParm'{name = Val} | PropParms], + Desc2 = Desc#'IndAudLocalControlDescriptor'{propertyParms = PropParms2}, + do_merge_indAudLocalControlDescriptor(Parms, Desc2) + end; +do_merge_indAudLocalControlDescriptor([], Desc) -> + case Desc#'IndAudLocalControlDescriptor'.propertyParms of + [_ | _] = PropParms -> % List has more then one element + PropParms2= lists:reverse(PropParms), + Desc#'IndAudLocalControlDescriptor'{propertyParms = PropParms2}; + _ -> + Desc + end. + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_indAudLocalParm,1}]}). +-endif. +ensure_indAudLocalParm(Token) -> + case Token of + {safeToken, _Line, "mode"} -> modeToken; + {safeToken, _Line, "mo"} -> modeToken; + {safeToken, _Line, "reservedgroup"} -> reservedGroupToken; + {safeToken, _Line, "rg"} -> reservedGroupToken; + {safeToken, _Line, "reservedvalue"} -> reservedValueToken; + {safeToken, _Line, "rv"} -> reservedValueToken; + PkgdName -> {pkgdName, + ensure_pkgdName(PkgdName)} + end. + +merge_indAudTerminationStateDescriptor({pkgdName, Val}) -> + PropParm = #'IndAudPropertyParm'{name = Val}, + #'IndAudTerminationStateDescriptor'{propertyParms = [PropParm]}; +merge_indAudTerminationStateDescriptor(serviceStatesToken) -> + #'IndAudTerminationStateDescriptor'{serviceState = 'NULL'}; +merge_indAudTerminationStateDescriptor(bufferToken) -> + #'IndAudTerminationStateDescriptor'{eventBufferControl = 'NULL'}. + + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_indAudEventBufferDescriptor,2}]}). +-endif. +merge_indAudEventBufferDescriptor(EventName, SpecParams) -> + IAEBD = #'IndAudEventBufferDescriptor'{eventName = EventName}, + do_merge_indAudEventBufferDescriptor(SpecParams, IAEBD). + +do_merge_indAudEventBufferDescriptor(asn1_NOVALUE, IAEBD) -> + IAEBD; +do_merge_indAudEventBufferDescriptor({streamID, StreamID}, IAEBD) -> + IAEBD#'IndAudEventBufferDescriptor'{streamID = StreamID}; +do_merge_indAudEventBufferDescriptor({eventParameterName, _Name} = EPN, + IAEBD) -> + %% BUGBUG BUGBUG BUGBUG + %% This is an ugly hack to allow the eventParamName which only + %% exists in the text encoding... + IAEBD#'IndAudEventBufferDescriptor'{streamID = EPN}. + + +ensure_indAudSignalListParm(SIG) when is_record(SIG, 'Signal') -> + ensure_indAudSignal(SIG). + +ensure_indAudSignal(#'Signal'{signalName = SignalName, + streamID = asn1_NOVALUE, + sigType = asn1_NOVALUE, + duration = asn1_NOVALUE, + notifyCompletion = asn1_NOVALUE, + keepActive = asn1_NOVALUE, + sigParList = []}) -> + #'IndAudSignal'{signalName = SignalName}. + + +ensure_IADMD({_TokenTag, _Line, + #'DigitMapDescriptor'{digitMapName = Name, + digitMapValue = asn1_NOVALUE}}) -> + #'IndAudDigitMapDescriptor'{digitMapName = Name}. + + +merge_indAudPackagesDescriptor(#'PackagesItem'{packageName = N, + packageVersion = V}) -> + #'IndAudPackagesDescriptor'{packageName = N, + packageVersion = V}. + + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_indAudTerminationStateParm,1}]}). +-endif. +ensure_indAudTerminationStateParm(Token) -> + case Token of + {safeToken, _Line, "servicestates"} -> serviceStatesToken; + {safeToken, _Line, "si"} -> serviceStatesToken; + {safeToken, _Line, "buffer"} -> bufferToken; + {safeToken, _Line, "bf"} -> bufferToken; + PkgdName -> {pkgdName, + ensure_pkgdName(PkgdName)} + end. + + +%% Types modified by v2: + +merge_auditDescriptor([]) -> + #'AuditDescriptor'{}; +merge_auditDescriptor(Tokens) when is_list(Tokens) -> + case lists:keysearch(terminationAudit, 1, Tokens) of + {value, {terminationAudit, TA}} -> + case lists:keydelete(terminationAudit, 1, Tokens) of + [] -> + #'AuditDescriptor'{auditPropertyToken = TA}; + AuditTokens -> + #'AuditDescriptor'{auditToken = AuditTokens, + auditPropertyToken = TA} + end; + false -> + #'AuditDescriptor'{auditToken = Tokens} + end; +merge_auditDescriptor(_) -> + #'AuditDescriptor'{}. + + +%% v2 - end + + + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_ServiceChangeParm,1}]}). +-endif. +merge_ServiceChangeParm(Parms) -> + Required = [serviceChangeReason, serviceChangeMethod], + merge_ServiceChangeParm(Parms, #'ServiceChangeParm'{}, Required). + +merge_ServiceChangeParm([], SCP, []) -> + SCP; + +merge_ServiceChangeParm([], _SCP, Required) -> + exit({missing_required_serviceChangeParm, Required}); + +merge_ServiceChangeParm([{address, Val}|Parms], SCP0, Req) + when (SCP0#'ServiceChangeParm'.serviceChangeAddress == asn1_NOVALUE) andalso + (SCP0#'ServiceChangeParm'.serviceChangeMgcId == asn1_NOVALUE) -> + SCP = SCP0#'ServiceChangeParm'{serviceChangeAddress = Val}, + merge_ServiceChangeParm(Parms, SCP, Req); +merge_ServiceChangeParm([{address, Val}|_Parms], SCP0, _Req) + when SCP0#'ServiceChangeParm'.serviceChangeAddress == asn1_NOVALUE -> + MgcId = SCP0#'ServiceChangeParm'.serviceChangeMgcId, + exit({not_both_address_mgcid_serviceChangeParm, Val, MgcId}); + +merge_ServiceChangeParm([{mgc_id, Val}|Parms], SCP0, Req) + when (SCP0#'ServiceChangeParm'.serviceChangeMgcId == asn1_NOVALUE) andalso + (SCP0#'ServiceChangeParm'.serviceChangeAddress == asn1_NOVALUE) -> + SCP = SCP0#'ServiceChangeParm'{serviceChangeMgcId = Val}, + merge_ServiceChangeParm(Parms, SCP, Req); +merge_ServiceChangeParm([{mgc_id, Val}|_Parms], SCP0, _Req) + when SCP0#'ServiceChangeParm'.serviceChangeMgcId == asn1_NOVALUE -> + Addr = SCP0#'ServiceChangeParm'.serviceChangeAddress, + exit({not_both_address_mgcid_serviceChangeParm, Val, Addr}); + +merge_ServiceChangeParm([{profile, Val}|Parms], SCP0, Req) + when SCP0#'ServiceChangeParm'.serviceChangeProfile == asn1_NOVALUE -> + SCP = SCP0#'ServiceChangeParm'{serviceChangeProfile = Val}, + merge_ServiceChangeParm(Parms, SCP, Req); + +merge_ServiceChangeParm([{version, Val}|Parms], SCP0, Req) + when SCP0#'ServiceChangeParm'.serviceChangeVersion == asn1_NOVALUE -> + SCP = SCP0#'ServiceChangeParm'{serviceChangeVersion = Val}, + merge_ServiceChangeParm(Parms, SCP, Req); + +%% REQUIRED (i.e. no default value) +merge_ServiceChangeParm([{reason, Val}|Parms], SCP0, Req0) + when SCP0#'ServiceChangeParm'.serviceChangeReason == undefined -> + SCP = SCP0#'ServiceChangeParm'{serviceChangeReason = Val}, + Req = lists:delete(serviceChangeReason, Req0), + merge_ServiceChangeParm(Parms, SCP, Req); + +merge_ServiceChangeParm([{delay, Val}|Parms], SCP0, Req) + when SCP0#'ServiceChangeParm'.serviceChangeDelay == asn1_NOVALUE -> + SCP = SCP0#'ServiceChangeParm'{serviceChangeDelay = Val}, + merge_ServiceChangeParm(Parms, SCP, Req); + +%% REQUIRED (i.e. no default value) +merge_ServiceChangeParm([{method, Val}|Parms], SCP0, Req0) + when SCP0#'ServiceChangeParm'.serviceChangeMethod == undefined -> + SCP = SCP0#'ServiceChangeParm'{serviceChangeMethod = Val}, + Req = lists:delete(serviceChangeMethod, Req0), + merge_ServiceChangeParm(Parms, SCP, Req); + +merge_ServiceChangeParm([{time_stamp, Val}|Parms], SCP0, Req) + when SCP0#'ServiceChangeParm'.timeStamp == asn1_NOVALUE -> + SCP = SCP0#'ServiceChangeParm'{timeStamp = Val}, + merge_ServiceChangeParm(Parms, SCP, Req); + +merge_ServiceChangeParm([{extension, _Val}|Parms], SCP0, Req) -> + merge_ServiceChangeParm(Parms, SCP0, Req); + +merge_ServiceChangeParm([{audit_item, Val}|Parms], SCP0, Req) + when (SCP0#'ServiceChangeParm'.serviceChangeInfo == asn1_NOVALUE) andalso + is_atom(Val) -> + SCI = #'AuditDescriptor'{auditToken = [Val]}, + SCP = SCP0#'ServiceChangeParm'{serviceChangeInfo = SCI}, + merge_ServiceChangeParm(Parms, SCP, Req); +merge_ServiceChangeParm([{audit_item, Val}|Parms], SCP0, Req) + when (SCP0#'ServiceChangeParm'.serviceChangeInfo == asn1_NOVALUE) andalso + is_tuple(Val) -> + SCI = #'AuditDescriptor'{auditPropertyToken = [Val]}, + SCP = SCP0#'ServiceChangeParm'{serviceChangeInfo = SCI}, + merge_ServiceChangeParm(Parms, SCP, Req); +merge_ServiceChangeParm([{audit_item, Val}|Parms], SCP0, Req) + when is_record(SCP0#'ServiceChangeParm'.serviceChangeInfo, 'AuditDescriptor') andalso + is_atom(Val) -> + SCI0 = SCP0#'ServiceChangeParm'.serviceChangeInfo, + L = SCI0#'AuditDescriptor'.auditToken, + SCI = SCI0#'AuditDescriptor'{auditToken = [Val|L]}, + SCP = SCP0#'ServiceChangeParm'{serviceChangeInfo = SCI}, + merge_ServiceChangeParm(Parms, SCP, Req); +merge_ServiceChangeParm([{audit_item, Val}|Parms], SCP0, Req) + when is_record(SCP0#'ServiceChangeParm'.serviceChangeInfo, 'AuditDescriptor') andalso + is_tuple(Val) -> + SCI0 = SCP0#'ServiceChangeParm'.serviceChangeInfo, + L = SCI0#'AuditDescriptor'.auditPropertyToken, + SCI = SCI0#'AuditDescriptor'{auditPropertyToken = [Val|L]}, + SCP = SCP0#'ServiceChangeParm'{serviceChangeInfo = SCI}, + merge_ServiceChangeParm(Parms, SCP, Req); + +merge_ServiceChangeParm([incomplete|Parms], SCP0, Req) + when SCP0#'ServiceChangeParm'.serviceChangeIncompleteFlag == asn1_NOVALUE -> + SCP = SCP0#'ServiceChangeParm'{serviceChangeIncompleteFlag = 'NULL'}, + merge_ServiceChangeParm(Parms, SCP, Req); + +merge_ServiceChangeParm([{Tag, Val}|_Parms], SCP, _Req) -> + Val2 = + case Tag of + address -> + SCP#'ServiceChangeParm'.serviceChangeAddress; + mgc_id -> + SCP#'ServiceChangeParm'.serviceChangeMgcId; + profile -> + SCP#'ServiceChangeParm'.serviceChangeProfile; + version -> + SCP#'ServiceChangeParm'.serviceChangeVersion; + reason -> + SCP#'ServiceChangeParm'.serviceChangeReason; + delay -> + SCP#'ServiceChangeParm'.serviceChangeDelay; + method -> + SCP#'ServiceChangeParm'.serviceChangeMethod; + time_stamp -> + SCP#'ServiceChangeParm'.timeStamp; + audit_item -> + SCP#'ServiceChangeParm'.serviceChangeInfo + end, + exit({at_most_once_serviceChangeParm, {Tag, Val, Val2}}); +merge_ServiceChangeParm([Parm|_Parms], SCP, _Req) -> + Parm2 = + case Parm of + incomplete -> + SCP#'ServiceChangeParm'.serviceChangeIncompleteFlag + end, + exit({at_most_once_serviceChangeParm, {Parm, Parm2}}). + + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_ServiceChangeResParm,1}]}). +-endif. +merge_ServiceChangeResParm(Parms) -> + merge_ServiceChangeResParm(Parms, #'ServiceChangeResParm'{}). + +merge_ServiceChangeResParm([], SCRP) -> + SCRP; +merge_ServiceChangeResParm([{address, Val}|Parms], SCRP0) + when (SCRP0#'ServiceChangeResParm'.serviceChangeAddress == asn1_NOVALUE) andalso + (SCRP0#'ServiceChangeResParm'.serviceChangeMgcId == asn1_NOVALUE) -> + SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeAddress = Val}, + merge_ServiceChangeResParm(Parms, SCRP); +merge_ServiceChangeResParm([{address, Val}|_Parms], SCRP0) + when SCRP0#'ServiceChangeResParm'.serviceChangeAddress == asn1_NOVALUE -> + MgcId = SCRP0#'ServiceChangeResParm'.serviceChangeMgcId, + exit({not_both_address_mgcid_servChgReplyParm, Val, MgcId}); + +merge_ServiceChangeResParm([{mgc_id, Val}|Parms], SCRP0) + when (SCRP0#'ServiceChangeResParm'.serviceChangeMgcId == asn1_NOVALUE) andalso + (SCRP0#'ServiceChangeResParm'.serviceChangeAddress == asn1_NOVALUE) -> + SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeMgcId = Val}, + merge_ServiceChangeResParm(Parms, SCRP); +merge_ServiceChangeResParm([{mgc_id, Val}|_Parms], SCRP0) + when SCRP0#'ServiceChangeResParm'.serviceChangeMgcId == asn1_NOVALUE -> + Addr = SCRP0#'ServiceChangeResParm'.serviceChangeAddress, + exit({not_both_address_mgcid_servChgReplyParm, Val, Addr}); + +merge_ServiceChangeResParm([{profile, Val}|Parms], SCRP0) + when SCRP0#'ServiceChangeResParm'.serviceChangeProfile == asn1_NOVALUE -> + SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeProfile = Val}, + merge_ServiceChangeResParm(Parms, SCRP); + +merge_ServiceChangeResParm([{version, Val}|Parms], SCRP0) + when SCRP0#'ServiceChangeResParm'.serviceChangeVersion == asn1_NOVALUE -> + SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeVersion = Val}, + merge_ServiceChangeResParm(Parms, SCRP); + +merge_ServiceChangeResParm([{time_stamp, Val}|Parms], SCRP0) + when SCRP0#'ServiceChangeResParm'.timeStamp == asn1_NOVALUE -> + SCRP = SCRP0#'ServiceChangeResParm'{timeStamp = Val}, + merge_ServiceChangeResParm(Parms, SCRP); + +merge_ServiceChangeResParm([{Tag, Val}|_Parms], SCRP) -> + Val2 = + case Tag of + address -> SCRP#'ServiceChangeResParm'.serviceChangeAddress; + mgc_id -> SCRP#'ServiceChangeResParm'.serviceChangeMgcId; + profile -> SCRP#'ServiceChangeResParm'.serviceChangeProfile; + version -> SCRP#'ServiceChangeResParm'.serviceChangeVersion; + time_stamp -> SCRP#'ServiceChangeResParm'.timeStamp + end, + exit({at_most_once_servChgReplyParm, {Tag, Val, Val2}}). + + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_serviceChangeMethod,1}]}). +-endif. +ensure_serviceChangeMethod(Token) -> + case Token of + {safeToken, _Line, "fl"} -> + failover; + {safeToken, _Line, "failover"} -> + failover; + {safeToken, _Line, "fo"} -> + forced; + {safeToken, _Line, "forced"} -> + forced; + {safeToken, _Line, "gr"} -> + graceful; + {safeToken, _Line, "graceful"} -> + graceful; + {safeToken, _Line, "rs"} -> + restart; + {safeToken, _Line, "restart"} -> + restart; + {safeToken, _Line, "dc"} -> + disconnected; + {safeToken, _Line, "disconnected"} -> + disconnected; + {safeToken, _Line, "ho"} -> + handOff; + {safeToken, _Line, "handoff"} -> + handOff; + {safeToken, Line, Text} -> + return_error(Line, {bad_serviceChangeMethod, Text}) + end. + + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_profile,1}]}). +-endif. +ensure_profile(Token) -> + {_TokenTag, Line, Text} = Token, + case string:tokens(Text, [$/]) of + [Name, Version] -> + Version2 = ensure_version(Version), + #'ServiceChangeProfile'{profileName = Name, version = Version2}; + _ -> + return_error(Line, {bad_profile, Text}) + end. + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_version,1}]}). +-endif. +ensure_version(Version) -> + ensure_uint(Version, 0, 99). + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_signalRequest,2}]}). +-endif. +merge_signalRequest(SignalName, PropertyParms) -> + Sig = #'Signal'{signalName = SignalName}, + SPL = [], + do_merge_signalRequest(Sig, PropertyParms, SPL). + +do_merge_signalRequest(Sig, [H | T], SPL) -> + case H of + {stream, SID} when Sig#'Signal'.streamID == asn1_NOVALUE -> + do_merge_signalRequest(Sig#'Signal'{streamID = SID}, T, SPL); + {signal_type, SigType} when Sig#'Signal'.sigType == asn1_NOVALUE -> + do_merge_signalRequest(Sig#'Signal'{sigType = SigType}, T, SPL); + {duration, Duration} when Sig#'Signal'.duration == asn1_NOVALUE -> + do_merge_signalRequest(Sig#'Signal'{duration = Duration}, T, SPL); + {notify_completion, NC} when Sig#'Signal'.notifyCompletion == asn1_NOVALUE -> + do_merge_signalRequest(Sig#'Signal'{notifyCompletion = NC}, T, SPL); + keepActive when Sig#'Signal'.keepActive == asn1_NOVALUE-> + do_merge_signalRequest(Sig#'Signal'{keepActive = true}, T, SPL); + {other, Name, PP} -> + SP = #'SigParameter'{sigParameterName = Name, + value = PP#'PropertyParm'.value, + extraInfo = PP#'PropertyParm'.extraInfo}, + do_merge_signalRequest(Sig, T, [SP | SPL]); + {direction, Dir} when Sig#'Signal'.direction == asn1_NOVALUE-> + do_merge_signalRequest(Sig#'Signal'{direction = Dir}, T, SPL); + {requestId, RID} when Sig#'Signal'.requestID == asn1_NOVALUE-> + do_merge_signalRequest(Sig#'Signal'{requestID = RID}, T, SPL); + _ -> + return_error(0, {bad_sigParm, H}) + end; +do_merge_signalRequest(Sig, [], SPL) -> + Sig#'Signal'{sigParList = lists:reverse(SPL)} . + + +%% eventStream = StreamToken EQUAL StreamID +%% eventOther = eventParameterName parmValue +-ifdef(megaco_parser_inline). +-compile({inline,[{select_stream_or_other,2}]}). +-endif. +select_stream_or_other(EventParameterName, ParmValue) -> + if + (EventParameterName =:= "st") orelse + (EventParameterName =:= "stream") -> + case ParmValue of + #'PropertyParm'{value = [Value]} -> + {stream, ensure_uint16(Value)}; + _ -> + {stream, ensure_uint16(ParmValue)} + end; + true -> + #'PropertyParm'{value = Value} = ParmValue, + EP = #'EventParameter'{eventParameterName = EventParameterName, + value = Value}, + {other, EP} + end. + +%% select_stream_or_other("st", #'PropertyParm'{value = [Value]}) -> +%% {stream, ensure_uint16(Value)}; +%% select_stream_or_other("st", Value) -> +%% {stream, ensure_uint16(Value)}; +%% select_stream_or_other("stream", #'PropertyParm'{value = [Value]}) -> +%% {stream, ensure_uint16(Value)}; +%% select_stream_or_other("stream", Value) -> +%% {stream, ensure_uint16(Value)}; +%% select_stream_or_other(Name, #'PropertyParm'{value = Value}) -> +%% EP = #'EventParameter'{eventParameterName = Name, +%% value = Value}, +%% {other, EP}. + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_eventDM,1}]}). +-endif. +ensure_eventDM(Token) -> + {_TokenTag, Line, DMD} = Token, + if + is_record(DMD, 'DigitMapDescriptor') -> + Name = DMD#'DigitMapDescriptor'.digitMapName, + Val = DMD#'DigitMapDescriptor'.digitMapValue, + if + (Name =:= asn1_NOVALUE) andalso (Val =/= asn1_NOVALUE) -> + {'DigitMapValue', Start, Short, Long, Duration, Body} = Val, + DMV = #'DigitMapValue'{startTimer = Start, + shortTimer = Short, + longTimer = Long, + digitMapBody = Body, + durationTimer = Duration}, + {eventDM, {digitMapValue, DMV}}; + (Name =/= asn1_NOVALUE) andalso (Val =:= asn1_NOVALUE) -> + {eventDM, {digitMapName, Name}}; + true -> + return_error(Line, {bad_eventDM, DMD}) + end; + true -> + return_error(Line, {bad_eventDM, DMD}) + end. + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_DMD,1}]}). +-endif. +ensure_DMD(Token) -> + {_TokenTag, Line, DMD} = Token, + if + is_record(DMD, 'DigitMapDescriptor') -> + Val2 = + case DMD#'DigitMapDescriptor'.digitMapValue of + %% Note that the values of the digitMapBody and + %% durationTimers are swapped by the scanner + %% (this is done because of a problem in the flex scanner). + #'DigitMapValue'{startTimer = asn1_NOVALUE, + shortTimer = asn1_NOVALUE, + longTimer = asn1_NOVALUE, + durationTimer = [], + digitMapBody = asn1_NOVALUE} -> + asn1_NOVALUE; + #'DigitMapValue'{durationTimer = Body, + digitMapBody = Duration} = DMV -> + %% Convert to version 1 DigitMapValue + DMV#'DigitMapValue'{digitMapBody = Body, + durationTimer = Duration}; + Other -> + Other + end, + DMD#'DigitMapDescriptor'{digitMapValue = Val2}; + true -> + return_error(Line, {bad_DigitMapDescriptor, DMD}) + end. + + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_observed_event,3}]}). +-endif. +merge_observed_event(ObservedEvents, EventName, TimeStamp) -> + StreamId = asn1_NOVALUE, + EPL = [], + do_merge_observed_event(ObservedEvents, EventName, TimeStamp, StreamId, EPL). + +do_merge_observed_event([{stream, StreamID} | T], EventName, TimeStamp, asn1_NOVALUE, EPL) -> + do_merge_observed_event(T, EventName, TimeStamp, StreamID, EPL); +do_merge_observed_event([{other, PP} | T], EventName, TimeStamp, StreamID, EPL) -> + do_merge_observed_event(T, EventName, TimeStamp, StreamID, [PP | EPL]); +do_merge_observed_event([], EventName, TimeStamp, StreamID, EPL) -> + #'ObservedEvent'{eventName = EventName, + timeNotation = TimeStamp, + streamID = StreamID, + eventParList = lists:reverse(EPL)}. + +merge_eventSpec(OE) + when is_record(OE, 'ObservedEvent') andalso + (OE#'ObservedEvent'.timeNotation == asn1_NOVALUE) -> + #'EventSpec'{eventName = OE#'ObservedEvent'.eventName, + streamID = OE#'ObservedEvent'.streamID, + eventParList = OE#'ObservedEvent'.eventParList}; +merge_eventSpec(OE) -> + return_error(0, {bad_event_spec, OE}). + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_eventParameters,1}]}). +-endif. +merge_eventParameters(Params) -> + StreamId = asn1_NOVALUE, + EPL = [], + RA = #'RequestedActions'{}, + HasA = no, + do_merge_eventParameters(Params, StreamId, EPL, RA, HasA) . + +do_merge_eventParameters([H | T], StreamId, EPL, RA, HasA) -> + case H of + keepActive when RA#'RequestedActions'.keepActive =:= asn1_NOVALUE -> + RA2 = RA#'RequestedActions'{keepActive = true}, + do_merge_eventParameters(T, StreamId, EPL, RA2, yes); + {embed, SD, SED} when RA#'RequestedActions'.signalsDescriptor =:= asn1_NOVALUE -> + RA2 = RA#'RequestedActions'{signalsDescriptor = SD, + secondEvent = SED}, + do_merge_eventParameters(T, StreamId, EPL, RA2, yes); + {eventDM, DM} when RA#'RequestedActions'.eventDM =:= asn1_NOVALUE -> + RA2 = RA#'RequestedActions'{eventDM = DM}, + do_merge_eventParameters(T, StreamId, EPL, RA2, yes); + {stream, NewStreamId} when StreamId =:= asn1_NOVALUE -> + do_merge_eventParameters(T, NewStreamId, EPL, RA, HasA); + {other, PP} when is_record(PP, 'PropertyParm') -> + EP = #'EventParameter'{eventParameterName = PP#'PropertyParm'.name, + value = PP#'PropertyParm'.value, + extraInfo = PP#'PropertyParm'.extraInfo}, + do_merge_eventParameters(T, StreamId, [EP | EPL], RA, HasA); + {other, EP} when is_record(EP, 'EventParameter') -> + do_merge_eventParameters(T, StreamId, [EP | EPL], RA, HasA); + _ -> + return_error(0, {bad_eventParameter, H}) + end; +do_merge_eventParameters([], StreamId, EPL, RA, yes) -> + #'RequestedEvent'{streamID = StreamId, + eventAction = RA, + evParList = lists:reverse(EPL)}; +do_merge_eventParameters([], StreamId, EPL, _RA, no) -> + #'RequestedEvent'{streamID = StreamId, + eventAction = asn1_NOVALUE, + evParList = lists:reverse(EPL)}. + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_secondEventParameters,1}]}). +-endif. +merge_secondEventParameters(Params) -> + StreamId = asn1_NOVALUE, + EPL = [], + SRA = #'SecondRequestedActions'{}, + HasA = no, + do_merge_secondEventParameters(Params, StreamId, EPL, SRA, HasA) . + +do_merge_secondEventParameters([H | T], StreamId, EPL, SRA, HasA) -> + case H of + keepActive when SRA#'SecondRequestedActions'.keepActive =:= asn1_NOVALUE -> + SRA2 = SRA#'SecondRequestedActions'{keepActive = true}, + do_merge_secondEventParameters(T, StreamId, EPL, SRA2, yes); + {second_embed, SD} when SRA#'SecondRequestedActions'.signalsDescriptor =:= asn1_NOVALUE -> + SRA2 = SRA#'SecondRequestedActions'{signalsDescriptor = SD}, + do_merge_secondEventParameters(T, StreamId, EPL, SRA2, yes); + {eventDM, DM} when SRA#'SecondRequestedActions'.eventDM =:= asn1_NOVALUE -> + SRA2 = SRA#'SecondRequestedActions'{eventDM = DM}, + do_merge_secondEventParameters(T, StreamId, EPL, SRA2, yes); + {stream, NewStreamId} when StreamId =:= asn1_NOVALUE -> + do_merge_secondEventParameters(T, NewStreamId, EPL, SRA, HasA); + {other, PP} when is_record(PP, 'PropertyParm') -> + EP = #'EventParameter'{eventParameterName = PP#'PropertyParm'.name, + value = PP#'PropertyParm'.value, + extraInfo = PP#'PropertyParm'.extraInfo}, + do_merge_secondEventParameters(T, StreamId, [EP | EPL], SRA, HasA); + {other, EP} when is_record(EP, 'EventParameter') -> + do_merge_secondEventParameters(T, StreamId, [EP | EPL], SRA, HasA); + _ -> + return_error(0, {bad_secondEventParameter, H}) + end; +do_merge_secondEventParameters([], StreamId, EPL, SRA, yes) -> + #'SecondRequestedEvent'{streamID = StreamId, + eventAction = SRA, + evParList = lists:reverse(EPL)}; +do_merge_secondEventParameters([], StreamId, EPL, _SRA, no) -> + #'SecondRequestedEvent'{streamID = StreamId, + eventAction = asn1_NOVALUE, + evParList = lists:reverse(EPL)}. + +%% terminationID = "ROOT" / pathName / "$" / "*" +%% Total length of pathName must not exceed 64 chars. +%% pathName = ["*"] NAME *("/" / "*"/ ALPHA / DIGIT /"_" / "$" ) +%% ["@" pathDomainName ] +%% ABNF allows two or more consecutive "." although it is meaningless +%% in a path domain name. +%% pathDomainName = (ALPHA / DIGIT / "*" ) +%% *63(ALPHA / DIGIT / "-" / "*" / ".") +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_terminationID,1}]}). +-endif. +ensure_terminationID(Token) -> + {safeToken, _Line, LowerText} = Token, + %% terminationID = "ROOT" / pathName / "$" / "*" + decode_term_id(LowerText, false, [], []). + +decode_term_id([H | T], Wild, Id, Component) -> + case H of + $/ -> decode_term_id(T, Wild, [lists:reverse(Component) | Id], []); + $* -> decode_term_id(T, true, Id, [?megaco_all | Component]); + $$ -> decode_term_id(T, true, Id, [?megaco_choose | Component]); + _ -> decode_term_id(T, Wild, Id, [H | Component]) + end; +decode_term_id([], Wild, Id, Component) -> + Id2 = [lists:reverse(Component) | Id], + #megaco_term_id{contains_wildcards = Wild, id = lists:reverse(Id2)}. + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_pathName,1}]}). +-endif. +ensure_pathName(Token) -> + {_TokenTag, _Line, Text} = Token, + Text. %% BUGBUG: ensure values + +%% TimeStamp = Date "T" Time ; per ISO 8601:1988 +%% Date = 8(DIGIT) ; Date = yyyymmdd +%% Time = 8(DIGIT) ; Time = hhmmssss +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_timeStamp,1}]}). +-endif. +ensure_timeStamp(Token) -> + {'TimeStampToken', Line, Text} = Token, + case string:tokens(Text, [$T, $t]) of + [Date, Time] -> + #'TimeNotation'{date = Date, time = Time}; + _ -> + return_error(Line, {bad_timeStamp, Text}) + end. + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_transactionID,1}]}). +-endif. +ensure_transactionID(TransId) -> + ensure_uint32(TransId). + +%% transactionAck = transactionID / (transactionID "-" transactionID) +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_transactionAck,1}]}). +-endif. +ensure_transactionAck(Tokens) -> + {safeToken, _Line, Text} = Tokens, + ensure_transactionAck2(Text, []). + +ensure_transactionAck2([], Acc) -> + Id = lists:reverse(Acc), + #'TransactionAck'{firstAck = ensure_transactionID(Id)}; +ensure_transactionAck2([$- | Id2], Acc) -> + Id1 = lists:reverse(Acc), + #'TransactionAck'{firstAck = ensure_transactionID(Id1), + lastAck = ensure_transactionID(Id2)}; +ensure_transactionAck2([H|T], Acc) -> + ensure_transactionAck2(T, [H|Acc]). + + +merge_context_request(asn1_NOVALUE, Prop) -> + merge_context_request(#'ContextRequest'{}, Prop); + +merge_context_request(#'ContextRequest'{priority = asn1_NOVALUE} = CR, + {priority, Int}) -> + CR#'ContextRequest'{priority = Int}; + +merge_context_request(#'ContextRequest'{emergency = asn1_NOVALUE} = CR, + {emergency, Bool}) -> + CR#'ContextRequest'{emergency = Bool}; + +merge_context_request(#'ContextRequest'{topologyReq = asn1_NOVALUE} = CR, + {topology, Desc}) -> + CR#'ContextRequest'{topologyReq = Desc}; + +merge_context_request(#'ContextRequest'{iepscallind = asn1_NOVALUE} = CR, + {iepsCallind, Ind}) -> + CR#'ContextRequest'{iepscallind = Ind}; + +merge_context_request(#'ContextRequest'{contextProp = asn1_NOVALUE} = CR, + {contextProp, Props}) -> + CR#'ContextRequest'{contextProp = Props}; + +%% The parser handles this, but we drop it in this version +%% merge_context_request(#'ContextRequest'{contextList = asn1_NOVALUE} = CR, +%% {contextList, _IDs}) -> +%% CR#'ContextRequest'{contextList = IDs}; +merge_context_request(CR, {contextList, _IDs}) -> + CR; + +merge_context_request(CR, {Tag, Val}) -> + Val2 = + case Tag of + priority -> CR#'ContextRequest'.priority; + emergency -> CR#'ContextRequest'.emergency; + topology -> CR#'ContextRequest'.topologyReq; + iepsCallind -> CR#'ContextRequest'.iepscallind; + contextProp -> CR#'ContextRequest'.contextProp%% ; + %% contextList -> CR#'ContextRequest'.contextList + end, + exit({at_most_once_contextProperty, {Tag, Val, Val2}}). + + +merge_context_attr_audit_request(CAAR, []) -> + CAAR; +merge_context_attr_audit_request(CAAR, [H|T]) -> + case H of + priorityAudit when CAAR#'ContextAttrAuditRequest'.priority == asn1_NOVALUE -> + CAAR2 = CAAR#'ContextAttrAuditRequest'{priority = 'NULL'}, + merge_context_attr_audit_request(CAAR2, T); + + emergencyAudit when CAAR#'ContextAttrAuditRequest'.emergency == asn1_NOVALUE -> + CAAR2 = CAAR#'ContextAttrAuditRequest'{emergency = 'NULL'}, + merge_context_attr_audit_request(CAAR2, T); + + topologyAudit when CAAR#'ContextAttrAuditRequest'.topology == asn1_NOVALUE -> + CAAR2 = CAAR#'ContextAttrAuditRequest'{topology = 'NULL'}, + merge_context_attr_audit_request(CAAR2, T); + + iepsCallind when CAAR#'ContextAttrAuditRequest'.iepscallind == asn1_NOVALUE -> + CAAR2 = CAAR#'ContextAttrAuditRequest'{iepscallind = 'NULL'}, + merge_context_attr_audit_request(CAAR2, T); + + {prop, Name} when CAAR#'ContextAttrAuditRequest'.contextPropAud == asn1_NOVALUE -> + CPA = [#'IndAudPropertyParm'{name = Name}], + CAAR2 = CAAR#'ContextAttrAuditRequest'{contextPropAud = CPA}, + merge_context_attr_audit_request(CAAR2, T); + + {prop, Name} -> + CPA = CAAR#'ContextAttrAuditRequest'.contextPropAud, + CPA2 = [#'IndAudPropertyParm'{name = Name}|CPA], + CAAR2 = CAAR#'ContextAttrAuditRequest'{contextPropAud = CPA2}, + merge_context_attr_audit_request(CAAR2, T) + + end. + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_action_request,2}]}). +-endif. +merge_action_request(CtxId, Items) -> + do_merge_action_request(Items, [], asn1_NOVALUE, asn1_NOVALUE, CtxId). + +do_merge_action_request([H|T], CmdReqs, CtxReq, CtxAuditReq, CtxId) -> + case H of + {commandRequest, CmdReq} -> + do_merge_action_request(T, [CmdReq|CmdReqs], + CtxReq, CtxAuditReq, CtxId); + + {contextProp, ContextProp} -> + do_merge_action_request(T, CmdReqs, + merge_context_request(CtxReq, ContextProp), + CtxAuditReq, CtxId); + + {contextAudit, ContextAuditReq} when CtxAuditReq == asn1_NOVALUE -> + do_merge_action_request(T, CmdReqs, + CtxReq, ContextAuditReq, CtxId) + end; +do_merge_action_request([], CmdReqs, CtxReq, CtxAuditReq, CtxId) -> + #'ActionRequest'{contextId = CtxId, + contextRequest = strip_ContextRequest(CtxReq), + contextAttrAuditReq = strip_ContextAttrAuditRequest(CtxAuditReq), + commandRequests = lists:reverse(CmdReqs)}. + + +%% OTP-5085: +%% In order to solve a problem in the parser, the error descriptor +%% has been put last in the non-empty commandReplyList, if it is not +%% asn1_NOVALUE +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_action_reply,1}]}). +-endif. +merge_action_reply(Items) -> + do_merge_action_reply(Items, asn1_NOVALUE, asn1_NOVALUE, []). + +do_merge_action_reply([], Err, Ctx, Cmds) -> + #'ActionReply'{errorDescriptor = Err, + contextReply = strip_ContextRequest(Ctx), + commandReply = lists:reverse(Cmds)}; +do_merge_action_reply([H|T], Err0, CR, Cmds) -> + case H of + {error, Err1} when Err0 == asn1_NOVALUE -> + do_merge_action_reply(T, Err1, CR, Cmds); + {command, Cmd} -> + do_merge_action_reply(T, Err0, CR, [Cmd | Cmds]); + {context, CtxProp} -> + do_merge_action_reply(T, Err0, + merge_context_request(CR, CtxProp), Cmds) + end. + +strip_ContextRequest(#'ContextRequest'{priority = asn1_NOVALUE, + emergency = asn1_NOVALUE, + topologyReq = asn1_NOVALUE, + iepscallind = asn1_NOVALUE, + contextProp = asn1_NOVALUE}) -> + asn1_NOVALUE; +strip_ContextRequest(#'ContextRequest'{priority = asn1_NOVALUE, + emergency = asn1_NOVALUE, + topologyReq = asn1_NOVALUE, + iepscallind = asn1_NOVALUE, + contextProp = []}) -> + asn1_NOVALUE; +strip_ContextRequest(asn1_NOVALUE) -> + asn1_NOVALUE; +strip_ContextRequest(R) -> + R. + +strip_ContextAttrAuditRequest(asn1_NOVALUE) -> + asn1_NOVALUE; +strip_ContextAttrAuditRequest( + #'ContextAttrAuditRequest'{priority = asn1_NOVALUE, + emergency = asn1_NOVALUE, + topology = asn1_NOVALUE, + iepscallind = asn1_NOVALUE, + contextPropAud = asn1_NOVALUE}) -> + asn1_NOVALUE; +strip_ContextAttrAuditRequest( + #'ContextAttrAuditRequest'{priority = asn1_NOVALUE, + emergency = asn1_NOVALUE, + topology = asn1_NOVALUE, + iepscallind = asn1_NOVALUE, + contextPropAud = []}) -> + asn1_NOVALUE; +strip_ContextAttrAuditRequest(R) -> + R. + +merge_AmmRequest_descriptors([], Acc) -> + lists:reverse(Acc); +merge_AmmRequest_descriptors([{_, deprecated}|Descs], Acc) -> + merge_AmmRequest_descriptors(Descs, Acc); +merge_AmmRequest_descriptors([Desc|Descs], Acc) -> + merge_AmmRequest_descriptors(Descs, [Desc|Acc]). + +make_commandRequest({CmdTag, {_TokenTag, _Line, Text}}, Cmd) -> + Req = #'CommandRequest'{command = {CmdTag, Cmd}}, + case Text of + [$w, $- | _] -> + Req#'CommandRequest'{wildcardReturn = 'NULL'}; + [$o, $-, $w, $- | _] -> + Req#'CommandRequest'{optional = 'NULL', wildcardReturn = 'NULL'}; + [$o, $- | _] -> + Req#'CommandRequest'{optional = 'NULL'}; + _ -> + Req + end. + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_terminationAudit,1}]}). +-endif. +merge_terminationAudit(AuditReturnParameters) -> + lists:reverse(do_merge_terminationAudit(AuditReturnParameters, [], [])). + +do_merge_terminationAudit([H| T], ARPs, AuditItems) -> + case H of + {auditReturnItem, AuditItem} -> + do_merge_terminationAudit(T, ARPs, [AuditItem | AuditItems]); + AuditReturnParameter -> + do_merge_terminationAudit(T, [AuditReturnParameter | ARPs], AuditItems) + end; +do_merge_terminationAudit([], AuditReturnParameters, []) -> + AuditReturnParameters; +do_merge_terminationAudit([], AuditReturnParameters, AuditItems) -> + AuditDescriptor = #'AuditDescriptor'{auditToken = AuditItems}, + AuditReturnParameter = {emptyDescriptors, AuditDescriptor}, + [AuditReturnParameter | AuditReturnParameters]. + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_mediaDescriptor,1}]}). +-endif. +merge_mediaDescriptor(MediaParms) -> + do_merge_mediaDescriptor(MediaParms, asn1_NOVALUE, [], []). + +do_merge_mediaDescriptor([H | T], TS, One, Multi) -> + case H of + {streamParm, Parm} when Multi =:= [] -> + do_merge_mediaDescriptor(T, TS, [Parm | One], Multi); + {streamDescriptor, Desc} when One =:= [] -> + do_merge_mediaDescriptor(T, TS, One, [Desc | Multi]); + {termState, TS2} when TS =:= asn1_NOVALUE -> + do_merge_mediaDescriptor(T, TS2, One, Multi); + _ -> + return_error(0, {bad_merge_mediaDescriptor, [H, TS, One, Multi]}) + end; +do_merge_mediaDescriptor([], TS, One, Multi) -> + if + (One =:= []) -> + if (Multi =:= []) -> + #'MediaDescriptor'{streams = asn1_NOVALUE, + termStateDescr = TS}; + true -> % (Multi =/= []) + Streams = {multiStream, lists:reverse(Multi)}, + #'MediaDescriptor'{streams = Streams, + termStateDescr = TS} + end; + true -> % (One =/= []) + if + (Multi =:= []) -> + Streams = {oneStream, merge_streamParms(One)}, + #'MediaDescriptor'{streams = Streams, + termStateDescr = TS}; + true -> % (Multi =/= []) + return_error(0, + {bad_merge_mediaDescriptor, [TS, One, Multi]}) + end + end. + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_streamParms,1}]}). +-endif. +merge_streamParms(TaggedStreamParms) -> + SP = #'StreamParms'{}, + do_merge_streamParms(TaggedStreamParms, SP). + +do_merge_streamParms([{Tag, D} | T] = All, SP) -> + case Tag of + local when SP#'StreamParms'.localDescriptor =:= asn1_NOVALUE -> + do_merge_streamParms(T, SP#'StreamParms'{localDescriptor = D}); + remote when SP#'StreamParms'.remoteDescriptor =:= asn1_NOVALUE -> + do_merge_streamParms(T, SP#'StreamParms'{remoteDescriptor = D}); + control -> + LCD = + case SP#'StreamParms'.localControlDescriptor of + asn1_NOVALUE -> + #'LocalControlDescriptor'{propertyParms = []}; + PrevLCD -> + PrevLCD + end, + LCD2 = do_merge_control_streamParms(D, LCD), + do_merge_streamParms(T, SP#'StreamParms'{localControlDescriptor = LCD2}); + statistics when SP#'StreamParms'.statisticsDescriptor =:= asn1_NOVALUE -> + do_merge_streamParms(T, SP#'StreamParms'{statisticsDescriptor = D}); + _ -> + return_error(0, {do_merge_streamParms, [All, SP]}) + end; +do_merge_streamParms([], SP) + when is_record(SP#'StreamParms'.localControlDescriptor, + 'LocalControlDescriptor') -> + LCD = SP#'StreamParms'.localControlDescriptor, + PP = LCD#'LocalControlDescriptor'.propertyParms, + LCD2 = LCD#'LocalControlDescriptor'{propertyParms = lists:reverse(PP)}, + SP#'StreamParms'{localControlDescriptor = LCD2}; +do_merge_streamParms([], SP) -> + SP. + + +do_merge_control_streamParms([{SubTag, SD} | T] = All, LCD) -> + case SubTag of + group when LCD#'LocalControlDescriptor'.reserveGroup =:= asn1_NOVALUE -> + LCD2 = LCD#'LocalControlDescriptor'{reserveGroup = SD}, + do_merge_control_streamParms(T, LCD2); + value when LCD#'LocalControlDescriptor'.reserveValue =:= asn1_NOVALUE -> + LCD2 = LCD#'LocalControlDescriptor'{reserveValue = SD}, + do_merge_control_streamParms(T, LCD2); + mode when LCD#'LocalControlDescriptor'.streamMode =:= asn1_NOVALUE -> + LCD2 = LCD#'LocalControlDescriptor'{streamMode = SD}, + do_merge_control_streamParms(T, LCD2); + prop -> + PP = LCD#'LocalControlDescriptor'.propertyParms, + LCD2 = LCD#'LocalControlDescriptor'{propertyParms = [SD | PP]}, + do_merge_control_streamParms(T, LCD2); + _ -> + return_error(0, {do_merge_control_streamParms, [All, LCD]}) + end; +do_merge_control_streamParms([], LCD) -> + LCD. + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_terminationStateDescriptor,1}]}). +-endif. +merge_terminationStateDescriptor(Parms) -> + TSD = #'TerminationStateDescriptor'{propertyParms = []}, + do_merge_terminationStateDescriptor(Parms, TSD). + +do_merge_terminationStateDescriptor([{Tag, Val} | T], TSD) -> + case Tag of + serviceState when TSD#'TerminationStateDescriptor'.serviceState =:= asn1_NOVALUE -> + TSD2 = TSD#'TerminationStateDescriptor'{serviceState = Val}, + do_merge_terminationStateDescriptor(T, TSD2); + eventBufferControl when TSD#'TerminationStateDescriptor'.eventBufferControl =:= asn1_NOVALUE-> + TSD2 = TSD#'TerminationStateDescriptor'{eventBufferControl = Val}, + do_merge_terminationStateDescriptor(T, TSD2); + propertyParm -> + PP = TSD#'TerminationStateDescriptor'.propertyParms, + TSD2 = TSD#'TerminationStateDescriptor'{propertyParms = [Val | PP]}, + do_merge_terminationStateDescriptor(T, TSD2) + end; +do_merge_terminationStateDescriptor([], TSD) -> + PP = TSD#'TerminationStateDescriptor'.propertyParms, + TSD#'TerminationStateDescriptor'{propertyParms = lists:reverse(PP)}. + + +-ifdef(megaco_nscanner_props). + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_prop_groups,1}]}). +-endif. +ensure_prop_groups(Token) -> + {_TokenTag, _Line, Text} = Token, + Group = [], + parse_prop_name(Text, Group). + +parse_prop_name([Char | Rest] = All, Group) -> + if + ?white_space(Char) -> + parse_prop_name(Rest, Group); + ?end_of_line(Char) -> + parse_prop_name(Rest, Group); + true -> + Name = [], + do_parse_prop_name(All, Name, Group) + end; +parse_prop_name([] = All, Group) -> + Name = [], + do_parse_prop_name(All, Name, Group). + +do_parse_prop_name([Char | Rest], Name, Group) + when (Char =:= $=) andalso (Name =/= []) -> + %% Now we have a complete name + if + (Name =:= "v") andalso (Group =/= []) -> + %% v= is a property group delimiter, + %% lets create yet another property group. + NewGroup = [], + [lists:reverse(Group) | parse_prop_value(Rest, Name, NewGroup)]; + true -> + %% Use current property group + parse_prop_value(Rest, Name, Group) + end; +do_parse_prop_name([Char | Rest], Name, Group) -> + case ?classify_char4(Char) of + safe_char_upper -> + do_parse_prop_name(Rest, [Char | Name], Group); + safe_char -> + do_parse_prop_name(Rest, [Char | Name], Group); + _ -> + return_error(0, {bad_prop_name, lists:reverse(Name), Char}) + end; +do_parse_prop_name([], [], []) -> + []; +do_parse_prop_name([], [], Group) -> + [lists:reverse(Group)]; +do_parse_prop_name([], Name, Group) when Name =/= [] -> + %% Assume end of line + Value = [], + PP = make_prop_parm(Name, Value), + Group2 = lists:reverse([PP | Group]), + [Group2]. + +-ifdef(megaco_parser_inline). +-compile({inline,[{parse_prop_value,3}]}). +-endif. +parse_prop_value(Chars, Name, Group) -> + Value = [], + do_parse_prop_value(Chars, Name, Value, Group). + +do_parse_prop_value([Char | Rest], Name, Value, Group) -> + if + ?end_of_line(Char) -> + %% Now we have a complete "name=value" pair + PP = make_prop_parm(Name, Value), + parse_prop_name(Rest, [PP | Group]); + true -> + do_parse_prop_value(Rest, Name, [Char | Value], Group) + end; +do_parse_prop_value([], Name, Value, Group) -> + %% Assume end of line + PP = make_prop_parm(Name, Value), + Group2 = lists:reverse([PP | Group]), + [Group2]. + +-ifdef(megaco_parser_inline). +-compile({inline,[{make_prop_parm,2}]}). +-endif. +make_prop_parm(Name, Value) -> + #'PropertyParm'{name = lists:reverse(Name), + value = [lists:reverse(Value)]}. + +-else. % -ifdef(megaco_nscanner_props). + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_prop_groups,1}]}). +-endif. +ensure_prop_groups(Token) -> + {_TokenTag, _Line, Groups} = Token, + Groups. + +%% do_ensure_prop_groups(Groups) when is_list(Groups) -> +%% [ensure_prop_group(Group) || Group <- Groups]; +%% do_ensure_prop_groups(BadGroups) -> +%% throw({error, {?MODULE, {bad_property_groups, BadGroups}}}). + +%% -ifdef(megaco_parser_inline). +%% -compile({inline,[{ensure_prop_group,1}]}). +%% -endif. +%% ensure_prop_group(Group) when is_list(Group) -> +%% [ensure_prop_parm(PropParm) || PropParm <- Group]; +%% ensure_prop_group(BadGroup) -> +%% throw({error, {?MODULE, {bad_property_group, BadGroup}}}). + +%% -ifdef(megaco_parser_inline). +%% -compile({inline,[{ensure_prop_parm,1}]}). +%% -endif. +%% ensure_prop_parm(#property_parm{name = Name, +%% value = Value}) -> +%% #'PropertyParm'{name = Name, +%% value = Value}; +%% ensure_prop_parm(PP) when is_record(PP, 'PropertyParm') -> +%% PP; +%% ensure_prop_parm(BadPropParm) -> +%% throw({error, {?MODULE, {bad_property_parm, BadPropParm}}}). + +-endif. % -ifdef(megaco_nscanner_props). + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_uint,3}]}). +-endif. +ensure_uint(Token, Min, Max) -> + case Token of + {_TokenTag, Line, Val} when is_integer(Val) -> + ensure_uint(Val, Min, Max, Line); + {_TokenTag, Line, Text} -> + case (catch list_to_integer(Text)) of + {'EXIT', _} -> + return_error(Line, {not_an_integer, Text}); + Val when is_integer(Val) -> + ensure_uint(Val, Min, Max, Line) + end; + Val when is_integer(Val) -> + ensure_uint(Val, Min, Max, 0); + Text -> + case (catch list_to_integer(Text)) of + {'EXIT', _} -> + return_error(0, {not_an_integer, Text}); + Val when is_integer(Val) -> + ensure_uint(Val, Min, Max, 0) + end + end. + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_uint,4}]}). +-endif. +ensure_uint(Val, Min, Max, Line) -> + if + is_integer(Min) andalso (Val >= Min) -> + if + is_integer(Max) andalso (Val =< Max) -> + Val; + Max =:= infinity -> + Val; + true -> + return_error(Line, {too_large_integer, Val, Max}) + end; + true -> + return_error(Line, {too_small_integer, Val, Min}) + end. + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_uint16,1}]}). +-endif. +ensure_uint16(Int) -> + ensure_uint(Int, 0, 65535). + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_uint32,1}]}). +-endif. +ensure_uint32(Int) -> + ensure_uint(Int, 0, 4294967295) . + +%% OTP-4710 +ensure_hex({_TokenTag, _Line, [$0, $x |Chars]}, Min, Max) -> + ensure_uint(length(Chars), Min, Max), + hex_to_int(Chars, []); +ensure_hex({_TokenTag, _Line, [$0, $X |Chars]}, Min, Max) -> + ensure_uint(length(Chars), Min, Max), + hex_to_int(Chars, []); +ensure_hex([$0, $x |Chars], Min, Max) -> + ensure_uint(length(Chars), Min, Max), + hex_to_int(Chars, []); +ensure_hex([$0, $X |Chars], Min, Max) -> + ensure_uint(length(Chars), Min, Max), + hex_to_int(Chars, []). + +%% OTP-4710 +hex_to_int([], Acc) -> + lists:reverse(Acc); +hex_to_int([Char1,Char2|Tail], Acc) -> + Int1 = hchar_to_int(Char1), + Int2 = hchar_to_int(Char2), + Val = Int2 bor (Int1 bsl 4), + hex_to_int(Tail, [Val| Acc]); +hex_to_int([Char], Acc) -> + Int = hchar_to_int(Char), + lists:reverse([Int|Acc]). + +hchar_to_int(Char) when ($0 =< Char) andalso (Char =< $9) -> + Char - $0; +hchar_to_int(Char) when ($A =< Char) andalso (Char =< $F) -> + Char - $A + 10; % OTP-4710 +hchar_to_int(Char) when ($a =< Char) andalso (Char =< $f) -> + Char - $a + 10. % OTP-4710 + +-ifdef(megaco_parser_inline). +-compile({inline,[{value_of,1}]}). +-endif. +value_of(Token) -> + {_TokenTag, _Line, Text} = Token, + Text. + + +%% ------------------------------------------------------------------- + +%% d(F) -> +%% d(F,[]). +%% d(F, A) -> +%% %% d(true, F, A). +%% d(get(dbg), F, A). + +%% d(true, F, A) -> +%% io:format("DBG:~w:" ++ F ++ "~n", [?MODULE | A]); +%% d(_, _, _) -> +%% ok. + diff --git a/lib/megaco/src/text/megaco_text_parser_prev3b.yrl b/lib/megaco/src/text/megaco_text_parser_prev3b.yrl new file mode 100644 index 0000000000..d660fb787a --- /dev/null +++ b/lib/megaco/src/text/megaco_text_parser_prev3b.yrl @@ -0,0 +1,1601 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2005-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: YECC grammar for text encoding of Megaco/H.248 +%%---------------------------------------------------------------------- + +%%---------------------------------------------------------------------- +%% Annex B TEXT ENCODING OF THE PROTOCOL (NORMATIVE) +%% +%% B.1 Coding of wildcards +%% +%% In a text encoding of the protocol, while TerminationIDs are +%% arbitrary, by judicious choice of names, the wildcard character, "*" +%% may be made more useful. When the wildcard character is encountered, +%% it will "match" all TerminationIDs having the same previous and +%% following characters (if appropriate). For example, if there were +%% TerminationIDs of R13/3/1, R13/3/2 and R13/3/3, the TerminationID +%% R13/3/* would match all of them. There are some circumstances where +%% ALL Terminations must be referred to. The TerminationID "*" suffices, +%% and is referred to as ALL. The CHOOSE TerminationID "$" may be used to +%% signal to the MG that it has to create an ephemeral Termination or +%% select an idle physical Termination. +%% +%% B.2 ABNF specification +%% +%% The protocol syntax is presented in ABNF according to RFC2234. The +%% protocol is not case sensitive. Identifiers are not case sensitive. +%% +%% NOTE 1 - This syntax specification does not enforce all restrictions +%% on element inclusions and values. Some additional +%% restrictions are stated in comments and other restrictions +%% appear in the text of this Recommendation. These additional +%% restrictions are part of the protocol even though not +%% enforced by this Recommendation. +%% NOTE 2 - The syntax is context-dependent. For example, "Add" can be +%% the AddToken or a NAME depending on the context in which it +%% occurs. +%% +%% Everything in the ABNF and text encoding is case insensitive. This +%% includes TerminationIDs, digitmap Ids etc. SDP is case sensitive as +%% per RFC 2327. +%% +%%---------------------------------------------------------------------- + +%%---------------------------------------------------------------------- +%% Number of expected shift/reduce warnings +%% This is ugly but... +%%---------------------------------------------------------------------- + +Expect 117. + + +%%---------------------------------------------------------------------- +%% Non-terminals +%%---------------------------------------------------------------------- + +Nonterminals + + actionReply + actionReplyBody + actionReplyList + actionRequest + actionRequestBody + actionRequestItem + actionRequestItems + actionRequestList + alternativeValue + ammParameter + ammParameters + ammRequest + ammRequestBody + ammToken + ammsReply + ammsReplyBody + ammsToken + auditDescriptor + auditDescriptorBody + auditItem + auditItemList + auditOther + auditReply + auditRequest + auditReturnItem + auditReturnParameter + auditReturnParameterList + authenticationHeader + commandReplyList + commandReplys %% v3 + commandRequest + contextAttrDescriptor %% v3 + contextAudit + contextAuditProperties + contextAuditProperty + contextID + contextIdList %% v3 + contextIDs %% v3 +%% contextProperties %% v3 + contextProperty +%% contextPropertyList + contextTerminationAudit + daddr + deviceName + digitMapDescriptor + direction %% v3 + domainAddress + domainName + embedFirst + embedNoSig + embedSig + embedWithSig + errorCode + errorDescriptor + errorText + eventBufferControl + eventBufferControlState + eventBufferDescriptor + eventDM + eventParameter + eventParameterName + eventParameters + eventSpec + eventSpecList + eventStream + eventStreamOrOther + eventsDescriptor + extension + extensionParameter + + iepsValue + + %% v2 - start + indAudauditReturnParameter + indAuddigitMapDescriptor + indAudeventBufferDescriptor + indAudeventSpec + indAudeventSpecParameter + %% indAudeventSpecParameterList + indAudeventsDescriptor + indAudlocalControlDescriptor + indAudlocalParm + indAudlocalParmList + indAudmediaDescriptor + indAudmediaParm + indAudmediaParms %% v3 + %% indAudmediaParmList + indAudpackagesDescriptor + indAudrequestedEvent + indAudsignalsDescriptor + indAudsignalList + %% indAudsignalListParm + indAudsignalParm + %% indAudsignalRequest + indAudstreamDescriptor + indAudstreamParm + indAudstatisticsDescriptor + indAudterminationAudit + indAudterminationAuditList + indAudterminationStateDescriptor + indAudterminationStateParm + %% indAudterminationStateParmList + optIndAudeventSpecParameter + optIndAudsignalParm + %% v2 - end + + indAudcontextAttrDescriptor %% v3 + + localControlDescriptor + localParm + localParmList + mId + mediaDescriptor + mediaParm + mediaParmList + megacoMessage + message + messageBody + modemDescriptor % Deprecated as of Corr 1 + modemType % Deprecated as of Corr 1 + modemTypeList % Deprecated as of Corr 1 + mtpAddress + muxDescriptor + muxType + notificationReason + notificationReasons + notifyReply + notifyReplyBody + notifyRequest + notifyRequestBody + observedEvent + observedEventBody + observedEventParameter + observedEventParameters + % observedEventTimeStamp + observedEvents + observedEventsDescriptor + onOrOff + optAuditDescriptor + optImmAckRequired + optPropertyParms + optSep + packagesDescriptor + packagesItem + packagesItems + %% parmName + parmValue + pathName + pkgdName + portNumber + priority + propertyParm + propertyParms + propertyParmList + requestID + requestedEvent + requestedEventBody + requestedEvents + safeToken + safeToken2 + secondEventParameter + secondEventParameters + secondRequestedEvent + secondRequestedEventBody + secondRequestedEvents + servChgReplyParm + servChgReplyParms + serviceChangeAddress + serviceChangeDelay + serviceChangeDescriptor + serviceChangeMethod + serviceChangeMgcId + serviceChangeParm + serviceChangeParms + serviceChangeProfile + serviceChangeReason + serviceChangeReply + serviceChangeReplyBody + serviceChangeReplyDescriptor + serviceChangeRequest + serviceChangeVersion + serviceState + serviceStates + sigParameter + sigParameters + signalList + signalListId + signalListParm + signalListParms + signalName + signalParm + signalParms + signalRequest + signalsDescriptor + signalType + statisticsDescriptor + statisticsParameter + statisticsParameters + streamDescriptor + streamID + streamModes + streamParm + streamParmList + subtractRequest + terminationA + terminationAudit + terminationB + terminationID + terminationIDList + terminationIDListRepeat + terminationStateDescriptor + terminationStateParm + terminationStateParms + timeStamp + topologyDescriptor + topologyDirection + topologyTriple + topologyTripleList + transactionAck + transactionAckList + transactionID + transactionItem + transactionList + transactionPending + transactionReply + transactionReplyBody + transactionRequest + transactionResponseAck + value + valueList + +. + +%%---------------------------------------------------------------------- +%% Terminals +%%---------------------------------------------------------------------- + +Terminals + + 'AddToken' + 'AuditCapToken' + 'AuditToken' + 'AuditValueToken' + 'AuthToken' + 'BothToken' %% v3 + 'BothwayToken' + 'BriefToken' + 'BufferToken' + 'COLON' + 'COMMA' + 'ContextAttrToken' %% v3 + 'ContextAuditToken' + 'ContextListToken' %% v3 + 'CtxToken' + 'DelayToken' + 'DigitMapToken' + 'DigitMapDescriptorToken' + 'DirectionToken' %% v3 + 'DiscardToken' + 'DisconnectedToken' + 'DurationToken' + 'EQUAL' + 'EmbedToken' + 'EmergencyToken' + 'EmergencyOffToken' + 'ErrorToken' + 'EventBufferToken' + 'EventsToken' + 'ExternalToken' %% v3 + 'FailoverToken' + 'ForcedToken' + 'GREATER' + 'GracefulToken' + 'H221Token' + 'H223Token' + 'H226Token' + 'HandOffToken' + 'IEPSToken' %% v3 + 'ImmAckRequiredToken' + 'InSvcToken' + 'InactiveToken' + 'InternalToken' %% v3 + 'InterruptByEventToken' + 'InterruptByNewSignalsDescrToken' + 'IsolateToken' + 'KeepActiveToken' + 'LBRKT' + 'LESSER' + 'LSBRKT' + 'LocalControlToken' + 'LocalDescriptorToken' + 'LockStepToken' + 'LoopbackToken' + 'MediaToken' + %% 'MegacopToken' + 'MethodToken' + 'MgcIdToken' + 'ModeToken' + 'ModemToken' + 'ModifyToken' + 'MoveToken' + 'MtpAddressToken' + 'MuxToken' + 'NEQUAL' + 'NotifyCompletionToken' + 'NotifyToken' + 'Nx64Token' %% v2 + 'ObservedEventsToken' + 'OffToken' + 'OnToken' + 'OnOffToken' + 'OnewayToken' + 'OtherReasonToken' + 'OutOfSvcToken' + 'PackagesToken' + 'PendingToken' + 'PriorityToken' + 'ProfileToken' + 'QuotedChars' + 'RBRKT' + 'RSBRKT' + 'ReasonToken' + 'RecvonlyToken' + 'RemoteDescriptorToken' + 'ReplyToken' + 'RequestIDToken' %% v3 + 'ReservedGroupToken' + 'ReservedValueToken' + 'ResponseAckToken' + 'RestartToken' + 'SEP' + 'SafeChars' + 'SendonlyToken' + 'SendrecvToken' + 'ServiceChangeAddressToken' + 'ServiceChangeToken' + 'ServiceChangeIncompleteToken' + 'ServiceStatesToken' + 'ServicesToken' + 'SignalListToken' + 'SignalTypeToken' + 'SignalsToken' + 'StatsToken' + 'StreamToken' + 'SubtractToken' + 'SynchISDNToken' + 'TerminationStateToken' + 'TestToken' + 'TimeOutToken' + 'TimeStampToken' + 'TopologyToken' + 'TransToken' + 'V18Token' + 'V22Token' + 'V22bisToken' + 'V32Token' + 'V32bisToken' + 'V34Token' + 'V76Token' + 'V90Token' + 'V91Token' + 'VersionToken' + 'AndAUDITSelectToken' %% OTP-7534: v3-fix + 'EmergencyValueToken' %% OTP-7534: v3-fix + 'IntsigDelayToken' %% OTP-7534: v3-fix + 'IterationToken' %% OTP-7534: v3-fix + 'MessageSegmentToken' %% OTP-7534: v3-fix + 'NeverNotifyToken' %% OTP-7534: v3-fix + 'NotifyImmediateToken' %% OTP-7534: v3-fix + 'NotifyRegulatedToken' %% OTP-7534: v3-fix + 'OnewayBothToken' %% OTP-7534: v3-fix + 'OnewayExternalToken' %% OTP-7534: v3-fix + 'OrAUDITselectToken' %% OTP-7534: v3-fix + 'ResetEventsDescriptorToken' %% OTP-7534: v3-fix + 'SegmentationCompleteToken' %% OTP-7534: v3-fix + endOfMessage + +. + +%%---------------------------------------------------------------------- +%% Root symbol +%%---------------------------------------------------------------------- + +Rootsymbol megacoMessage. + +%%---------------------------------------------------------------------- +%% The grammar +%%---------------------------------------------------------------------- + +%% megacoMessage = LWSP [authenticationHeader SEP ] message +%% authenticationHeader = AuthToken EQUAL SecurityParmIndex COLON +%% SequenceNum COLON AuthData +%% +%% SecurityParmIndex = "0x" 8(HEXDIG) +%% SequenceNum = "0x" 8(HEXDIG) +%% AuthData = "0x" 24*64(HEXDIG) +%% message = MegacopToken SLASH version SEP mId SEP messageBody +%% version = 1*2(DIGIT) . + +megacoMessage -> optSep authenticationHeader message endOfMessage + : #'MegacoMessage'{authHeader = '$2', mess = '$3'} . + +optSep -> 'SEP' : sep . +optSep -> '$empty' : no_sep . + +authenticationHeader -> 'AuthToken' 'EQUAL' safeToken 'COLON' + safeToken 'COLON' safeToken optSep + : ensure_auth_header('$3', '$5', '$7') . +authenticationHeader -> '$empty' : asn1_NOVALUE . + +message -> safeToken mId messageBody : ensure_message('$1', '$2', '$3') . + +messageBody -> errorDescriptor : {messageError, '$1'} . +messageBody -> transactionList : {transactions, '$1'} . + +transactionList -> transactionItem : ['$1'] . +transactionList -> transactionItem transactionList : ['$1' | '$2'] . + +transactionItem -> transactionRequest : {transactionRequest, '$1'} . +transactionItem -> transactionReply : {transactionReply, '$1'}. +transactionItem -> transactionPending : {transactionPending, '$1'} . +transactionItem -> transactionResponseAck : {transactionResponseAck, '$1'} . + +transactionResponseAck -> 'ResponseAckToken' + 'LBRKT' transactionAck transactionAckList 'RBRKT' : ['$3' | '$4'] . + +transactionAckList -> 'COMMA' transactionAck transactionAckList : ['$2' | '$3'] . +transactionAckList -> '$empty' : [] . + +transactionAck -> safeToken : ensure_transactionAck('$1') . + +transactionPending -> 'PendingToken' 'EQUAL' transactionID 'LBRKT' 'RBRKT' + : #'TransactionPending'{transactionId = ensure_transactionID('$3') } . + +transactionRequest -> 'TransToken' + 'LBRKT' actionRequest actionRequestList 'RBRKT' + : #'TransactionRequest'{transactionId = asn1_NOVALUE, + actions = ['$3' | '$4']} . +transactionRequest -> 'TransToken' 'EQUAL' + 'LBRKT' actionRequest actionRequestList 'RBRKT' + : #'TransactionRequest'{transactionId = asn1_NOVALUE, + actions = ['$4' | '$5']} . +transactionRequest -> 'TransToken' 'EQUAL' transactionID + 'LBRKT' actionRequest actionRequestList 'RBRKT' + : #'TransactionRequest'{transactionId = ensure_transactionID('$3'), + actions = ['$5' | '$6']} . + +actionRequestList -> 'COMMA' actionRequest actionRequestList : ['$2' | '$3'] . +actionRequestList -> '$empty' : [] . + +actionRequest -> 'CtxToken' 'EQUAL' contextID + 'LBRKT' actionRequestBody 'RBRKT' + : merge_action_request('$3', '$5') . + +actionRequestBody -> actionRequestItem actionRequestItems : ['$1' | '$2'] . + +actionRequestItems -> 'COMMA' actionRequestItem actionRequestItems + : ['$2' | '$3'] . +actionRequestItems -> '$empty' : [] . + +%% actionRequestItem -> contextProperties : '$1' . +actionRequestItem -> contextProperty : {contextProp, '$1'} . +actionRequestItem -> contextAudit : {contextAudit, '$1'} . +actionRequestItem -> commandRequest : {commandRequest, '$1'} . + +%% contextProperties -> contextProperty contextPropertyList : +%% merge_context_request(#'ContextRequest'{}, ['$1' | '$2']) . + +%% contextPropertyList -> 'COMMA' contextProperty contextPropertyList : ['$2' | '$3' ] . +%% contextPropertyList -> '$empty' : [] . + +%% at-most-once +contextProperty -> topologyDescriptor : {topology, '$1'}. +contextProperty -> priority : {priority, '$1'}. +contextProperty -> 'EmergencyToken' : {emergency, true}. +contextProperty -> 'EmergencyOffToken' : {emergency, false}. +contextProperty -> iepsValue : {iepsCallind, '$1'} . +contextProperty -> contextAttrDescriptor : '$1' . + +contextAttrDescriptor -> 'ContextAttrToken' 'LBRKT' propertyParms 'RBRKT' : + {contextProp, '$3'}. +contextAttrDescriptor -> 'ContextAttrToken' 'LBRKT' contextIdList 'RBRKT' : + {contextList, '$3'}. + +contextIdList -> 'ContextListToken' 'EQUAL' + 'LBRKT' contextID contextIDs 'RBRKT' : ['$4' | '$5'] . + +contextIDs -> 'COMMA' contextID contextIDs : ['$2' | '$3'] . +contextIDs -> '$empty' : [] . + +contextAudit -> 'ContextAuditToken' 'LBRKT' indAudcontextAttrDescriptor 'RBRKT' + : merge_context_attr_audit_request( + #'ContextAttrAuditRequest'{}, '$3') . + +indAudcontextAttrDescriptor -> 'ContextAttrToken' + 'LBRKT' contextAuditProperty + contextAuditProperties 'RBRKT' + : ['$3' | '$4'] . + +contextAuditProperties -> 'COMMA' contextAuditProperty contextAuditProperties + : ['$2' | '$3'] . +contextAuditProperties -> '$empty' : [] . + +%% at-most-once . +contextAuditProperty -> 'TopologyToken' : topologyAudit . +contextAuditProperty -> 'EmergencyToken' : emergencyAudit . +contextAuditProperty -> 'PriorityToken' : priorityAudit . +contextAuditProperty -> 'IEPSToken' : iepsCallind . +contextAuditProperty -> pkgdName : {prop, '$1'} . + +commandRequest -> ammRequest : '$1'. +commandRequest -> subtractRequest : '$1'. +commandRequest -> auditRequest : '$1'. +commandRequest -> notifyRequest : '$1'. +commandRequest -> serviceChangeRequest : '$1'. + +transactionReply -> 'ReplyToken' 'EQUAL' transactionID + 'LBRKT' + optImmAckRequired transactionReplyBody + 'RBRKT' + : #'TransactionReply'{transactionId = '$3', + immAckRequired = '$5', + transactionResult = '$6'} . + +optImmAckRequired -> 'ImmAckRequiredToken' 'COMMA' : 'NULL' . +optImmAckRequired -> '$empty' : asn1_NOVALUE . + +transactionReplyBody -> errorDescriptor : {transactionError, '$1'} . +transactionReplyBody -> actionReply actionReplyList : {actionReplies, ['$1' | '$2']} . + +actionReplyList -> 'COMMA' actionReply actionReplyList : ['$2' | '$3'] . +actionReplyList -> '$empty' : [] . + +actionReply -> 'CtxToken' 'EQUAL' contextID + 'LBRKT' actionReplyBody 'RBRKT' : + setelement(#'ActionReply'.contextId, '$5', '$3') . + +actionReplyBody -> errorDescriptor : + #'ActionReply'{errorDescriptor = '$1'} . +actionReplyBody -> commandReplys commandReplyList : + merge_action_reply(['$1' | '$2']) . + +%% OTP-5085 +%% This ugly thing is to fool the parser. The errorDescriptor does not +%% realy belong here. The merge_action_reply will remove it and put it +%% in it's right place later. +commandReplyList -> 'COMMA' errorDescriptor : + [{error, '$2'}] . +commandReplyList -> 'COMMA' commandReplys commandReplyList : + ['$2' | '$3'] . +commandReplyList -> '$empty' : [] . + +commandReplys -> serviceChangeReply : {command, '$1'} . +commandReplys -> auditReply : {command, '$1'} . +commandReplys -> ammsReply : {command, '$1'} . +commandReplys -> notifyReply : {command, '$1'} . +commandReplys -> contextProperty : {context, '$1'} . + +%Add Move and Modify have the same request parameter +ammRequest -> ammToken 'EQUAL' terminationID ammRequestBody : + Descs = merge_AmmRequest_descriptors('$4', []), + make_commandRequest('$1', + #'AmmRequest'{terminationID = ['$3'], + descriptors = Descs}) . + +ammToken -> 'AddToken' : {addReq, '$1'} . +ammToken -> 'MoveToken' : {moveReq, '$1'} . +ammToken -> 'ModifyToken' : {modReq, '$1'} . + +ammRequestBody -> 'LBRKT' ammParameter ammParameters 'RBRKT' : ['$2' | '$3'] . +ammRequestBody -> '$empty' : [] . + +ammParameters -> 'COMMA' ammParameter ammParameters : ['$2' | '$3'] . +ammParameters -> '$empty' : [] . + +%at-most-once +ammParameter -> mediaDescriptor : {mediaDescriptor, '$1'}. +ammParameter -> modemDescriptor : {modemDescriptor, deprecated}. +ammParameter -> muxDescriptor : {muxDescriptor, '$1'}. +ammParameter -> eventsDescriptor : {eventsDescriptor, '$1'}. +ammParameter -> eventBufferDescriptor : {eventBufferDescriptor, '$1'}. +ammParameter -> signalsDescriptor : {signalsDescriptor, '$1'}. +ammParameter -> digitMapDescriptor : {digitMapDescriptor, '$1'}. +ammParameter -> auditDescriptor : {auditDescriptor, '$1'}. +ammParameter -> statisticsDescriptor : {statisticsDescriptor, '$1'}. + +ammsReply -> ammsToken 'EQUAL' terminationID ammsReplyBody + : {'$1', #'AmmsReply'{terminationID = ['$3'], + terminationAudit = '$4'}} . + +ammsToken -> 'AddToken' : addReply . +ammsToken -> 'MoveToken' : moveReply . +ammsToken -> 'ModifyToken' : modReply . +ammsToken -> 'SubtractToken' : subtractReply . + +ammsReplyBody -> 'LBRKT' terminationAudit 'RBRKT' : '$2' . +ammsReplyBody -> '$empty' : asn1_NOVALUE . + +subtractRequest -> 'SubtractToken' 'EQUAL' terminationID + optAuditDescriptor + : make_commandRequest({subtractReq, '$1'}, + #'SubtractRequest'{terminationID = ['$3'], + auditDescriptor = '$4'}) . + + +optAuditDescriptor -> 'LBRKT' auditDescriptor 'RBRKT' : '$2'. +optAuditDescriptor -> '$empty' : asn1_NOVALUE . + +auditRequest -> 'AuditValueToken' 'EQUAL' + terminationID optAuditDescriptor : + make_commandRequest({auditValueRequest, '$1'}, + #'AuditRequest'{terminationID = '$3', + auditDescriptor = '$4'}) . +auditRequest -> 'AuditCapToken' 'EQUAL' + terminationID optAuditDescriptor : + make_commandRequest({auditCapRequest, '$1'}, + #'AuditRequest'{terminationID = '$3', + auditDescriptor = '$4'}) . + +auditReply -> 'AuditValueToken' 'EQUAL' 'CtxToken' contextTerminationAudit + : {auditValueReply, '$4'} . +auditReply -> 'AuditCapToken' 'EQUAL' 'CtxToken' contextTerminationAudit + : {auditCapReply, '$4'} . +auditReply -> 'AuditValueToken' 'EQUAL' auditOther + : {auditValueReply, '$3'} . +auditReply -> 'AuditCapToken' 'EQUAL' auditOther + : {auditCapReply, '$3'} . + +contextTerminationAudit -> terminationIDList : + {contextAuditResult, '$1'} . +contextTerminationAudit -> 'LBRKT' errorDescriptor 'RBRKT' : + {error, '$2'} . + +auditOther -> terminationID : + {auditResult, + #'AuditResult'{terminationID = '$1', + terminationAuditResult = []}} . +auditOther -> terminationID 'LBRKT' terminationAudit 'RBRKT' : + {auditResult, + #'AuditResult'{terminationID = '$1', + terminationAuditResult = '$3'}} . + + +terminationAudit -> auditReturnParameter auditReturnParameterList : + merge_terminationAudit(['$1' |'$2' ]) . + +auditReturnParameterList -> 'COMMA' auditReturnParameter auditReturnParameterList : ['$2' | '$3'] . +auditReturnParameterList -> '$empty' : [] . + +auditReturnParameter -> mediaDescriptor : {mediaDescriptor, '$1'} . +auditReturnParameter -> modemDescriptor. +auditReturnParameter -> muxDescriptor : {muxDescriptor, '$1'} . +auditReturnParameter -> eventsDescriptor : {eventsDescriptor, '$1'} . +auditReturnParameter -> signalsDescriptor : {signalsDescriptor, '$1'} . +auditReturnParameter -> digitMapDescriptor : {digitMapDescriptor, '$1'} . +auditReturnParameter -> observedEventsDescriptor : {observedEventsDescriptor, '$1'} . +auditReturnParameter -> eventBufferDescriptor : {eventBufferDescriptor, '$1'} . +auditReturnParameter -> statisticsDescriptor : {statisticsDescriptor, '$1'} . +auditReturnParameter -> packagesDescriptor : {packagesDescriptor, '$1'} . +auditReturnParameter -> errorDescriptor : {errorDescriptor, '$1'} . +auditReturnParameter -> auditReturnItem : {auditReturnItem, '$1'} . + +auditDescriptor -> 'AuditToken' 'LBRKT' auditDescriptorBody 'RBRKT' : + merge_auditDescriptor('$3') . + +auditDescriptorBody -> auditItem auditItemList : ['$1' | '$2']. +auditDescriptorBody -> '$empty' : asn1_NOVALUE . + +auditItemList -> 'COMMA' auditItem auditItemList : ['$2' | '$3'] . +auditItemList -> '$empty' : [] . + +%% IGv11 - begin +%% +auditReturnItem -> 'MuxToken' : muxToken . +auditReturnItem -> 'ModemToken' : modemToken . +auditReturnItem -> 'MediaToken' : mediaToken . +auditReturnItem -> 'DigitMapToken' : digitMapToken . +auditReturnItem -> 'StatsToken' : statsToken . +auditReturnItem -> 'ObservedEventsToken' : observedEventsToken . +auditReturnItem -> 'PackagesToken' : packagesToken . + +%% at-most-once, and DigitMapToken and PackagesToken are not allowed +%% in AuditCapabilities command +auditItem -> auditReturnItem : '$1' . +auditItem -> 'SignalsToken' : signalsToken. +auditItem -> 'EventBufferToken' : eventBufferToken. +auditItem -> 'EventsToken' : eventsToken . +auditItem -> indAudterminationAudit : {terminationAudit, '$1'} . % v2 +%% +%% IGv11 - end + + +%% v2 - start +%% +indAudterminationAudit -> indAudauditReturnParameter + indAudterminationAuditList + : ['$1' | '$2'] . + +indAudterminationAuditList -> 'COMMA' indAudauditReturnParameter + indAudterminationAuditList + : ['$2' | '$3'] . +indAudterminationAuditList -> '$empty' : [] . + +indAudauditReturnParameter -> indAudmediaDescriptor + : {indAudMediaDescriptor, '$1'} . +indAudauditReturnParameter -> indAudeventsDescriptor + : {indAudEventsDescriptor, '$1'} . +indAudauditReturnParameter -> indAudsignalsDescriptor + : {indAudSignalsDescriptor, '$1'} . +indAudauditReturnParameter -> indAuddigitMapDescriptor + : {indAudDigitMapDescriptor, '$1'} . +indAudauditReturnParameter -> indAudeventBufferDescriptor + : {indAudEventBufferDescriptor, '$1'} . +indAudauditReturnParameter -> indAudstatisticsDescriptor + : {indAudStatisticsDescriptor, '$1'} . +indAudauditReturnParameter -> indAudpackagesDescriptor + : {indAudPackagesDescriptor, '$1'} . + + +indAudmediaDescriptor -> 'MediaToken' 'LBRKT' + indAudmediaParm indAudmediaParms 'RBRKT' + : merge_indAudMediaDescriptor(['$3'|'$4']) . + +%% at-most-once per item +%% and either streamParm or streamDescriptor but not both +%% + +indAudmediaParm -> indAudstreamParm : {streamParm, '$1'} . +indAudmediaParm -> indAudstreamDescriptor : {streamDescr, '$1'} . +indAudmediaParm -> indAudterminationStateDescriptor : {termStateDescr, '$1'} . + +indAudmediaParms -> 'COMMA' indAudmediaParm indAudmediaParms : ['$2' | '$3'] . +indAudmediaParms -> '$empty' : [] . + +%% at-most-once +indAudstreamParm -> indAudlocalControlDescriptor + : #'IndAudStreamParms'{localControlDescriptor = '$1'} . +indAudstreamParm -> indAudstatisticsDescriptor + : #'IndAudStreamParms'{statisticsDescriptor = '$1'} . + +indAudstreamDescriptor -> 'StreamToken' 'EQUAL' streamID + 'LBRKT' indAudstreamParm 'RBRKT' + : #'IndAudStreamDescriptor'{streamID = '$3', + streamParms = '$5'} . + + +indAudlocalControlDescriptor -> 'LocalControlToken' + 'LBRKT' indAudlocalParm indAudlocalParmList 'RBRKT' : + merge_indAudLocalControlDescriptor(['$3' | '$4']) . + +indAudlocalParmList -> 'COMMA' indAudlocalParm indAudlocalParmList : ['$2' | '$3'] . +indAudlocalParmList -> '$empty' : [] . + +%% at-most-once per item +%% +indAudlocalParm -> safeToken : ensure_indAudLocalParm('$1') . + +indAudterminationStateDescriptor -> 'TerminationStateToken' + 'LBRKT' indAudterminationStateParm 'RBRKT' + : + merge_indAudTerminationStateDescriptor('$3') . + +%% at-most-once per item +%% + +indAudterminationStateParm -> safeToken : + ensure_indAudTerminationStateParm('$1') . + +indAudeventBufferDescriptor -> 'EventBufferToken' + 'LBRKT' indAudeventSpec 'RBRKT' : '$3' . + +indAudeventSpec -> pkgdName optIndAudeventSpecParameter + : merge_indAudEventBufferDescriptor('$1','$2') . + +optIndAudeventSpecParameter -> 'LBRKT' indAudeventSpecParameter 'RBRKT' + : '$2' . +optIndAudeventSpecParameter -> '$empty' : asn1_NOVALUE . + + +indAudeventSpecParameter -> eventStream : {streamID, '$1'} . +indAudeventSpecParameter -> eventParameterName : {eventParameterName, '$1'} . + +indAudeventsDescriptor -> 'EventsToken' 'EQUAL' requestID + 'LBRKT' indAudrequestedEvent 'RBRKT' + : #'IndAudEventsDescriptor'{requestID = '$3', + pkgdName = '$5'} . + +indAudrequestedEvent -> pkgdName : '$1' . + + +indAudsignalsDescriptor -> 'SignalsToken' optIndAudsignalParm : '$2' . + + +optIndAudsignalParm -> 'LBRKT' 'RBRKT' : asn1_NOVALUE . +optIndAudsignalParm -> 'LBRKT' indAudsignalParm 'RBRKT' : '$2' . + +indAudsignalParm -> indAudsignalList : {seqSigList, '$1'} . +indAudsignalParm -> signalRequest : {signal, ensure_indAudSignal('$1')} . + +indAudsignalList -> 'SignalListToken' 'EQUAL' signalListId + 'LBRKT' signalListParm 'RBRKT' : + #'IndAudSeqSigList'{id = ensure_uint16('$3'), + signalList = + ensure_indAudSignalListParm('$5')} . + + +%% The DigitMapDescriptorToken is specially treated by the scanner +indAuddigitMapDescriptor -> 'DigitMapDescriptorToken' : + ensure_IADMD('$1') . + +indAudstatisticsDescriptor -> 'StatsToken' 'LBRKT' pkgdName 'RBRKT' : + #'IndAudStatisticsDescriptor'{statName = '$3'} . + +indAudpackagesDescriptor -> 'PackagesToken' 'LBRKT' packagesItem 'RBRKT' + : merge_indAudPackagesDescriptor('$3') . + +eventStream -> 'StreamToken' 'EQUAL' streamID : '$3' . + + +%% +%% v2 - end + +notifyRequest -> 'NotifyToken' 'EQUAL' terminationID + 'LBRKT' notifyRequestBody 'RBRKT' + : make_commandRequest({notifyReq, '$1'}, + setelement(#'NotifyRequest'.terminationID, '$5', ['$3'])) . + +notifyRequestBody -> observedEventsDescriptor + : #'NotifyRequest'{observedEventsDescriptor = '$1'}. +notifyRequestBody -> errorDescriptor + : #'NotifyRequest'{errorDescriptor = '$1'}. + +notifyReply -> 'NotifyToken' 'EQUAL' terminationID notifyReplyBody + : {notifyReply, + #'NotifyReply'{terminationID = ['$3'], + errorDescriptor = '$4'}} . + +notifyReplyBody -> 'LBRKT' errorDescriptor 'RBRKT' : '$2'. +notifyReplyBody -> '$empty' : asn1_NOVALUE . + +serviceChangeRequest -> 'ServiceChangeToken' 'EQUAL' terminationID + 'LBRKT' serviceChangeDescriptor 'RBRKT' + : make_commandRequest({serviceChangeReq, '$1'}, + #'ServiceChangeRequest'{terminationID = ['$3'], + serviceChangeParms = '$5'}) . + +serviceChangeReply -> 'ServiceChangeToken' 'EQUAL' terminationID serviceChangeReplyBody + : {serviceChangeReply, + #'ServiceChangeReply'{terminationID = ['$3'], + serviceChangeResult = '$4'}} . + +serviceChangeReplyBody -> 'LBRKT' errorDescriptor 'RBRKT' + : {errorDescriptor, '$2'} . +serviceChangeReplyBody -> 'LBRKT' serviceChangeReplyDescriptor 'RBRKT' + : {serviceChangeResParms, '$2'} . +serviceChangeReplyBody -> '$empty' : {serviceChangeResParms, #'ServiceChangeResParm'{}}. + +errorDescriptor -> 'ErrorToken' 'EQUAL' errorCode 'LBRKT' errorText 'RBRKT' + : #'ErrorDescriptor'{errorCode = '$3', + errorText = '$5'} . + +errorCode -> safeToken : ensure_uint('$1', 0, 999) . + +errorText -> 'QuotedChars' : value_of('$1') . +errorText -> '$empty' : asn1_NOVALUE . + +transactionID -> safeToken : ensure_uint32('$1') . + +mId -> domainName : '$1' . +mId -> domainAddress : '$1' . +mId -> optSep mtpAddress optSep : '$2' . +mId -> optSep deviceName optSep : '$2' . + +domainName -> 'LESSER' safeToken 'GREATER' 'COLON' portNumber optSep + : ensure_domainName('$2', '$5') . +domainName -> 'LESSER' safeToken 'GREATER' + : ensure_domainName('$2', asn1_NOVALUE) . + +deviceName -> pathName : {deviceName, '$1'} . + +%% '-' is used for NULL context +contextID -> safeToken : ensure_contextID('$1') . + +domainAddress -> 'LSBRKT' daddr 'RSBRKT' 'COLON' portNumber optSep + : ensure_domainAddress('$2', '$5') . +domainAddress -> 'LSBRKT' daddr 'RSBRKT' + : ensure_domainAddress('$2', asn1_NOVALUE) . + +daddr -> '$empty' : [] . +daddr -> 'COLON' daddr : [colon| '$2'] . +daddr -> safeToken daddr : ['$1'| '$2'] . + + +portNumber -> safeToken : ensure_uint16('$1') . + +mtpAddress -> 'MtpAddressToken' : ensure_mtpAddress('$1') . + +%% terminationIDList -> LBRKT terminationID *(COMMA terminationID) RBRKT . + +terminationIDList -> 'LBRKT' terminationID terminationIDListRepeat 'RBRKT' + : ['$2' | '$3'] . + +terminationIDListRepeat -> 'COMMA' terminationID terminationIDListRepeat + : ['$2'| '$3'] . +terminationIDListRepeat -> '$empty' : [] . + + +pathName -> safeToken : ensure_pathName('$1') . + +terminationID -> safeToken : ensure_terminationID('$1') . + +mediaDescriptor -> 'MediaToken' 'LBRKT' mediaParm mediaParmList 'RBRKT' + : merge_mediaDescriptor(['$3' | '$4']) . + +mediaParmList -> 'COMMA' mediaParm mediaParmList : ['$2' | '$3'] . +mediaParmList -> '$empty' : [] . + + +%% at-most-once per item +%% using either streamParms or streamDescriptors but not both +mediaParm -> streamParm + : {streamParm, '$1'} . +mediaParm -> streamDescriptor + : {streamDescriptor, '$1'} . +mediaParm -> terminationStateDescriptor + : {termState, '$1'} . + +%% at-most-onc . +%% Specially treated by the scanner. +streamParm -> 'LocalDescriptorToken' : + PGs = ensure_prop_groups('$1'), + {local, #'LocalRemoteDescriptor'{propGrps = PGs}} . +streamParm -> 'RemoteDescriptorToken' : + PGs = ensure_prop_groups('$1'), + {remote, #'LocalRemoteDescriptor'{propGrps = PGs}} . +streamParm -> localControlDescriptor : {control, '$1'} . +streamParm -> statisticsDescriptor : {statistics, '$1'} . + +streamDescriptor -> 'StreamToken' 'EQUAL' streamID + 'LBRKT' streamParm streamParmList 'RBRKT' + : #'StreamDescriptor'{streamID = '$3', + streamParms = merge_streamParms(['$5' | '$6'])} . + +streamParmList -> 'COMMA' streamParm streamParmList : ['$2' | '$3'] . +streamParmList -> '$empty' : [] . + +localControlDescriptor -> 'LocalControlToken' 'LBRKT' localParm localParmList 'RBRKT' + : ['$3' | '$4'] . + +localParmList -> 'COMMA' localParm localParmList : ['$2' | '$3'] . +localParmList -> '$empty': [] . + +terminationStateDescriptor -> 'TerminationStateToken' + 'LBRKT' terminationStateParm + terminationStateParms 'RBRKT' + : merge_terminationStateDescriptor(['$3' | '$4']) . + +terminationStateParms -> 'COMMA' terminationStateParm terminationStateParms : ['$2' | '$3'] . +terminationStateParms -> '$empty' : [] . + +%% at-most-once per item except for propertyParm +localParm -> 'ReservedGroupToken' 'EQUAL' onOrOff : {group, '$3'} . +localParm -> 'ReservedValueToken' 'EQUAL' onOrOff : {value, '$3'} . +localParm -> 'ModeToken' 'EQUAL' streamModes : {mode, '$3'} . +localParm -> propertyParm : {prop, '$1'} . + +onOrOff -> 'OnToken' : true . +onOrOff -> 'OffToken' : false . + +%% at-most-once +streamModes -> 'SendonlyToken' : sendOnly . +streamModes -> 'RecvonlyToken' : recvOnly . +streamModes -> 'SendrecvToken' : sendRecv . +streamModes -> 'InactiveToken' : inactive . +streamModes -> 'LoopbackToken' : loopBack . + +propertyParm -> pkgdName parmValue : + setelement(#'PropertyParm'.name, '$2', '$1') . + +parmValue -> 'EQUAL' alternativeValue : + '$2' . + +parmValue -> 'NEQUAL' value : + #'PropertyParm'{value = ['$2'], + extraInfo = {relation, unequalTo}} . +parmValue -> 'LESSER' value : + #'PropertyParm'{value = ['$2'], + extraInfo = {relation, smallerThan}} . +parmValue -> 'GREATER' value : + #'PropertyParm'{value = ['$2'], + extraInfo = {relation, greaterThan}} . + +%% OTP-4013 +%% alternativeValue = ( VALUE / +%% LSBRKT VALUE *(COMMA VALUE) RSBRKT / +%% LSBRKT VALUE COLON VALUE RSBRKT ) / +%% LBRKT VALUE *(COMMA VALUE) RBRKT +alternativeValue -> 'LBRKT' value valueList 'RBRKT' + : #'PropertyParm'{value = ['$2' | '$3'], + extraInfo = {sublist, false}}. % OR + +alternativeValue -> 'LSBRKT' value 'COLON' value 'RSBRKT' + : #'PropertyParm'{value = ['$2', '$4'], + extraInfo = {range, true}}. + +alternativeValue -> 'LSBRKT' value valueList 'RSBRKT' + : #'PropertyParm'{value = ['$2' | '$3'], + extraInfo = {sublist, true}}. % AND + +alternativeValue -> value : + #'PropertyParm'{value = ['$1']} . + +valueList -> 'COMMA' value valueList : ['$2' | '$3'] . +valueList -> '$empty' : [] . + + +eventBufferDescriptor -> 'EventBufferToken' : [] . +eventBufferDescriptor -> 'EventBufferToken' 'LBRKT' eventSpec eventSpecList 'RBRKT' + : ['$3' | '$4'] . + +eventSpecList -> 'COMMA' eventSpec eventSpecList : ['$2' | '$3'] . +eventSpecList -> '$empty' : [] . + +eventSpec -> observedEvent : merge_eventSpec('$1') . + +%% at-most-once per item except for propertyParm +terminationStateParm -> serviceStates : {serviceState, '$1'} . +terminationStateParm -> eventBufferControl : {eventBufferControl, '$1'} . +terminationStateParm -> propertyParm : {propertyParm, '$1'} . + +serviceStates -> 'ServiceStatesToken' 'EQUAL' serviceState : '$3' . + +serviceState -> 'TestToken' : test . +serviceState -> 'OutOfSvcToken' : outOfSvc . +serviceState -> 'InSvcToken' : inSvc . + +eventBufferControl -> 'BufferToken' 'EQUAL' eventBufferControlState : '$3' . + +eventBufferControlState -> 'OffToken' : off . +eventBufferControlState -> 'LockStepToken' : lockStep . + +muxDescriptor -> 'MuxToken' 'EQUAL' muxType terminationIDList : + #'MuxDescriptor'{muxType = '$3', + termList = '$4'} . + +muxType -> safeToken : ensure_muxType('$1') . + +streamID -> safeToken : ensure_streamID('$1') . + +pkgdName -> safeToken : ensure_pkgdName('$1') . + +eventsDescriptor -> 'EventsToken' : + #'EventsDescriptor'{requestID = asn1_NOVALUE, + eventList = []} . +eventsDescriptor -> 'EventsToken' 'EQUAL' requestID + 'LBRKT' requestedEvent requestedEvents 'RBRKT' : + #'EventsDescriptor'{requestID = '$3', + eventList = ['$5' | '$6']} . + +requestedEvents -> 'COMMA' requestedEvent requestedEvents : ['$2' | '$3'] . +requestedEvents -> '$empty' : [] . + +requestedEvent -> pkgdName requestedEventBody : + setelement(#'RequestedEvent'.pkgdName, '$2', '$1') . + +requestedEventBody -> 'LBRKT' eventParameter eventParameters 'RBRKT' : + merge_eventParameters(['$2' | '$3']) . +requestedEventBody -> '$empty' : #'RequestedEvent'{evParList = []} . + +eventParameters -> 'COMMA' eventParameter eventParameters : + ['$2' | '$3'] . +eventParameters -> '$empty' : [] . + +%% at-most-once each of embedOrKeepActive , eventDM or eventStream +eventParameter -> 'KeepActiveToken' : keepActive . +eventParameter -> embedWithSig : '$1'. +eventParameter -> embedNoSig : '$1'. +eventParameter -> eventDM : '$1'. +eventParameter -> eventStreamOrOther : '$1'. + +embedWithSig -> 'EmbedToken' 'LBRKT' signalsDescriptor + 'COMMA' embedFirst 'RBRKT' + : {embed, '$3', '$5'} . +embedWithSig -> 'EmbedToken' 'LBRKT' signalsDescriptor 'RBRKT' + : {embed, '$3', asn1_NOVALUE} . + +embedNoSig -> 'EmbedToken' 'LBRKT' embedFirst 'RBRKT' + : {embed, asn1_NOVALUE, '$3'} . + +embedFirst -> 'EventsToken' : + #'SecondEventsDescriptor'{requestID = asn1_NOVALUE, + eventList = []} . +embedFirst -> 'EventsToken' 'EQUAL' requestID + 'LBRKT' secondRequestedEvent secondRequestedEvents 'RBRKT' : + #'SecondEventsDescriptor'{requestID = '$3', + eventList = ['$5' | '$6']} . + +secondRequestedEvents -> 'COMMA' secondRequestedEvent secondRequestedEvents : ['$2' | '$3'] . +secondRequestedEvents -> '$empty' : [] . + +%% at-most-once of each +secondRequestedEvent -> pkgdName secondRequestedEventBody + : setelement(#'SecondRequestedEvent'.pkgdName, '$2', '$1') . + +secondRequestedEventBody -> 'LBRKT' secondEventParameter secondEventParameters 'RBRKT' + : merge_secondEventParameters(['$2' | '$3']) . +secondRequestedEventBody -> '$empty' : #'SecondRequestedEvent'{evParList = []} . + +secondEventParameters -> 'COMMA' secondEventParameter secondEventParameters : ['$2' | '$3'] . +secondEventParameters -> '$empty' : [] . + +%% at-most-once each of embedOrKeepActive , eventDM or eventStream +secondEventParameter -> 'KeepActiveToken' : keepActive . +secondEventParameter -> embedSig : '$1' . +secondEventParameter -> eventDM : '$1' . +secondEventParameter -> eventStreamOrOther : '$1' . + +embedSig -> 'EmbedToken' 'LBRKT' signalsDescriptor 'RBRKT' + : {second_embed, '$3'} . + +eventStreamOrOther -> eventParameterName parmValue : + select_stream_or_other('$1', '$2') . + +eventParameterName -> safeToken : ensure_NAME('$1') . + +%% The DigitMapDescriptorToken is specially treated by the scanner +eventDM -> 'DigitMapDescriptorToken' : + ensure_eventDM('$1') . + +%% H248S-IG (IGv11) +signalsDescriptor -> 'SignalsToken' 'LBRKT' signalParm signalParms 'RBRKT' : + ['$3' | '$4'] . +signalsDescriptor -> 'SignalsToken' : [] . + +signalParms -> 'COMMA' signalParm signalParms : [ '$2' | '$3'] . +signalParms -> '$empty' : [] . + +signalParm -> signalList : {seqSigList, '$1'} . +signalParm -> signalRequest : {signal, '$1'} . + +signalRequest -> signalName 'LBRKT' sigParameter sigParameters 'RBRKT' + : merge_signalRequest('$1', ['$3' | '$4']). +signalRequest -> signalName : merge_signalRequest('$1', []). + +sigParameters -> 'COMMA' sigParameter sigParameters : ['$2' | '$3'] . +sigParameters -> '$empty' : [] . + +%% sigParameter = sigStream / sigSignalType / sigDuration / sigOther / +%% notifyCompletion / KeepActiveToken / +%% direction / sigRequestID +%% sigStream = StreamToken EQUAL StreamID +%% sigOther = sigParameterName parmValue +%% sigParameterName = NAME +%% sigSignalType = SignalTypeToken EQUAL signalType +%% signalType = (OnOffToken / TimeOutToken / BriefToken) +%% sigDuration = DurationToken EQUAL UINT16 +%% notifyCompletion = NotifyCompletionToken EQUAL (LBRKT +%% notificationReason *(COMMA notificationReason) +%% RBRKT) +%% +%% notificationReason = ( TimeOutToken / InterruptByEventToken / +%% InterruptByNewSignalsDescrToken / +%% OtherReasonToken ) +%% sigDirection = DirectionToken EQUAL direction +%% sigRequestID = RequestIDToken EQUAL RequestID + +sigParameter -> 'StreamToken' 'EQUAL' streamID : + {stream, '$3'}. +sigParameter -> 'SignalTypeToken' 'EQUAL' signalType : + {signal_type, '$3'} . +sigParameter -> 'DurationToken' 'EQUAL' safeToken : + {duration, ensure_uint16('$3')} . +sigParameter -> 'NotifyCompletionToken' 'EQUAL' + 'LBRKT' notificationReason notificationReasons 'RBRKT' : + {notify_completion, ['$4' | '$5']} . +sigParameter -> 'KeepActiveToken' : keepActive . +sigParameter -> 'DirectionToken' 'EQUAL' direction : {direction, '$3'} . +sigParameter -> 'RequestIDToken' 'EQUAL' requestID : {requestId, '$3'} . +sigParameter -> safeToken parmValue : + {other, ensure_NAME('$1'), '$2'}. + +signalType -> 'OnOffToken' : onOff. +signalType -> 'TimeOutToken' : timeOut. +signalType -> 'BriefToken' : brief. + +direction -> 'ExternalToken' : external . +direction -> 'InternalToken' : internal . +direction -> 'BothToken' : both . + +notificationReasons -> 'COMMA' notificationReason notificationReasons : ['$2' | '$3'] . +notificationReasons -> '$empty' : [] . + +notificationReason -> 'TimeOutToken' : onTimeOut . +notificationReason -> 'InterruptByEventToken' : onInterruptByEvent . +notificationReason -> 'InterruptByNewSignalsDescrToken' : onInterruptByNewSignalDescr . +notificationReason -> 'OtherReasonToken' : otherReason . + +signalList -> 'SignalListToken' 'EQUAL' signalListId + 'LBRKT' signalListParm signalListParms 'RBRKT' + : #'SeqSigList'{id = ensure_uint16('$3'), + signalList = ['$5' | '$6']} . + +signalListParms -> 'COMMA' signalListParm signalListParms : + ['$2' | '$3'] . +signalListParms -> '$empty' : [] . + +signalListId -> safeToken : ensure_uint16('$1') . + +%% exactly once signalType, +%% at most once duration and every signal parameter +signalListParm -> signalRequest : '$1'. + +signalName -> pkgdName : '$1'. + +observedEventsDescriptor -> 'ObservedEventsToken' 'EQUAL' requestID + 'LBRKT' observedEvent observedEvents 'RBRKT' + : #'ObservedEventsDescriptor'{requestId = '$3', + observedEventLst = ['$5' | '$6']} . + +observedEvents -> 'COMMA' observedEvent observedEvents : ['$2' | '$3'] . +observedEvents -> '$empty' : [] . + +%%time per event, because it might be buffered + +observedEvent -> timeStamp optSep 'COLON' optSep pkgdName observedEventBody : + merge_observed_event('$6', '$5', '$1') . +observedEvent -> optSep pkgdName observedEventBody : + merge_observed_event('$3', '$2', asn1_NOVALUE) . + +observedEventBody -> 'LBRKT' observedEventParameter + observedEventParameters 'RBRKT' + : ['$2' | '$3'] . +observedEventBody -> '$empty' : [] . + +observedEventParameters -> 'COMMA' observedEventParameter observedEventParameters : ['$2' | '$3'] . +observedEventParameters -> '$empty' : [] . + +%%at-most-once eventStream, every eventParameterName at most once +observedEventParameter -> eventStreamOrOther : '$1' . + +requestID -> safeToken : ensure_requestID('$1') . + +%% Deprecated as of Corr 1 +modemDescriptor -> 'ModemToken' 'EQUAL' modemType optPropertyParms . +modemDescriptor -> 'ModemToken' 'LSBRKT' modemType modemTypeList 'RSBRKT' + optPropertyParms. +modemTypeList -> 'COMMA' modemType modemTypeList. +modemTypeList -> '$empty'. +modemType -> safeToken. + +optPropertyParms -> 'LBRKT' propertyParm propertyParmList 'RBRKT' : + ['$2' | '$3'] . +optPropertyParms -> '$empty' : [] . + +propertyParms -> propertyParm propertyParmList : ['$1' | '$2'] . +propertyParmList -> 'COMMA' propertyParm propertyParmList : ['$2' | '$3'] . +propertyParmList -> '$empty' : [] . + +% parmName -> safeToken : ensure_NAME('$1') . + +%% The DigitMapDescriptorToken is specially treated by the scanner +digitMapDescriptor -> 'DigitMapDescriptorToken' : + ensure_DMD('$1') . + +%% each parameter at-most-once, except auditItem +%% at most one of either serviceChangeAddress or serviceChangeMgcId but +%% not both. serviceChangeMethod and serviceChangeReason are REQUIRED +serviceChangeDescriptor -> 'ServicesToken' + 'LBRKT' serviceChangeParm + serviceChangeParms 'RBRKT' : + merge_ServiceChangeParm(['$3' | '$4']) . + +serviceChangeParms -> 'COMMA' serviceChangeParm serviceChangeParms : + ['$2' | '$3'] . +serviceChangeParms -> '$empty' : [] . + +serviceChangeParm -> serviceChangeMethod : {method, '$1'} . +serviceChangeParm -> serviceChangeReason : {reason, '$1'} . +serviceChangeParm -> serviceChangeDelay : {delay, '$1'} . +serviceChangeParm -> serviceChangeAddress : {address, '$1'} . +serviceChangeParm -> serviceChangeProfile : {profile, '$1'} . +serviceChangeParm -> extension : {extension, '$1'} . +serviceChangeParm -> timeStamp : {time_stamp, '$1'} . +serviceChangeParm -> serviceChangeMgcId : {mgc_id, '$1'} . +serviceChangeParm -> serviceChangeVersion : {version, '$1'} . +serviceChangeParm -> 'ServiceChangeIncompleteToken' : incomplete . % v3 +serviceChangeParm -> auditItem : {audit_item, '$1'} . % v2 + +serviceChangeMethod -> 'MethodToken' 'EQUAL' safeToken : + ensure_serviceChangeMethod('$3') . + +serviceChangeReason -> 'ReasonToken' 'EQUAL' value : ['$3'] . + +serviceChangeDelay -> 'DelayToken' 'EQUAL' safeToken : ensure_uint32('$3'). + +serviceChangeAddress -> 'ServiceChangeAddressToken' 'EQUAL' mId : '$3' . +serviceChangeAddress -> 'ServiceChangeAddressToken' 'EQUAL' portNumber : + {portNumber, '$3'} . + +serviceChangeMgcId -> 'MgcIdToken' 'EQUAL' mId : '$3' . + +serviceChangeProfile -> 'ProfileToken' 'EQUAL' safeToken : ensure_profile('$3'). + +serviceChangeVersion -> 'VersionToken' 'EQUAL' safeToken : ensure_version('$3') . + +extension -> extensionParameter parmValue + : setelement(#'PropertyParm'.name, '$2', '$1') . + +%% at most once. Version is REQUIRED on first ServiceChange response +%% at most of either serviceChangeAddress or serviceChangeMgcId but not both +serviceChangeReplyDescriptor -> 'ServicesToken' + 'LBRKT' servChgReplyParm + servChgReplyParms 'RBRKT' : + merge_ServiceChangeResParm(['$3' | '$4']) . + +servChgReplyParms -> 'COMMA' servChgReplyParm servChgReplyParms : + ['$2' | '$3'] . +servChgReplyParms -> '$empty' : [] . + +servChgReplyParm -> serviceChangeAddress : {address, '$1'} . +servChgReplyParm -> serviceChangeMgcId : {mgc_id, '$1'} . +servChgReplyParm -> serviceChangeProfile : {profile, '$1'} . +servChgReplyParm -> serviceChangeVersion : {version, '$1'} . +servChgReplyParm -> timeStamp : {time_stamp,'$1'} . + +packagesDescriptor -> 'PackagesToken' 'LBRKT' packagesItem + packagesItems 'RBRKT' + : ['$3' | '$4'] . + +packagesItems -> 'COMMA' packagesItem packagesItems : ['$2' | '$3'] . +packagesItems -> '$empty' : [] . + +packagesItem -> safeToken : ensure_packagesItem('$1') . + +timeStamp -> TimeStampToken : ensure_timeStamp('$1') . + +statisticsDescriptor -> 'StatsToken' + 'LBRKT' statisticsParameter + statisticsParameters 'RBRKT' + : ['$3' | '$4'] . + +statisticsParameters -> 'COMMA' statisticsParameter statisticsParameters : ['$2' | '$3'] . +statisticsParameters -> '$empty' : [] . + +%%at-most-once per item +statisticsParameter -> pkgdName + : #'StatisticsParameter'{statName = '$1', + statValue = asn1_NOVALUE} . +statisticsParameter -> pkgdName 'EQUAL' value + : #'StatisticsParameter'{statName = '$1', + statValue = ['$3']} . + +topologyDescriptor -> 'TopologyToken' 'LBRKT' topologyTriple + topologyTripleList 'RBRKT' : ['$3' | '$4'] . + +terminationA -> terminationID : '$1' . + +terminationB -> terminationID : '$1' . + +topologyTriple -> terminationA 'COMMA' + terminationB 'COMMA' + topologyDirection : + #'TopologyRequest'{terminationFrom = '$1', + terminationTo = '$3', + topologyDirection = '$5'} . + +topologyTripleList -> '$empty' : [] . +topologyTripleList -> 'COMMA' topologyTriple topologyTripleList : + ['$2' | '$3'] . + +topologyDirection -> 'BothwayToken' : bothway . +topologyDirection -> 'IsolateToken' : isolate . +topologyDirection -> 'OnewayToken' : oneway . + +iepsValue -> 'IEPSToken' 'EQUAL' onOrOff : '$3' . + +priority -> 'PriorityToken' 'EQUAL' safeToken : ensure_uint16('$3') . + +extensionParameter -> safeToken : ensure_extensionParameter('$1') . + +value -> 'QuotedChars' : ensure_value('$1') . +value -> safeToken : ensure_value('$1'). + +safeToken -> safeToken2 : make_safe_token('$1') . + +safeToken2 -> 'SafeChars' : '$1' . +%% BMK BMK safeToken2 -> 'AddToken' : '$1' . +safeToken2 -> 'AuditToken' : '$1' . +safeToken2 -> 'AuditCapToken' : '$1' . +safeToken2 -> 'AuditValueToken' : '$1' . +safeToken2 -> 'AuthToken' : '$1' . +safeToken2 -> 'BothToken' : '$1' . % v3 +safeToken2 -> 'BothwayToken' : '$1' . +safeToken2 -> 'BriefToken' : '$1' . +safeToken2 -> 'BufferToken' : '$1' . +safeToken2 -> 'CtxToken' : '$1' . +%% v3-safeToken2 -> 'ContextAttrToken' : '$1' . % v3 +safeToken2 -> 'ContextAuditToken' : '$1' . +%% v3-safeToken2 -> 'ContextListToken' : '$1' . % v3 +%% v2-safeToken2 -> 'DigitMapToken' : '$1' . +%% safeToken2 -> 'DigitMapDescriptorToken' : '$1' . +%% v3- +safeToken2 -> 'DirectionToken' : '$1' . % v3 +safeToken2 -> 'DiscardToken' : '$1' . +safeToken2 -> 'DisconnectedToken' : '$1' . +safeToken2 -> 'DelayToken' : '$1' . +safeToken2 -> 'DurationToken' : '$1' . +safeToken2 -> 'EmbedToken' : '$1' . +%% BMK BMK safeToken2 -> 'EmergencyToken' : '$1' . +%% BMK BMK safeToken2 -> 'EmergencyOffToken' : '$1' . +safeToken2 -> 'ErrorToken' : '$1' . +%% v2-safeToken2 -> 'EventBufferToken' : '$1' . +%% v2-safeToken2 -> 'EventsToken' : '$1' . +%% v3-safeToken2 -> 'ExternalToken' : '$1' . % v3 +safeToken2 -> 'FailoverToken' : '$1' . +safeToken2 -> 'ForcedToken' : '$1' . +safeToken2 -> 'GracefulToken' : '$1' . +safeToken2 -> 'H221Token' : '$1' . +safeToken2 -> 'H223Token' : '$1' . +safeToken2 -> 'H226Token' : '$1' . +safeToken2 -> 'HandOffToken' : '$1' . +%% v3-safeToken2 -> 'IEPSToken' : '$1' . % v3 +safeToken2 -> 'ImmAckRequiredToken' : '$1' . +safeToken2 -> 'InactiveToken' : '$1' . +%% v3-safeToken2 -> 'InternalToken' : '$1' . % v3 +safeToken2 -> 'InterruptByEventToken' : '$1' . +safeToken2 -> 'InterruptByNewSignalsDescrToken' : '$1' . +safeToken2 -> 'IsolateToken' : '$1' . +safeToken2 -> 'InSvcToken' : '$1' . +safeToken2 -> 'KeepActiveToken' : '$1' . +%% safeToken2 -> 'LocalToken' : '$1' . +%% safeToken2 -> 'LocalDescriptorToken' : '$1' . +safeToken2 -> 'LocalControlToken' : '$1' . +safeToken2 -> 'LoopbackToken' : '$1' . +safeToken2 -> 'LockStepToken' : '$1' . +%% v2-safeToken2 -> 'MediaToken' : '$1' . +%% safeToken2 -> 'MegacopToken' : '$1' . +safeToken2 -> 'MethodToken' : '$1' . +safeToken2 -> 'MgcIdToken' : '$1' . +safeToken2 -> 'ModeToken' : '$1' . +%% BMK BMK safeToken2 -> 'ModifyToken' : '$1' . +%% v2-safeToken2 -> 'ModemToken' : '$1' . +%% BMK BMK safeToken2 -> 'MoveToken' : '$1' . +%% safeToken2 -> 'MtpToken' : '$1' . +%% safeToken2 -> 'MtpAddressToken' : '$1' . +%% v2-safeToken2 -> 'MuxToken' : '$1' . +safeToken2 -> 'NotifyToken' : '$1' . +safeToken2 -> 'NotifyCompletionToken' : '$1' . +safeToken2 -> 'Nx64Token' : '$1' . +%% v2-safeToken2 -> 'ObservedEventsToken' : '$1' . +safeToken2 -> 'OnewayToken' : '$1' . +safeToken2 -> 'OffToken' : '$1' . +safeToken2 -> 'OnToken' : '$1' . +safeToken2 -> 'OnOffToken' : '$1' . +safeToken2 -> 'OutOfSvcToken' : '$1' . +safeToken2 -> 'OtherReasonToken' : '$1' . +%% v2-safeToken2 -> 'PackagesToken' : '$1' . +safeToken2 -> 'PendingToken' : '$1' . +%% BMK BMK safeToken2 -> 'PriorityToken' : '$1' . +safeToken2 -> 'ProfileToken' : '$1' . +safeToken2 -> 'ReasonToken' : '$1' . +safeToken2 -> 'RecvonlyToken' : '$1' . +safeToken2 -> 'ReplyToken' : '$1' . +%% v3- +safeToken2 -> 'RequestIDToken' : '$1' . % v3 +safeToken2 -> 'ResponseAckToken' : '$1' . +safeToken2 -> 'RestartToken' : '$1' . +%% safeToken2 -> 'RemoteToken' : '$1' . +%% safeToken2 -> 'RemoteDescriptorToken' : '$1' . +safeToken2 -> 'ReservedGroupToken' : '$1' . +safeToken2 -> 'ReservedValueToken' : '$1' . +safeToken2 -> 'SendonlyToken' : '$1' . +safeToken2 -> 'SendrecvToken' : '$1' . +safeToken2 -> 'ServicesToken' : '$1' . +safeToken2 -> 'ServiceStatesToken' : '$1' . +safeToken2 -> 'ServiceChangeToken' : '$1' . +%% v3-safeToken2 -> 'ServiceChangeIncompleteToken' : '$1' . % v3 +safeToken2 -> 'ServiceChangeAddressToken' : '$1' . +safeToken2 -> 'SignalListToken' : '$1' . +%% v2-safeToken2 -> 'SignalsToken' : '$1' . +safeToken2 -> 'SignalTypeToken' : '$1' . +%% v2-safeToken2 -> 'StatsToken' : '$1' . +safeToken2 -> 'StreamToken' : '$1' . +%% BMK safeToken2 -> 'SubtractToken' : '$1' . +safeToken2 -> 'SynchISDNToken' : '$1' . +safeToken2 -> 'TerminationStateToken' : '$1' . +safeToken2 -> 'TestToken' : '$1' . +safeToken2 -> 'TimeOutToken' : '$1' . +%% BMK safeToken2 -> 'TopologyToken' : '$1' . +safeToken2 -> 'TransToken' : '$1' . +safeToken2 -> 'V18Token' : '$1' . +safeToken2 -> 'V22Token' : '$1' . +safeToken2 -> 'V22bisToken' : '$1' . +safeToken2 -> 'V32Token' : '$1' . +safeToken2 -> 'V32bisToken' : '$1' . +safeToken2 -> 'V34Token' : '$1' . +safeToken2 -> 'V76Token' : '$1' . +safeToken2 -> 'V90Token' : '$1' . +safeToken2 -> 'V91Token' : '$1' . +safeToken2 -> 'VersionToken' : '$1' . +%% <OTP-7534> +safeToken2 -> 'AndAUDITSelectToken' : '$1' . % v3 +safeToken2 -> 'EmergencyValueToken' : '$1' . % v3 +safeToken2 -> 'IntsigDelayToken' : '$1' . % v3 +safeToken2 -> 'IterationToken' : '$1' . % v3 +safeToken2 -> 'MessageSegmentToken' : '$1' . % v3 +safeToken2 -> 'NeverNotifyToken' : '$1' . % v3 +safeToken2 -> 'NotifyImmediateToken' : '$1' . % v3 +safeToken2 -> 'NotifyRegulatedToken' : '$1' . % v3 +safeToken2 -> 'OnewayBothToken' : '$1' . % v3 +safeToken2 -> 'OnewayExternalToken' : '$1' . % v3 +safeToken2 -> 'OrAUDITselectToken' : '$1' . % v3 +safeToken2 -> 'ResetEventsDescriptorToken' : '$1' . % v3 +safeToken2 -> 'SegmentationCompleteToken' : '$1' . % v3 +%% </OTP-7534> + +Erlang code. + +%% The following directive is needed for (significantly) faster compilation +%% of the generated .erl file by the HiPE compiler. Please do not remove. +-compile([{hipe,[{regalloc,linear_scan}]}]). + +-include("megaco_text_parser_prev3b.hrl"). + + diff --git a/lib/megaco/src/text/megaco_text_parser_prev3c.hrl b/lib/megaco/src/text/megaco_text_parser_prev3c.hrl new file mode 100644 index 0000000000..ab099e5a24 --- /dev/null +++ b/lib/megaco/src/text/megaco_text_parser_prev3c.hrl @@ -0,0 +1,1980 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2005-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 : Define semantic text parser actions +%%---------------------------------------------------------------------- + + +-include_lib("megaco/include/megaco.hrl"). +-include_lib("megaco/include/megaco_message_prev3c.hrl"). +-include("megaco_text_tokens.hrl"). + +-ifdef(megaco_parser_inline). +-compile({inline,[{make_safe_token,1}]}). +-endif. +make_safe_token(Token) -> + {_TokenTag, Line, Text} = Token, + {safeToken, Line, Text}. + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_value,1}]}). +-endif. +ensure_value(Token) -> + case Token of + {safeToken, _Line, Text} when is_list(Text) -> + Text; % We really should ensure length + {'QuotedChars', _Line, Text} when is_list(Text) -> + Text; % We really should ensure length + Text when is_list(Text) -> + Text % We really should ensure length + end. + +%% NAME = ALPHA *63(ALPHA / DIGIT / "_" ) +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_NAME,1}]}). +-endif. +ensure_NAME(Token) -> + {_TokenTag, _Line, Text} = Token, + Text. %% BUGBUG: ensure length and chars + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_requestID,1}]}). +-endif. +ensure_requestID(Token) -> + case Token of + {safeToken, _Line, "*"} -> + ?megaco_all_request_id; + _ -> + ensure_uint32(Token) + end. + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_streamID,1}]}). +-endif. +ensure_streamID(StreamId) -> + ensure_uint16(StreamId). + +ensure_auth_header(SpiToken, SnToken, AdToken) -> + Spi = ensure_hex(SpiToken, 8, 8), + Sn = ensure_hex(SnToken, 8, 8), + Ad = ensure_hex(AdToken, 24, 64), + #'AuthenticationHeader'{secParmIndex = Spi, seqNum = Sn, ad = Ad}. + +%% The values 0x0, 0xFFFFFFFE and 0xFFFFFFFF are reserved. +%% ContextID = (UINT32 / "*" / "-" / "$") +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_contextID,1}]}). +-endif. +ensure_contextID(Token) -> + {_TokenTag, Line, Text} = Token, + case Text of + "*" -> ?megaco_all_context_id; + "-" -> ?megaco_null_context_id; + "\$" -> ?megaco_choose_context_id; + Int -> + CID = ensure_uint32(Int), + if + (CID =/= 0) andalso + (CID =/= 16#FFFFFFFE) andalso + (CID =/= 16#FFFFFFFF) -> + CID; + true -> + return_error(Line, {bad_ContextID, CID}) + end + end. + +ensure_domainAddress([{_T, _L, _A} = Addr0], Port) -> + Addr = ensure_ip4addr(Addr0), + {ip4Address, #'IP4Address'{address = Addr, portNumber = Port}}; +ensure_domainAddress([colon,colon], Port) -> + Addr = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + {ip6Address, #'IP6Address'{address = Addr, portNumber = Port}}; +ensure_domainAddress(Addr0, Port) -> + Addr = ensure_ip6addr(Addr0), + {ip6Address, #'IP6Address'{address = Addr, portNumber = Port}}. + +split_ip4addr_text([], Acc) -> + [ lists:reverse(Acc) ]; +split_ip4addr_text([$. | Rest], Acc) -> + [ lists:reverse(Acc) | split_ip4addr_text(Rest, []) ]; +split_ip4addr_text([H | T], Acc) -> + split_ip4addr_text(T, [H | Acc]). + + +ensure_ip4addr(Token) -> + {_TokenTag, Line, Addr} = Token, + case split_ip4addr_text(Addr, []) of + [T1, T2, T3, T4] -> + %% We optimize by sending only the text part (Addr) of + %% the token to the function. + %% If something is wrong, then we do not get a proper + %% position and therefor we catch and issue the + %% the error again (with the proper line number). + case (catch [ + ensure_uint(T1, 0, 255), + ensure_uint(T2, 0, 255), + ensure_uint(T3, 0, 255), + ensure_uint(T4, 0, 255) + ]) of + A when is_list(A) -> + A; + _ -> + return_error(Line, {bad_IP4address, Addr}) + end; + _ -> + return_error(Line, {bad_IP4address, Addr}) + end. + + +ensure_ip6addr([colon,colon|T]) -> + [H1|T1] = lists:reverse(T), + case do_ensure_ip6addr(T1, true, [ensure_hex4_or_ip4addr(H1)], 1) of + {true, A} when length(A) == 16 -> + A; + {true, B} when length(B) < 16 -> + lists:duplicate(16 - length(B), 0) ++ B; + {true, C} -> + throw({error, {?MODULE, {bad_mid_ip6addr_length, C}}}) + end; +ensure_ip6addr(L) -> + case lists:reverse(L) of + [colon, colon| T] -> + case do_ensure_ip6addr(T, true, [], 1) of + {true, A} when length(A) == 16 -> + A; + {true, B} when length(B) < 16 -> + B ++ lists:duplicate(16 - length(B), 0); + {true, C} -> + throw({error, {?MODULE, {bad_mid_ip6addr_length, C}}}) + end; + [H|L1] -> % A (last element) could be an ip4 address + case do_ensure_ip6addr(L1,false,[ensure_hex4_or_ip4addr(H)],1) of + {false, A} when length(A) == 16 -> + A; + %% allow a pad even if the address is full (i.e. 16) + {true, B} when length(B) =< 17 -> + do_ensure_ip6addr_padding(B, 0); + {Pad, C} -> + throw({error, {?MODULE, {bad_mid_ip6addr_length, Pad, C}}}) + end + + end. + + +do_ensure_ip6addr([], Pad, Acc, _) -> + {Pad, lists:flatten(Acc)}; +do_ensure_ip6addr([colon,colon|T], false, Acc, Line) -> + do_ensure_ip6addr(T, true, [pad|Acc], Line); +do_ensure_ip6addr([colon,colon|T], true, Acc, Line) -> + return_error(Line, {bad_mid_duplicate_padding, T, Acc}); +do_ensure_ip6addr([colon|T], Pad, Acc, Line) -> + do_ensure_ip6addr(T, Pad, Acc, Line); +do_ensure_ip6addr([{_, Line, _} = A|T], Pad, Acc, _) -> + do_ensure_ip6addr(T, Pad, [ensure_hex4(A)|Acc], Line). + +do_ensure_ip6addr_padding([], _) -> + []; +do_ensure_ip6addr_padding([pad|T], N) -> + lists:duplicate(16 - (N + length(T)), 0) ++ T; +do_ensure_ip6addr_padding([H|T], N) -> + [H|do_ensure_ip6addr_padding(T, N+1)]. + +ensure_hex4_or_ip4addr({TokenTag, Line, Addr} = V) -> + case string:tokens(Addr, [$.]) of + [T1, T2, T3, T4] -> + A1 = ensure_uint({TokenTag, Line, T1}, 0, 255), + A2 = ensure_uint({TokenTag, Line, T2}, 0, 255), + A3 = ensure_uint({TokenTag, Line, T3}, 0, 255), + A4 = ensure_uint({TokenTag, Line, T4}, 0, 255), + [A1, A2, A3, A4]; + _ -> + ensure_hex4(V) + %% %% BMK BMK BMK + %% %% Here we should test for hexseq + %% return_error(Line, {bad_IP4address, Addr}) + end. + +ensure_hex4({_TokenTag, Line, Hex4}) + when length(Hex4) =< 4, length(Hex4) > 0 -> + case (catch do_ensure_hex4(Hex4)) of + IL when is_list(IL) andalso (length(IL) =:= 2) -> + IL; + Error -> + return_error(Line, {bad_hex4, Hex4, Error}) + end. + +do_ensure_hex4([_H1, _H2, _H3, _H4] = H) -> + hex_to_int(H, []); +do_ensure_hex4([H2, H3, H4]) -> + hex_to_int([$0, H2, H3, H4], []); +do_ensure_hex4([H3, H4]) -> + hex_to_int([$0, $0, H3, H4], []); +do_ensure_hex4([H4]) -> + hex_to_int([$0, $0, $0, H4], []). + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_domainName,2}]}). +-endif. +ensure_domainName(Token, Port) -> + {_TokenTag, _Line, Name} = Token, + %% BUGBUG: validate name + {domainName, #'DomainName'{name = Name, portNumber = Port}}. + +%% extensionParameter= "X" ("-" / "+") 1*6(ALPHA / DIGIT) +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_extensionParameter,1}]}). +-endif. +ensure_extensionParameter(Token) -> + {_TokenTag, Line, Text} = Token, + case Text of + [X, S | _Chars] -> + if + X /= $X, X /= $x, + S /= $+, S /= $- -> + return_error(Line, {bad_extension_parameter, Text}); + true -> + {extension_parameter, Text} + end; + _ -> + return_error(Line, {bad_extension_parameter, Text}) + end. + +ensure_message(MegacopToken, MID, Body) -> +%% #'ServiceChangeProfile'{profileName = Name, +%% version = Version} = +%% ensure_profile(MegacopToken), +%% case Name of +%% "megaco" -> +%% #'Message'{version = Version, mId = MID, messageBody = Body}; +%% [$!] -> +%% #'Message'{version = Version, mId = MID, messageBody = Body} +%% end. + {_TokenTag, Line, Text} = MegacopToken, + case split_Megacop(Text, []) of + {Name, Version} -> + Version2 = ensure_version(Version), + case Name of + "megaco" -> + #'Message'{version = Version2, + mId = MID, + messageBody = Body}; + [$!] -> + #'Message'{version = Version2, + mId = MID, + messageBody = Body} + end; + _ -> + return_error(Line, {bad_name_or_version, Text}) + end. + +split_Megacop([], _) -> + error; +split_Megacop([$/ | Version], Acc) -> + {lists:reverse(Acc), Version}; +split_Megacop([H | T], Acc) -> + split_Megacop(T, [H | Acc]). + + +%% Corr1: +%% As of corr 1 ModemDescriptor has been deprecated. +%% and since this functon is only used when creating +%% a ModemDescriptor, iit is removed. +%% modemType = (V32bisToken / V22bisToken / V18Token / +%% V22Token / V32Token / V34Token / V90Token / +%% V91Token / SynchISDNToken / extensionParameter) +%% ensure_modemType({_TokenTag, _Line, Text} = Token) -> +%% case Text of +%% "v32b" -> v32bis; +%% "v22b" -> v22bis; +%% "v18" -> v18; +%% "v22" -> v22; +%% "v32" -> v32; +%% "v34" -> v34; +%% "v90" -> v90; +%% "v91" -> v91; +%% "synchisdn" -> synchISDN; +%% "sn" -> synchISDN; +%% [$x | _] -> ensure_extensionParameter(Token) +%% end. + +%% An mtp address is five octets long +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_mtpAddress,1}]}). +-endif. +ensure_mtpAddress(Token) -> + {_TokenTag, _Line, Addr} = Token, + %% BUGBUG: validate address + {mtpAddress, Addr}. + +%% MuxType = ( H221Token / H223Token / H226Token / V76Token / extensionParameter ) +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_muxType,1}]}). +-endif. +ensure_muxType(Token) -> + {_TokenTag, _Line, Text} = Token, + case Text of + "h221" -> h221; + "h223" -> h223; + "h226" -> h226; + "v76" -> v76; + "nx64k" -> nx64k; % v2 + [$x | _] -> ensure_extensionParameter(Token) + end. + +%% packagesItem = NAME "-" UINT16 +%% NAME = ALPHA *63(ALPHA / DIGIT / "_" ) +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_packagesItem,1}]}). +-endif. +ensure_packagesItem(Token) -> + {_TokenTag, Line, Text} = Token, + case split_packagesItem(Text, []) of + {Name, Version} -> + %% As we don't ensure length of the names, there is no point + %% in doing the ensure_NAME thing... + #'PackagesItem'{packageName = Name, + packageVersion = ensure_uint(Version, 0, 99)}; + _ -> + return_error(Line, {bad_PackagesItem, Text}) + end. + +split_packagesItem([], _) -> + error; +split_packagesItem([$- | Version], Acc) -> + {lists:reverse(Acc), Version}; +split_packagesItem([H|T], Acc) -> + split_packagesItem(T, [H|Acc]). + + +%% pkgdName = (PackageName / "*") SLASH (ItemID / "*" ) +%% PackageName = NAME +%% ItemID = NAME +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_pkgdName,1}]}). +-endif. +ensure_pkgdName(Token) -> + {_TokenTag, Line, Text} = Token, + case ensure_pkgdName(Text, []) of + ok -> + %% As we don't really do any checks on the strings + %% (length or content) there is really no point in + %% "ensuring" the name and item part of the + %% package name + %% ensure_name_or_star(Name), + %% ensure_name_or_star(Item), + Text; + _ -> + return_error(Line, {bad_pkgdName, Text}) + end. + +ensure_pkgdName([], _) -> + error; +ensure_pkgdName([$/ | T], Acc) + when ((length(T) > 0) andalso (length(Acc) > 0)) -> + ok; +ensure_pkgdName([H | T], Acc) -> + ensure_pkgdName(T, [H | Acc]). + + +%% -compile({inline,[{ensure_name_or_star,1}]}). +%% ensure_name_or_star(Val) -> +%% %% case Token of +%% %% {_, _, Name} when Name =:= "*" -> +%% %% Name; +%% %% _ -> +%% %% ensure_NAME(Token) +%% %% end. +%% if +%% Val =:= "*" -> +%% Val; +%% true -> +%% %% as we don't really validate the text part of the token(s), +%% %% we can just return the value assuming it to be correct... +%% Val +%% end. + + + +%% v2 - start + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_indAudMediaDescriptor,1}]}). +-endif. +merge_indAudMediaDescriptor(Vals) -> + merge_indAudMediaDescriptor(Vals, #'IndAudMediaDescriptor'{}). + +merge_indAudMediaDescriptor( + [], #'IndAudMediaDescriptor'{streams = Streams1} = D) -> + Streams2 = + case Streams1 of + {multiStream, Descs} -> + {multiStream, lists:reverse(Descs)}; + _ -> + Streams1 + end, + D#'IndAudMediaDescriptor'{streams = Streams2}; +merge_indAudMediaDescriptor([{termStateDescr, Val}|Vals], D) + when D#'IndAudMediaDescriptor'.termStateDescr == asn1_NOVALUE -> + D2 = #'IndAudMediaDescriptor'{termStateDescr = Val}, + merge_indAudMediaDescriptor(Vals, D2); +merge_indAudMediaDescriptor([{streamParm, Val}|Vals], D) + when D#'IndAudMediaDescriptor'.streams == asn1_NOVALUE -> + D2 = #'IndAudMediaDescriptor'{streams = {oneStream, Val}}, + merge_indAudMediaDescriptor(Vals, D2); +merge_indAudMediaDescriptor([{streamDescr, Val}|Vals], D) + when D#'IndAudMediaDescriptor'.streams == asn1_NOVALUE -> + D2 = #'IndAudMediaDescriptor'{streams = {multiStream, [Val]}}, + merge_indAudMediaDescriptor(Vals, D2); +merge_indAudMediaDescriptor([{streamDescr, Val}|Vals], + #'IndAudMediaDescriptor'{streams = Streams1} = D1) -> + Streams2 = + case Streams1 of + {multiStream, Descs} -> + {multiStream, [Val|Descs]}; + _ -> + return_error(0, {bad_IndAudMediaDescriptor_streamDescr, + Val, Streams1}) + end, + D2 = D1#'IndAudMediaDescriptor'{streams = Streams2}, + merge_indAudMediaDescriptor(Vals, D2); +merge_indAudMediaDescriptor([{Tag, Val}|_], D) -> + case Tag of + termStateDescr -> + return_error(0, {bad_IndAudMediaDescriptor_termStateDescr, + Val, D#'IndAudMediaDescriptor'.termStateDescr}); + streamParm -> + return_error(0, {bad_IndAudMediaDescriptor_streamParm, + Val, D#'IndAudMediaDescriptor'.streams}); + streamDescr -> + return_error(0, {bad_IndAudMediaDescriptor_streamDescr, + Val, D#'IndAudMediaDescriptor'.streams}); + _ -> + return_error(0, {bad_IndAudMediaDescriptor_tag, Tag, Val}) + end. + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_indAudLocalControlDescriptor,1}]}). +-endif. +merge_indAudLocalControlDescriptor(Parms) -> + merge_indAudLocalControlDescriptor(Parms, + #'IndAudLocalControlDescriptor'{}, + asn1_NOVALUE). + +merge_indAudLocalControlDescriptor([modeToken | Parms], D, PP) + when (D#'IndAudLocalControlDescriptor'.streamMode == asn1_NOVALUE) andalso + (D#'IndAudLocalControlDescriptor'.streamModeSel == asn1_NOVALUE) -> + D2 = D#'IndAudLocalControlDescriptor'{streamMode = 'NULL'}, + merge_indAudLocalControlDescriptor(Parms, D2, PP); + +merge_indAudLocalControlDescriptor([modeToken | Parms], D, PP) + when (D#'IndAudLocalControlDescriptor'.streamMode == asn1_NOVALUE) -> + merge_indAudLocalControlDescriptor(Parms, D, PP); + +merge_indAudLocalControlDescriptor([{mode, Val} | Parms], D, PP) + when (D#'IndAudLocalControlDescriptor'.streamMode == asn1_NOVALUE) andalso + (D#'IndAudLocalControlDescriptor'.streamModeSel == asn1_NOVALUE) -> + D2 = + case Val of + {equal, Val2} -> + D#'IndAudLocalControlDescriptor'{streamModeSel = Val2}; + {inequal, Val2} -> + D#'IndAudLocalControlDescriptor'{streamModeSel = Val2} + end, + merge_indAudLocalControlDescriptor(Parms, D2, PP); + +merge_indAudLocalControlDescriptor([{mode, Val} | Parms], D, PP) + when (D#'IndAudLocalControlDescriptor'.streamModeSel == asn1_NOVALUE) -> + D2 = + case Val of + {equal, Val2} -> + D#'IndAudLocalControlDescriptor'{streamMode = asn1_NOVALUE, + streamModeSel = Val2}; + {inequal, Val2} -> + D#'IndAudLocalControlDescriptor'{streamMode = asn1_NOVALUE, + streamModeSel = Val2} + end, + merge_indAudLocalControlDescriptor(Parms, D2, PP); + +merge_indAudLocalControlDescriptor([reservedGroupToken | Parms], D, PP) + when D#'IndAudLocalControlDescriptor'.reserveGroup == asn1_NOVALUE -> + D2 = D#'IndAudLocalControlDescriptor'{reserveGroup = 'NULL'}, + merge_indAudLocalControlDescriptor(Parms, D2, PP); + +merge_indAudLocalControlDescriptor([reservedValueToken | Parms], D, PP) + when D#'IndAudLocalControlDescriptor'.reserveValue == asn1_NOVALUE -> + D2 = D#'IndAudLocalControlDescriptor'{reserveValue = 'NULL'}, + merge_indAudLocalControlDescriptor(Parms, D2, PP); + +%% This is really wierd in the standard, so at this point this is the +%% best I can do... BUGBUG BUGBUG BUGBUG +%% +merge_indAudLocalControlDescriptor([{name, Val} | Parms], D, asn1_NOVALUE) -> + PP = #'IndAudPropertyParm'{name = Val}, + merge_indAudLocalControlDescriptor(Parms, D, PP); + +merge_indAudLocalControlDescriptor([{name, Val} | Parms], D, PP) + when D#'IndAudLocalControlDescriptor'.propertyParms == asn1_NOVALUE -> + D2 = D#'IndAudLocalControlDescriptor'{propertyParms = [PP]}, + PP2 = #'IndAudPropertyParm'{name = Val}, + merge_indAudLocalControlDescriptor(Parms, D2, PP2); + +merge_indAudLocalControlDescriptor([{name, Val} | Parms], D, PP) -> + PPs = D#'IndAudLocalControlDescriptor'.propertyParms, + D2 = D#'IndAudLocalControlDescriptor'{propertyParms = [PP|PPs]}, + PP2 = #'IndAudPropertyParm'{name = Val}, + merge_indAudLocalControlDescriptor(Parms, D2, PP2); + +%% BUGBUG BUGBUG I cannot construct a proper IndAudPropertyParm with +%% just the prop (the mandatory name part is missing), so for now I +%% assume that it this has been used, then the name part +%% (pkgdName) must precide it? +merge_indAudLocalControlDescriptor([{prop, Val} | Parms], D, PP) + when (PP =/= asn1_NOVALUE) andalso + (D#'IndAudLocalControlDescriptor'.propertyParms == asn1_NOVALUE) -> + PP2 = PP#'IndAudPropertyParm'{propertyParms = Val}, + D2 = D#'IndAudLocalControlDescriptor'{propertyParms = [PP2]}, + merge_indAudLocalControlDescriptor(Parms, D2, asn1_NOVALUE); + +merge_indAudLocalControlDescriptor([{prop, Val} | Parms], D, PP) + when (PP =/= asn1_NOVALUE) andalso + is_list(D#'IndAudLocalControlDescriptor'.propertyParms) -> + PPs = D#'IndAudLocalControlDescriptor'.propertyParms, + PP2 = PP#'IndAudPropertyParm'{propertyParms = Val}, + D2 = D#'IndAudLocalControlDescriptor'{propertyParms = [PP2|PPs]}, + merge_indAudLocalControlDescriptor(Parms, D2, asn1_NOVALUE); + +merge_indAudLocalControlDescriptor([H | _T], _D, _PP) -> + return_error(0, {bad_indAudLocalControlDescriptor_parm, H}); + +merge_indAudLocalControlDescriptor([], D, asn1_NOVALUE) + when D#'IndAudLocalControlDescriptor'.propertyParms == asn1_NOVALUE -> + D; +merge_indAudLocalControlDescriptor([], D, asn1_NOVALUE) -> + PPs = D#'IndAudLocalControlDescriptor'.propertyParms, + PropParms2 = lists:reverse(PPs), + D#'IndAudLocalControlDescriptor'{propertyParms = PropParms2}; +merge_indAudLocalControlDescriptor([], D, PP) + when D#'IndAudLocalControlDescriptor'.propertyParms == asn1_NOVALUE -> + D#'IndAudLocalControlDescriptor'{propertyParms = [PP]}; +merge_indAudLocalControlDescriptor([], D, PP) -> + PPs = D#'IndAudLocalControlDescriptor'.propertyParms, + PPs2 = lists:reverse([PP|PPs]), + D#'IndAudLocalControlDescriptor'{propertyParms = PPs2}. + + +merge_indAudTerminationStateDescriptor({name, Val}) -> + PropParm = #'IndAudPropertyParm'{name = Val}, + #'IndAudTerminationStateDescriptor'{propertyParms = [PropParm]}; +%% BUGBUG BUGBUG BUGBUG +merge_indAudTerminationStateDescriptor({prop, Val}) -> + exit({incomplete_propertyParm_in_indAudTerminationStateDescriptor, Val}); +merge_indAudTerminationStateDescriptor(serviceStatesToken) -> + #'IndAudTerminationStateDescriptor'{serviceState = 'NULL'}; +merge_indAudTerminationStateDescriptor({serviceStates, {equal, Val}}) -> + #'IndAudTerminationStateDescriptor'{serviceStateSel = Val}; +merge_indAudTerminationStateDescriptor({serviceStates, {inequal, Val}}) -> + #'IndAudTerminationStateDescriptor'{serviceStateSel = Val}; +merge_indAudTerminationStateDescriptor(bufferToken) -> + #'IndAudTerminationStateDescriptor'{eventBufferControl = 'NULL'}. + + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_indAudEventBufferDescriptor,2}]}). +-endif. +merge_indAudEventBufferDescriptor(EventName, SpecParams) -> + IAEBD = #'IndAudEventBufferDescriptor'{eventName = EventName}, + do_merge_indAudEventBufferDescriptor(SpecParams, IAEBD). + +do_merge_indAudEventBufferDescriptor(asn1_NOVALUE, IAEBD) -> + IAEBD; +do_merge_indAudEventBufferDescriptor({streamID, StreamID}, IAEBD) -> + IAEBD#'IndAudEventBufferDescriptor'{streamID = StreamID}; +do_merge_indAudEventBufferDescriptor({eventParameterName, _Name} = EPN, + IAEBD) -> + %% BUGBUG BUGBUG BUGBUG + %% This is an ugly hack to allow the eventParamName which only + %% exists in the text encoding... + IAEBD#'IndAudEventBufferDescriptor'{streamID = EPN}. + + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_indAudSignalListParm,1}]}). +-endif. +ensure_indAudSignalListParm(SIG) -> + if + is_record(SIG, 'Signal') -> + ensure_indAudSignal(SIG); + true -> + return_error(0, {bad_Signal, SIG}) + end. + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_indAudSignal,1}]}). +-endif. +ensure_indAudSignal(Sig) -> + #'Signal'{signalName = SignalName, + streamID = SID, + sigType = asn1_NOVALUE, + duration = asn1_NOVALUE, + notifyCompletion = asn1_NOVALUE, + keepActive = asn1_NOVALUE, + sigParList = [], + requestID = RID} = Sig, + #'IndAudSignal'{signalName = SignalName, + streamID = SID, + signalRequestID = RID}. + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_IADMD,1}]}). +-endif. +ensure_IADMD(Token) -> + {_TokenTag, _Line, DMD} = Token, + #'DigitMapDescriptor'{digitMapName = Name, + digitMapValue = asn1_NOVALUE} = DMD, + #'IndAudDigitMapDescriptor'{digitMapName = Name}. + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_indAudPackagesDescriptor,1}]}). +-endif. +merge_indAudPackagesDescriptor(Pkgs) -> + #'PackagesItem'{packageName = N, + packageVersion = V} = Pkgs, + #'IndAudPackagesDescriptor'{packageName = N, + packageVersion = V}. + + +%% ensure_indAudTerminationStateParm(Token) -> +%% case Token of +%% {safeToken, _Line, "servicestates"} -> serviceStatesToken; +%% {safeToken, _Line, "si"} -> serviceStatesToken; +%% {safeToken, _Line, "buffer"} -> bufferToken; +%% {safeToken, _Line, "bf"} -> bufferToken; +%% PkgdName -> {pkgdName, +%% ensure_pkgdName(PkgdName)} +%% end. + + +%% Types modified by v2: + +merge_auditDescriptor([]) -> + #'AuditDescriptor'{}; +merge_auditDescriptor(Tokens) when is_list(Tokens) -> + case lists:keysearch(terminationAudit, 1, Tokens) of + {value, {terminationAudit, TA}} -> + case lists:keydelete(terminationAudit, 1, Tokens) of + [] -> + #'AuditDescriptor'{auditPropertyToken = TA}; + AuditTokens -> + #'AuditDescriptor'{auditToken = AuditTokens, + auditPropertyToken = TA} + end; + false -> + #'AuditDescriptor'{auditToken = Tokens} + end; +merge_auditDescriptor(_) -> + #'AuditDescriptor'{}. + + +%% v2 - end + + + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_ServiceChangeParm,1}]}). +-endif. +merge_ServiceChangeParm(Parms) -> + Required = [serviceChangeReason, serviceChangeMethod], + merge_ServiceChangeParm(Parms, #'ServiceChangeParm'{}, Required). + +merge_ServiceChangeParm([], SCP, []) -> + SCP; + +merge_ServiceChangeParm([], _SCP, Required) -> + exit({missing_required_serviceChangeParm, Required}); + +merge_ServiceChangeParm([{address, Val}|Parms], SCP0, Req) + when SCP0#'ServiceChangeParm'.serviceChangeAddress == asn1_NOVALUE, + SCP0#'ServiceChangeParm'.serviceChangeMgcId == asn1_NOVALUE -> + SCP = SCP0#'ServiceChangeParm'{serviceChangeAddress = Val}, + merge_ServiceChangeParm(Parms, SCP, Req); +merge_ServiceChangeParm([{address, Val}|_Parms], SCP0, _Req) + when SCP0#'ServiceChangeParm'.serviceChangeAddress == asn1_NOVALUE -> + MgcId = SCP0#'ServiceChangeParm'.serviceChangeMgcId, + exit({not_both_address_mgcid_serviceChangeParm, Val, MgcId}); + +merge_ServiceChangeParm([{mgc_id, Val}|Parms], SCP0, Req) + when SCP0#'ServiceChangeParm'.serviceChangeMgcId == asn1_NOVALUE, + SCP0#'ServiceChangeParm'.serviceChangeAddress == asn1_NOVALUE -> + SCP = SCP0#'ServiceChangeParm'{serviceChangeMgcId = Val}, + merge_ServiceChangeParm(Parms, SCP, Req); +merge_ServiceChangeParm([{mgc_id, Val}|_Parms], SCP0, _Req) + when SCP0#'ServiceChangeParm'.serviceChangeMgcId == asn1_NOVALUE -> + Addr = SCP0#'ServiceChangeParm'.serviceChangeAddress, + exit({not_both_address_mgcid_serviceChangeParm, Val, Addr}); + +merge_ServiceChangeParm([{profile, Val}|Parms], SCP0, Req) + when SCP0#'ServiceChangeParm'.serviceChangeProfile == asn1_NOVALUE -> + SCP = SCP0#'ServiceChangeParm'{serviceChangeProfile = Val}, + merge_ServiceChangeParm(Parms, SCP, Req); + +merge_ServiceChangeParm([{version, Val}|Parms], SCP0, Req) + when SCP0#'ServiceChangeParm'.serviceChangeVersion == asn1_NOVALUE -> + SCP = SCP0#'ServiceChangeParm'{serviceChangeVersion = Val}, + merge_ServiceChangeParm(Parms, SCP, Req); + +%% REQUIRED (i.e. no default value) +merge_ServiceChangeParm([{reason, Val}|Parms], SCP0, Req0) + when SCP0#'ServiceChangeParm'.serviceChangeReason == undefined -> + SCP = SCP0#'ServiceChangeParm'{serviceChangeReason = Val}, + Req = lists:delete(serviceChangeReason, Req0), + merge_ServiceChangeParm(Parms, SCP, Req); + +merge_ServiceChangeParm([{delay, Val}|Parms], SCP0, Req) + when SCP0#'ServiceChangeParm'.serviceChangeDelay == asn1_NOVALUE -> + SCP = SCP0#'ServiceChangeParm'{serviceChangeDelay = Val}, + merge_ServiceChangeParm(Parms, SCP, Req); + +%% REQUIRED (i.e. no default value) +merge_ServiceChangeParm([{method, Val}|Parms], SCP0, Req0) + when SCP0#'ServiceChangeParm'.serviceChangeMethod == undefined -> + SCP = SCP0#'ServiceChangeParm'{serviceChangeMethod = Val}, + Req = lists:delete(serviceChangeMethod, Req0), + merge_ServiceChangeParm(Parms, SCP, Req); + +merge_ServiceChangeParm([{time_stamp, Val}|Parms], SCP0, Req) + when SCP0#'ServiceChangeParm'.timeStamp == asn1_NOVALUE -> + SCP = SCP0#'ServiceChangeParm'{timeStamp = Val}, + merge_ServiceChangeParm(Parms, SCP, Req); + +merge_ServiceChangeParm([{extension, _Val}|Parms], SCP0, Req) -> + merge_ServiceChangeParm(Parms, SCP0, Req); + +merge_ServiceChangeParm([{audit_item, Val}|Parms], SCP0, Req) + when (SCP0#'ServiceChangeParm'.serviceChangeInfo == asn1_NOVALUE) andalso + is_atom(Val) -> + SCI = #'AuditDescriptor'{auditToken = [Val]}, + SCP = SCP0#'ServiceChangeParm'{serviceChangeInfo = SCI}, + merge_ServiceChangeParm(Parms, SCP, Req); +merge_ServiceChangeParm([{audit_item, Val}|Parms], SCP0, Req) + when (SCP0#'ServiceChangeParm'.serviceChangeInfo == asn1_NOVALUE) andalso + is_tuple(Val) -> + SCI = #'AuditDescriptor'{auditPropertyToken = [Val]}, + SCP = SCP0#'ServiceChangeParm'{serviceChangeInfo = SCI}, + merge_ServiceChangeParm(Parms, SCP, Req); +merge_ServiceChangeParm([{audit_item, Val}|Parms], SCP0, Req) + when is_record(SCP0#'ServiceChangeParm'.serviceChangeInfo, 'AuditDescriptor') andalso + is_atom(Val) -> + SCI0 = SCP0#'ServiceChangeParm'.serviceChangeInfo, + L = SCI0#'AuditDescriptor'.auditToken, + SCI = SCI0#'AuditDescriptor'{auditToken = [Val|L]}, + SCP = SCP0#'ServiceChangeParm'{serviceChangeInfo = SCI}, + merge_ServiceChangeParm(Parms, SCP, Req); +merge_ServiceChangeParm([{audit_item, Val}|Parms], SCP0, Req) + when is_record(SCP0#'ServiceChangeParm'.serviceChangeInfo, 'AuditDescriptor') andalso + is_tuple(Val) -> + SCI0 = SCP0#'ServiceChangeParm'.serviceChangeInfo, + L = SCI0#'AuditDescriptor'.auditPropertyToken, + SCI = SCI0#'AuditDescriptor'{auditPropertyToken = [Val|L]}, + SCP = SCP0#'ServiceChangeParm'{serviceChangeInfo = SCI}, + merge_ServiceChangeParm(Parms, SCP, Req); + +merge_ServiceChangeParm([incomplete|Parms], SCP0, Req) + when SCP0#'ServiceChangeParm'.serviceChangeIncompleteFlag == asn1_NOVALUE -> + SCP = SCP0#'ServiceChangeParm'{serviceChangeIncompleteFlag = 'NULL'}, + merge_ServiceChangeParm(Parms, SCP, Req); + +merge_ServiceChangeParm([{Tag, Val}|_Parms], SCP, _Req) -> + Val2 = + case Tag of + address -> + SCP#'ServiceChangeParm'.serviceChangeAddress; + mgc_id -> + SCP#'ServiceChangeParm'.serviceChangeMgcId; + profile -> + SCP#'ServiceChangeParm'.serviceChangeProfile; + version -> + SCP#'ServiceChangeParm'.serviceChangeVersion; + reason -> + SCP#'ServiceChangeParm'.serviceChangeReason; + delay -> + SCP#'ServiceChangeParm'.serviceChangeDelay; + method -> + SCP#'ServiceChangeParm'.serviceChangeMethod; + time_stamp -> + SCP#'ServiceChangeParm'.timeStamp; + audit_item -> + SCP#'ServiceChangeParm'.serviceChangeInfo + end, + exit({at_most_once_serviceChangeParm, {Tag, Val, Val2}}); +merge_ServiceChangeParm([Parm|_Parms], SCP, _Req) -> + Parm2 = + case Parm of + incomplete -> + SCP#'ServiceChangeParm'.serviceChangeIncompleteFlag + end, + exit({at_most_once_serviceChangeParm, {Parm, Parm2}}). + + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_ServiceChangeResParm,1}]}). +-endif. +merge_ServiceChangeResParm(Parms) -> + merge_ServiceChangeResParm(Parms, #'ServiceChangeResParm'{}). + +merge_ServiceChangeResParm([], SCRP) -> + SCRP; +merge_ServiceChangeResParm([{address, Val}|Parms], SCRP0) + when (SCRP0#'ServiceChangeResParm'.serviceChangeAddress == asn1_NOVALUE) andalso + (SCRP0#'ServiceChangeResParm'.serviceChangeMgcId == asn1_NOVALUE) -> + SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeAddress = Val}, + merge_ServiceChangeResParm(Parms, SCRP); +merge_ServiceChangeResParm([{address, Val}|_Parms], SCRP0) + when SCRP0#'ServiceChangeResParm'.serviceChangeAddress == asn1_NOVALUE -> + MgcId = SCRP0#'ServiceChangeResParm'.serviceChangeMgcId, + exit({not_both_address_mgcid_servChgReplyParm, Val, MgcId}); + +merge_ServiceChangeResParm([{mgc_id, Val}|Parms], SCRP0) + when (SCRP0#'ServiceChangeResParm'.serviceChangeMgcId == asn1_NOVALUE) andalso + (SCRP0#'ServiceChangeResParm'.serviceChangeAddress == asn1_NOVALUE) -> + SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeMgcId = Val}, + merge_ServiceChangeResParm(Parms, SCRP); +merge_ServiceChangeResParm([{mgc_id, Val}|_Parms], SCRP0) + when SCRP0#'ServiceChangeResParm'.serviceChangeMgcId == asn1_NOVALUE -> + Addr = SCRP0#'ServiceChangeResParm'.serviceChangeAddress, + exit({not_both_address_mgcid_servChgReplyParm, Val, Addr}); + +merge_ServiceChangeResParm([{profile, Val}|Parms], SCRP0) + when SCRP0#'ServiceChangeResParm'.serviceChangeProfile == asn1_NOVALUE -> + SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeProfile = Val}, + merge_ServiceChangeResParm(Parms, SCRP); + +merge_ServiceChangeResParm([{version, Val}|Parms], SCRP0) + when SCRP0#'ServiceChangeResParm'.serviceChangeVersion == asn1_NOVALUE -> + SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeVersion = Val}, + merge_ServiceChangeResParm(Parms, SCRP); + +merge_ServiceChangeResParm([{time_stamp, Val}|Parms], SCRP0) + when SCRP0#'ServiceChangeResParm'.timeStamp == asn1_NOVALUE -> + SCRP = SCRP0#'ServiceChangeResParm'{timeStamp = Val}, + merge_ServiceChangeResParm(Parms, SCRP); + +merge_ServiceChangeResParm([{Tag, Val}|_Parms], SCRP) -> + Val2 = + case Tag of + address -> SCRP#'ServiceChangeResParm'.serviceChangeAddress; + mgc_id -> SCRP#'ServiceChangeResParm'.serviceChangeMgcId; + profile -> SCRP#'ServiceChangeResParm'.serviceChangeProfile; + version -> SCRP#'ServiceChangeResParm'.serviceChangeVersion; + time_stamp -> SCRP#'ServiceChangeResParm'.timeStamp + end, + exit({at_most_once_servChgReplyParm, {Tag, Val, Val2}}). + + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_serviceChangeMethod,1}]}). +-endif. +ensure_serviceChangeMethod(Token) -> + case Token of + {safeToken, _Line, "fl"} -> + failover; + {safeToken, _Line, "failover"} -> + failover; + {safeToken, _Line, "fo"} -> + forced; + {safeToken, _Line, "forced"} -> + forced; + {safeToken, _Line, "gr"} -> + graceful; + {safeToken, _Line, "graceful"} -> + graceful; + {safeToken, _Line, "rs"} -> + restart; + {safeToken, _Line, "restart"} -> + restart; + {safeToken, _Line, "dc"} -> + disconnected; + {safeToken, _Line, "disconnected"} -> + disconnected; + {safeToken, _Line, "ho"} -> + handOff; + {safeToken, _Line, "handoff"} -> + handOff; + {safeToken, Line, Text} -> + return_error(Line, {bad_serviceChangeMethod, Text}) + end. + + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_topologyDescriptor,1}]}). +-endif. +merge_topologyDescriptor(Components) -> + merge_topologyDescriptor(Components, #'TopologyRequest'{}, []). + +merge_topologyDescriptor([], TR, TRs) -> + lists:reverse([ensure_TopologyRequest(TR)|TRs]); +merge_topologyDescriptor( + [{tid, From}|Comps], + #'TopologyRequest'{terminationFrom = undefined} = TR1, TRs) -> + TR2 = TR1#'TopologyRequest'{terminationFrom = From}, + merge_topologyDescriptor(Comps, TR2, TRs); +merge_topologyDescriptor( + [{tid, To}|Comps], + #'TopologyRequest'{terminationTo = undefined} = TR1, + TRs) -> + TR2 = TR1#'TopologyRequest'{terminationTo = To}, + merge_topologyDescriptor(Comps, TR2, TRs); +merge_topologyDescriptor([{tid, From}|Comps], TR1, TRs) -> + TR2 = #'TopologyRequest'{terminationFrom = From}, + merge_topologyDescriptor(Comps, TR2, [TR1 | TRs]); +merge_topologyDescriptor([{direction, Dir}|Comps], TR1, TRs) -> + TR2 = TR1#'TopologyRequest'{topologyDirection = Dir}, + merge_topologyDescriptor(Comps, TR2, TRs); +merge_topologyDescriptor([{sid, SID}|Comps], TR1, TRs) -> + TR2 = TR1#'TopologyRequest'{streamID = SID}, + merge_topologyDescriptor(Comps, TR2, TRs); +merge_topologyDescriptor( + [{direction_ext, EDir}|Comps], + #'TopologyRequest'{topologyDirection = asn1_NOVALUE} = TR1, TRs) -> + TR2 = TR1#'TopologyRequest'{topologyDirection = oneway, + topologyDirectionExtension = EDir}, + merge_topologyDescriptor(Comps, TR2, TRs); +merge_topologyDescriptor([{direction_ext, EDir}|Comps], TR1, TRs) -> + TR2 = TR1#'TopologyRequest'{topologyDirectionExtension = EDir}, + merge_topologyDescriptor(Comps, TR2, TRs); +merge_topologyDescriptor(Comps, TR, TRs) -> + return_error(0, {bad_topologyDescriptor, Comps, TR, TRs}). + + +ensure_TopologyRequest(#'TopologyRequest'{terminationFrom = From, + terminationTo = To, + topologyDirection = Dir} = R) + when (From =/= asn1_NOVALUE) andalso + (To =/= asn1_NOVALUE) andalso + (Dir =/= asn1_NOVALUE) -> + R; +ensure_TopologyRequest(R) -> + return_error(0, {bad_TopologyRequest, R}). + + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_profile,1}]}). +-endif. +ensure_profile(Token) -> + {_TokenTag, Line, Text} = Token, + case string:tokens(Text, [$/]) of + [Name, Version] -> + Version2 = ensure_version(Version), + #'ServiceChangeProfile'{profileName = Name, version = Version2}; + _ -> + return_error(Line, {bad_profile, Text}) + end. + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_version,1}]}). +-endif. +ensure_version(Version) -> + ensure_uint(Version, 0, 99). + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_signalRequest,2}]}). +-endif. +merge_signalRequest(SignalName, PropertyParms) -> + Sig = #'Signal'{signalName = SignalName}, + SPL = [], + do_merge_signalRequest(Sig, PropertyParms, SPL). + +do_merge_signalRequest(Sig, [H | T], SPL) -> + case H of + {stream, SID} when Sig#'Signal'.streamID == asn1_NOVALUE -> + do_merge_signalRequest(Sig#'Signal'{streamID = SID}, T, SPL); + {signal_type, SigType} when Sig#'Signal'.sigType == asn1_NOVALUE -> + do_merge_signalRequest(Sig#'Signal'{sigType = SigType}, T, SPL); + {duration, Duration} when Sig#'Signal'.duration == asn1_NOVALUE -> + do_merge_signalRequest(Sig#'Signal'{duration = Duration}, T, SPL); + {notify_completion, NC} when Sig#'Signal'.notifyCompletion == asn1_NOVALUE -> + do_merge_signalRequest(Sig#'Signal'{notifyCompletion = NC}, T, SPL); + keepActive when Sig#'Signal'.keepActive == asn1_NOVALUE -> + do_merge_signalRequest(Sig#'Signal'{keepActive = true}, T, SPL); + {other, Name, PP} -> + SP = #'SigParameter'{sigParameterName = Name, + value = PP#'PropertyParm'.value, + extraInfo = PP#'PropertyParm'.extraInfo}, + do_merge_signalRequest(Sig, T, [SP | SPL]); + {direction, Dir} when Sig#'Signal'.direction == asn1_NOVALUE -> + do_merge_signalRequest(Sig#'Signal'{direction = Dir}, T, SPL); + {requestId, RID} when Sig#'Signal'.requestID == asn1_NOVALUE -> + do_merge_signalRequest(Sig#'Signal'{requestID = RID}, T, SPL); + {intersigDelay, ISD} when Sig#'Signal'.intersigDelay == asn1_NOVALUE -> + do_merge_signalRequest(Sig#'Signal'{intersigDelay = ISD}, T, SPL); + _ -> + return_error(0, {bad_sigParm, H}) + end; +do_merge_signalRequest(Sig, [], SPL) -> + Sig#'Signal'{sigParList = lists:reverse(SPL)} . + +%% eventStream = StreamToken EQUAL StreamID +%% eventOther = eventParameterName parmValue +-ifdef(megaco_parser_inline). +-compile({inline,[{select_stream_or_other,2}]}). +-endif. +select_stream_or_other(EventParameterName, ParmValue) -> +%% io:format("select_stream_or_other -> entry with" +%% "~n EventParameterName: ~p" +%% "~n ParmValue: ~p" +%% "~n", [EventParameterName, ParmValue]), + if + (EventParameterName =:= "st") orelse + (EventParameterName =:= "stream") -> + case ParmValue of + #'PropertyParm'{value = [Value]} -> + {stream, ensure_uint16(Value)}; + _ -> + {stream, ensure_uint16(ParmValue)} + end; + true -> + #'PropertyParm'{value = Value} = ParmValue, + EP = #'EventParameter'{eventParameterName = EventParameterName, + value = Value}, + {other, EP} + end. + +%% select_stream_or_other("st", #'PropertyParm'{value = [Value]}) -> +%% {stream, ensure_uint16(Value)}; +%% select_stream_or_other("st", Value) -> +%% {stream, ensure_uint16(Value)}; +%% select_stream_or_other("stream", #'PropertyParm'{value = [Value]}) -> +%% {stream, ensure_uint16(Value)}; +%% select_stream_or_other("stream", Value) -> +%% {stream, ensure_uint16(Value)}; +%% select_stream_or_other(Name, #'PropertyParm'{value = Value}) -> +%% EP = #'EventParameter'{eventParameterName = Name, +%% value = Value}, +%% {other, EP}. + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_eventDM,1}]}). +-endif. +ensure_eventDM(Token) -> + {_TokenTag, Line, DMD} = Token, + if + is_record(DMD, 'DigitMapDescriptor') -> + Name = DMD#'DigitMapDescriptor'.digitMapName, + Val = DMD#'DigitMapDescriptor'.digitMapValue, + if + (Name =:= asn1_NOVALUE) andalso (Val =/= asn1_NOVALUE) -> + {'DigitMapValue', Start, Short, Long, Duration, Body} = Val, + DMV = #'DigitMapValue'{startTimer = Start, + shortTimer = Short, + longTimer = Long, + digitMapBody = Body, + durationTimer = Duration}, + {eventDM, {digitMapValue, DMV}}; + (Name =/= asn1_NOVALUE) andalso (Val =:= asn1_NOVALUE) -> + {eventDM, {digitMapName, Name}}; + true -> + return_error(Line, {bad_eventDM, DMD}) + end; + true -> + return_error(Line, {bad_eventDM, DMD}) + end. + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_DMD,1}]}). +-endif. +ensure_DMD(Token) -> + {_TokenTag, Line, DMD} = Token, + if + is_record(DMD, 'DigitMapDescriptor') -> + Val2 = + case DMD#'DigitMapDescriptor'.digitMapValue of + %% Note that the values of the digitMapBody and + %% durationTimers are swapped by the scanner + %% (this is done because of a problem in the flex scanner). + #'DigitMapValue'{startTimer = asn1_NOVALUE, + shortTimer = asn1_NOVALUE, + longTimer = asn1_NOVALUE, + durationTimer = [], + digitMapBody = asn1_NOVALUE} -> + asn1_NOVALUE; + #'DigitMapValue'{durationTimer = Body, + digitMapBody = Duration} = DMV -> + %% Convert to version 1 DigitMapValue + DMV#'DigitMapValue'{digitMapBody = Body, + durationTimer = Duration}; + Other -> + Other + end, + DMD#'DigitMapDescriptor'{digitMapValue = Val2}; + true -> + return_error(Line, {bad_DigitMapDescriptor, DMD}) + end. + + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_observed_event,3}]}). +-endif. +merge_observed_event(ObservedEvents, EventName, TimeStamp) -> + StreamId = asn1_NOVALUE, + EPL = [], + do_merge_observed_event(ObservedEvents, EventName, TimeStamp, StreamId, EPL). + +do_merge_observed_event([{stream, StreamID} | T], EventName, TimeStamp, asn1_NOVALUE, EPL) -> + do_merge_observed_event(T, EventName, TimeStamp, StreamID, EPL); +do_merge_observed_event([{other, PP} | T], EventName, TimeStamp, StreamID, EPL) -> + do_merge_observed_event(T, EventName, TimeStamp, StreamID, [PP | EPL]); +do_merge_observed_event([], EventName, TimeStamp, StreamID, EPL) -> + #'ObservedEvent'{eventName = EventName, + timeNotation = TimeStamp, + streamID = StreamID, + eventParList = lists:reverse(EPL)}. + +merge_eventSpec(OE) + when is_record(OE, 'ObservedEvent') andalso + (OE#'ObservedEvent'.timeNotation == asn1_NOVALUE) -> + #'EventSpec'{eventName = OE#'ObservedEvent'.eventName, + streamID = OE#'ObservedEvent'.streamID, + eventParList = OE#'ObservedEvent'.eventParList}; +merge_eventSpec(OE) -> + return_error(0, {bad_event_spec, OE}). + +make_RegulatedEmbeddedDescriptor({embed, SD, SED}) -> + #'RegulatedEmbeddedDescriptor'{secondEvent = SED, + signalsDescriptor = SD}. + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_eventParameters,1}]}). +-endif. +merge_eventParameters(Params) -> +%% io:format("merge_eventParameters -> entry" +%% "~n", []), + SID = asn1_NOVALUE, + EPL = [], + RA = #'RequestedActions'{}, + HasA = no, + do_merge_eventParameters(Params, SID, EPL, RA, HasA) . + +do_merge_eventParameters([H | T], SID, EPL, RA, HasA) -> +%% io:format("do_merge_eventParameters -> entry with" +%% "~n H: ~p" +%% "~n SID: ~p" +%% "~n EPL: ~p" +%% "~n RA: ~p" +%% "~n HasA: ~p" +%% "~n", [H, SID, EPL, RA, HasA]), + case H of + keepActive when RA#'RequestedActions'.keepActive =:= asn1_NOVALUE -> + RA2 = RA#'RequestedActions'{keepActive = true}, + do_merge_eventParameters(T, SID, EPL, RA2, yes); + resetEventsDescriptor when RA#'RequestedActions'.resetEventsDescriptor =:= asn1_NOVALUE -> + RA2 = RA#'RequestedActions'{resetEventsDescriptor = 'NULL'}, + do_merge_eventParameters(T, SID, EPL, RA2, yes); + {embed, SD, SED} when RA#'RequestedActions'.signalsDescriptor =:= asn1_NOVALUE -> + RA2 = RA#'RequestedActions'{signalsDescriptor = SD, + secondEvent = SED}, + do_merge_eventParameters(T, SID, EPL, RA2, yes); + {eventDM, DM} when RA#'RequestedActions'.eventDM =:= asn1_NOVALUE -> + RA2 = RA#'RequestedActions'{eventDM = DM}, + do_merge_eventParameters(T, SID, EPL, RA2, yes); + {stream, NewSID} when SID =:= asn1_NOVALUE -> + do_merge_eventParameters(T, NewSID, EPL, RA, HasA); + {other, PP} when is_record(PP, 'PropertyParm') -> + EP = #'EventParameter'{eventParameterName = PP#'PropertyParm'.name, + value = PP#'PropertyParm'.value, + extraInfo = PP#'PropertyParm'.extraInfo}, + do_merge_eventParameters(T, SID, [EP | EPL], RA, HasA); + {other, EP} when is_record(EP, 'EventParameter') -> + do_merge_eventParameters(T, SID, [EP | EPL], RA, HasA); + {notifyBehaviour, NB} when RA#'RequestedActions'.notifyBehaviour =:= asn1_NOVALUE -> + RA2 = RA#'RequestedActions'{notifyBehaviour = NB}, + do_merge_eventParameters(T, SID, EPL, RA2, yes); + _ -> + return_error(0, {bad_eventParameter, H}) + end; +do_merge_eventParameters([], SID, EPL, RA, yes) -> +%% io:format("do_merge_eventParameters(yes) -> entry with" +%% "~n SID: ~p" +%% "~n EPL: ~p" +%% "~n RA: ~p" +%% "~n", [SID, EPL, RA]), + #'RequestedEvent'{streamID = SID, + eventAction = RA, + evParList = lists:reverse(EPL)}; +do_merge_eventParameters([], SID, EPL, _RA, no) -> +%% io:format("do_merge_eventParameters(no) -> entry with" +%% "~n SID: ~p" +%% "~n EPL: ~p" +%% "~n", [SID, EPL]), + #'RequestedEvent'{streamID = SID, + eventAction = asn1_NOVALUE, + evParList = lists:reverse(EPL)}. + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_secondEventParameters,1}]}). +-endif. +merge_secondEventParameters(Params) -> + SID = asn1_NOVALUE, + EPL = [], + SRA = #'SecondRequestedActions'{}, + HasA = no, + do_merge_secondEventParameters(Params, SID, EPL, SRA, HasA) . + +do_merge_secondEventParameters([H | T], SID, EPL, SRA, HasA) -> + case H of + keepActive when SRA#'SecondRequestedActions'.keepActive =:= asn1_NOVALUE -> + SRA2 = SRA#'SecondRequestedActions'{keepActive = true}, + do_merge_secondEventParameters(T, SID, EPL, SRA2, yes); + + resetEventsDescriptor when SRA#'SecondRequestedActions'.resetEventsDescriptor =:= asn1_NOVALUE -> + SRA2 = SRA#'SecondRequestedActions'{resetEventsDescriptor = 'NULL'}, + do_merge_secondEventParameters(T, SID, EPL, SRA2, yes); + + {second_embed, SD} when SRA#'SecondRequestedActions'.signalsDescriptor =:= asn1_NOVALUE -> + SRA2 = SRA#'SecondRequestedActions'{signalsDescriptor = SD}, + do_merge_secondEventParameters(T, SID, EPL, SRA2, yes); + + {eventDM, DM} when SRA#'SecondRequestedActions'.eventDM =:= asn1_NOVALUE -> + SRA2 = SRA#'SecondRequestedActions'{eventDM = DM}, + do_merge_secondEventParameters(T, SID, EPL, SRA2, yes); + + {stream, NewSID} when SID =:= asn1_NOVALUE -> + do_merge_secondEventParameters(T, NewSID, EPL, SRA, HasA); + + {other, PP} when is_record(PP, 'PropertyParm') -> + EP = #'EventParameter'{eventParameterName = PP#'PropertyParm'.name, + value = PP#'PropertyParm'.value, + extraInfo = PP#'PropertyParm'.extraInfo}, + do_merge_secondEventParameters(T, SID, [EP | EPL], SRA, HasA); + + {other, EP} when is_record(EP, 'EventParameter') -> + do_merge_secondEventParameters(T, SID, [EP | EPL], SRA, HasA); + + {notifyBehaviour, NB} when SRA#'SecondRequestedActions'.notifyBehaviour =:= asn1_NOVALUE -> + SRA2 = SRA#'SecondRequestedActions'{notifyBehaviour = NB}, + do_merge_secondEventParameters(T, SID, EPL, SRA2, yes); + + _ -> + return_error(0, {bad_secondEventParameter, H}) + end; +do_merge_secondEventParameters([], SID, EPL, SRA, yes) -> + #'SecondRequestedEvent'{streamID = SID, + eventAction = SRA, + evParList = lists:reverse(EPL)}; +do_merge_secondEventParameters([], SID, EPL, _SRA, no) -> + #'SecondRequestedEvent'{streamID = SID, + eventAction = asn1_NOVALUE, + evParList = lists:reverse(EPL)}. + +%% terminationID = "ROOT" / pathName / "$" / "*" +%% Total length of pathName must not exceed 64 chars. +%% pathName = ["*"] NAME *("/" / "*"/ ALPHA / DIGIT /"_" / "$" ) +%% ["@" pathDomainName ] +%% ABNF allows two or more consecutive "." although it is meaningless +%% in a path domain name. +%% pathDomainName = (ALPHA / DIGIT / "*" ) +%% *63(ALPHA / DIGIT / "-" / "*" / ".") +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_terminationID,1}]}). +-endif. +ensure_terminationID(Token) -> + {safeToken, _Line, LowerText} = Token, + %% terminationID = "ROOT" / pathName / "$" / "*" + decode_term_id(LowerText, false, [], []). + +decode_term_id([H | T], Wild, Id, Component) -> + case H of + $/ -> decode_term_id(T, Wild, [lists:reverse(Component) | Id], []); + $* -> decode_term_id(T, true, Id, [?megaco_all | Component]); + $$ -> decode_term_id(T, true, Id, [?megaco_choose | Component]); + _ -> decode_term_id(T, Wild, Id, [H | Component]) + end; +decode_term_id([], Wild, Id, Component) -> + Id2 = [lists:reverse(Component) | Id], + #megaco_term_id{contains_wildcards = Wild, id = lists:reverse(Id2)}. + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_pathName,1}]}). +-endif. +ensure_pathName(Token) -> + {_TokenTag, _Line, Text} = Token, + Text. %% BUGBUG: ensure values + +%% TimeStamp = Date "T" Time ; per ISO 8601:1988 +%% Date = 8(DIGIT) ; Date = yyyymmdd +%% Time = 8(DIGIT) ; Time = hhmmssss +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_timeStamp,1}]}). +-endif. +ensure_timeStamp(Token) -> + {'TimeStampToken', Line, Text} = Token, + case string:tokens(Text, [$T, $t]) of + [Date, Time] -> + #'TimeNotation'{date = Date, time = Time}; + _ -> + return_error(Line, {bad_timeStamp, Text}) + end. + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_transactionID,1}]}). +-endif. +ensure_transactionID(TransId) -> + ensure_uint32(TransId). + +%% transactionAck = transactionID / (transactionID "-" transactionID) +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_transactionAck,1}]}). +-endif. +ensure_transactionAck(Tokens) -> + {safeToken, _Line, Text} = Tokens, + ensure_transactionAck2(Text, []). + +ensure_transactionAck2([], Acc) -> + Id = lists:reverse(Acc), + #'TransactionAck'{firstAck = ensure_transactionID(Id)}; +ensure_transactionAck2([$- | Id2], Acc) -> + Id1 = lists:reverse(Acc), + #'TransactionAck'{firstAck = ensure_transactionID(Id1), + lastAck = ensure_transactionID(Id2)}; +ensure_transactionAck2([H|T], Acc) -> + ensure_transactionAck2(T, [H|Acc]). + + +merge_context_request(asn1_NOVALUE, Prop) -> + merge_context_request(#'ContextRequest'{}, Prop); + +merge_context_request(#'ContextRequest'{priority = asn1_NOVALUE} = CR, + {priority, Int}) -> + CR#'ContextRequest'{priority = Int}; + +merge_context_request(#'ContextRequest'{emergency = asn1_NOVALUE} = CR, + {emergency, Bool}) -> + CR#'ContextRequest'{emergency = Bool}; + +merge_context_request(#'ContextRequest'{topologyReq = asn1_NOVALUE} = CR, + {topology, Desc}) -> + CR#'ContextRequest'{topologyReq = Desc}; + +merge_context_request(#'ContextRequest'{iepscallind = asn1_NOVALUE} = CR, + {iepsCallind, Ind}) -> + CR#'ContextRequest'{iepscallind = Ind}; + +merge_context_request(#'ContextRequest'{contextProp = asn1_NOVALUE} = CR, + {contextProp, Props}) -> + CR#'ContextRequest'{contextProp = Props}; + +merge_context_request(#'ContextRequest'{contextList = asn1_NOVALUE} = CR, + {contextList, IDs}) -> + CR#'ContextRequest'{contextList = IDs}; + +merge_context_request(CR, {Tag, Val}) -> + Val2 = + case Tag of + priority -> CR#'ContextRequest'.priority; + emergency -> CR#'ContextRequest'.emergency; + topology -> CR#'ContextRequest'.topologyReq; + iepsCallind -> CR#'ContextRequest'.iepscallind; + contextProp -> CR#'ContextRequest'.contextProp; + contextList -> CR#'ContextRequest'.contextList + end, + exit({at_most_once_contextProperty, {Tag, Val, Val2}}). + + +merge_context_attr_audit_request( + #'ContextAttrAuditRequest'{contextPropAud = asn1_NOVALUE} = CAAR, []) -> + + CAAR; +merge_context_attr_audit_request( + #'ContextAttrAuditRequest'{contextPropAud = CPA} = CAAR, []) -> + + CAAR#'ContextAttrAuditRequest'{contextPropAud = lists:reverse(CPA)}; +merge_context_attr_audit_request(CAAR, [H|T]) -> + case H of + priorityAudit when CAAR#'ContextAttrAuditRequest'.priority == asn1_NOVALUE -> + CAAR2 = CAAR#'ContextAttrAuditRequest'{priority = 'NULL'}, + merge_context_attr_audit_request(CAAR2, T); + + emergencyAudit when CAAR#'ContextAttrAuditRequest'.emergency == asn1_NOVALUE -> + CAAR2 = CAAR#'ContextAttrAuditRequest'{emergency = 'NULL'}, + merge_context_attr_audit_request(CAAR2, T); + + topologyAudit when CAAR#'ContextAttrAuditRequest'.topology == asn1_NOVALUE -> + CAAR2 = CAAR#'ContextAttrAuditRequest'{topology = 'NULL'}, + merge_context_attr_audit_request(CAAR2, T); + + iepsCallind when CAAR#'ContextAttrAuditRequest'.iepscallind == asn1_NOVALUE -> + CAAR2 = CAAR#'ContextAttrAuditRequest'{iepscallind = 'NULL'}, + merge_context_attr_audit_request(CAAR2, T); + + {prop, Name} when CAAR#'ContextAttrAuditRequest'.contextPropAud == asn1_NOVALUE -> + CPA = [#'IndAudPropertyParm'{name = Name}], + CAAR2 = CAAR#'ContextAttrAuditRequest'{contextPropAud = CPA}, + merge_context_attr_audit_request(CAAR2, T); + + {prop, Name} -> + CPA = CAAR#'ContextAttrAuditRequest'.contextPropAud, + CPA2 = [#'IndAudPropertyParm'{name = Name}|CPA], + CAAR2 = CAAR#'ContextAttrAuditRequest'{contextPropAud = CPA2}, + merge_context_attr_audit_request(CAAR2, T); + + {select_prio, Prio} when CAAR#'ContextAttrAuditRequest'.selectpriority == asn1_NOVALUE -> + CAAR2 = CAAR#'ContextAttrAuditRequest'{selectpriority = Prio}, + merge_context_attr_audit_request(CAAR2, T); + + {select_emergency, EV} when CAAR#'ContextAttrAuditRequest'.selectemergency == asn1_NOVALUE -> + CAAR2 = CAAR#'ContextAttrAuditRequest'{selectemergency = EV}, + merge_context_attr_audit_request(CAAR2, T); + + {select_ieps, IV} when CAAR#'ContextAttrAuditRequest'.selectiepscallind == asn1_NOVALUE -> + CAAR2 = CAAR#'ContextAttrAuditRequest'{selectiepscallind = IV}, + merge_context_attr_audit_request(CAAR2, T); + + {select_logic, SL} when CAAR#'ContextAttrAuditRequest'.selectLogic == asn1_NOVALUE -> + CAAR2 = CAAR#'ContextAttrAuditRequest'{selectLogic = SL}, + merge_context_attr_audit_request(CAAR2, T); + + %% BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG + %% + %% For some strange reason, contextAttrDescriptor was added + %% to contextAuditSelector. But there is no place for this + %% info in the ContextAttrAuditRequest. Since contextAttrDescriptor + %% can also be found in contextProperty (which correspond to + %% ContextRequest), the question is if this info should go there + %% or if we shall just drop it. For now we drop it. + %% + {contextProp, _PPs} -> + merge_context_attr_audit_request(CAAR, T); + + {contextList, _IDs} -> + merge_context_attr_audit_request(CAAR, T); + + _ -> + exit({unexpected_contextAttrAudit_item, H}) + + end. + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_action_request,2}]}). +-endif. +merge_action_request(CtxId, Items) -> + do_merge_action_request(Items, [], asn1_NOVALUE, asn1_NOVALUE, CtxId). + +do_merge_action_request([H|T], CmdReqs, CtxReq, CtxAuditReq, CtxId) -> + case H of + {commandRequest, CmdReq} -> + do_merge_action_request(T, [CmdReq|CmdReqs], + CtxReq, CtxAuditReq, CtxId); + + {contextProp, ContextProp} -> + do_merge_action_request(T, CmdReqs, + merge_context_request(CtxReq, ContextProp), + CtxAuditReq, CtxId); + + {contextAudit, ContextAuditReq} when CtxAuditReq == asn1_NOVALUE -> + do_merge_action_request(T, CmdReqs, + CtxReq, ContextAuditReq, CtxId) + end; +do_merge_action_request([], CmdReqs, CtxReq, CtxAuditReq, CtxId) -> + #'ActionRequest'{contextId = CtxId, + contextRequest = strip_ContextRequest(CtxReq), + contextAttrAuditReq = strip_ContextAttrAuditRequest(CtxAuditReq), + commandRequests = lists:reverse(CmdReqs)}. + + +%% OTP-5085: +%% In order to solve a problem in the parser, the error descriptor +%% has been put last in the non-empty commandReplyList, if it is not +%% asn1_NOVALUE +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_action_reply,1}]}). +-endif. +merge_action_reply(Items) -> + do_merge_action_reply(Items, asn1_NOVALUE, asn1_NOVALUE, []). + +do_merge_action_reply([], Err, Ctx, Cmds) -> + #'ActionReply'{errorDescriptor = Err, + contextReply = strip_ContextRequest(Ctx), + commandReply = lists:reverse(Cmds)}; +do_merge_action_reply([H|T], Err0, CR, Cmds) -> + case H of + {error, Err1} when Err0 == asn1_NOVALUE -> + do_merge_action_reply(T, Err1, CR, Cmds); + {command, Cmd} -> + do_merge_action_reply(T, Err0, CR, [Cmd | Cmds]); + {context, CtxProp} -> + do_merge_action_reply(T, Err0, + merge_context_request(CR, CtxProp), Cmds) + end. + +merge_auditOther([TID], TAR) -> + {auditResult, + #'AuditResult'{terminationID = TID, + terminationAuditResult = TAR}}; +merge_auditOther(TIDs, TAR) -> + {auditResultTermList, + #'TermListAuditResult'{terminationIDList = TIDs, + terminationAuditResult = TAR}}. + +strip_ContextRequest(#'ContextRequest'{priority = asn1_NOVALUE, + emergency = asn1_NOVALUE, + topologyReq = asn1_NOVALUE, + iepscallind = asn1_NOVALUE, + contextProp = asn1_NOVALUE, + contextList = asn1_NOVALUE}) -> + asn1_NOVALUE; +strip_ContextRequest(#'ContextRequest'{priority = asn1_NOVALUE, + emergency = asn1_NOVALUE, + topologyReq = asn1_NOVALUE, + iepscallind = asn1_NOVALUE, + contextProp = [], + contextList = asn1_NOVALUE}) -> + asn1_NOVALUE; +%% strip_ContextRequest(asn1_NOVALUE) -> +%% asn1_NOVALUE; +strip_ContextRequest(R) -> + R. + +strip_ContextAttrAuditRequest( + #'ContextAttrAuditRequest'{priority = asn1_NOVALUE, + emergency = asn1_NOVALUE, + topology = asn1_NOVALUE, + iepscallind = asn1_NOVALUE, + contextPropAud = asn1_NOVALUE, + selectpriority = asn1_NOVALUE, + selectemergency = asn1_NOVALUE, + selectiepscallind = asn1_NOVALUE, + selectLogic = asn1_NOVALUE}) -> + asn1_NOVALUE; +strip_ContextAttrAuditRequest( + #'ContextAttrAuditRequest'{priority = asn1_NOVALUE, + emergency = asn1_NOVALUE, + topology = asn1_NOVALUE, + iepscallind = asn1_NOVALUE, + contextPropAud = [], + selectpriority = asn1_NOVALUE, + selectemergency = asn1_NOVALUE, + selectiepscallind = asn1_NOVALUE, + selectLogic = asn1_NOVALUE}) -> + asn1_NOVALUE; +strip_ContextAttrAuditRequest(R) -> + R. + +merge_AmmRequest_descriptors([], Acc) -> + lists:reverse(Acc); +merge_AmmRequest_descriptors([{_, deprecated}|Descs], Acc) -> + merge_AmmRequest_descriptors(Descs, Acc); +merge_AmmRequest_descriptors([Desc|Descs], Acc) -> + merge_AmmRequest_descriptors(Descs, [Desc|Acc]). + +make_auditRequest([TID], AD) -> + #'AuditRequest'{terminationID = TID, + auditDescriptor = AD}; +make_auditRequest([TID|_] = TIDList, AD) -> + #'AuditRequest'{terminationID = TID, + auditDescriptor = AD, + terminationIDList = TIDList}. + +make_commandRequest({CmdTag, {_TokenTag, _Line, Text}}, Cmd) -> + Req = #'CommandRequest'{command = {CmdTag, Cmd}}, + case Text of + [$w, $- | _] -> + Req#'CommandRequest'{wildcardReturn = 'NULL'}; + [$o, $-, $w, $- | _] -> + Req#'CommandRequest'{optional = 'NULL', wildcardReturn = 'NULL'}; + [$o, $- | _] -> + Req#'CommandRequest'{optional = 'NULL'}; + _ -> + Req + end. + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_terminationAudit,1}]}). +-endif. +merge_terminationAudit(AuditReturnParameters) -> + lists:reverse(do_merge_terminationAudit(AuditReturnParameters, [], [])). + +do_merge_terminationAudit([H| T], ARPs, AuditItems) -> + case H of + {auditReturnItem, AuditItem} -> + do_merge_terminationAudit(T, ARPs, [AuditItem | AuditItems]); + AuditReturnParameter -> + do_merge_terminationAudit(T, [AuditReturnParameter | ARPs], AuditItems) + end; +do_merge_terminationAudit([], AuditReturnParameters, []) -> + AuditReturnParameters; +do_merge_terminationAudit([], AuditReturnParameters, AuditItems) -> + AuditDescriptor = #'AuditDescriptor'{auditToken = AuditItems}, + AuditReturnParameter = {emptyDescriptors, AuditDescriptor}, + [AuditReturnParameter | AuditReturnParameters]. + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_mediaDescriptor,1}]}). +-endif. +merge_mediaDescriptor(MediaParms) -> + do_merge_mediaDescriptor(MediaParms, asn1_NOVALUE, [], []). + +do_merge_mediaDescriptor([H | T], TS, One, Multi) -> + case H of + {streamParm, Parm} when Multi =:= [] -> + do_merge_mediaDescriptor(T, TS, [Parm | One], Multi); + {streamDescriptor, Desc} when One =:= [] -> + do_merge_mediaDescriptor(T, TS, One, [Desc | Multi]); + {termState, TS2} when TS =:= asn1_NOVALUE -> + do_merge_mediaDescriptor(T, TS2, One, Multi); + _ -> + return_error(0, {bad_merge_mediaDescriptor, [H, TS, One, Multi]}) + end; +do_merge_mediaDescriptor([], TS, One, Multi) -> + if + (One =:= []) -> + if (Multi =:= []) -> + #'MediaDescriptor'{streams = asn1_NOVALUE, + termStateDescr = TS}; + true -> % (Multi =/= []) + Streams = {multiStream, lists:reverse(Multi)}, + #'MediaDescriptor'{streams = Streams, + termStateDescr = TS} + end; + true -> % (One =/= []) + if + (Multi =:= []) -> + Streams = {oneStream, merge_streamParms(One)}, + #'MediaDescriptor'{streams = Streams, + termStateDescr = TS}; + true -> % (Multi =/= []) + return_error(0, + {bad_merge_mediaDescriptor, [TS, One, Multi]}) + end + end. + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_streamParms,1}]}). +-endif. +merge_streamParms(TaggedStreamParms) -> + SP = #'StreamParms'{}, + do_merge_streamParms(TaggedStreamParms, SP). + +do_merge_streamParms([{Tag, D} | T] = All, SP) -> + case Tag of + local when SP#'StreamParms'.localDescriptor =:= asn1_NOVALUE -> + do_merge_streamParms(T, SP#'StreamParms'{localDescriptor = D}); + remote when SP#'StreamParms'.remoteDescriptor =:= asn1_NOVALUE -> + do_merge_streamParms(T, SP#'StreamParms'{remoteDescriptor = D}); + control -> + LCD = + case SP#'StreamParms'.localControlDescriptor of + asn1_NOVALUE -> + #'LocalControlDescriptor'{propertyParms = []}; + PrevLCD -> + PrevLCD + end, + LCD2 = do_merge_control_streamParms(D, LCD), + do_merge_streamParms(T, SP#'StreamParms'{localControlDescriptor = LCD2}); + statistics when SP#'StreamParms'.statisticsDescriptor =:= asn1_NOVALUE -> + do_merge_streamParms(T, SP#'StreamParms'{statisticsDescriptor = D}); + _ -> + return_error(0, {do_merge_streamParms, [All, SP]}) + end; +do_merge_streamParms([], SP) + when is_record(SP#'StreamParms'.localControlDescriptor, + 'LocalControlDescriptor') -> + LCD = SP#'StreamParms'.localControlDescriptor, + PP = LCD#'LocalControlDescriptor'.propertyParms, + LCD2 = LCD#'LocalControlDescriptor'{propertyParms = lists:reverse(PP)}, + SP#'StreamParms'{localControlDescriptor = LCD2}; +do_merge_streamParms([], SP) -> + SP. + + +do_merge_control_streamParms([{SubTag, SD} | T] = All, LCD) -> + case SubTag of + group when LCD#'LocalControlDescriptor'.reserveGroup =:= asn1_NOVALUE -> + LCD2 = LCD#'LocalControlDescriptor'{reserveGroup = SD}, + do_merge_control_streamParms(T, LCD2); + value when LCD#'LocalControlDescriptor'.reserveValue =:= asn1_NOVALUE -> + LCD2 = LCD#'LocalControlDescriptor'{reserveValue = SD}, + do_merge_control_streamParms(T, LCD2); + mode when LCD#'LocalControlDescriptor'.streamMode =:= asn1_NOVALUE -> + LCD2 = LCD#'LocalControlDescriptor'{streamMode = SD}, + do_merge_control_streamParms(T, LCD2); + prop -> + PP = LCD#'LocalControlDescriptor'.propertyParms, + LCD2 = LCD#'LocalControlDescriptor'{propertyParms = [SD | PP]}, + do_merge_control_streamParms(T, LCD2); + _ -> + return_error(0, {do_merge_control_streamParms, [All, LCD]}) + end; +do_merge_control_streamParms([], LCD) -> + LCD. + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_terminationStateDescriptor,1}]}). +-endif. +merge_terminationStateDescriptor(Parms) -> + TSD = #'TerminationStateDescriptor'{propertyParms = []}, + do_merge_terminationStateDescriptor(Parms, TSD). + +do_merge_terminationStateDescriptor([{Tag, Val} | T], TSD) -> + case Tag of + serviceState when TSD#'TerminationStateDescriptor'.serviceState =:= asn1_NOVALUE -> + TSD2 = TSD#'TerminationStateDescriptor'{serviceState = Val}, + do_merge_terminationStateDescriptor(T, TSD2); + eventBufferControl when TSD#'TerminationStateDescriptor'.eventBufferControl =:= asn1_NOVALUE-> + TSD2 = TSD#'TerminationStateDescriptor'{eventBufferControl = Val}, + do_merge_terminationStateDescriptor(T, TSD2); + propertyParm -> + PP = TSD#'TerminationStateDescriptor'.propertyParms, + TSD2 = TSD#'TerminationStateDescriptor'{propertyParms = [Val | PP]}, + do_merge_terminationStateDescriptor(T, TSD2) + end; +do_merge_terminationStateDescriptor([], TSD) -> + PP = TSD#'TerminationStateDescriptor'.propertyParms, + TSD#'TerminationStateDescriptor'{propertyParms = lists:reverse(PP)}. + +-ifdef(megaco_nscanner_props). + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_prop_groups,1}]}). +-endif. +ensure_prop_groups(Token) -> + {_TokenTag, _Line, Text} = Token, + Group = [], + parse_prop_name(Text, Group). + +parse_prop_name([Char | Rest] = All, Group) -> + if + ?white_space(Char) -> + parse_prop_name(Rest, Group); + ?end_of_line(Char) -> + parse_prop_name(Rest, Group); + true -> + Name = [], + do_parse_prop_name(All, Name, Group) + end; +parse_prop_name([] = All, Group) -> + Name = [], + do_parse_prop_name(All, Name, Group). + +do_parse_prop_name([Char | Rest], Name, Group) + when (Char =:= $=) andalso (Name =/= []) -> + %% Now we have a complete name + if + (Name =:= "v") andalso (Group =/= []) -> + %% v= is a property group delimiter, + %% lets create yet another property group. + NewGroup = [], + [lists:reverse(Group) | parse_prop_value(Rest, Name, NewGroup)]; + true -> + %% Use current property group + parse_prop_value(Rest, Name, Group) + end; +do_parse_prop_name([Char | Rest], Name, Group) -> + case ?classify_char4(Char) of + safe_char_upper -> + do_parse_prop_name(Rest, [Char | Name], Group); + safe_char -> + do_parse_prop_name(Rest, [Char | Name], Group); + _ -> + return_error(0, {bad_prop_name, lists:reverse(Name), Char}) + end; +do_parse_prop_name([], [], []) -> + []; +do_parse_prop_name([], [], Group) -> + [lists:reverse(Group)]; +do_parse_prop_name([], Name, Group) when Name =/= [] -> + %% Assume end of line + Value = [], + PP = make_prop_parm(Name, Value), + Group2 = lists:reverse([PP | Group]), + [Group2]. + +-ifdef(megaco_parser_inline). +-compile({inline,[{parse_prop_value,3}]}). +-endif. +parse_prop_value(Chars, Name, Group) -> + Value = [], + do_parse_prop_value(Chars, Name, Value, Group). + +do_parse_prop_value([Char | Rest], Name, Value, Group) -> + if + ?end_of_line(Char) -> + %% Now we have a complete "name=value" pair + PP = make_prop_parm(Name, Value), + parse_prop_name(Rest, [PP | Group]); + true -> + do_parse_prop_value(Rest, Name, [Char | Value], Group) + end; +do_parse_prop_value([], Name, Value, Group) -> + %% Assume end of line + PP = make_prop_parm(Name, Value), + Group2 = lists:reverse([PP | Group]), + [Group2]. + +-ifdef(megaco_parser_inline). +-compile({inline,[{make_prop_parm,2}]}). +-endif. +make_prop_parm(Name, Value) -> + #'PropertyParm'{name = lists:reverse(Name), + value = [lists:reverse(Value)]}. + +-else. % -ifdef(megaco_nscanner_props). + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_prop_groups,1}]}). +-endif. +ensure_prop_groups(Token) -> + {_TokenTag, _Line, Groups} = Token, + Groups. + +%% do_ensure_prop_groups(Groups) when is_list(Groups) -> +%% [ensure_prop_group(Group) || Group <- Groups]; +%% do_ensure_prop_groups(BadGroups) -> +%% throw({error, {?MODULE, {bad_property_groups, BadGroups}}}). + +%% -ifdef(megaco_parser_inline). +%% -compile({inline,[{ensure_prop_group,1}]}). +%% -endif. +%% ensure_prop_group(Group) when is_list(Group) -> +%% [ensure_prop_parm(PropParm) || PropParm <- Group]; +%% ensure_prop_group(BadGroup) -> +%% throw({error, {?MODULE, {bad_property_group, BadGroup}}}). + +%% -ifdef(megaco_parser_inline). +%% -compile({inline,[{ensure_prop_parm,1}]}). +%% -endif. +%% ensure_prop_parm(#property_parm{name = Name, +%% value = Value}) -> +%% #'PropertyParm'{name = Name, +%% value = Value}; +%% ensure_prop_parm(PP) when is_record(PP, 'PropertyParm') -> +%% PP; +%% ensure_prop_parm(BadPropParm) -> +%% throw({error, {?MODULE, {bad_property_parm, BadPropParm}}}). + +-endif. % -ifdef(megaco_nscanner_props). + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_uint,3}]}). +-endif. +ensure_uint(Token, Min, Max) -> + case Token of + {_TokenTag, Line, Val} when is_integer(Val) -> + ensure_uint(Val, Min, Max, Line); + {_TokenTag, Line, Text} -> + case (catch list_to_integer(Text)) of + {'EXIT', _} -> + return_error(Line, {not_an_integer, Text}); + Val when is_integer(Val) -> + ensure_uint(Val, Min, Max, Line) + end; + Val when is_integer(Val) -> + ensure_uint(Val, Min, Max, 0); + Text -> + case (catch list_to_integer(Text)) of + {'EXIT', _} -> + return_error(0, {not_an_integer, Text}); + Val when is_integer(Val) -> + ensure_uint(Val, Min, Max, 0) + end + end. + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_uint,4}]}). +-endif. +ensure_uint(Val, Min, Max, Line) -> + if + is_integer(Min) andalso (Val >= Min) -> + if + is_integer(Max) andalso (Val =< Max) -> + Val; + Max == infinity -> + Val; + true -> + return_error(Line, {too_large_integer, Val, Max}) + end; + true -> + return_error(Line, {too_small_integer, Val, Min}) + end. + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_uint16,1}]}). +-endif. +ensure_uint16(Int) -> + ensure_uint(Int, 0, 65535). + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_uint32,1}]}). +-endif. +ensure_uint32(Int) -> + ensure_uint(Int, 0, 4294967295) . + +%% OTP-4710 +ensure_hex({_TokenTag, _Line, [$0, $x |Chars]}, Min, Max) -> + ensure_uint(length(Chars), Min, Max), + hex_to_int(Chars, []); +ensure_hex({_TokenTag, _Line, [$0, $X |Chars]}, Min, Max) -> + ensure_uint(length(Chars), Min, Max), + hex_to_int(Chars, []); +ensure_hex([$0, $x |Chars], Min, Max) -> + ensure_uint(length(Chars), Min, Max), + hex_to_int(Chars, []); +ensure_hex([$0, $X |Chars], Min, Max) -> + ensure_uint(length(Chars), Min, Max), + hex_to_int(Chars, []). + +%% OTP-4710 +hex_to_int([], Acc) -> + lists:reverse(Acc); +hex_to_int([Char1,Char2|Tail], Acc) -> + Int1 = hchar_to_int(Char1), + Int2 = hchar_to_int(Char2), + Val = Int2 bor (Int1 bsl 4), + hex_to_int(Tail, [Val| Acc]); +hex_to_int([Char], Acc) -> + Int = hchar_to_int(Char), + lists:reverse([Int|Acc]). + +hchar_to_int(Char) when ($0 =< Char) andalso (Char =< $9) -> + Char - $0; +hchar_to_int(Char) when ($A =< Char) andalso (Char =< $F) -> + Char - $A + 10; % OTP-4710 +hchar_to_int(Char) when ($a =< Char) andalso (Char =< $f) -> + Char - $a + 10. % OTP-4710 + +-ifdef(megaco_parser_inline). +-compile({inline,[{value_of,1}]}). +-endif. +value_of(Token) -> + {_TokenTag, _Line, Text} = Token, + Text. + + +%% ------------------------------------------------------------------- + +%% d(F) -> +%% d(F,[]). +%% d(F, A) -> +%% %% d(true, F, A). +%% d(get(dbg), F, A). + +%% d(true, F, A) -> +%% io:format("DBG:~w:" ++ F ++ "~n", [?MODULE | A]); +%% d(_, _, _) -> +%% ok. + diff --git a/lib/megaco/src/text/megaco_text_parser_prev3c.yrl b/lib/megaco/src/text/megaco_text_parser_prev3c.yrl new file mode 100644 index 0000000000..9b7984deab --- /dev/null +++ b/lib/megaco/src/text/megaco_text_parser_prev3c.yrl @@ -0,0 +1,1673 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2005-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: YECC grammar for text encoding of Megaco/H.248 +%%---------------------------------------------------------------------- + +%%---------------------------------------------------------------------- +%% Annex B TEXT ENCODING OF THE PROTOCOL (NORMATIVE) +%% +%% B.1 Coding of wildcards +%% +%% In a text encoding of the protocol, while TerminationIDs are +%% arbitrary, by judicious choice of names, the wildcard character, "*" +%% may be made more useful. When the wildcard character is encountered, +%% it will "match" all TerminationIDs having the same previous and +%% following characters (if appropriate). For example, if there were +%% TerminationIDs of R13/3/1, R13/3/2 and R13/3/3, the TerminationID +%% R13/3/* would match all of them. There are some circumstances where +%% ALL Terminations must be referred to. The TerminationID "*" suffices, +%% and is referred to as ALL. The CHOOSE TerminationID "$" may be used to +%% signal to the MG that it has to create an ephemeral Termination or +%% select an idle physical Termination. +%% +%% B.2 ABNF specification +%% +%% The protocol syntax is presented in ABNF according to RFC2234. The +%% protocol is not case sensitive. Identifiers are not case sensitive. +%% +%% NOTE 1 - This syntax specification does not enforce all restrictions +%% on element inclusions and values. Some additional +%% restrictions are stated in comments and other restrictions +%% appear in the text of this Recommendation. These additional +%% restrictions are part of the protocol even though not +%% enforced by this Recommendation. +%% NOTE 2 - The syntax is context-dependent. For example, "Add" can be +%% the AddToken or a NAME depending on the context in which it +%% occurs. +%% +%% Everything in the ABNF and text encoding is case insensitive. This +%% includes TerminationIDs, digitmap Ids etc. SDP is case sensitive as +%% per RFC 2327. +%% +%%---------------------------------------------------------------------- + +%%---------------------------------------------------------------------- +%% Number of expected shift/reduce warnings +%% This is ugly but... +%%---------------------------------------------------------------------- + +Expect 93. + + +%%---------------------------------------------------------------------- +%% Non-terminals +%%---------------------------------------------------------------------- + +Nonterminals + + actionReply + actionReplyBody + actionReplyList + actionRequest + actionRequestBody + actionRequestItem + actionRequestItems + actionRequestList + alternativeValue + ammParameter + ammParameters + ammRequest + ammRequestBody + ammToken + ammsReply + ammsReplyBody + ammsToken + auditDescriptor + auditDescriptorBody + auditItem + auditItemList + auditOther + auditReply + auditRequest + auditReturnItem + auditReturnParameter + auditReturnParameterList + auditSelectLogic %% v3 + authenticationHeader + commandReplyList + commandReplys %% v3 + commandRequest + contextAttrDescriptor %% v3 + contextAudit + contextAuditProperties + contextAuditProperty + contextAuditSelector %% v3 + contextID + contextIdList %% v3 + contextIDs %% v3 +%% contextProperties %% v3 + contextProperty +%% contextPropertyList + contextTerminationAudit + daddr + deviceName + digitMapDescriptor + direction %% v3 + domainAddress + domainName + embedFirst + embedNoSig + embedSig + embedWithSig + emergencyValue %% v3 + errorCode + errorDescriptor + errorText + eventBufferControl + eventBufferControlValue %% v3 + eventBufferDescriptor + eventDM + eventParameter + eventParameterName + eventParameters + eventSpec + eventSpecList + eventStream + eventStreamOrOther + eventsDescriptor + extension + extensionParameter + + iaServiceStates %% v3 + iepsValue + + %% v2 - start + indAudauditReturnParameter + indAuddigitMapDescriptor + indAudeventBufferDescriptor + indAudeventSpec + indAudeventSpecParameter + %% indAudeventSpecParameterList + indAudeventsDescriptor + indAudlocalControlDescriptor + indAudlocalParm + indAudlocalParmList + indAudmediaDescriptor + indAudmediaParm + indAudmediaParms %% v3 + %% indAudmediaParmList + indAudpackagesDescriptor + indAudrequestedEvent + indAudsignalsDescriptor + indAudsignalList + %% indAudsignalListParm + indAudsignalParm + %% indAudsignalRequest + indAudstreamDescriptor + indAudstreamParm + indAudstatisticsDescriptor + indAudterminationAudit + indAudterminationAuditList + indAudterminationStateDescriptor + indAudterminationStateParm + %% indAudterminationStateParmList + optIndAudeventSpecParameter + optIndAudsignalParm + %% v2 - end + + indAudcontextAttrDescriptor %% v3 + + localControlDescriptor + localParm + localParmList + mId + mediaDescriptor + mediaParm + mediaParmList + megacoMessage + message + messageBody + modemDescriptor % Deprecated as of Corr 1 + modemType % Deprecated as of Corr 1 + modemTypeList % Deprecated as of Corr 1 + mtpAddress + muxDescriptor + muxType + notificationReason + notificationReasons + notifyBehaviour %% v3 + notifyRegulated %% v3 + notifyReply + notifyReplyBody + notifyRequest + notifyRequestBody + observedEvent + observedEventBody + observedEventParameter + observedEventParameters + % observedEventTimeStamp + observedEvents + observedEventsDescriptor + onOrOff + optAuditDescriptor + optImmAckRequired + optPropertyParms + optSep + packagesDescriptor + packagesItem + packagesItems + %% parmName + parmValue + pathName + pkgdName + portNumber + priority + propertyParm + propertyParms + propertyParmList + requestID + requestedEvent + requestedEventBody + requestedEvents + safeToken + safeToken2 + secondEventParameter + secondEventParameters + secondRequestedEvent + secondRequestedEventBody + secondRequestedEvents + servChgReplyParm + servChgReplyParms + serviceChangeAddress + serviceChangeDelay + serviceChangeDescriptor + serviceChangeMethod + serviceChangeMgcId + serviceChangeParm + serviceChangeParms + serviceChangeProfile + serviceChangeReason + serviceChangeReply + serviceChangeReplyBody + serviceChangeReplyDescriptor + serviceChangeRequest + serviceChangeVersion + serviceStates + serviceStatesValue %% v3 + sigParameter + sigParameters + signalList + signalListId + signalListParm + signalListParms + signalName + signalParm + signalParms + signalRequest + signalsDescriptor + signalType + statisticsDescriptor + statisticsParameter + statisticsParameters + streamDescriptor + streamID + streamModes + streamParm + streamParmList + subtractRequest + termIDList %% v3 + terminationAudit + terminationID + terminationIDList + terminationIDListRepeat + terminationStateDescriptor + terminationStateParm + terminationStateParms + timeStamp + topologyDescriptor + topologyDirection + topologyDescComp + topologyDescCompList + transactionAck + transactionAckList + transactionID + transactionItem + transactionList + transactionPending + transactionReply + transactionReplyBody + transactionRequest + transactionResponseAck + value + valueList + +. + +%%---------------------------------------------------------------------- +%% Terminals +%%---------------------------------------------------------------------- + +Terminals + + 'AddToken' + 'AndAUDITselectToken' %% v3 + 'AuditCapToken' + 'AuditToken' + 'AuditValueToken' + 'AuthToken' + 'BothToken' %% v3 + 'BothwayToken' + 'BriefToken' + 'BufferToken' + 'COLON' + 'COMMA' + 'ContextAttrToken' %% v3 + 'ContextAuditToken' + 'ContextListToken' %% v3 + 'CtxToken' + 'DelayToken' + 'DigitMapToken' + 'DigitMapDescriptorToken' + 'DirectionToken' %% v3 + 'DiscardToken' + 'DisconnectedToken' + 'DurationToken' + 'EQUAL' + 'EmbedToken' + 'EmergencyToken' + 'EmergencyOffToken' + 'EmergencyValueToken' %% v3 + 'ErrorToken' + 'EventBufferToken' + 'EventsToken' + 'ExternalToken' %% v3 + 'FailoverToken' + 'ForcedToken' + 'GREATER' + 'GracefulToken' + 'H221Token' + 'H223Token' + 'H226Token' + 'HandOffToken' + 'IEPSToken' %% v3 + 'ImmAckRequiredToken' + 'INEQUAL' %% v3 + 'InSvcToken' + 'InactiveToken' + 'InternalToken' %% v3 + 'InterruptByEventToken' + 'InterruptByNewSignalsDescrToken' + 'IntsigDelayToken' %% v3 + 'IsolateToken' + 'IterationToken' %% v3 + 'KeepActiveToken' + 'LBRKT' + 'LESSER' + 'LSBRKT' + 'LocalControlToken' + 'LocalDescriptorToken' + 'LockStepToken' + 'LoopbackToken' + 'MediaToken' + %% 'MegacopToken' + 'MethodToken' + 'MgcIdToken' + 'ModeToken' + 'ModemToken' + 'ModifyToken' + 'MoveToken' + 'MtpAddressToken' + 'MuxToken' + 'NEQUAL' + 'NeverNotifyToken' %% v3 + 'NotifyCompletionToken' + 'NotifyImmediateToken' %% v3 + 'NotifyRegulatedToken' %% v3 + 'NotifyToken' + 'Nx64Token' %% v2 + 'ObservedEventsToken' + 'OffToken' + 'OnToken' + 'OnOffToken' + 'OnewayToken' + 'OnewayExternalToken' %% v3 + 'OnewayBothToken' %% v3 + 'OrAUDITselectToken' %% v3 + 'OtherReasonToken' + 'OutOfSvcToken' + 'PackagesToken' + 'PendingToken' + 'PriorityToken' + 'ProfileToken' + 'QuotedChars' + 'RBRKT' + 'RSBRKT' + 'ReasonToken' + 'RecvonlyToken' + 'RemoteDescriptorToken' + 'ReplyToken' + 'RequestIDToken' %% v3 + 'ReservedGroupToken' + 'ReservedValueToken' + 'ResetEventsDescriptorToken' %% v3 + 'ResponseAckToken' + 'RestartToken' + 'SEP' + 'SafeChars' + 'SendonlyToken' + 'SendrecvToken' + 'ServiceChangeAddressToken' + 'ServiceChangeToken' + 'ServiceChangeIncompleteToken' + 'ServiceStatesToken' + 'ServicesToken' + 'SignalListToken' + 'SignalTypeToken' + 'SignalsToken' + 'StatsToken' + 'StreamToken' + 'SubtractToken' + 'SynchISDNToken' + 'TerminationStateToken' + 'TestToken' + 'TimeOutToken' + 'TimeStampToken' + 'TopologyToken' + 'TransToken' + 'V18Token' + 'V22Token' + 'V22bisToken' + 'V32Token' + 'V32bisToken' + 'V34Token' + 'V76Token' + 'V90Token' + 'V91Token' + 'VersionToken' + 'MessageSegmentToken' %% OTP-7534: v3-fix + 'SegmentationCompleteToken' %% OTP-7534: v3-fix + endOfMessage + +. + +%%---------------------------------------------------------------------- +%% Root symbol +%%---------------------------------------------------------------------- + +Rootsymbol megacoMessage. + +%%---------------------------------------------------------------------- +%% The grammar +%%---------------------------------------------------------------------- + +%% megacoMessage = LWSP [authenticationHeader SEP ] message +%% authenticationHeader = AuthToken EQUAL SecurityParmIndex COLON +%% SequenceNum COLON AuthData +%% +%% SecurityParmIndex = "0x" 8(HEXDIG) +%% SequenceNum = "0x" 8(HEXDIG) +%% AuthData = "0x" 24*64(HEXDIG) +%% message = MegacopToken SLASH version SEP mId SEP messageBody +%% version = 1*2(DIGIT) . + +megacoMessage -> optSep authenticationHeader message endOfMessage + : #'MegacoMessage'{authHeader = '$2', mess = '$3'} . + +optSep -> 'SEP' : sep . +optSep -> '$empty' : no_sep . + +authenticationHeader -> 'AuthToken' 'EQUAL' safeToken 'COLON' + safeToken 'COLON' safeToken optSep + : ensure_auth_header('$3', '$5', '$7') . +authenticationHeader -> '$empty' : asn1_NOVALUE . + +message -> safeToken mId messageBody : + ensure_message('$1', '$2', '$3') . + +messageBody -> errorDescriptor : {messageError, '$1'} . +messageBody -> transactionList : {transactions, '$1'} . + +transactionList -> transactionItem : ['$1'] . +transactionList -> transactionItem transactionList : ['$1' | '$2'] . + +transactionItem -> transactionRequest : {transactionRequest, '$1'} . +transactionItem -> transactionReply : {transactionReply, '$1'}. +transactionItem -> transactionPending : {transactionPending, '$1'} . +transactionItem -> transactionResponseAck : {transactionResponseAck, '$1'} . + +transactionResponseAck -> 'ResponseAckToken' + 'LBRKT' transactionAck + transactionAckList 'RBRKT' : ['$3' | '$4'] . + +transactionAckList -> 'COMMA' transactionAck + transactionAckList : ['$2' | '$3'] . +transactionAckList -> '$empty' : [] . + +transactionAck -> safeToken : ensure_transactionAck('$1') . + +transactionPending -> 'PendingToken' 'EQUAL' transactionID 'LBRKT' 'RBRKT' : + #'TransactionPending'{transactionId = ensure_transactionID('$3') } . + +transactionRequest -> 'TransToken' 'LBRKT' actionRequest + actionRequestList 'RBRKT' : + #'TransactionRequest'{transactionId = asn1_NOVALUE, + actions = ['$3' | '$4']} . +transactionRequest -> 'TransToken' 'EQUAL' 'LBRKT' actionRequest + actionRequestList 'RBRKT' : + #'TransactionRequest'{transactionId = asn1_NOVALUE, + actions = ['$4' | '$5']} . +transactionRequest -> 'TransToken' 'EQUAL' transactionID + 'LBRKT' actionRequest actionRequestList 'RBRKT' : + #'TransactionRequest'{transactionId = ensure_transactionID('$3'), + actions = ['$5' | '$6']} . + +actionRequestList -> 'COMMA' actionRequest actionRequestList : ['$2' | '$3'] . +actionRequestList -> '$empty' : [] . + +%% actionRequest = CtxToken EQUAL ContextID LBRKT ((contextRequest +%% [COMMA commandRequestList]) / +%% commandRequestList) RBRKT +%% contextRequest = ((contextProperties [COMMA contextAudit]) / +%% contextAudit) +%% contextProperties = contextProperty *(COMMA contextProperty) + +actionRequest -> 'CtxToken' 'EQUAL' contextID + 'LBRKT' actionRequestBody 'RBRKT' : + merge_action_request('$3', '$5') . + +actionRequestBody -> actionRequestItem actionRequestItems : ['$1' | '$2'] . + +actionRequestItems -> 'COMMA' actionRequestItem + actionRequestItems : ['$2' | '$3'] . +actionRequestItems -> '$empty' : [] . + +actionRequestItem -> contextProperty : {contextProp, '$1'} . +actionRequestItem -> contextAudit : {contextAudit, '$1'} . +actionRequestItem -> commandRequest : {commandRequest, '$1'} . + + +%% at-most-once (presumebly in contextProperties) +contextProperty -> topologyDescriptor : {topology, '$1'}. +contextProperty -> priority : {priority, '$1'}. +contextProperty -> 'EmergencyToken' : {emergency, true}. +contextProperty -> 'EmergencyOffToken' : {emergency, false}. +contextProperty -> iepsValue : {iepsCallind, '$1'} . +contextProperty -> contextAttrDescriptor : '$1' . + +contextAttrDescriptor -> 'ContextAttrToken' 'LBRKT' propertyParms 'RBRKT' : + {contextProp, '$3'}. +contextAttrDescriptor -> 'ContextAttrToken' 'LBRKT' contextIdList 'RBRKT' : + {contextList, '$3'}. + +contextIdList -> 'ContextListToken' 'EQUAL' + 'LBRKT' contextID contextIDs 'RBRKT' : ['$4' | '$5'] . + +contextIDs -> 'COMMA' contextID contextIDs : ['$2' | '$3'] . +contextIDs -> '$empty' : [] . + +contextAudit -> 'ContextAuditToken' 'LBRKT' + indAudcontextAttrDescriptor 'RBRKT' : + merge_context_attr_audit_request( + #'ContextAttrAuditRequest'{}, '$3') . +contextAudit -> 'ContextAuditToken' 'LBRKT' + contextAuditProperty contextAuditProperties 'RBRKT' : + merge_context_attr_audit_request( + #'ContextAttrAuditRequest'{}, ['$3' | '$4']) . + +indAudcontextAttrDescriptor -> 'ContextAttrToken' + 'LBRKT' contextAuditProperty + contextAuditProperties 'RBRKT' + : ['$3' | '$4'] . + +contextAuditProperties -> 'COMMA' contextAuditProperty contextAuditProperties + : ['$2' | '$3'] . +contextAuditProperties -> '$empty' : [] . + +%% at-most-once except contextAuditSelector. +contextAuditProperty -> 'TopologyToken' : topologyAudit . +contextAuditProperty -> 'EmergencyToken' : emergencyAudit . +contextAuditProperty -> 'PriorityToken' : priorityAudit . +contextAuditProperty -> 'IEPSToken' : iepsCallind . +contextAuditProperty -> pkgdName : {prop, '$1'} . +contextAuditProperty -> contextAuditSelector : '$1' . + +%% at-most-once +contextAuditSelector -> priority : {select_prio, '$1'} . +contextAuditSelector -> emergencyValue : {select_emergency, '$1'} . +contextAuditSelector -> iepsValue : {select_ieps, '$1'} . +contextAuditSelector -> auditSelectLogic : {select_logic, '$1'} . +contextAuditSelector -> contextAttrDescriptor : '$1' . + +auditSelectLogic -> 'AndAUDITselectToken' : {andAUDITSelect, 'NULL'} . +auditSelectLogic -> 'OrAUDITselectToken' : {orAUDITSelect, 'NULL'} . + +commandRequest -> ammRequest : '$1'. +commandRequest -> subtractRequest : '$1'. +commandRequest -> auditRequest : '$1'. +commandRequest -> notifyRequest : '$1'. +commandRequest -> serviceChangeRequest : '$1'. + +transactionReply -> 'ReplyToken' 'EQUAL' transactionID + 'LBRKT' + optImmAckRequired transactionReplyBody + 'RBRKT' + : #'TransactionReply'{transactionId = '$3', + immAckRequired = '$5', + transactionResult = '$6'} . + +optImmAckRequired -> 'ImmAckRequiredToken' 'COMMA' : 'NULL' . +optImmAckRequired -> '$empty' : asn1_NOVALUE . + +transactionReplyBody -> errorDescriptor : {transactionError, '$1'} . +transactionReplyBody -> actionReply actionReplyList : {actionReplies, ['$1' | '$2']} . + +actionReplyList -> 'COMMA' actionReply actionReplyList : ['$2' | '$3'] . +actionReplyList -> '$empty' : [] . + +actionReply -> 'CtxToken' 'EQUAL' contextID + 'LBRKT' actionReplyBody 'RBRKT' : + setelement(#'ActionReply'.contextId, '$5', '$3') . +actionReply -> 'CtxToken' 'EQUAL' contextID : + #'ActionReply'{contextId = '$3'} . + +actionReplyBody -> errorDescriptor : + #'ActionReply'{errorDescriptor = '$1'} . +actionReplyBody -> commandReplys commandReplyList : + merge_action_reply(['$1' | '$2']) . + +%% OTP-5085 +%% This ugly thing is to fool the parser. The errorDescriptor does not +%% realy belong here. The merge_action_reply will remove it and put it +%% in it's right place later. +commandReplyList -> 'COMMA' errorDescriptor : + [{error, '$2'}] . +commandReplyList -> 'COMMA' commandReplys commandReplyList : + ['$2' | '$3'] . +commandReplyList -> '$empty' : [] . + +commandReplys -> serviceChangeReply : {command, '$1'} . +commandReplys -> auditReply : {command, '$1'} . +commandReplys -> ammsReply : {command, '$1'} . +commandReplys -> notifyReply : {command, '$1'} . +commandReplys -> contextProperty : {context, '$1'} . + +%Add Move and Modify have the same request parameter +ammRequest -> ammToken 'EQUAL' termIDList ammRequestBody : + Descs = merge_AmmRequest_descriptors('$4', []), + make_commandRequest('$1', + #'AmmRequest'{terminationID = '$3', + descriptors = Descs}) . + +ammToken -> 'AddToken' : {addReq, '$1'} . +ammToken -> 'MoveToken' : {moveReq, '$1'} . +ammToken -> 'ModifyToken' : {modReq, '$1'} . + +ammRequestBody -> 'LBRKT' ammParameter ammParameters 'RBRKT' : ['$2' | '$3'] . +ammRequestBody -> '$empty' : [] . + +ammParameters -> 'COMMA' ammParameter ammParameters : ['$2' | '$3'] . +ammParameters -> '$empty' : [] . + +%at-most-once +ammParameter -> mediaDescriptor : {mediaDescriptor, '$1'}. +ammParameter -> modemDescriptor : {modemDescriptor, deprecated}. +ammParameter -> muxDescriptor : {muxDescriptor, '$1'}. +ammParameter -> eventsDescriptor : {eventsDescriptor, '$1'}. +ammParameter -> eventBufferDescriptor : {eventBufferDescriptor, '$1'}. +ammParameter -> signalsDescriptor : {signalsDescriptor, '$1'}. +ammParameter -> digitMapDescriptor : {digitMapDescriptor, '$1'}. +ammParameter -> auditDescriptor : {auditDescriptor, '$1'}. +ammParameter -> statisticsDescriptor : {statisticsDescriptor, '$1'}. + +ammsReply -> ammsToken 'EQUAL' termIDList ammsReplyBody + : {'$1', #'AmmsReply'{terminationID = '$3', + terminationAudit = '$4'}} . + +ammsToken -> 'AddToken' : addReply . +ammsToken -> 'MoveToken' : moveReply . +ammsToken -> 'ModifyToken' : modReply . +ammsToken -> 'SubtractToken' : subtractReply . + +ammsReplyBody -> 'LBRKT' terminationAudit 'RBRKT' : '$2' . +ammsReplyBody -> '$empty' : asn1_NOVALUE . + +subtractRequest -> 'SubtractToken' 'EQUAL' termIDList optAuditDescriptor : + SR = #'SubtractRequest'{terminationID = '$3', + auditDescriptor = '$4'}, + make_commandRequest({subtractReq, '$1'}, SR) . + + +optAuditDescriptor -> 'LBRKT' auditDescriptor 'RBRKT' : '$2'. +optAuditDescriptor -> '$empty' : asn1_NOVALUE . + +auditRequest -> 'AuditValueToken' 'EQUAL' termIDList optAuditDescriptor : + make_commandRequest({auditValueRequest, '$1'}, + make_auditRequest('$3', '$4')) . +auditRequest -> 'AuditCapToken' 'EQUAL' termIDList optAuditDescriptor : + make_commandRequest({auditCapRequest, '$1'}, + make_auditRequest('$3', '$4')) . + +auditReply -> 'AuditValueToken' 'EQUAL' 'CtxToken' contextTerminationAudit : + {auditValueReply, '$4'} . +auditReply -> 'AuditCapToken' 'EQUAL' 'CtxToken' contextTerminationAudit : + {auditCapReply, '$4'} . +auditReply -> 'AuditValueToken' 'EQUAL' auditOther : + {auditValueReply, '$3'} . +auditReply -> 'AuditCapToken' 'EQUAL' auditOther : + {auditCapReply, '$3'} . + +contextTerminationAudit -> terminationIDList : + {contextAuditResult, '$1'} . +contextTerminationAudit -> 'LBRKT' errorDescriptor 'RBRKT' : + {error, '$2'} . + +auditOther -> termIDList : + merge_auditOther('$1', []) . +auditOther -> termIDList 'LBRKT' terminationAudit 'RBRKT' : + merge_auditOther('$1', '$3') . + + +terminationAudit -> auditReturnParameter auditReturnParameterList : + merge_terminationAudit(['$1' |'$2' ]) . + +auditReturnParameterList -> 'COMMA' auditReturnParameter auditReturnParameterList : ['$2' | '$3'] . +auditReturnParameterList -> '$empty' : [] . + +auditReturnParameter -> mediaDescriptor : {mediaDescriptor, '$1'} . +auditReturnParameter -> modemDescriptor. +auditReturnParameter -> muxDescriptor : {muxDescriptor, '$1'} . +auditReturnParameter -> eventsDescriptor : {eventsDescriptor, '$1'} . +auditReturnParameter -> signalsDescriptor : {signalsDescriptor, '$1'} . +auditReturnParameter -> digitMapDescriptor : {digitMapDescriptor, '$1'} . +auditReturnParameter -> observedEventsDescriptor : {observedEventsDescriptor, '$1'} . +auditReturnParameter -> eventBufferDescriptor : {eventBufferDescriptor, '$1'} . +auditReturnParameter -> statisticsDescriptor : {statisticsDescriptor, '$1'} . +auditReturnParameter -> packagesDescriptor : {packagesDescriptor, '$1'} . +auditReturnParameter -> errorDescriptor : {errorDescriptor, '$1'} . +auditReturnParameter -> auditReturnItem : {auditReturnItem, '$1'} . + +auditDescriptor -> 'AuditToken' 'LBRKT' auditDescriptorBody 'RBRKT' : + merge_auditDescriptor('$3') . + +auditDescriptorBody -> auditItem auditItemList : ['$1' | '$2']. +auditDescriptorBody -> '$empty' : asn1_NOVALUE . + +auditItemList -> 'COMMA' auditItem auditItemList : ['$2' | '$3'] . +auditItemList -> '$empty' : [] . + +%% IGv11 - begin +%% +auditReturnItem -> 'MuxToken' : muxToken . +auditReturnItem -> 'ModemToken' : modemToken . +auditReturnItem -> 'MediaToken' : mediaToken . +auditReturnItem -> 'DigitMapToken' : digitMapToken . +auditReturnItem -> 'StatsToken' : statsToken . +auditReturnItem -> 'ObservedEventsToken' : observedEventsToken . +auditReturnItem -> 'PackagesToken' : packagesToken . + +%% at-most-once, and DigitMapToken and PackagesToken are not allowed +%% in AuditCapabilities command +auditItem -> auditReturnItem : '$1' . +auditItem -> 'SignalsToken' : signalsToken. +auditItem -> 'EventBufferToken' : eventBufferToken. +auditItem -> 'EventsToken' : eventsToken . +auditItem -> indAudterminationAudit : {terminationAudit, '$1'} . % v2 +%% +%% IGv11 - end + + +%% v2 - start +%% +indAudterminationAudit -> indAudauditReturnParameter + indAudterminationAuditList + : ['$1' | '$2'] . + +indAudterminationAuditList -> 'COMMA' indAudauditReturnParameter + indAudterminationAuditList + : ['$2' | '$3'] . +indAudterminationAuditList -> '$empty' : [] . + +indAudauditReturnParameter -> indAudmediaDescriptor + : {indAudMediaDescriptor, '$1'} . +indAudauditReturnParameter -> indAudeventsDescriptor + : {indAudEventsDescriptor, '$1'} . +indAudauditReturnParameter -> indAudsignalsDescriptor + : {indAudSignalsDescriptor, '$1'} . +indAudauditReturnParameter -> indAuddigitMapDescriptor + : {indAudDigitMapDescriptor, '$1'} . +indAudauditReturnParameter -> indAudeventBufferDescriptor + : {indAudEventBufferDescriptor, '$1'} . +indAudauditReturnParameter -> indAudstatisticsDescriptor + : {indAudStatisticsDescriptor, '$1'} . +indAudauditReturnParameter -> indAudpackagesDescriptor + : {indAudPackagesDescriptor, '$1'} . + + +indAudmediaDescriptor -> 'MediaToken' 'LBRKT' + indAudmediaParm indAudmediaParms 'RBRKT' + : merge_indAudMediaDescriptor(['$3'|'$4']) . + +%% at-most-once per item +%% and either streamParm or streamDescriptor but not both +%% + +indAudmediaParm -> indAudstreamParm : {streamParm, '$1'} . +indAudmediaParm -> indAudstreamDescriptor : {streamDescr, '$1'} . +indAudmediaParm -> indAudterminationStateDescriptor : {termStateDescr, '$1'} . + +indAudmediaParms -> 'COMMA' indAudmediaParm indAudmediaParms : ['$2' | '$3'] . +indAudmediaParms -> '$empty' : [] . + +%% at-most-once +indAudstreamParm -> 'RemoteDescriptorToken' : + RD = ensure_prop_groups('$1'), + #'IndAudStreamParms'{remoteDescriptor = RD} . +indAudstreamParm -> 'LocalDescriptorToken' : + LD = ensure_prop_groups('$1'), + #'IndAudStreamParms'{localDescriptor = LD} . +indAudstreamParm -> indAudlocalControlDescriptor : + #'IndAudStreamParms'{localControlDescriptor = '$1'} . +indAudstreamParm -> indAudstatisticsDescriptor : + #'IndAudStreamParms'{statisticsDescriptor = '$1'} . + +indAudstreamDescriptor -> 'StreamToken' 'EQUAL' streamID + 'LBRKT' indAudstreamParm 'RBRKT' + : #'IndAudStreamDescriptor'{streamID = '$3', + streamParms = '$5'} . + + +indAudlocalControlDescriptor -> 'LocalControlToken' + 'LBRKT' indAudlocalParm + indAudlocalParmList 'RBRKT' : + merge_indAudLocalControlDescriptor(['$3' | '$4']) . + +indAudlocalParmList -> 'COMMA' indAudlocalParm + indAudlocalParmList : ['$2' | '$3'] . +indAudlocalParmList -> '$empty' : [] . + +%% at-most-once per item +%% +%% propertyparm and streamModes are used only to specify audit selection +%% criteria. AND/OR selection logic is specified at context level. +%% +indAudlocalParm -> 'ReservedGroupToken' : reservedGroupToken . +indAudlocalParm -> 'ReservedValueToken' : reservedValueToken . +indAudlocalParm -> 'ModeToken' : modeToken . +indAudlocalParm -> 'ModeToken' 'EQUAL' streamModes : {mode, {equal, '$3'}} . +indAudlocalParm -> 'ModeToken' 'INEQUAL' streamModes : {mode, {inequal,'$3'}} . +indAudlocalParm -> propertyParm : {prop, '$1'} . +indAudlocalParm -> pkgdName : {name, '$1'} . + +indAudterminationStateDescriptor -> 'TerminationStateToken' + 'LBRKT' indAudterminationStateParm 'RBRKT' + : + merge_indAudTerminationStateDescriptor('$3') . + +%% at-most-once per item +%% + +%% at-most-once per item except for propertyParm +indAudterminationStateParm -> iaServiceStates : '$1' . +indAudterminationStateParm -> 'BufferToken' : bufferToken . +indAudterminationStateParm -> propertyParm : {prop, '$1'} . +indAudterminationStateParm -> pkgdName : {name, '$1'} . + +iaServiceStates -> 'ServiceStatesToken' : + serviceStatesToken . +iaServiceStates -> 'ServiceStatesToken' 'EQUAL' serviceStatesValue : + {serviceStates, {equal, '$3'}} . +iaServiceStates -> 'ServiceStatesToken' 'INEQUAL' serviceStatesValue : + {serviceStates, {inequal, '$3'}} . + +indAudeventBufferDescriptor -> 'EventBufferToken' + 'LBRKT' indAudeventSpec 'RBRKT' : '$3' . + +indAudeventSpec -> pkgdName optIndAudeventSpecParameter + : merge_indAudEventBufferDescriptor('$1','$2') . + +optIndAudeventSpecParameter -> 'LBRKT' indAudeventSpecParameter 'RBRKT' + : '$2' . +optIndAudeventSpecParameter -> '$empty' : asn1_NOVALUE . + + +indAudeventSpecParameter -> eventStream : {streamID, '$1'} . +indAudeventSpecParameter -> eventParameterName : {eventParameterName, '$1'} . + +indAudeventsDescriptor -> 'EventsToken' 'LBRKT' indAudrequestedEvent 'RBRKT' : + #'IndAudEventsDescriptor'{pkgdName = '$3'} . +indAudeventsDescriptor -> 'EventsToken' 'EQUAL' requestID + 'LBRKT' indAudrequestedEvent 'RBRKT' : + #'IndAudEventsDescriptor'{requestID = '$3', + pkgdName = '$5'} . + +indAudrequestedEvent -> pkgdName : '$1' . + + +indAudsignalsDescriptor -> 'SignalsToken' optIndAudsignalParm : '$2' . + + +optIndAudsignalParm -> 'LBRKT' 'RBRKT' : asn1_NOVALUE . +optIndAudsignalParm -> 'LBRKT' indAudsignalParm 'RBRKT' : '$2' . + +indAudsignalParm -> indAudsignalList : {seqSigList, '$1'} . +indAudsignalParm -> signalRequest : {signal, ensure_indAudSignal('$1')} . + +indAudsignalList -> 'SignalListToken' 'EQUAL' signalListId : + #'IndAudSeqSigList'{id = ensure_uint16('$3')} . +indAudsignalList -> 'SignalListToken' 'EQUAL' signalListId + 'LBRKT' signalListParm 'RBRKT' : + #'IndAudSeqSigList'{id = ensure_uint16('$3'), + signalList = + ensure_indAudSignalListParm('$5')} . + + +%% The DigitMapDescriptorToken is specially treated by the scanner +indAuddigitMapDescriptor -> 'DigitMapDescriptorToken' : + ensure_IADMD('$1') . + +indAudstatisticsDescriptor -> 'StatsToken' 'LBRKT' pkgdName 'RBRKT' : + #'IndAudStatisticsDescriptor'{statName = '$3'} . + +indAudpackagesDescriptor -> 'PackagesToken' 'LBRKT' packagesItem 'RBRKT' + : merge_indAudPackagesDescriptor('$3') . + +eventStream -> 'StreamToken' 'EQUAL' streamID : '$3' . + + +%% +%% v2 - end + +notifyRequest -> 'NotifyToken' 'EQUAL' termIDList + 'LBRKT' notifyRequestBody 'RBRKT' : + NR = setelement(#'NotifyRequest'.terminationID, + '$5', '$3'), + make_commandRequest({notifyReq, '$1'}, NR) . + +notifyRequestBody -> observedEventsDescriptor : + #'NotifyRequest'{observedEventsDescriptor = '$1'}. +notifyRequestBody -> errorDescriptor : + #'NotifyRequest'{errorDescriptor = '$1'}. + +notifyReply -> 'NotifyToken' 'EQUAL' termIDList notifyReplyBody : + {notifyReply, #'NotifyReply'{terminationID = '$3', + errorDescriptor = '$4'}} . + +notifyReplyBody -> 'LBRKT' errorDescriptor 'RBRKT' : '$2'. +notifyReplyBody -> '$empty' : asn1_NOVALUE . + +serviceChangeRequest -> 'ServiceChangeToken' 'EQUAL' termIDList + 'LBRKT' serviceChangeDescriptor 'RBRKT' : + make_commandRequest({serviceChangeReq, '$1'}, + #'ServiceChangeRequest'{terminationID = '$3', + serviceChangeParms = '$5'}) . + +serviceChangeReply -> 'ServiceChangeToken' 'EQUAL' termIDList + serviceChangeReplyBody : + {serviceChangeReply, + #'ServiceChangeReply'{terminationID = '$3', + serviceChangeResult = '$4'}} . + +serviceChangeReplyBody -> 'LBRKT' errorDescriptor 'RBRKT' : + {errorDescriptor, '$2'} . +serviceChangeReplyBody -> 'LBRKT' serviceChangeReplyDescriptor 'RBRKT' : + {serviceChangeResParms, '$2'} . +serviceChangeReplyBody -> '$empty' : + {serviceChangeResParms, #'ServiceChangeResParm'{}}. + +errorDescriptor -> 'ErrorToken' 'EQUAL' errorCode 'LBRKT' + errorText 'RBRKT' : + #'ErrorDescriptor'{errorCode = '$3', + errorText = '$5'} . + +errorCode -> safeToken : ensure_uint('$1', 0, 999) . + +errorText -> 'QuotedChars' : value_of('$1') . +errorText -> '$empty' : asn1_NOVALUE . + +transactionID -> safeToken : ensure_uint32('$1') . + +mId -> domainName : '$1' . +mId -> domainAddress : '$1' . +mId -> optSep mtpAddress optSep : '$2' . +mId -> optSep deviceName optSep : '$2' . + +domainName -> 'LESSER' safeToken 'GREATER' 'COLON' portNumber optSep + : ensure_domainName('$2', '$5') . +domainName -> 'LESSER' safeToken 'GREATER' + : ensure_domainName('$2', asn1_NOVALUE) . + +deviceName -> pathName : {deviceName, '$1'} . + +%% '-' is used for NULL context +contextID -> safeToken : ensure_contextID('$1') . + +domainAddress -> 'LSBRKT' daddr 'RSBRKT' 'COLON' portNumber optSep + : ensure_domainAddress('$2', '$5') . +domainAddress -> 'LSBRKT' daddr 'RSBRKT' + : ensure_domainAddress('$2', asn1_NOVALUE) . + +daddr -> '$empty' : [] . +daddr -> 'COLON' daddr : [colon| '$2'] . +daddr -> safeToken daddr : ['$1'| '$2'] . + + +portNumber -> safeToken : ensure_uint16('$1') . + +mtpAddress -> 'MtpAddressToken' : ensure_mtpAddress('$1') . + +termIDList -> terminationID : ['$1'] . +termIDList -> LSBRKT terminationID terminationIDListRepeat RSBRKT : + ['$2' | '$3'] . + +terminationIDList -> 'LBRKT' terminationID terminationIDListRepeat 'RBRKT' : + ['$2' | '$3'] . + +terminationIDListRepeat -> 'COMMA' terminationID terminationIDListRepeat : + ['$2'| '$3'] . +terminationIDListRepeat -> '$empty' : [] . + + +pathName -> safeToken : ensure_pathName('$1') . + +terminationID -> safeToken : ensure_terminationID('$1') . + +mediaDescriptor -> 'MediaToken' 'LBRKT' mediaParm mediaParmList 'RBRKT' + : merge_mediaDescriptor(['$3' | '$4']) . + +mediaParmList -> 'COMMA' mediaParm mediaParmList : ['$2' | '$3'] . +mediaParmList -> '$empty' : [] . + + +%% at-most-once per item +%% using either streamParms or streamDescriptors but not both +mediaParm -> streamParm + : {streamParm, '$1'} . +mediaParm -> streamDescriptor + : {streamDescriptor, '$1'} . +mediaParm -> terminationStateDescriptor + : {termState, '$1'} . + +%% at-most-once . +%% Specially treated by the scanner. +streamParm -> 'LocalDescriptorToken' : + PGs = ensure_prop_groups('$1'), + {local, #'LocalRemoteDescriptor'{propGrps = PGs} } . +streamParm -> 'RemoteDescriptorToken' : + PGs = ensure_prop_groups('$1'), + {remote, #'LocalRemoteDescriptor'{propGrps = PGs}} . +streamParm -> localControlDescriptor : {control, '$1'} . +streamParm -> statisticsDescriptor : {statistics, '$1'} . + +streamDescriptor -> 'StreamToken' 'EQUAL' streamID + 'LBRKT' streamParm streamParmList 'RBRKT' + : #'StreamDescriptor'{streamID = '$3', + streamParms = merge_streamParms(['$5' | '$6'])} . + +streamParmList -> 'COMMA' streamParm streamParmList : ['$2' | '$3'] . +streamParmList -> '$empty' : [] . + +localControlDescriptor -> 'LocalControlToken' 'LBRKT' localParm localParmList 'RBRKT' + : ['$3' | '$4'] . + +localParmList -> 'COMMA' localParm localParmList : ['$2' | '$3'] . +localParmList -> '$empty': [] . + +terminationStateDescriptor -> 'TerminationStateToken' + 'LBRKT' terminationStateParm + terminationStateParms 'RBRKT' + : merge_terminationStateDescriptor(['$3' | '$4']) . + +terminationStateParms -> 'COMMA' terminationStateParm terminationStateParms : ['$2' | '$3'] . +terminationStateParms -> '$empty' : [] . + +%% at-most-once per item except for propertyParm +localParm -> 'ReservedGroupToken' 'EQUAL' onOrOff : {group, '$3'} . +localParm -> 'ReservedValueToken' 'EQUAL' onOrOff : {value, '$3'} . +localParm -> 'ModeToken' 'EQUAL' streamModes : {mode, '$3'} . +localParm -> propertyParm : {prop, '$1'} . + +onOrOff -> 'OnToken' : true . +onOrOff -> 'OffToken' : false . + +%% at-most-once +streamModes -> 'SendonlyToken' : sendOnly . +streamModes -> 'RecvonlyToken' : recvOnly . +streamModes -> 'SendrecvToken' : sendRecv . +streamModes -> 'InactiveToken' : inactive . +streamModes -> 'LoopbackToken' : loopBack . + +propertyParm -> pkgdName parmValue : + setelement(#'PropertyParm'.name, '$2', '$1') . + +parmValue -> 'EQUAL' alternativeValue : + '$2' . + +parmValue -> 'NEQUAL' value : + #'PropertyParm'{value = ['$2'], + extraInfo = {relation, unequalTo}} . +parmValue -> 'LESSER' value : + #'PropertyParm'{value = ['$2'], + extraInfo = {relation, smallerThan}} . +parmValue -> 'GREATER' value : + #'PropertyParm'{value = ['$2'], + extraInfo = {relation, greaterThan}} . + +%% OTP-4013 +%% alternativeValue = ( VALUE / +%% LSBRKT VALUE *(COMMA VALUE) RSBRKT / +%% LSBRKT VALUE COLON VALUE RSBRKT ) / +%% LBRKT VALUE *(COMMA VALUE) RBRKT +alternativeValue -> 'LBRKT' value valueList 'RBRKT' : + #'PropertyParm'{value = ['$2' | '$3'], + extraInfo = {sublist, false}}. % OR + +alternativeValue -> 'LSBRKT' value 'COLON' value 'RSBRKT' : + #'PropertyParm'{value = ['$2', '$4'], + extraInfo = {range, true}}. + +alternativeValue -> 'LSBRKT' value valueList 'RSBRKT' : + #'PropertyParm'{value = ['$2' | '$3'], + extraInfo = {sublist, true}}. % AND + +alternativeValue -> value : + #'PropertyParm'{value = ['$1']} . + +valueList -> 'COMMA' value valueList : ['$2' | '$3'] . +valueList -> '$empty' : [] . + + +eventBufferDescriptor -> 'EventBufferToken' : [] . +eventBufferDescriptor -> 'EventBufferToken' 'LBRKT' eventSpec + eventSpecList 'RBRKT' : + ['$3' | '$4'] . + +eventSpecList -> 'COMMA' eventSpec eventSpecList : ['$2' | '$3'] . +eventSpecList -> '$empty' : [] . + +eventSpec -> observedEvent : merge_eventSpec('$1') . + +%% at-most-once per item except for propertyParm +terminationStateParm -> serviceStates : {serviceState, '$1'} . +terminationStateParm -> eventBufferControl : {eventBufferControl, '$1'} . +terminationStateParm -> propertyParm : {propertyParm, '$1'} . + +serviceStates -> 'ServiceStatesToken' 'EQUAL' serviceStatesValue : '$3'. + +serviceStatesValue -> 'TestToken' : test . +serviceStatesValue -> 'OutOfSvcToken' : outOfSvc . +serviceStatesValue -> 'InSvcToken' : inSvc . + +eventBufferControl -> 'BufferToken' 'EQUAL' eventBufferControlValue : '$3' . + +eventBufferControlValue -> 'OffToken' : off . +eventBufferControlValue -> 'LockStepToken' : lockStep . + +muxDescriptor -> 'MuxToken' 'EQUAL' muxType terminationIDList : + #'MuxDescriptor'{muxType = '$3', + termList = '$4'} . + +muxType -> safeToken : ensure_muxType('$1') . + +streamID -> safeToken : ensure_streamID('$1') . + +pkgdName -> safeToken : ensure_pkgdName('$1') . + +eventsDescriptor -> 'EventsToken' : + #'EventsDescriptor'{requestID = asn1_NOVALUE, + eventList = []} . +eventsDescriptor -> 'EventsToken' 'EQUAL' requestID + 'LBRKT' requestedEvent requestedEvents 'RBRKT' : + #'EventsDescriptor'{requestID = '$3', + eventList = ['$5' | '$6']} . + +requestedEvents -> 'COMMA' requestedEvent requestedEvents : ['$2' | '$3'] . +requestedEvents -> '$empty' : [] . + +requestedEvent -> pkgdName requestedEventBody : + setelement(#'RequestedEvent'.pkgdName, '$2', '$1') . + +requestedEventBody -> 'LBRKT' eventParameter eventParameters 'RBRKT' : + merge_eventParameters(['$2' | '$3']) . +requestedEventBody -> '$empty' : #'RequestedEvent'{evParList = []} . + + +notifyRegulated -> 'NotifyRegulatedToken' : + #'RegulatedEmbeddedDescriptor'{} . +notifyRegulated -> 'NotifyRegulatedToken' 'LBRKT' embedWithSig 'RBRKT' : + make_RegulatedEmbeddedDescriptor('$3') . +notifyRegulated -> 'NotifyRegulatedToken' 'LBRKT' embedNoSig 'RBRKT' : + make_RegulatedEmbeddedDescriptor('$3') . + +notifyBehaviour -> 'NotifyImmediateToken' : {notifyImmediate, 'NULL'} . +notifyBehaviour -> 'NeverNotifyToken' : {neverNotify, 'NULL'} . +notifyBehaviour -> notifyRegulated : {notifyRegulated, '$1'} . + +eventParameters -> 'COMMA' eventParameter eventParameters : + ['$2' | '$3'] . +eventParameters -> '$empty' : [] . + +%% at-most-once each of embedOrKeepActive , eventDM or eventStream +eventParameter -> 'KeepActiveToken' : keepActive . +eventParameter -> embedWithSig : '$1'. +eventParameter -> embedNoSig : '$1'. +eventParameter -> eventDM : '$1'. +eventParameter -> eventStreamOrOther : '$1'. +eventParameter -> notifyBehaviour : {notifyBehaviour, '$1'}. +eventParameter -> 'ResetEventsDescriptorToken' : resetEventsDescriptor . + +embedWithSig -> 'EmbedToken' 'LBRKT' signalsDescriptor + 'COMMA' embedFirst 'RBRKT' + : {embed, '$3', '$5'} . +embedWithSig -> 'EmbedToken' 'LBRKT' signalsDescriptor 'RBRKT' + : {embed, '$3', asn1_NOVALUE} . + +embedNoSig -> 'EmbedToken' 'LBRKT' embedFirst 'RBRKT' + : {embed, asn1_NOVALUE, '$3'} . + +embedFirst -> 'EventsToken' : + #'SecondEventsDescriptor'{requestID = asn1_NOVALUE, + eventList = []} . +embedFirst -> 'EventsToken' 'EQUAL' requestID + 'LBRKT' secondRequestedEvent secondRequestedEvents 'RBRKT' : + #'SecondEventsDescriptor'{requestID = '$3', + eventList = ['$5' | '$6']} . + +secondRequestedEvents -> 'COMMA' secondRequestedEvent secondRequestedEvents : ['$2' | '$3'] . +secondRequestedEvents -> '$empty' : [] . + +%% at-most-once of each +secondRequestedEvent -> pkgdName secondRequestedEventBody + : setelement(#'SecondRequestedEvent'.pkgdName, '$2', '$1') . + +secondRequestedEventBody -> 'LBRKT' secondEventParameter secondEventParameters 'RBRKT' + : merge_secondEventParameters(['$2' | '$3']) . +secondRequestedEventBody -> '$empty' : #'SecondRequestedEvent'{evParList = []} . + +secondEventParameters -> 'COMMA' secondEventParameter secondEventParameters : ['$2' | '$3'] . +secondEventParameters -> '$empty' : [] . + +%% at-most-once each of embedOrKeepActive , eventDM or eventStream +secondEventParameter -> 'KeepActiveToken' : keepActive . +secondEventParameter -> embedSig : '$1' . +secondEventParameter -> eventDM : '$1' . +secondEventParameter -> eventStreamOrOther : '$1' . +secondEventParameter -> notifyBehaviour : {notifyBehaviour, '$1'}. +secondEventParameter -> 'ResetEventsDescriptorToken' : resetEventsDescriptor . + +embedSig -> 'EmbedToken' 'LBRKT' signalsDescriptor 'RBRKT' + : {second_embed, '$3'} . + +eventStreamOrOther -> eventParameterName parmValue : + select_stream_or_other('$1', '$2') . + +eventParameterName -> safeToken : ensure_NAME('$1') . + +%% The DigitMapDescriptorToken is specially treated by the scanner +eventDM -> 'DigitMapDescriptorToken' : + ensure_eventDM('$1') . + +%% H248S-IG (IGv11) +signalsDescriptor -> 'SignalsToken' 'LBRKT' signalParm signalParms 'RBRKT' : + ['$3' | '$4'] . +signalsDescriptor -> 'SignalsToken' : [] . + +signalParms -> 'COMMA' signalParm signalParms : [ '$2' | '$3'] . +signalParms -> '$empty' : [] . + +signalParm -> signalList : {seqSigList, '$1'} . +signalParm -> signalRequest : {signal, '$1'} . + +signalRequest -> signalName 'LBRKT' sigParameter sigParameters 'RBRKT' + : merge_signalRequest('$1', ['$3' | '$4']). +signalRequest -> signalName : merge_signalRequest('$1', []). + +sigParameters -> 'COMMA' sigParameter sigParameters : ['$2' | '$3'] . +sigParameters -> '$empty' : [] . + +%% sigParameter = sigStream / sigSignalType / sigDuration / sigOther / +%% notifyCompletion / KeepActiveToken / +%% direction / sigRequestID +%% sigStream = StreamToken EQUAL StreamID +%% sigOther = sigParameterName parmValue +%% sigParameterName = NAME +%% sigSignalType = SignalTypeToken EQUAL signalType +%% signalType = (OnOffToken / TimeOutToken / BriefToken) +%% sigDuration = DurationToken EQUAL UINT16 +%% notifyCompletion = NotifyCompletionToken EQUAL (LBRKT +%% notificationReason *(COMMA notificationReason) +%% RBRKT) +%% +%% notificationReason = ( TimeOutToken / InterruptByEventToken / +%% InterruptByNewSignalsDescrToken / +%% OtherReasonToken ) +%% sigDirection = DirectionToken EQUAL direction +%% sigRequestID = RequestIDToken EQUAL RequestID +%% sigIntsigDelay = IntsigDelayToken EQUAL UINT16 + +sigParameter -> 'StreamToken' 'EQUAL' streamID : + {stream, '$3'}. +sigParameter -> 'SignalTypeToken' 'EQUAL' signalType : + {signal_type, '$3'} . +sigParameter -> 'DurationToken' 'EQUAL' safeToken : + {duration, ensure_uint16('$3')} . +sigParameter -> 'NotifyCompletionToken' 'EQUAL' + 'LBRKT' notificationReason notificationReasons 'RBRKT' : + {notify_completion, ['$4' | '$5']} . +sigParameter -> 'KeepActiveToken' : keepActive . +sigParameter -> 'DirectionToken' 'EQUAL' direction : + {direction, '$3'} . +sigParameter -> 'RequestIDToken' 'EQUAL' requestID : + {requestId, '$3'} . +sigParameter -> 'IntsigDelayToken' 'EQUAL' safeToken : + {intersigDelay, ensure_uint16('$3')} . +sigParameter -> safeToken parmValue : + {other, ensure_NAME('$1'), '$2'}. + +signalType -> 'OnOffToken' : onOff. +signalType -> 'TimeOutToken' : timeOut. +signalType -> 'BriefToken' : brief. + +direction -> 'ExternalToken' : external . +direction -> 'InternalToken' : internal . +direction -> 'BothToken' : both . + +notificationReasons -> 'COMMA' notificationReason notificationReasons : ['$2' | '$3'] . +notificationReasons -> '$empty' : [] . + +notificationReason -> 'TimeOutToken' : onTimeOut . +notificationReason -> 'InterruptByEventToken' : onInterruptByEvent . +notificationReason -> 'InterruptByNewSignalsDescrToken' : onInterruptByNewSignalDescr . +notificationReason -> 'OtherReasonToken' : otherReason . +notificationReason -> 'IterationToken' : iteration . + +signalList -> 'SignalListToken' 'EQUAL' signalListId + 'LBRKT' signalListParm signalListParms 'RBRKT' + : #'SeqSigList'{id = ensure_uint16('$3'), + signalList = ['$5' | '$6']} . + +signalListParms -> 'COMMA' signalListParm signalListParms : + ['$2' | '$3'] . +signalListParms -> '$empty' : [] . + +signalListId -> safeToken : ensure_uint16('$1') . + +%% exactly once signalType, +%% at most once duration and every signal parameter +signalListParm -> signalRequest : '$1'. + +signalName -> pkgdName : '$1'. + +observedEventsDescriptor -> 'ObservedEventsToken' 'EQUAL' requestID + 'LBRKT' observedEvent observedEvents 'RBRKT' + : #'ObservedEventsDescriptor'{requestId = '$3', + observedEventLst = ['$5' | '$6']} . + +observedEvents -> 'COMMA' observedEvent observedEvents : ['$2' | '$3'] . +observedEvents -> '$empty' : [] . + +%%time per event, because it might be buffered + +observedEvent -> timeStamp optSep 'COLON' optSep pkgdName observedEventBody : + merge_observed_event('$6', '$5', '$1') . +observedEvent -> optSep pkgdName observedEventBody : + merge_observed_event('$3', '$2', asn1_NOVALUE) . + +observedEventBody -> 'LBRKT' observedEventParameter + observedEventParameters 'RBRKT' + : ['$2' | '$3'] . +observedEventBody -> '$empty' : [] . + +observedEventParameters -> 'COMMA' observedEventParameter observedEventParameters : ['$2' | '$3'] . +observedEventParameters -> '$empty' : [] . + +%%at-most-once eventStream, every eventParameterName at most once +observedEventParameter -> eventStreamOrOther : '$1' . + +requestID -> safeToken : ensure_requestID('$1') . + +%% Deprecated as of Corr 1 +modemDescriptor -> 'ModemToken' 'EQUAL' modemType optPropertyParms . +modemDescriptor -> 'ModemToken' 'LSBRKT' modemType modemTypeList 'RSBRKT' + optPropertyParms. +modemTypeList -> 'COMMA' modemType modemTypeList. +modemTypeList -> '$empty'. +modemType -> safeToken. + +optPropertyParms -> 'LBRKT' propertyParm propertyParmList 'RBRKT' : + ['$2' | '$3'] . +optPropertyParms -> '$empty' : [] . + +propertyParms -> propertyParm propertyParmList : ['$1' | '$2'] . +propertyParmList -> 'COMMA' propertyParm propertyParmList : ['$2' | '$3'] . +propertyParmList -> '$empty' : [] . + +% parmName -> safeToken : ensure_NAME('$1') . + +%% The DigitMapDescriptorToken is specially treated by the scanner +digitMapDescriptor -> 'DigitMapDescriptorToken' : + ensure_DMD('$1') . + +%% each parameter at-most-once, except auditItem +%% at most one of either serviceChangeAddress or serviceChangeMgcId but +%% not both. serviceChangeMethod and serviceChangeReason are REQUIRED +serviceChangeDescriptor -> 'ServicesToken' + 'LBRKT' serviceChangeParm + serviceChangeParms 'RBRKT' : + merge_ServiceChangeParm(['$3' | '$4']) . + +serviceChangeParms -> 'COMMA' serviceChangeParm serviceChangeParms : + ['$2' | '$3'] . +serviceChangeParms -> '$empty' : [] . + +serviceChangeParm -> serviceChangeMethod : {method, '$1'} . +serviceChangeParm -> serviceChangeReason : {reason, '$1'} . +serviceChangeParm -> serviceChangeDelay : {delay, '$1'} . +serviceChangeParm -> serviceChangeAddress : {address, '$1'} . +serviceChangeParm -> serviceChangeProfile : {profile, '$1'} . +serviceChangeParm -> extension : {extension, '$1'} . +serviceChangeParm -> timeStamp : {time_stamp, '$1'} . +serviceChangeParm -> serviceChangeMgcId : {mgc_id, '$1'} . +serviceChangeParm -> serviceChangeVersion : {version, '$1'} . +serviceChangeParm -> 'ServiceChangeIncompleteToken' : incomplete . % v3 +serviceChangeParm -> auditItem : {audit_item, '$1'} . % v2 + +serviceChangeMethod -> 'MethodToken' 'EQUAL' safeToken : + ensure_serviceChangeMethod('$3') . + +serviceChangeReason -> 'ReasonToken' 'EQUAL' value : ['$3'] . + +serviceChangeDelay -> 'DelayToken' 'EQUAL' safeToken : ensure_uint32('$3'). + +serviceChangeAddress -> 'ServiceChangeAddressToken' 'EQUAL' mId : '$3' . +serviceChangeAddress -> 'ServiceChangeAddressToken' 'EQUAL' portNumber : + {portNumber, '$3'} . + +serviceChangeMgcId -> 'MgcIdToken' 'EQUAL' mId : '$3' . + +serviceChangeProfile -> 'ProfileToken' 'EQUAL' safeToken : ensure_profile('$3'). + +serviceChangeVersion -> 'VersionToken' 'EQUAL' safeToken : ensure_version('$3') . + +extension -> extensionParameter parmValue + : setelement(#'PropertyParm'.name, '$2', '$1') . + +%% at most once. Version is REQUIRED on first ServiceChange response +%% at most of either serviceChangeAddress or serviceChangeMgcId but not both +serviceChangeReplyDescriptor -> 'ServicesToken' + 'LBRKT' servChgReplyParm + servChgReplyParms 'RBRKT' : + merge_ServiceChangeResParm(['$3' | '$4']) . + +servChgReplyParms -> 'COMMA' servChgReplyParm servChgReplyParms : + ['$2' | '$3'] . +servChgReplyParms -> '$empty' : [] . + +servChgReplyParm -> serviceChangeAddress : {address, '$1'} . +servChgReplyParm -> serviceChangeMgcId : {mgc_id, '$1'} . +servChgReplyParm -> serviceChangeProfile : {profile, '$1'} . +servChgReplyParm -> serviceChangeVersion : {version, '$1'} . +servChgReplyParm -> timeStamp : {time_stamp,'$1'} . + +packagesDescriptor -> 'PackagesToken' 'LBRKT' packagesItem + packagesItems 'RBRKT' + : ['$3' | '$4'] . + +packagesItems -> 'COMMA' packagesItem packagesItems : ['$2' | '$3'] . +packagesItems -> '$empty' : [] . + +packagesItem -> safeToken : ensure_packagesItem('$1') . + +timeStamp -> TimeStampToken : ensure_timeStamp('$1') . + +statisticsDescriptor -> 'StatsToken' + 'LBRKT' statisticsParameter + statisticsParameters 'RBRKT' + : ['$3' | '$4'] . + +statisticsParameters -> 'COMMA' statisticsParameter statisticsParameters : ['$2' | '$3'] . +statisticsParameters -> '$empty' : [] . + +%%at-most-once per item +statisticsParameter -> pkgdName : + #'StatisticsParameter'{statName = '$1', + statValue = asn1_NOVALUE} . +statisticsParameter -> pkgdName 'EQUAL' value : + #'StatisticsParameter'{statName = '$1', + statValue = ['$3']} . +statisticsParameter -> pkgdName 'EQUAL' 'LSBRKT' value valueList 'RSBRKT' : + #'StatisticsParameter'{statName = '$1', + statValue = ['$4' | '$5']} . + + +topologyDescriptor -> 'TopologyToken' 'LBRKT' + topologyDescComp topologyDescCompList 'RBRKT' : + merge_topologyDescriptor(['$3' | '$4']) . + +topologyDescComp -> terminationID : {tid, '$1'} . +topologyDescComp -> eventStream : {sid, '$1'} . +topologyDescComp -> topologyDirection : '$1' . + +topologyDescCompList -> '$empty' : [] . +topologyDescCompList -> 'COMMA' topologyDescComp topologyDescCompList : + ['$2' | '$3'] . + +topologyDirection -> 'BothwayToken' : {direction, bothway} . +topologyDirection -> 'IsolateToken' : {direction, isolate} . +topologyDirection -> 'OnewayToken' : {direction, oneway} . +topologyDirection -> 'OnewayExternalToken' : {direction_ext, onewayexternal} . +topologyDirection -> 'OnewayBothToken' : {direction_ext, onewayboth} . + +iepsValue -> 'IEPSToken' 'EQUAL' onOrOff : '$3' . + +emergencyValue -> 'EmergencyValueToken' 'EQUAL' 'EmergencyToken' : true . +emergencyValue -> 'EmergencyValueToken' 'EQUAL' 'EmergencyOffToken' : false . + +priority -> 'PriorityToken' 'EQUAL' safeToken : ensure_uint16('$3') . + +extensionParameter -> safeToken : ensure_extensionParameter('$1') . + +value -> 'QuotedChars' : ensure_value('$1') . +value -> safeToken : ensure_value('$1'). + +safeToken -> safeToken2 : make_safe_token('$1') . + +safeToken2 -> 'SafeChars' : '$1' . +%% BMK BMK safeToken2 -> 'AddToken' : '$1' . +safeToken2 -> 'AuditToken' : '$1' . +safeToken2 -> 'AuditCapToken' : '$1' . +safeToken2 -> 'AuditValueToken' : '$1' . +safeToken2 -> 'AuthToken' : '$1' . +safeToken2 -> 'BothToken' : '$1' . % v3 +%% v3-safeToken2 -> 'BothwayToken' : '$1' . +safeToken2 -> 'BriefToken' : '$1' . +%% v3-safeToken2 -> 'BufferToken' : '$1' . +safeToken2 -> 'CtxToken' : '$1' . +%% v3-safeToken2 -> 'ContextAttrToken' : '$1' . % v3 +safeToken2 -> 'ContextAuditToken' : '$1' . +%% v3-safeToken2 -> 'ContextListToken' : '$1' . % v3 +%% v2-safeToken2 -> 'DigitMapToken' : '$1' . +%% safeToken2 -> 'DigitMapDescriptorToken' : '$1' . +%% v3- +safeToken2 -> 'DirectionToken' : '$1' . % v3 +safeToken2 -> 'DiscardToken' : '$1' . +safeToken2 -> 'DisconnectedToken' : '$1' . +safeToken2 -> 'DelayToken' : '$1' . +safeToken2 -> 'DurationToken' : '$1' . +safeToken2 -> 'EmbedToken' : '$1' . +%% BMK BMK safeToken2 -> 'EmergencyToken' : '$1' . +%% BMK BMK safeToken2 -> 'EmergencyOffToken' : '$1' . +safeToken2 -> 'ErrorToken' : '$1' . +%% v2-safeToken2 -> 'EventBufferToken' : '$1' . +%% v2-safeToken2 -> 'EventsToken' : '$1' . +%% v3-safeToken2 -> 'ExternalToken' : '$1' . % v3 +safeToken2 -> 'FailoverToken' : '$1' . +safeToken2 -> 'ForcedToken' : '$1' . +safeToken2 -> 'GracefulToken' : '$1' . +safeToken2 -> 'H221Token' : '$1' . +safeToken2 -> 'H223Token' : '$1' . +safeToken2 -> 'H226Token' : '$1' . +safeToken2 -> 'HandOffToken' : '$1' . +%% v3-safeToken2 -> 'IEPSToken' : '$1' . % v3 +safeToken2 -> 'ImmAckRequiredToken' : '$1' . +safeToken2 -> 'InactiveToken' : '$1' . +%% v3-safeToken2 -> 'InternalToken' : '$1' . % v3 +safeToken2 -> 'InterruptByEventToken' : '$1' . +safeToken2 -> 'InterruptByNewSignalsDescrToken' : '$1' . +%% v3-safeToken2 -> 'IsolateToken' : '$1' . +safeToken2 -> 'InSvcToken' : '$1' . +safeToken2 -> 'KeepActiveToken' : '$1' . +%% safeToken2 -> 'LocalToken' : '$1' . +%% safeToken2 -> 'LocalDescriptorToken' : '$1' . +safeToken2 -> 'LocalControlToken' : '$1' . +safeToken2 -> 'LoopbackToken' : '$1' . +safeToken2 -> 'LockStepToken' : '$1' . +%% v2-safeToken2 -> 'MediaToken' : '$1' . +%% safeToken2 -> 'MegacopToken' : '$1' . +safeToken2 -> 'MethodToken' : '$1' . +safeToken2 -> 'MgcIdToken' : '$1' . +%% v3-safeToken2 -> 'ModeToken' : '$1' . +%% BMK BMK safeToken2 -> 'ModifyToken' : '$1' . +%% v2-safeToken2 -> 'ModemToken' : '$1' . +%% BMK BMK safeToken2 -> 'MoveToken' : '$1' . +%% safeToken2 -> 'MtpToken' : '$1' . +%% safeToken2 -> 'MtpAddressToken' : '$1' . +%% v2-safeToken2 -> 'MuxToken' : '$1' . +safeToken2 -> 'NotifyToken' : '$1' . +safeToken2 -> 'NotifyCompletionToken' : '$1' . +safeToken2 -> 'Nx64Token' : '$1' . +%% v2-safeToken2 -> 'ObservedEventsToken' : '$1' . +%% v3-safeToken2 -> 'OnewayToken' : '$1' . +%% v3-safeToken2 -> 'OnewayExternalToken' : '$1' . +%% v3-safeToken2 -> 'OnewayBothToken' : '$1' . +safeToken2 -> 'OffToken' : '$1' . +safeToken2 -> 'OnToken' : '$1' . +safeToken2 -> 'OnOffToken' : '$1' . +safeToken2 -> 'OutOfSvcToken' : '$1' . +safeToken2 -> 'OtherReasonToken' : '$1' . +%% v2-safeToken2 -> 'PackagesToken' : '$1' . +safeToken2 -> 'PendingToken' : '$1' . +%% BMK BMK safeToken2 -> 'PriorityToken' : '$1' . +safeToken2 -> 'ProfileToken' : '$1' . +safeToken2 -> 'ReasonToken' : '$1' . +safeToken2 -> 'RecvonlyToken' : '$1' . +safeToken2 -> 'ReplyToken' : '$1' . +%% v3- +safeToken2 -> 'RequestIDToken' : '$1' . % v3 +safeToken2 -> 'ResponseAckToken' : '$1' . +safeToken2 -> 'RestartToken' : '$1' . +%% safeToken2 -> 'RemoteToken' : '$1' . +%% safeToken2 -> 'RemoteDescriptorToken' : '$1' . +%% v3-safeToken2 -> 'ReservedGroupToken' : '$1' . +%% v3-safeToken2 -> 'ReservedValueToken' : '$1' . +safeToken2 -> 'SendonlyToken' : '$1' . +safeToken2 -> 'SendrecvToken' : '$1' . +safeToken2 -> 'ServicesToken' : '$1' . +%% v3-safeToken2 -> 'ServiceStatesToken' : '$1' . +safeToken2 -> 'ServiceChangeToken' : '$1' . +%% v3-safeToken2 -> 'ServiceChangeIncompleteToken' : '$1' . % v3 +safeToken2 -> 'ServiceChangeAddressToken' : '$1' . +safeToken2 -> 'SignalListToken' : '$1' . +%% v2-safeToken2 -> 'SignalsToken' : '$1' . +safeToken2 -> 'SignalTypeToken' : '$1' . +%% v2-safeToken2 -> 'StatsToken' : '$1' . +safeToken2 -> 'StreamToken' : '$1' . +%% BMK BMK safeToken2 -> 'SubtractToken' : '$1' . +safeToken2 -> 'SynchISDNToken' : '$1' . +safeToken2 -> 'TerminationStateToken' : '$1' . +safeToken2 -> 'TestToken' : '$1' . +safeToken2 -> 'TimeOutToken' : '$1' . +%% BMK BMK safeToken2 -> 'TopologyToken' : '$1' . +safeToken2 -> 'TransToken' : '$1' . +safeToken2 -> 'V18Token' : '$1' . +safeToken2 -> 'V22Token' : '$1' . +safeToken2 -> 'V22bisToken' : '$1' . +safeToken2 -> 'V32Token' : '$1' . +safeToken2 -> 'V32bisToken' : '$1' . +safeToken2 -> 'V34Token' : '$1' . +safeToken2 -> 'V76Token' : '$1' . +safeToken2 -> 'V90Token' : '$1' . +safeToken2 -> 'V91Token' : '$1' . +safeToken2 -> 'VersionToken' : '$1' . +%% <OTP-7534> +safeToken2 -> 'MessageSegmentToken' : '$1' . % v3 +safeToken2 -> 'SegmentationCompleteToken' : '$1' . % v3 +%% </OTP-7534> + +Erlang code. + +%% The following directive is needed for (significantly) faster compilation +%% of the generated .erl file by the HiPE compiler. Please do not remove. +-compile([{hipe,[{regalloc,linear_scan}]}]). + +-include("megaco_text_parser_prev3c.hrl"). + + diff --git a/lib/megaco/src/text/megaco_text_parser_v1.hrl b/lib/megaco/src/text/megaco_text_parser_v1.hrl new file mode 100644 index 0000000000..ebc43c0352 --- /dev/null +++ b/lib/megaco/src/text/megaco_text_parser_v1.hrl @@ -0,0 +1,1410 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2000-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 : Define semantic text parser actions +%%---------------------------------------------------------------------- + + +-include_lib("megaco/include/megaco.hrl"). +-include_lib("megaco/include/megaco_message_v1.hrl"). +-define(encoder_version_pre_prev3c,true). +-include("megaco_text_tokens.hrl"). + +-ifdef(megaco_parser_inline). +-compile({inline,[{make_safe_token,1}]}). +-endif. +make_safe_token(Token) -> + {_TokenTag, Line, Text} = Token, + {safeToken, Line, Text}. + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_value,1}]}). +-endif. +ensure_value(Token) -> + case Token of + {safeToken, _Line, Text} when is_list(Text) -> + Text; % We really should ensure length + {'QuotedChars', _Line, Text} when is_list(Text) -> + Text; % We really should ensure length + Text when is_list(Text) -> + Text % We really should ensure length + end. + +%% NAME = ALPHA *63(ALPHA / DIGIT / "_" ) +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_NAME,1}]}). +-endif. +ensure_NAME(Token) -> + {_TokenTag, _Line, Text} = Token, + Text. % We really should ensure length and chars + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_requestID,1}]}). +-endif. +ensure_requestID(Token) -> + case Token of + {safeToken, _Line, "*"} -> + ?megaco_all_request_id; + _ -> + ensure_uint32(Token) + end. + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_streamID,1}]}). +-endif. +ensure_streamID(StreamId) -> + ensure_uint16(StreamId). + +ensure_auth_header(SpiToken, SnToken, AdToken) -> + Spi = ensure_hex(SpiToken, 8, 8), + Sn = ensure_hex(SnToken, 8, 8), + Ad = ensure_hex(AdToken, 24, 64), + #'AuthenticationHeader'{secParmIndex = Spi, seqNum = Sn, ad = Ad}. + +%% The values 0x0, 0xFFFFFFFE and 0xFFFFFFFF are reserved. +%% ContextID = (UINT32 / "*" / "-" / "$") +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_contextID,1}]}). +-endif. +ensure_contextID(Token) -> + {_TokenTag, Line, Text} = Token, + case Text of + "*" -> ?megaco_all_context_id; + "-" -> ?megaco_null_context_id; + "\$" -> ?megaco_choose_context_id; + Int -> + CID = ensure_uint32(Int), + if + (CID =/= 0) andalso + (CID =/= 16#FFFFFFFE) andalso + (CID =/= 16#FFFFFFFF) -> + CID; + true -> + return_error(Line, {bad_ContextID, CID}) + end + end. + +ensure_domainAddress([{_T, _L, _A} = Addr0], Port) -> + Addr = ensure_ip4addr(Addr0), + {ip4Address, #'IP4Address'{address = Addr, portNumber = Port}}; +ensure_domainAddress([colon,colon], Port) -> + Addr = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + {ip6Address, #'IP6Address'{address = Addr, portNumber = Port}}; +ensure_domainAddress(Addr0, Port) -> + Addr = ensure_ip6addr(Addr0), + {ip6Address, #'IP6Address'{address = Addr, portNumber = Port}}. + +ensure_ip4addr(Token) -> + {_TokenTag, Line, Addr} = Token, + case split_ip4addr_text(Addr, []) of + [T1, T2, T3, T4] -> + %% We optimize by sending only the text part (Addr) of + %% the token to the function. + %% If something is wrong, then we do not get a proper + %% position and therefor we catch and issue the + %% error again (with the proper line number). + case (catch [ + ensure_uint(T1, 0, 255), + ensure_uint(T2, 0, 255), + ensure_uint(T3, 0, 255), + ensure_uint(T4, 0, 255) + ]) of + A when is_list(A) -> + A; + _ -> + return_error(Line, {bad_IP4address, Addr}) + end; + _ -> + return_error(Line, {bad_IP4address, Addr}) + end. + +split_ip4addr_text([], Acc) -> + [ lists:reverse(Acc) ]; +split_ip4addr_text([$. | Rest], Acc) -> + [ lists:reverse(Acc) | split_ip4addr_text(Rest, []) ]; +split_ip4addr_text([H | T], Acc) -> + split_ip4addr_text(T, [H | Acc]). + + +ensure_ip6addr([colon,colon|T]) -> + [H1|T1] = lists:reverse(T), + case do_ensure_ip6addr(T1, true, [ensure_hex4_or_ip4addr(H1)], 1) of + {true, A} when length(A) == 16 -> + A; + {true, B} when length(B) < 16 -> + lists:duplicate(16 - length(B), 0) ++ B; + {true, C} -> + throw({error, {?MODULE, {bad_mid_ip6addr_length, C}}}) + end; +ensure_ip6addr(L) -> + case lists:reverse(L) of + [colon, colon| T] -> + case do_ensure_ip6addr(T, true, [], 1) of + {true, A} when length(A) == 16 -> + A; + {true, B} when length(B) < 16 -> + B ++ lists:duplicate(16 - length(B), 0); + {true, C} -> + throw({error, {?MODULE, {bad_mid_ip6addr_length, C}}}) + end; + [H|L1] -> % A (last element) could be an ip4 address + case do_ensure_ip6addr(L1,false,[ensure_hex4_or_ip4addr(H)],1) of + {false, A} when length(A) == 16 -> + A; + %% allow a pad even if the address is full (i.e. 16) + {true, B} when length(B) =< 17 -> + do_ensure_ip6addr_padding(B, 0); + {Pad, C} -> + throw({error, {?MODULE, {bad_mid_ip6addr_length, Pad, C}}}) + end + + end. + + +do_ensure_ip6addr([], Pad, Acc, _) -> + {Pad, lists:flatten(Acc)}; +do_ensure_ip6addr([colon,colon|T], false, Acc, Line) -> + do_ensure_ip6addr(T, true, [pad|Acc], Line); +do_ensure_ip6addr([colon,colon|T], true, Acc, Line) -> + return_error(Line, {bad_mid_duplicate_padding, T, Acc}); +do_ensure_ip6addr([colon|T], Pad, Acc, Line) -> + do_ensure_ip6addr(T, Pad, Acc, Line); +do_ensure_ip6addr([{_, Line, _} = A|T], Pad, Acc, _) -> + do_ensure_ip6addr(T, Pad, [ensure_hex4(A)|Acc], Line). + +do_ensure_ip6addr_padding([], _) -> + []; +do_ensure_ip6addr_padding([pad|T], N) -> + lists:duplicate(16 - (N + length(T)), 0) ++ T; +do_ensure_ip6addr_padding([H|T], N) -> + [H|do_ensure_ip6addr_padding(T, N+1)]. + +ensure_hex4_or_ip4addr({TokenTag, Line, Addr} = V) -> + case string:tokens(Addr, [$.]) of + [T1, T2, T3, T4] -> + A1 = ensure_uint({TokenTag, Line, T1}, 0, 255), + A2 = ensure_uint({TokenTag, Line, T2}, 0, 255), + A3 = ensure_uint({TokenTag, Line, T3}, 0, 255), + A4 = ensure_uint({TokenTag, Line, T4}, 0, 255), + [A1, A2, A3, A4]; + _ -> + ensure_hex4(V) + %% %% BMK BMK BMK + %% %% Here we should test for hexseq + %% return_error(Line, {bad_IP4address, Addr}) + end. + +ensure_hex4({_TokenTag, Line, Hex4}) + when length(Hex4) =< 4, length(Hex4) > 0 -> + case (catch do_ensure_hex4(Hex4)) of + IL when is_list(IL) andalso (length(IL) =:= 2) -> + IL; + Error -> + return_error(Line, {bad_hex4, Hex4, Error}) + end. + +do_ensure_hex4([_H1, _H2, _H3, _H4] = H) -> + hex_to_int(H, []); +do_ensure_hex4([H2, H3, H4]) -> + hex_to_int([$0, H2, H3, H4], []); +do_ensure_hex4([H3, H4]) -> + hex_to_int([$0, $0, H3, H4], []); +do_ensure_hex4([H4]) -> + hex_to_int([$0, $0, $0, H4], []). + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_domainName,2}]}). +-endif. +ensure_domainName(Token, Port) -> + {_TokenTag, _Line, Name} = Token, + %% BUGBUG: validate name + {domainName, #'DomainName'{name = Name, portNumber = Port}}. + +%% extensionParameter= "X" ("-" / "+") 1*6(ALPHA / DIGIT) +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_extensionParameter,1}]}). +-endif. +ensure_extensionParameter(Token) -> + {_TokenTag, Line, Text} = Token, + case Text of + [X, S | _Chars] -> + if + (X =/= $X) andalso (X =/= $x) andalso + (S =/= $+) andalso (S =/= $-) -> + return_error(Line, {bad_extension_parameter, Text}); + true -> + {extension_parameter, Text} + end; + _ -> + return_error(Line, {bad_extension_parameter, Text}) + end. + +ensure_message(MegacopToken, MID, Body) -> +%% #'ServiceChangeProfile'{profileName = Name, +%% version = Version} = +%% ensure_profile(MegacopToken), +%% case Name of +%% "megaco" -> +%% #'Message'{version = Version, mId = MID, messageBody = Body}; +%% [$!] -> +%% #'Message'{version = Version, mId = MID, messageBody = Body} +%% end. + {_TokenTag, Line, Text} = MegacopToken, + case split_Megacop(Text, []) of + {Name, Version} -> + Version2 = ensure_version(Version), + case Name of + "megaco" -> + #'Message'{version = Version2, + mId = MID, + messageBody = Body}; + [$!] -> + #'Message'{version = Version2, + mId = MID, + messageBody = Body} + end; + _ -> + return_error(Line, {bad_name_or_version, Text}) + end. + +split_Megacop([], _) -> + error; +split_Megacop([$/ | Version], Acc) -> + {lists:reverse(Acc), Version}; +split_Megacop([H | T], Acc) -> + split_Megacop(T, [H | Acc]). + + +%% modemType = (V32bisToken / V22bisToken / V18Token / +%% V22Token / V32Token / V34Token / V90Token / +%% V91Token / SynchISDNToken / extensionParameter) +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_modemType,1}]}). +-endif. +ensure_modemType(Token) -> + {_TokenTag, _Line, Text} = Token, + case Text of + "v32b" -> v32bis; + "v22b" -> v22bis; + "v18" -> v18; + "v22" -> v22; + "v32" -> v32; + "v34" -> v34; + "v90" -> v90; + "v91" -> v91; + "synchisdn" -> synchISDN; + "sn" -> synchISDN; + [$x | _] -> ensure_extensionParameter(Token) + end. + +%% An mtp address is five octets long +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_mtpAddress,1}]}). +-endif. +ensure_mtpAddress(Token) -> + {_TokenTag, _Line, Addr} = Token, + %% BUGBUG: validate address + {mtpAddress, Addr}. + +%% MuxType = ( H221Token / H223Token / H226Token / V76Token / extensionParameter ) +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_muxType,1}]}). +-endif. +ensure_muxType(Token) -> + {_TokenTag, _Line, Text} = Token, + case Text of + "h221" -> h221; + "h223" -> h223; + "h226" -> h226; + "v76" -> v76; + [$x | _] -> ensure_extensionParameter(Token) + end. + +%% packagesItem = NAME "-" UINT16 +%% NAME = ALPHA *63(ALPHA / DIGIT / "_" ) +ensure_packagesItem(Token) -> + {_TokenTag, Line, Text} = Token, + case split_packagesItem(Text, []) of + {Name, Version} -> + %% As we don't ensure length of the names, there is no point + %% in doing the ensure_NAME thing... + #'PackagesItem'{packageName = Name, + packageVersion = ensure_uint(Version, 0, 99)}; + _ -> + return_error(Line, {bad_PackagesItem, Text}) + end. + +split_packagesItem([], _) -> + error; +split_packagesItem([$- | Version], Acc) -> + {lists:reverse(Acc), Version}; +split_packagesItem([H|T], Acc) -> + split_packagesItem(T, [H|Acc]). + + +%% pkgdName = (PackageName / "*") SLASH (ItemID / "*" ) +%% PackageName = NAME +%% ItemID = NAME +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_pkgdName,1}]}). +-endif. +ensure_pkgdName(Token) -> + {_TokenTag, Line, Text} = Token, + case ensure_pkgdName(Text, []) of + ok -> + %% As we don't really do any checks on the strings + %% (neither length nor content) there is really no + %% point in "ensuring" the name and item part of the + %% package name + %% ensure_name_or_star(Name), + %% ensure_name_or_star(Item), + Text; + _ -> + return_error(Line, {bad_pkgdName, Text}) + end. + +ensure_pkgdName([], _) -> + error; +ensure_pkgdName([$/ | T], Acc) + when ((length(T) > 0) andalso (length(Acc) > 0)) -> + ok; +ensure_pkgdName([H | T], Acc) -> + ensure_pkgdName(T, [H | Acc]). + + +%% -compile({inline,[{ensure_name_or_star,1}]}). +%% ensure_name_or_star(Val) -> +%% %% case Token of +%% %% {_, _, Name} when Name =:= "*" -> +%% %% Name; +%% %% _ -> +%% %% ensure_NAME(Token) +%% %% end. +%% if +%% Val =:= "*" -> +%% Val; +%% true -> +%% %% as we don't really validate the text part of the token(s), +%% %% we can just return the value assuming it to be correct... +%% Val +%% end. + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_ServiceChangeParm,1}]}). +-endif. +merge_ServiceChangeParm(Parms) -> + Required = [serviceChangeReason, serviceChangeMethod], + merge_ServiceChangeParm(Parms, #'ServiceChangeParm'{}, Required). + +merge_ServiceChangeParm([], SCP, []) -> + SCP; + +merge_ServiceChangeParm([], _SCP, Required) -> + exit({missing_required_serviceChangeParm, Required}); + +merge_ServiceChangeParm([{address, Val}|Parms], SCP0, Req) + when ((SCP0#'ServiceChangeParm'.serviceChangeAddress =:= asn1_NOVALUE) + andalso + (SCP0#'ServiceChangeParm'.serviceChangeMgcId =:= asn1_NOVALUE)) -> + SCP = SCP0#'ServiceChangeParm'{serviceChangeAddress = Val}, + merge_ServiceChangeParm(Parms, SCP, Req); +merge_ServiceChangeParm([{address, Val}|_Parms], SCP0, _Req) + when (SCP0#'ServiceChangeParm'.serviceChangeAddress =:= asn1_NOVALUE) -> + MgcId = SCP0#'ServiceChangeParm'.serviceChangeMgcId, + exit({not_both_address_mgcid_serviceChangeParm, Val, MgcId}); + +merge_ServiceChangeParm([{mgc_id, Val}|Parms], SCP0, Req) + when ((SCP0#'ServiceChangeParm'.serviceChangeMgcId =:= asn1_NOVALUE) andalso + (SCP0#'ServiceChangeParm'.serviceChangeAddress =:= asn1_NOVALUE)) -> + SCP = SCP0#'ServiceChangeParm'{serviceChangeMgcId = Val}, + merge_ServiceChangeParm(Parms, SCP, Req); +merge_ServiceChangeParm([{mgc_id, Val}|_Parms], SCP0, _Req) + when (SCP0#'ServiceChangeParm'.serviceChangeMgcId =:= asn1_NOVALUE) -> + Addr = SCP0#'ServiceChangeParm'.serviceChangeAddress, + exit({not_both_address_mgcid_serviceChangeParm, Val, Addr}); + +merge_ServiceChangeParm([{profile, Val}|Parms], SCP0, Req) + when (SCP0#'ServiceChangeParm'.serviceChangeProfile =:= asn1_NOVALUE) -> + SCP = SCP0#'ServiceChangeParm'{serviceChangeProfile = Val}, + merge_ServiceChangeParm(Parms, SCP, Req); + +merge_ServiceChangeParm([{version, Val}|Parms], SCP0, Req) + when (SCP0#'ServiceChangeParm'.serviceChangeVersion =:= asn1_NOVALUE) -> + SCP = SCP0#'ServiceChangeParm'{serviceChangeVersion = Val}, + merge_ServiceChangeParm(Parms, SCP, Req); + +%% REQUIRED (i.e. no default value) +merge_ServiceChangeParm([{reason, Val}|Parms], SCP0, Req0) + when (SCP0#'ServiceChangeParm'.serviceChangeReason =:= undefined) -> + SCP = SCP0#'ServiceChangeParm'{serviceChangeReason = Val}, + Req = lists:delete(serviceChangeReason, Req0), + merge_ServiceChangeParm(Parms, SCP, Req); + +merge_ServiceChangeParm([{delay, Val}|Parms], SCP0, Req) + when (SCP0#'ServiceChangeParm'.serviceChangeDelay =:= asn1_NOVALUE) -> + SCP = SCP0#'ServiceChangeParm'{serviceChangeDelay = Val}, + merge_ServiceChangeParm(Parms, SCP, Req); + +%% REQUIRED (i.e. no default value) +merge_ServiceChangeParm([{method, Val}|Parms], SCP0, Req0) + when (SCP0#'ServiceChangeParm'.serviceChangeMethod =:= undefined) -> + SCP = SCP0#'ServiceChangeParm'{serviceChangeMethod = Val}, + Req = lists:delete(serviceChangeMethod, Req0), + merge_ServiceChangeParm(Parms, SCP, Req); + +merge_ServiceChangeParm([{time_stamp, Val}|Parms], SCP0, Req) + when (SCP0#'ServiceChangeParm'.timeStamp =:= asn1_NOVALUE) -> + SCP = SCP0#'ServiceChangeParm'{timeStamp = Val}, + merge_ServiceChangeParm(Parms, SCP, Req); + +merge_ServiceChangeParm([{extension, _Val}|Parms], SCP0, Req) -> + merge_ServiceChangeParm(Parms, SCP0, Req); + +merge_ServiceChangeParm([{Tag, Val}|_Parms], SCP, _Req) -> + Val2 = + case Tag of + address -> + SCP#'ServiceChangeParm'.serviceChangeAddress; + mgc_id -> + SCP#'ServiceChangeParm'.serviceChangeMgcId; + profile -> + SCP#'ServiceChangeParm'.serviceChangeProfile; + version -> + SCP#'ServiceChangeParm'.serviceChangeVersion; + reason -> + SCP#'ServiceChangeParm'.serviceChangeReason; + delay -> + SCP#'ServiceChangeParm'.serviceChangeDelay; + method -> + SCP#'ServiceChangeParm'.serviceChangeMethod; + time_stamp -> + SCP#'ServiceChangeParm'.timeStamp + end, + exit({at_most_once_serviceChangeParm, {Tag, Val, Val2}}). + + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_ServiceChangeResParm,1}]}). +-endif. +merge_ServiceChangeResParm(Parms) -> + merge_ServiceChangeResParm(Parms, #'ServiceChangeResParm'{}). + +merge_ServiceChangeResParm([], SCRP) -> + SCRP; +merge_ServiceChangeResParm([{address, Val}|Parms], SCRP0) + when SCRP0#'ServiceChangeResParm'.serviceChangeAddress == asn1_NOVALUE, + SCRP0#'ServiceChangeResParm'.serviceChangeMgcId == asn1_NOVALUE -> + SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeAddress = Val}, + merge_ServiceChangeResParm(Parms, SCRP); +merge_ServiceChangeResParm([{address, Val}|_Parms], SCRP0) + when SCRP0#'ServiceChangeResParm'.serviceChangeAddress == asn1_NOVALUE -> + MgcId = SCRP0#'ServiceChangeResParm'.serviceChangeMgcId, + exit({not_both_address_mgcid_servChgReplyParm, Val, MgcId}); + +merge_ServiceChangeResParm([{mgc_id, Val}|Parms], SCRP0) + when SCRP0#'ServiceChangeResParm'.serviceChangeMgcId == asn1_NOVALUE, + SCRP0#'ServiceChangeResParm'.serviceChangeAddress == asn1_NOVALUE -> + SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeMgcId = Val}, + merge_ServiceChangeResParm(Parms, SCRP); +merge_ServiceChangeResParm([{mgc_id, Val}|_Parms], SCRP0) + when SCRP0#'ServiceChangeResParm'.serviceChangeMgcId == asn1_NOVALUE -> + Addr = SCRP0#'ServiceChangeResParm'.serviceChangeAddress, + exit({not_both_address_mgcid_servChgReplyParm, Val, Addr}); + +merge_ServiceChangeResParm([{profile, Val}|Parms], SCRP0) + when SCRP0#'ServiceChangeResParm'.serviceChangeProfile == asn1_NOVALUE -> + SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeProfile = Val}, + merge_ServiceChangeResParm(Parms, SCRP); + +merge_ServiceChangeResParm([{version, Val}|Parms], SCRP0) + when SCRP0#'ServiceChangeResParm'.serviceChangeVersion == asn1_NOVALUE -> + SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeVersion = Val}, + merge_ServiceChangeResParm(Parms, SCRP); + +merge_ServiceChangeResParm([{time_stamp, Val}|Parms], SCRP0) + when SCRP0#'ServiceChangeResParm'.timeStamp == asn1_NOVALUE -> + SCRP = SCRP0#'ServiceChangeResParm'{timeStamp = Val}, + merge_ServiceChangeResParm(Parms, SCRP); + +merge_ServiceChangeResParm([{Tag, Val}|_Parms], SCRP) -> + Val2 = + case Tag of + address -> SCRP#'ServiceChangeResParm'.serviceChangeAddress; + mgc_id -> SCRP#'ServiceChangeResParm'.serviceChangeMgcId; + profile -> SCRP#'ServiceChangeResParm'.serviceChangeProfile; + version -> SCRP#'ServiceChangeResParm'.serviceChangeVersion; + time_stamp -> SCRP#'ServiceChangeResParm'.timeStamp + end, + exit({at_most_once_servChgReplyParm, {Tag, Val, Val2}}). + + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_serviceChangeMethod,1}]}). +-endif. +ensure_serviceChangeMethod(Token) -> + case Token of + {safeToken, _Line, "fl"} -> + failover; + {safeToken, _Line, "failover"} -> + failover; + {safeToken, _Line, "fo"} -> + forced; + {safeToken, _Line, "forced"} -> + forced; + {safeToken, _Line, "gr"} -> + graceful; + {safeToken, _Line, "graceful"} -> + graceful; + {safeToken, _Line, "rs"} -> + restart; + {safeToken, _Line, "restart"} -> + restart; + {safeToken, _Line, "dc"} -> + disconnected; + {safeToken, _Line, "disconnected"} -> + disconnected; + {safeToken, _Line, "ho"} -> + handOff; + {safeToken, _Line, "handoff"} -> + handOff; + {safeToken, Line, Text} -> + return_error(Line, {bad_serviceChangeMethod, Text}) + end. + + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_profile,1}]}). +-endif. +ensure_profile(Token) -> + {_TokenTag, Line, Text} = Token, + case string:tokens(Text, [$/]) of + [Name, Version] -> + Version2 = ensure_version(Version), + #'ServiceChangeProfile'{profileName = Name, version = Version2}; + _ -> + return_error(Line, {bad_profile, Text}) + end. + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_version,1}]}). +-endif. +ensure_version(Version) -> + ensure_uint(Version, 0, 99). + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_signalRequest,2}]}). +-endif. +merge_signalRequest(SignalName, PropertyParms) -> + Sig = #'Signal'{signalName = SignalName}, + SPL = [], + do_merge_signalRequest(Sig, PropertyParms, SPL). + +do_merge_signalRequest(Sig, [H | T], SPL) -> + case H of + {stream, StreamId} when Sig#'Signal'.streamID == asn1_NOVALUE -> + do_merge_signalRequest(Sig#'Signal'{streamID = StreamId}, T, SPL); + {signal_type, SigType} when Sig#'Signal'.sigType == asn1_NOVALUE -> + do_merge_signalRequest(Sig#'Signal'{sigType = SigType}, T, SPL); + {duration, Duration} when Sig#'Signal'.duration == asn1_NOVALUE -> + do_merge_signalRequest(Sig#'Signal'{duration = Duration}, T, SPL); + {notify_completion, NC} when Sig#'Signal'.notifyCompletion == asn1_NOVALUE -> + do_merge_signalRequest(Sig#'Signal'{notifyCompletion = NC}, T, SPL); + keepActive when Sig#'Signal'.keepActive == asn1_NOVALUE-> + do_merge_signalRequest(Sig#'Signal'{keepActive = true}, T, SPL); + {other, Name, PP} -> + SP = #'SigParameter'{sigParameterName = Name, + value = PP#'PropertyParm'.value, + extraInfo = PP#'PropertyParm'.extraInfo}, + do_merge_signalRequest(Sig, T, [SP | SPL]); + _ -> + return_error(0, {bad_sigParm, H}) + end; +do_merge_signalRequest(Sig, [], SPL) -> + Sig#'Signal'{sigParList = lists:reverse(SPL)} . + +%% eventStream = StreamToken EQUAL StreamID +%% eventOther = eventParameterName parmValue +-ifdef(megaco_parser_inline). +-compile({inline,[{select_stream_or_other,2}]}). +-endif. +select_stream_or_other(EventParameterName, ParmValue) -> + if + (EventParameterName =:= "st") orelse + (EventParameterName =:= "stream") -> + case ParmValue of + #'PropertyParm'{value = [Value]} -> + {stream, ensure_uint16(Value)}; + _ -> + {stream, ensure_uint16(ParmValue)} + end; + true -> + #'PropertyParm'{value = Value} = ParmValue, + EP = #'EventParameter'{eventParameterName = EventParameterName, + value = Value}, + {other, EP} + end. + +%% select_stream_or_other("st", #'PropertyParm'{value = [Value]}) -> +%% {stream, ensure_uint16(Value)}; +%% select_stream_or_other("st", Value) -> +%% {stream, ensure_uint16(Value)}; +%% select_stream_or_other("stream", #'PropertyParm'{value = [Value]}) -> +%% {stream, ensure_uint16(Value)}; +%% select_stream_or_other("stream", Value) -> +%% {stream, ensure_uint16(Value)}; +%% select_stream_or_other(Name, #'PropertyParm'{value = Value}) -> +%% EP = #'EventParameter'{eventParameterName = Name, +%% value = Value}, +%% {other, EP}. + +%% Version 2 of the DigitMapValue has an extra item (after extension mark), +%% durationTimer, which does not exist in version 1. The record was created +%% as defined in megaco_message_internal.hrl, e.g. as in version 2, so we +%% have to fix it here. +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_eventDM,1}]}). +-endif. +ensure_eventDM(Token) -> + {_TokenTag, Line, DMD} = Token, + if + is_record(DMD, 'DigitMapDescriptor') -> + Name = DMD#'DigitMapDescriptor'.digitMapName, + Val = DMD#'DigitMapDescriptor'.digitMapValue, + if + (Name =:= asn1_NOVALUE) andalso (Val =/= asn1_NOVALUE) -> + %% Convert to version 1 DigitMapValue + {'DigitMapValue', Start, Short, Long, _DurationTimer, Body} = Val, + DMV = #'DigitMapValue'{startTimer = Start, + shortTimer = Short, + longTimer = Long, + digitMapBody = Body}, + {eventDM, {digitMapValue, DMV}}; + (Name =/= asn1_NOVALUE) andalso (Val =:= asn1_NOVALUE) -> + {eventDM, {digitMapName, Name}}; + true -> + return_error(Line, {bad_eventDM, DMD}) + end; + true -> + return_error(Line, {bad_eventDM, DMD}) + end. + +%% Version 2 of the DigitMapValue has an extra item (after extension mark), +%% durationTimer, which does not exist in version 1. The record is defined +%% (in megaco_message_internal.hrl) as in version 2, so we have to fix +%% it here. +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_DMD,1}]}). +-endif. +ensure_DMD(Token) -> + {_TokenTag, Line, DMD} = Token, + if + is_record(DMD, 'DigitMapDescriptor') -> + Val2 = + case DMD#'DigitMapDescriptor'.digitMapValue of + %% Note that the values of the digitMapBody and + %% durationTimers are swapped by the scanner + %% (this is done because of a problem in the flex scanner). + {'DigitMapValue', asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE, []} -> + asn1_NOVALUE; + {'DigitMapValue', Start, Short, Long, _DurationTimer, Body} -> + %% Convert to version 1 DigitMapValue + #'DigitMapValue'{startTimer = Start, + shortTimer = Short, + longTimer = Long, + digitMapBody = Body}; + Other -> + Other + end, + DMD#'DigitMapDescriptor'{digitMapValue = Val2}; + true -> + return_error(Line, {bad_DigitMapDescriptor, DMD}) + end. + + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_observed_event,3}]}). +-endif. +merge_observed_event(ObservedEvents, EventName, TimeStamp) -> + StreamId = asn1_NOVALUE, + EPL = [], + do_merge_observed_event(ObservedEvents, EventName, TimeStamp, StreamId, EPL). + +do_merge_observed_event([{stream, StreamID} | T], EventName, TimeStamp, asn1_NOVALUE, EPL) -> + do_merge_observed_event(T, EventName, TimeStamp, StreamID, EPL); +do_merge_observed_event([{other, PP} | T], EventName, TimeStamp, StreamID, EPL) -> + do_merge_observed_event(T, EventName, TimeStamp, StreamID, [PP | EPL]); +do_merge_observed_event([], EventName, TimeStamp, StreamID, EPL) -> + #'ObservedEvent'{eventName = EventName, + timeNotation = TimeStamp, + streamID = StreamID, + eventParList = lists:reverse(EPL)}. + +merge_eventSpec(OE) + when is_record(OE, 'ObservedEvent') andalso + (OE#'ObservedEvent'.timeNotation == asn1_NOVALUE) -> + #'EventSpec'{eventName = OE#'ObservedEvent'.eventName, + streamID = OE#'ObservedEvent'.streamID, + eventParList = OE#'ObservedEvent'.eventParList}; +merge_eventSpec(OE) -> + return_error(0, {bad_event_spec, OE}). + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_eventParameters,1}]}). +-endif. +merge_eventParameters(Params) -> + StreamId = asn1_NOVALUE, + EPL = [], + RA = #'RequestedActions'{}, + HasA = no, + do_merge_eventParameters(Params, StreamId, EPL, RA, HasA) . + +do_merge_eventParameters([H | T], StreamId, EPL, RA, HasA) -> + case H of + keepActive when RA#'RequestedActions'.keepActive == asn1_NOVALUE -> + RA2 = RA#'RequestedActions'{keepActive = true}, + do_merge_eventParameters(T, StreamId, EPL, RA2, yes); + {embed, SD, SED} when RA#'RequestedActions'.signalsDescriptor == asn1_NOVALUE -> + RA2 = RA#'RequestedActions'{signalsDescriptor = SD, + secondEvent = SED}, + do_merge_eventParameters(T, StreamId, EPL, RA2, yes); + {eventDM, DM} when RA#'RequestedActions'.eventDM == asn1_NOVALUE -> + RA2 = RA#'RequestedActions'{eventDM = DM}, + do_merge_eventParameters(T, StreamId, EPL, RA2, yes); + {stream, NewStreamId} when StreamId == asn1_NOVALUE -> + do_merge_eventParameters(T, NewStreamId, EPL, RA, HasA); + {other, PP} when is_record(PP, 'PropertyParm') -> + EP = #'EventParameter'{eventParameterName = PP#'PropertyParm'.name, + value = PP#'PropertyParm'.value, + extraInfo = PP#'PropertyParm'.extraInfo}, + do_merge_eventParameters(T, StreamId, [EP | EPL], RA, HasA); + {other, EP} when is_record(EP, 'EventParameter') -> + do_merge_eventParameters(T, StreamId, [EP | EPL], RA, HasA); + _ -> + return_error(0, {bad_eventParameter, H}) + end; +do_merge_eventParameters([], StreamId, EPL, RA, yes) -> + #'RequestedEvent'{streamID = StreamId, + eventAction = RA, + evParList = lists:reverse(EPL)}; +do_merge_eventParameters([], StreamId, EPL, _RA, no) -> + #'RequestedEvent'{streamID = StreamId, + eventAction = asn1_NOVALUE, + evParList = lists:reverse(EPL)}. + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_secondEventParameters,1}]}). +-endif. +merge_secondEventParameters(Params) -> + StreamId = asn1_NOVALUE, + EPL = [], + SRA = #'SecondRequestedActions'{}, + HasA = no, + do_merge_secondEventParameters(Params, StreamId, EPL, SRA, HasA) . + +do_merge_secondEventParameters([H | T], StreamId, EPL, SRA, HasA) -> + case H of + keepActive when (SRA#'SecondRequestedActions'.keepActive =:= asn1_NOVALUE) -> + SRA2 = SRA#'SecondRequestedActions'{keepActive = true}, + do_merge_secondEventParameters(T, StreamId, EPL, SRA2, yes); + {second_embed, SD} when (SRA#'SecondRequestedActions'.signalsDescriptor =:= asn1_NOVALUE) -> + SRA2 = SRA#'SecondRequestedActions'{signalsDescriptor = SD}, + do_merge_secondEventParameters(T, StreamId, EPL, SRA2, yes); + {eventDM, DM} when (SRA#'SecondRequestedActions'.eventDM =:= asn1_NOVALUE) -> + SRA2 = SRA#'SecondRequestedActions'{eventDM = DM}, + do_merge_secondEventParameters(T, StreamId, EPL, SRA2, yes); + {stream, NewStreamId} when (StreamId =:= asn1_NOVALUE) -> + do_merge_secondEventParameters(T, NewStreamId, EPL, SRA, HasA); + {other, PP} when is_record(PP, 'PropertyParm') -> + EP = #'EventParameter'{eventParameterName = PP#'PropertyParm'.name, + value = PP#'PropertyParm'.value, + extraInfo = PP#'PropertyParm'.extraInfo}, + do_merge_secondEventParameters(T, StreamId, [EP | EPL], SRA, HasA); + {other, EP} when is_record(EP, 'EventParameter') -> + do_merge_secondEventParameters(T, StreamId, [EP | EPL], SRA, HasA); + _ -> + return_error(0, {bad_secondEventParameter, H}) + end; +do_merge_secondEventParameters([], StreamId, EPL, SRA, yes) -> + #'SecondRequestedEvent'{streamID = StreamId, + eventAction = SRA, + evParList = lists:reverse(EPL)}; +do_merge_secondEventParameters([], StreamId, EPL, _SRA, no) -> + #'SecondRequestedEvent'{streamID = StreamId, + eventAction = asn1_NOVALUE, + evParList = lists:reverse(EPL)}. + +%% terminationID = "ROOT" / pathName / "$" / "*" +%% Total length of pathName must not exceed 64 chars. +%% pathName = ["*"] NAME *("/" / "*"/ ALPHA / DIGIT /"_" / "$" ) +%% ["@" pathDomainName ] +%% ABNF allows two or more consecutive "." although it is meaningless +%% in a path domain name. +%% pathDomainName = (ALPHA / DIGIT / "*" ) +%% *63(ALPHA / DIGIT / "-" / "*" / ".") +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_terminationID,1}]}). +-endif. +ensure_terminationID(Token) -> + {safeToken, _Line, LowerText} = Token, + %% terminationID = "ROOT" / pathName / "$" / "*" + decode_term_id(LowerText, false, [], []). + +decode_term_id([H | T], Wild, Id, Component) -> + case H of + $/ -> decode_term_id(T, Wild, [lists:reverse(Component) | Id], []); + $* -> decode_term_id(T, true, Id, [?megaco_all | Component]); + $$ -> decode_term_id(T, true, Id, [?megaco_choose | Component]); + _ -> decode_term_id(T, Wild, Id, [H | Component]) + end; +decode_term_id([], Wild, Id, Component) -> + Id2 = [lists:reverse(Component) | Id], + #megaco_term_id{contains_wildcards = Wild, id = lists:reverse(Id2)}. + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_pathName,1}]}). +-endif. +ensure_pathName(Token) -> + {_TokenTag, _Line, Text} = Token, + Text. %% BUGBUG: ensure values + +%% TimeStamp = Date "T" Time ; per ISO 8601:1988 +%% Date = 8(DIGIT) ; Date = yyyymmdd +%% Time = 8(DIGIT) ; Time = hhmmssss +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_timeStamp,1}]}). +-endif. +ensure_timeStamp(Token) -> + {'TimeStampToken', Line, Text} = Token, + case string:tokens(Text, [$T, $t]) of + [Date, Time] -> + #'TimeNotation'{date = Date, time = Time}; + _ -> + return_error(Line, {bad_timeStamp, Text}) + end. + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_transactionID,1}]}). +-endif. +ensure_transactionID(TransId) -> + ensure_uint32(TransId). + +%% transactionAck = transactionID / (transactionID "-" transactionID) +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_transactionAck,1}]}). +-endif. +ensure_transactionAck(Tokens) -> + {safeToken, _Line, Text} = Tokens, + ensure_transactionAck2(Text, []). + +ensure_transactionAck2([], Acc) -> + Id = lists:reverse(Acc), + #'TransactionAck'{firstAck = ensure_transactionID(Id)}; +ensure_transactionAck2([$- | Id2], Acc) -> + Id1 = lists:reverse(Acc), + #'TransactionAck'{firstAck = ensure_transactionID(Id1), + lastAck = ensure_transactionID(Id2)}; +ensure_transactionAck2([H|T], Acc) -> + ensure_transactionAck2(T, [H|Acc]). + + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_action_requests,2}]}). +-endif. +merge_action_requests(ContextId, Items) -> + CtxReq = #'ContextRequest'{}, + CtxAuditReq = #'ContextAttrAuditRequest'{}, + CmdReq = [], + TopReq = [], + do_merge_action_requests(ContextId, CtxReq, CtxAuditReq, CmdReq, TopReq, Items). + +do_merge_action_requests(ContextId, CtxReq, CtxAuditReq, CmdReq, TopReq, [H | T]) -> + case H of + _ when is_record(H, 'CommandRequest') -> + do_merge_action_requests(ContextId, CtxReq, CtxAuditReq, [H | CmdReq], TopReq, T); + + {priority, Int} when CtxReq#'ContextRequest'.priority == asn1_NOVALUE -> + CtxReq2 = CtxReq#'ContextRequest'{priority = Int}, + do_merge_action_requests(ContextId, CtxReq2, CtxAuditReq, CmdReq, + TopReq, T); + {emergency, Bool} when CtxReq#'ContextRequest'.emergency == asn1_NOVALUE -> + CtxReq2 = CtxReq#'ContextRequest'{emergency = Bool}, + do_merge_action_requests(ContextId, CtxReq2, CtxAuditReq, CmdReq, + TopReq, T); + {topology, Desc} -> + TopReq2 = Desc ++ TopReq, %% OTP-4088 + do_merge_action_requests(ContextId, CtxReq, CtxAuditReq, CmdReq, + TopReq2, T); + + priorityAudit when CtxAuditReq#'ContextAttrAuditRequest'.priority == asn1_NOVALUE -> + CtxAuditReq2 = CtxAuditReq#'ContextAttrAuditRequest'{priority = 'NULL'}, + do_merge_action_requests(ContextId, CtxReq, CtxAuditReq2, CmdReq, + TopReq, T); + emergencyAudit when CtxAuditReq#'ContextAttrAuditRequest'.emergency == asn1_NOVALUE -> + CtxAuditReq2 = CtxAuditReq#'ContextAttrAuditRequest'{emergency = 'NULL'}, + do_merge_action_requests(ContextId, CtxReq, CtxAuditReq2, CmdReq, + TopReq, T); + topologyAudit when CtxAuditReq#'ContextAttrAuditRequest'.topology == asn1_NOVALUE -> + CtxAuditReq2 = CtxAuditReq#'ContextAttrAuditRequest'{topology = 'NULL'}, + do_merge_action_requests(ContextId, CtxReq, CtxAuditReq2, CmdReq, + TopReq, T) + end; +do_merge_action_requests(ContextId, CtxReq, CtxAuditReq, CmdReq, TopReq, []) -> + #'ActionRequest'{contextId = ContextId, + contextRequest = strip_contextRequest(CtxReq, TopReq), + contextAttrAuditReq = strip_contextAttrAuditRequest(CtxAuditReq), + commandRequests = lists:reverse(CmdReq)}. + +%% OTP-5085: +%% In order to solve a problem in the parser, the error descriptor +%% has been put last in the non-empty commandReplyList, if it is not +%% asn1_NOVALUE +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_action_reply,1}]}). +-endif. +merge_action_reply(ReplyList) -> + CtxReq = #'ContextRequest'{}, + TopReq = [], + CmdList = [], + do_merge_action_reply(ReplyList, CtxReq, TopReq, CmdList). + +do_merge_action_reply([ED], CtxReq, TopReq, CmdList) + when is_record(ED, 'ErrorDescriptor') -> + #'ActionReply'{contextReply = strip_contextRequest(CtxReq, TopReq), + commandReply = lists:reverse(CmdList), + errorDescriptor = ED}; +do_merge_action_reply([H | T], CtxReq, TopReq, CmdList) -> + case H of + {command, Cmd} -> + do_merge_action_reply(T, CtxReq, TopReq, [Cmd | CmdList]); + {context, Ctx} -> + case Ctx of + {priority, Int} when CtxReq#'ContextRequest'.priority =:= asn1_NOVALUE -> + CtxReq2 = CtxReq#'ContextRequest'{priority = Int}, + do_merge_action_reply(T, CtxReq2, TopReq, CmdList); + {emergency, Bool} when CtxReq#'ContextRequest'.emergency =:= asn1_NOVALUE -> + CtxReq2 = CtxReq#'ContextRequest'{emergency = Bool}, + do_merge_action_reply(T, CtxReq2, TopReq, CmdList); + {topology, Desc} -> + TopReq2 = Desc ++ TopReq, %% OTP-4088 + do_merge_action_reply(T, CtxReq, TopReq2, CmdList) + end + end; +do_merge_action_reply([], CtxReq, TopReq, CmdList) -> + #'ActionReply'{contextReply = strip_contextRequest(CtxReq, TopReq), + commandReply = lists:reverse(CmdList)}. + +strip_contextRequest(R, TopReq) + when (R#'ContextRequest'.priority =:= asn1_NOVALUE) andalso + (R#'ContextRequest'.emergency =:= asn1_NOVALUE) andalso + (TopReq =:= []) -> + asn1_NOVALUE; +strip_contextRequest(R, []) -> + R#'ContextRequest'{topologyReq = asn1_NOVALUE}; +strip_contextRequest(R, TopReq) -> + R#'ContextRequest'{topologyReq = TopReq}. %% OTP-4088 + + +strip_contextAttrAuditRequest(R) + when (R#'ContextAttrAuditRequest'.priority =:= asn1_NOVALUE) andalso + (R#'ContextAttrAuditRequest'.emergency =:= asn1_NOVALUE) andalso + (R#'ContextAttrAuditRequest'.topology =:= asn1_NOVALUE) -> + asn1_NOVALUE; +strip_contextAttrAuditRequest(R) -> + R. + +make_commandRequest({CmdTag, {_TokenTag, _Line, Text}}, Cmd) -> + Req = #'CommandRequest'{command = {CmdTag, Cmd}}, + case Text of + [$w, $- | _] -> + Req#'CommandRequest'{wildcardReturn = 'NULL'}; + [$o, $-, $w, $- | _] -> + Req#'CommandRequest'{optional = 'NULL', wildcardReturn = 'NULL'}; + [$o, $- | _] -> + Req#'CommandRequest'{optional = 'NULL'}; + _ -> + Req + end. + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_terminationAudit,1}]}). +-endif. +merge_terminationAudit(AuditReturnParameters) -> + lists:reverse(do_merge_terminationAudit(AuditReturnParameters, [], [])). + +do_merge_terminationAudit([H| T], ARPs, AuditItems) -> + case H of + {auditReturnItem, AuditItem} -> + do_merge_terminationAudit(T, ARPs, [AuditItem | AuditItems]); + AuditReturnParameter -> + do_merge_terminationAudit(T, [AuditReturnParameter | ARPs], AuditItems) + end; +do_merge_terminationAudit([], AuditReturnParameters, []) -> + AuditReturnParameters; +do_merge_terminationAudit([], AuditReturnParameters, AuditItems) -> + AuditDescriptor = #'AuditDescriptor'{auditToken = AuditItems}, + AuditReturnParameter = {emptyDescriptors, AuditDescriptor}, + [AuditReturnParameter | AuditReturnParameters]. + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_mediaDescriptor,1}]}). +-endif. +merge_mediaDescriptor(MediaParms) -> + do_merge_mediaDescriptor(MediaParms, asn1_NOVALUE, [], []). + +do_merge_mediaDescriptor([H | T], TS, One, Multi) -> + case H of + {streamParm, Parm} when Multi =:= [] -> + do_merge_mediaDescriptor(T, TS, [Parm | One], Multi); + {streamDescriptor, Desc} when One =:= [] -> + do_merge_mediaDescriptor(T, TS, One, [Desc | Multi]); + {termState, TS2} when TS =:= asn1_NOVALUE -> + do_merge_mediaDescriptor(T, TS2, One, Multi); + _ -> + return_error(0, {bad_merge_mediaDescriptor, [H, TS, One, Multi]}) + end; +do_merge_mediaDescriptor([], TS, One, Multi) -> + if + (One =:= []) -> + if (Multi =:= []) -> + #'MediaDescriptor'{streams = asn1_NOVALUE, + termStateDescr = TS}; + true -> % (Multi =/= []) + Streams = {multiStream, lists:reverse(Multi)}, + #'MediaDescriptor'{streams = Streams, + termStateDescr = TS} + end; + true -> % (One =/= []) + if + (Multi =:= []) -> + Streams = {oneStream, merge_streamParms(One)}, + #'MediaDescriptor'{streams = Streams, + termStateDescr = TS}; + true -> % (Multi =/= []) + return_error(0, + {bad_merge_mediaDescriptor, [TS, One, Multi]}) + end + end. + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_streamParms,1}]}). +-endif. +merge_streamParms(TaggedStreamParms) -> + SP = #'StreamParms'{}, + do_merge_streamParms(TaggedStreamParms, SP). + +do_merge_streamParms([{Tag, D} | T] = All, SP) -> + case Tag of + local when SP#'StreamParms'.localDescriptor =:= asn1_NOVALUE -> + do_merge_streamParms(T, SP#'StreamParms'{localDescriptor = D}); + remote when SP#'StreamParms'.remoteDescriptor =:= asn1_NOVALUE -> + do_merge_streamParms(T, SP#'StreamParms'{remoteDescriptor = D}); + control -> + LCD = + case SP#'StreamParms'.localControlDescriptor of + asn1_NOVALUE -> + #'LocalControlDescriptor'{propertyParms = []}; + PrevLCD -> + PrevLCD + end, + LCD2 = do_merge_control_streamParms(D, LCD), + do_merge_streamParms(T, SP#'StreamParms'{localControlDescriptor = LCD2}); + _ -> + return_error(0, {do_merge_streamParms, [All, SP]}) + end; +do_merge_streamParms([], SP) + when is_record(SP#'StreamParms'.localControlDescriptor, + 'LocalControlDescriptor') -> + LCD = SP#'StreamParms'.localControlDescriptor, + PP = LCD#'LocalControlDescriptor'.propertyParms, + LCD2 = LCD#'LocalControlDescriptor'{propertyParms = lists:reverse(PP)}, + SP#'StreamParms'{localControlDescriptor = LCD2}; +do_merge_streamParms([], SP) -> + SP. + + +do_merge_control_streamParms([{SubTag, SD} | T] = All, LCD) -> + case SubTag of + group when LCD#'LocalControlDescriptor'.reserveGroup =:= asn1_NOVALUE -> + LCD2 = LCD#'LocalControlDescriptor'{reserveGroup = SD}, + do_merge_control_streamParms(T, LCD2); + value when LCD#'LocalControlDescriptor'.reserveValue =:= asn1_NOVALUE -> + LCD2 = LCD#'LocalControlDescriptor'{reserveValue = SD}, + do_merge_control_streamParms(T, LCD2); + mode when LCD#'LocalControlDescriptor'.streamMode =:= asn1_NOVALUE -> + LCD2 = LCD#'LocalControlDescriptor'{streamMode = SD}, + do_merge_control_streamParms(T, LCD2); + prop -> + PP = LCD#'LocalControlDescriptor'.propertyParms, + LCD2 = LCD#'LocalControlDescriptor'{propertyParms = [SD | PP]}, + do_merge_control_streamParms(T, LCD2); + _ -> + return_error(0, {do_merge_control_streamParms, [All, LCD]}) + end; +do_merge_control_streamParms([], LCD) -> + LCD. + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_terminationStateDescriptor,1}]}). +-endif. +merge_terminationStateDescriptor(Parms) -> + TSD = #'TerminationStateDescriptor'{propertyParms = []}, + do_merge_terminationStateDescriptor(Parms, TSD). + +do_merge_terminationStateDescriptor([{Tag, Val} | T], TSD) -> + case Tag of + serviceState when TSD#'TerminationStateDescriptor'.serviceState =:= asn1_NOVALUE -> + TSD2 = TSD#'TerminationStateDescriptor'{serviceState = Val}, + do_merge_terminationStateDescriptor(T, TSD2); + eventBufferControl when TSD#'TerminationStateDescriptor'.eventBufferControl =:= asn1_NOVALUE-> + TSD2 = TSD#'TerminationStateDescriptor'{eventBufferControl = Val}, + do_merge_terminationStateDescriptor(T, TSD2); + propertyParm -> + PP = TSD#'TerminationStateDescriptor'.propertyParms, + TSD2 = TSD#'TerminationStateDescriptor'{propertyParms = [Val | PP]}, + do_merge_terminationStateDescriptor(T, TSD2) + end; +do_merge_terminationStateDescriptor([], TSD) -> + PP = TSD#'TerminationStateDescriptor'.propertyParms, + TSD#'TerminationStateDescriptor'{propertyParms = lists:reverse(PP)}. + +-ifdef(megaco_nscanner_props). + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_prop_groups,1}]}). +-endif. +ensure_prop_groups(Token) -> + {_TokenTag, _Line, Text} = Token, + Group = [], + parse_prop_name(Text, Group). + +parse_prop_name([Char | Rest] = All, Group) -> + if + ?white_space(Char) -> + parse_prop_name(Rest, Group); + ?end_of_line(Char) -> + parse_prop_name(Rest, Group); + true -> + Name = [], + do_parse_prop_name(All, Name, Group) + end; +parse_prop_name([] = All, Group) -> + Name = [], + do_parse_prop_name(All, Name, Group). + +do_parse_prop_name([Char | Rest], Name, Group) + when (Char =:= $=) andalso (Name =/= []) -> + %% Now we have a complete name + if + (Name =:= "v") andalso (Group =/= []) -> + %% v= is a property group delimiter, + %% lets create yet another property group. + NewGroup = [], + [lists:reverse(Group) | parse_prop_value(Rest, Name, NewGroup)]; + true -> + %% Use current property group + parse_prop_value(Rest, Name, Group) + end; +do_parse_prop_name([Char | Rest], Name, Group) -> + case ?classify_char4(Char) of + safe_char_upper -> + do_parse_prop_name(Rest, [Char | Name], Group); + safe_char -> + do_parse_prop_name(Rest, [Char | Name], Group); + _ -> + return_error(0, {bad_prop_name, lists:reverse(Name), Char}) + end; +do_parse_prop_name([], [], []) -> + []; +do_parse_prop_name([], [], Group) -> + [lists:reverse(Group)]; +do_parse_prop_name([], Name, Group) when Name =/= [] -> + %% Assume end of line + Value = [], + PP = make_prop_parm(Name, Value), + Group2 = lists:reverse([PP | Group]), + [Group2]. + +-ifdef(megaco_parser_inline). +-compile({inline,[{parse_prop_value,3}]}). +-endif. +parse_prop_value(Chars, Name, Group) -> + Value = [], + do_parse_prop_value(Chars, Name, Value, Group). + +do_parse_prop_value([Char | Rest], Name, Value, Group) -> + if + ?end_of_line(Char) -> + %% Now we have a complete "name=value" pair + PP = make_prop_parm(Name, Value), + parse_prop_name(Rest, [PP | Group]); + true -> + do_parse_prop_value(Rest, Name, [Char | Value], Group) + end; +do_parse_prop_value([], Name, Value, Group) -> + %% Assume end of line + PP = make_prop_parm(Name, Value), + Group2 = lists:reverse([PP | Group]), + [Group2]. + +-ifdef(megaco_parser_inline). +-compile({inline,[{make_prop_parm,2}]}). +-endif. +make_prop_parm(Name, Value) -> + #'PropertyParm'{name = lists:reverse(Name), + value = [lists:reverse(Value)]}. + +-else. % -ifdef(megaco_nscanner_props). + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_prop_groups,1}]}). +-endif. +ensure_prop_groups(Token) -> + {_TokenTag, _Line, Groups} = Token, + %% do_ensure_prop_groups(Groups). + Groups. + +%% do_ensure_prop_groups(Groups) when is_list(Groups) -> +%% [ensure_prop_group(Group) || Group <- Groups]; +%% do_ensure_prop_groups(BadGroups) -> +%% throw({error, {?MODULE, {bad_property_groups, BadGroups}}}). + +%% -ifdef(megaco_parser_inline). +%% -compile({inline,[{ensure_prop_group,1}]}). +%% -endif. +%% ensure_prop_group(Group) when is_list(Group) -> +%% [ensure_prop_parm(PropParm) || PropParm <- Group]; +%% ensure_prop_group(BadGroup) -> +%% throw({error, {?MODULE, {bad_property_group, BadGroup}}}). + +%% -ifdef(megaco_parser_inline). +%% -compile({inline,[{ensure_prop_parm,1}]}). +%% -endif. +%% ensure_prop_parm(#property_parm{name = Name, +%% value = Value}) -> +%% #'PropertyParm'{name = Name, +%% value = Value}; +%% ensure_prop_parm(PP) when is_record(PP, 'PropertyParm') -> +%% PP; +%% ensure_prop_parm(BadPropParm) -> +%% throw({error, {?MODULE, {bad_property_parm, BadPropParm}}}). + +-endif. % -ifdef(megaco_nscanner_props). + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_uint,3}]}). +-endif. +ensure_uint(Token, Min, Max) -> + case Token of + {_TokenTag, Line, Val} when is_integer(Val) -> + ensure_uint(Val, Min, Max, Line); + {_TokenTag, Line, Text} -> + case (catch list_to_integer(Text)) of + {'EXIT', _} -> + return_error(Line, {not_an_integer, Text}); + Val when is_integer(Val) -> + ensure_uint(Val, Min, Max, Line) + end; + Val when is_integer(Val) -> + ensure_uint(Val, Min, Max, 0); + Text -> + case (catch list_to_integer(Text)) of + {'EXIT', _} -> + return_error(0, {not_an_integer, Text}); + Val when is_integer(Val) -> + ensure_uint(Val, Min, Max, 0) + end + end. + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_uint,4}]}). +-endif. +ensure_uint(Val, Min, Max, Line) -> + if + is_integer(Min) andalso (Val >= Min) -> + if + is_integer(Max) andalso (Val =< Max) -> + Val; + Max =:= infinity -> + Val; + true -> + return_error(Line, {too_large_integer, Val, Max}) + end; + true -> + return_error(Line, {too_small_integer, Val, Min}) + end. + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_uint16,1}]}). +-endif. +ensure_uint16(Int) -> + ensure_uint(Int, 0, 65535). + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_uint32,1}]}). +-endif. +ensure_uint32(Int) -> + ensure_uint(Int, 0, 4294967295) . + +%% OTP-4710 +ensure_hex({_TokenTag, _Line, [$0, $x |Chars]}, Min, Max) -> + ensure_uint(length(Chars), Min, Max), + hex_to_int(Chars, []); +ensure_hex({_TokenTag, _Line, [$0, $X |Chars]}, Min, Max) -> + ensure_uint(length(Chars), Min, Max), + hex_to_int(Chars, []); +ensure_hex([$0, $x |Chars], Min, Max) -> + ensure_uint(length(Chars), Min, Max), + hex_to_int(Chars, []); +ensure_hex([$0, $X |Chars], Min, Max) -> + ensure_uint(length(Chars), Min, Max), + hex_to_int(Chars, []). + +%% OTP-4710 +hex_to_int([], Acc) -> + lists:reverse(Acc); +hex_to_int([Char1,Char2|Tail], Acc) -> + Int1 = hchar_to_int(Char1), + Int2 = hchar_to_int(Char2), + Val = Int2 bor (Int1 bsl 4), + hex_to_int(Tail, [Val| Acc]); +hex_to_int([Char], Acc) -> + Int = hchar_to_int(Char), + lists:reverse([Int|Acc]). + +hchar_to_int(Char) when ($0 =< Char) andalso (Char =< $9) -> + Char - $0; +hchar_to_int(Char) when ($A =< Char) andalso (Char =< $F) -> + Char - $A + 10; % OTP-4710 +hchar_to_int(Char) when ($a =< Char) andalso (Char =< $f) -> + Char - $a + 10. % OTP-4710 + +-ifdef(megaco_parser_inline). +-compile({inline,[{value_of,1}]}). +-endif. +value_of(Token) -> + {_TokenTag, _Line, Text} = Token, + Text. + +% d(F) -> +% d(F,[]). +% d(F, A) -> +% io:format("~p:" ++ F ++ "~n", [?MODULE | A]). + diff --git a/lib/megaco/src/text/megaco_text_parser_v1.yrl b/lib/megaco/src/text/megaco_text_parser_v1.yrl new file mode 100644 index 0000000000..fd50d90523 --- /dev/null +++ b/lib/megaco/src/text/megaco_text_parser_v1.yrl @@ -0,0 +1,1364 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2000-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: YECC grammar for text encoding of Megaco/H.248 +%%---------------------------------------------------------------------- + +%%---------------------------------------------------------------------- +%% Annex B TEXT ENCODING OF THE PROTOCOL (NORMATIVE) +%% +%% B.1 Coding of wildcards +%% +%% In a text encoding of the protocol, while TerminationIDs are +%% arbitrary, by judicious choice of names, the wildcard character, "*" +%% may be made more useful. When the wildcard character is encountered, +%% it will "match" all TerminationIDs having the same previous and +%% following characters (if appropriate). For example, if there were +%% TerminationIDs of R13/3/1, R13/3/2 and R13/3/3, the TerminationID +%% R13/3/* would match all of them. There are some circumstances where +%% ALL Terminations must be referred to. The TerminationID "*" suffices, +%% and is referred to as ALL. The CHOOSE TerminationID "$" may be used to +%% signal to the MG that it has to create an ephemeral Termination or +%% select an idle physical Termination. +%% +%% B.2 ABNF specification +%% +%% The protocol syntax is presented in ABNF according to RFC2234. The +%% protocol is not case sensitive. Identifiers are not case sensitive. +%%---------------------------------------------------------------------- + +%%---------------------------------------------------------------------- +%% Number of expected shift/reduce warnings +%% This is ugly but... +%%---------------------------------------------------------------------- + +Expect 609. + + +%%---------------------------------------------------------------------- +%% Non-terminals +%%---------------------------------------------------------------------- + +Nonterminals + + actionReply + actionReplyBody + actionReplyList + actionRequest + actionRequestItem + actionRequestItems + actionRequestList + alternativeValue + ammParameter + ammParameters + ammRequest + ammRequestBody + ammToken + ammsReply + ammsReplyBody + ammsToken + auditDescriptor + auditDescriptorBody + auditItem + auditItemList + auditOther + auditReply + auditRequest + auditReturnItem + auditReturnParameter + auditReturnParameterList + authenticationHeader + commandReply + commandReplyList + commandRequest + contextAudit + contextAuditProperties + contextAuditProperty + contextID + contextProperty + contextTerminationAudit + daddr + deviceName + digitMapDescriptor + domainAddress + domainName + embedFirst + embedNoSig + embedSig + embedWithSig + errorCode + errorDescriptor + errorText + eventBufferControl + eventBufferControlState + eventBufferDescriptor + eventDM + eventParameter + eventParameterName + eventParameters + eventSpec + eventSpecList + eventStreamOrOther + eventsDescriptor + extension + extensionParameter + localControlDescriptor + localParm + localParmList + mId + mediaDescriptor + mediaParm + mediaParmList + megacoMessage + message + messageBody + modemDescriptor + modemType + modemTypeList + mtpAddress + muxDescriptor + muxType + notificationReason + notificationReasons + notifyReply + notifyReplyBody + notifyRequest + notifyRequestBody + observedEvent + observedEventBody + observedEventParameter + observedEventParameters + observedEventTimeStamp + observedEvents + observedEventsDescriptor + onOrOff + optAuditDescriptor + optImmAckRequired + optPropertyParms + optSep + packagesDescriptor + packagesItem + packagesItems + %% parmName + parmValue + pathName + pkgdName + portNumber + priority + propertyParm + propertyParms + requestID + requestedEvent + requestedEventBody + requestedEvents + safeToken + safeToken2 + secondEventParameter + secondEventParameters + secondRequestedEvent + secondRequestedEventBody + secondRequestedEvents + servChgReplyParm + servChgReplyParms + serviceChangeAddress + serviceChangeDelay + serviceChangeDescriptor + serviceChangeMethod + serviceChangeMgcId + serviceChangeParm + serviceChangeParms + serviceChangeProfile + serviceChangeReason + serviceChangeReply + serviceChangeReplyBody + serviceChangeReplyDescriptor + serviceChangeRequest + serviceChangeVersion + serviceState + serviceStates + sigParameter + sigParameters + signalList + signalListId + signalListParm + signalListParms + signalName + signalParm + signalParms + signalRequest + signalsDescriptor + signalType + statisticsDescriptor + statisticsParameter + statisticsParameters + streamDescriptor + streamID + streamModes + streamParm + streamParmList + subtractRequest + terminationA + terminationAudit + terminationB + terminationID + terminationIDList + terminationIDListRepeat + terminationStateDescriptor + terminationStateParm + terminationStateParms + timeStamp + topologyDescriptor + topologyDirection + topologyTriple + topologyTripleList + transactionAck + transactionAckList + transactionID + transactionItem + transactionList + transactionPending + transactionReply + transactionReplyBody + transactionRequest + transactionResponseAck + value + valueList + +. + +%%---------------------------------------------------------------------- +%% Terminals +%%---------------------------------------------------------------------- + +Terminals + + 'AddToken' + 'AuditCapToken' + 'AuditToken' + 'AuditValueToken' + 'AuthToken' + 'BothwayToken' + 'BriefToken' + 'BufferToken' + 'COLON' + 'COMMA' + 'ContextAuditToken' + 'CtxToken' + 'DelayToken' + 'DigitMapToken' + 'DigitMapDescriptorToken' + 'DiscardToken' + 'DisconnectedToken' + 'DurationToken' + 'EQUAL' + 'EmbedToken' + 'EmergencyToken' + 'ErrorToken' + 'EventBufferToken' + 'EventsToken' + 'FailoverToken' + 'ForcedToken' + 'GREATER' + 'GracefulToken' + 'H221Token' + 'H223Token' + 'H226Token' + 'HandOffToken' + 'ImmAckRequiredToken' + 'InSvcToken' + 'InactiveToken' + 'IsolateToken' + 'InterruptByEventToken' + 'InterruptByNewSignalsDescrToken' + 'KeepActiveToken' + 'LBRKT' + 'LESSER' + 'LSBRKT' + 'LocalControlToken' + 'LocalDescriptorToken' + 'LockStepToken' + 'LoopbackToken' + 'MediaToken' + %% 'MegacopToken' + 'MethodToken' + 'MgcIdToken' + 'ModeToken' + 'ModemToken' + 'ModifyToken' + 'MoveToken' + 'MtpAddressToken' + 'MuxToken' + 'NEQUAL' + 'NotifyCompletionToken' + 'NotifyToken' + 'ObservedEventsToken' + 'OffToken' + 'OnToken' + 'OnOffToken' + 'OnewayToken' + 'OtherReasonToken' + 'OutOfSvcToken' + 'PackagesToken' + 'PendingToken' + 'PriorityToken' + 'ProfileToken' + 'QuotedChars' + 'RBRKT' + 'RSBRKT' + 'ReasonToken' + 'RecvonlyToken' + 'RemoteDescriptorToken' + 'ReplyToken' + 'ReservedGroupToken' + 'ReservedValueToken' + 'ResponseAckToken' + 'RestartToken' + 'SEP' + 'SafeChars' + 'SendonlyToken' + 'SendrecvToken' + 'ServiceChangeAddressToken' + 'ServiceChangeToken' + 'ServiceStatesToken' + 'ServicesToken' + 'SignalListToken' + 'SignalTypeToken' + 'SignalsToken' + 'StatsToken' + 'StreamToken' + 'SubtractToken' + 'SynchISDNToken' + 'TerminationStateToken' + 'TestToken' + 'TimeOutToken' + 'TimeStampToken' + 'TopologyToken' + 'TransToken' + 'V18Token' + 'V22Token' + 'V22bisToken' + 'V32Token' + 'V32bisToken' + 'V34Token' + 'V76Token' + 'V90Token' + 'V91Token' + 'VersionToken' + 'AndAUDITSelectToken' %% OTP-7534: v3-fix + 'BothToken' %% OTP-7534: v3-fix + 'ContextAttrToken' %% OTP-7534: v3-fix + 'ContextListToken' %% OTP-7534: v3-fix + 'DirectionToken' %% OTP-7534: v3-fix + 'EmergencyOffToken' %% OTP-7534: v3-fix + 'EmergencyValueToken' %% OTP-7534: v3-fix + 'ExternalToken' %% OTP-7534: v3-fix + 'IEPSToken' %% OTP-7534: v3-fix + 'IntsigDelayToken' %% OTP-7534: v3-fix + 'InternalToken' %% OTP-7534: v3-fix + 'IterationToken' %% OTP-7534: v3-fix + 'MessageSegmentToken' %% OTP-7534: v3-fix + 'NeverNotifyToken' %% OTP-7534: v3-fix + 'NotifyImmediateToken' %% OTP-7534: v3-fix + 'NotifyRegulatedToken' %% OTP-7534: v3-fix + 'Nx64kToken' %% OTP-7534: v2-fix + 'OnewayBothToken' %% OTP-7534: v3-fix + 'OnewayExternalToken' %% OTP-7534: v3-fix + 'OrAUDITselectToken' %% OTP-7534: v3-fix + 'RequestIDToken' %% OTP-7534: v3-fix + 'ResetEventsDescriptorToken' %% OTP-7534: v3-fix + 'SegmentationCompleteToken' %% OTP-7534: v3-fix + 'ServiceChangeIncompleteToken' %% OTP-7534: v3-fix + endOfMessage + +. + +%%---------------------------------------------------------------------- +%% Root symbol +%%---------------------------------------------------------------------- + +Rootsymbol megacoMessage. + +%%---------------------------------------------------------------------- +%% The grammar +%%---------------------------------------------------------------------- + +%% megacoMessage = LWSP [authenticationHeader SEP ] message +%% authenticationHeader = AuthToken EQUAL SecurityParmIndex COLON +%% SequenceNum COLON AuthData +%% +%% SecurityParmIndex = "0x" 8(HEXDIG) +%% SequenceNum = "0x" 8(HEXDIG) +%% AuthData = "0x" 24*64(HEXDIG) +%% message = MegacopToken SLASH version SEP mId SEP messageBody +%% version = 1*2(DIGIT) . + +megacoMessage -> optSep authenticationHeader message endOfMessage : + #'MegacoMessage'{authHeader = '$2', mess = '$3'} . + +optSep -> 'SEP' : sep . +optSep -> '$empty' : no_sep . + +authenticationHeader -> 'AuthToken' 'EQUAL' + safeToken 'COLON' safeToken 'COLON' safeToken optSep : + ensure_auth_header('$3', '$5', '$7') . +authenticationHeader -> '$empty' : asn1_NOVALUE . + +message -> safeToken mId messageBody : + ensure_message('$1', '$2', '$3') . + +messageBody -> errorDescriptor : {messageError, '$1'} . +messageBody -> transactionList : {transactions, '$1'} . + +transactionList -> transactionItem : ['$1'] . +transactionList -> transactionItem transactionList : ['$1' | '$2'] . + +transactionItem -> transactionRequest : {transactionRequest, '$1'} . +transactionItem -> transactionReply : {transactionReply, '$1'}. +transactionItem -> transactionPending : {transactionPending, '$1'} . +transactionItem -> transactionResponseAck : {transactionResponseAck, '$1'} . + +transactionResponseAck -> 'ResponseAckToken' + 'LBRKT' transactionAck transactionAckList 'RBRKT' : + ['$3' | '$4'] . + +transactionAckList -> 'COMMA' transactionAck transactionAckList : ['$2' | '$3'] . +transactionAckList -> '$empty' : [] . + +transactionAck -> safeToken : ensure_transactionAck('$1') . + +transactionPending -> 'PendingToken' 'EQUAL' transactionID 'LBRKT' 'RBRKT' : + #'TransactionPending'{transactionId = ensure_transactionID('$3')} . + +transactionRequest -> 'TransToken' + 'LBRKT' actionRequest actionRequestList 'RBRKT' : + #'TransactionRequest'{transactionId = asn1_NOVALUE, + actions = ['$3' | '$4']} . +transactionRequest -> 'TransToken' 'EQUAL' + 'LBRKT' actionRequest actionRequestList 'RBRKT' : + #'TransactionRequest'{transactionId = asn1_NOVALUE, + actions = ['$4' | '$5']} . +transactionRequest -> 'TransToken' 'EQUAL' transactionID + 'LBRKT' actionRequest actionRequestList 'RBRKT' : + #'TransactionRequest'{transactionId = ensure_transactionID('$3'), + actions = ['$5' | '$6']} . + +actionRequestList -> 'COMMA' actionRequest actionRequestList : + ['$2' | '$3'] . +actionRequestList -> '$empty' : [] . + +actionRequest -> 'CtxToken' 'EQUAL' contextID + 'LBRKT' actionRequestItem actionRequestItems 'RBRKT' : + merge_action_requests('$3', ['$5' | '$6']) . + +actionRequestItems -> 'COMMA' actionRequestItem actionRequestItems : ['$2' | '$3'] . +actionRequestItems -> '$empty' : [] . + +actionRequestItem -> contextProperty : '$1'. +actionRequestItem -> contextAudit : '$1' . +actionRequestItem -> commandRequest : '$1'. + +%% at-most-once +contextProperty -> topologyDescriptor : {topology, '$1'}. +contextProperty -> priority : {priority, '$1'}. +contextProperty -> 'EmergencyToken' : {emergency, true}. + +contextAudit -> 'ContextAuditToken' + 'LBRKT' contextAuditProperty + contextAuditProperties 'RBRKT' : + ['$3' | '$4'] . + +contextAuditProperties -> 'COMMA' contextAuditProperty + contextAuditProperties : + ['$2' | '$3'] . +contextAuditProperties -> '$empty' : [] . + +%% at-most-once . +contextAuditProperty -> 'TopologyToken' : topologyAudit . +contextAuditProperty -> 'EmergencyToken' : emergencyAudit . +contextAuditProperty -> 'PriorityToken' : priorityAudit . + +commandRequest -> ammRequest : '$1'. +commandRequest -> subtractRequest : '$1'. +commandRequest -> auditRequest : '$1'. +commandRequest -> notifyRequest : '$1'. +commandRequest -> serviceChangeRequest : '$1'. + +transactionReply -> 'ReplyToken' 'EQUAL' transactionID + 'LBRKT' optImmAckRequired + transactionReplyBody 'RBRKT' : + #'TransactionReply'{transactionId = '$3', + immAckRequired = '$5', + transactionResult = '$6'} . + +optImmAckRequired -> 'ImmAckRequiredToken' 'COMMA' : 'NULL' . +optImmAckRequired -> '$empty' : asn1_NOVALUE . + +transactionReplyBody -> errorDescriptor : + {transactionError, '$1'} . +transactionReplyBody -> actionReply actionReplyList : + {actionReplies, ['$1' | '$2']} . + +actionReplyList -> 'COMMA' actionReply actionReplyList : ['$2' | '$3'] . +actionReplyList -> '$empty' : [] . + +actionReply -> 'CtxToken' 'EQUAL' contextID + 'LBRKT' actionReplyBody 'RBRKT' : + setelement(#'ActionReply'.contextId, '$5', '$3') . + +actionReplyBody -> errorDescriptor : + #'ActionReply'{errorDescriptor = '$1'} . +actionReplyBody -> commandReply commandReplyList : + merge_action_reply(['$1' | '$2']) . + +commandReply -> serviceChangeReply : {command, '$1'} . +commandReply -> auditReply : {command, '$1'} . +commandReply -> ammsReply : {command, '$1'} . +commandReply -> notifyReply : {command, '$1'} . +commandReply -> contextProperty : {context, '$1'} . + +%% OTP-5085 +%% This ugly thing is to fool the parser. The errorDescriptor does not +%% realy belong here. The merge_action_reply will remove it and put it +%% in it's right place later. +commandReplyList -> 'COMMA' errorDescriptor : + ['$2'] . +commandReplyList -> 'COMMA' commandReply commandReplyList : + ['$2' | '$3'] . +commandReplyList -> '$empty' : [] . + +%Add Move and Modify have the same request parameter +ammRequest -> ammToken 'EQUAL' terminationID ammRequestBody : + make_commandRequest('$1', + #'AmmRequest'{terminationID = ['$3'], + descriptors = '$4'}) . + +ammToken -> 'AddToken' : {addReq, '$1'} . +ammToken -> 'MoveToken' : {moveReq, '$1'} . +ammToken -> 'ModifyToken' : {modReq, '$1'} . + +ammRequestBody -> 'LBRKT' ammParameter ammParameters 'RBRKT' : ['$2' | '$3'] . +ammRequestBody -> '$empty' : [] . + +ammParameters -> 'COMMA' ammParameter ammParameters : ['$2' | '$3'] . +ammParameters -> '$empty' : [] . + +%at-most-once +ammParameter -> mediaDescriptor : {mediaDescriptor, '$1'}. +ammParameter -> modemDescriptor : {modemDescriptor, '$1'}. +ammParameter -> muxDescriptor : {muxDescriptor, '$1'}. +ammParameter -> eventsDescriptor : {eventsDescriptor, '$1'}. +ammParameter -> eventBufferDescriptor : {eventBufferDescriptor, '$1'}. +ammParameter -> signalsDescriptor : {signalsDescriptor, '$1'}. +ammParameter -> digitMapDescriptor : {digitMapDescriptor, '$1'}. +ammParameter -> auditDescriptor : {auditDescriptor, '$1'}. + +ammsReply -> ammsToken 'EQUAL' terminationID ammsReplyBody : + {'$1', #'AmmsReply'{terminationID = ['$3'], + terminationAudit = '$4'}} . + +ammsToken -> 'AddToken' : addReply . +ammsToken -> 'MoveToken' : moveReply . +ammsToken -> 'ModifyToken' : modReply . +ammsToken -> 'SubtractToken' : subtractReply . + +ammsReplyBody -> 'LBRKT' terminationAudit 'RBRKT' : '$2' . +ammsReplyBody -> '$empty' : asn1_NOVALUE . + +subtractRequest -> 'SubtractToken' 'EQUAL' + terminationID optAuditDescriptor : + make_commandRequest({subtractReq, '$1'}, + #'SubtractRequest'{terminationID = ['$3'], + auditDescriptor = '$4'}) . + + +optAuditDescriptor -> 'LBRKT' auditDescriptor 'RBRKT' : '$2'. +optAuditDescriptor -> '$empty' : asn1_NOVALUE . + +auditRequest -> 'AuditValueToken' 'EQUAL' + terminationID optAuditDescriptor : + make_commandRequest({auditValueRequest, '$1'}, + #'AuditRequest'{terminationID = '$3', + auditDescriptor = '$4'}) . +auditRequest -> 'AuditCapToken' 'EQUAL' + terminationID optAuditDescriptor : + make_commandRequest({auditCapRequest, '$1'}, + #'AuditRequest'{terminationID = '$3', + auditDescriptor = '$4'}) . + +auditReply -> 'AuditValueToken' 'EQUAL' 'CtxToken' contextTerminationAudit + : {auditValueReply, '$4'} . +auditReply -> 'AuditCapToken' 'EQUAL' 'CtxToken' contextTerminationAudit + : {auditCapReply, '$4'} . +auditReply -> 'AuditValueToken' 'EQUAL' auditOther + : {auditValueReply, '$3'} . +auditReply -> 'AuditCapToken' 'EQUAL' auditOther + : {auditCapReply, '$3'} . + +contextTerminationAudit -> terminationIDList : {contextAuditResult, '$1'} . +contextTerminationAudit -> 'LBRKT' errorDescriptor 'RBRKT' : {contextAuditResult, '$2'} . + +auditOther -> terminationID : + {auditResult, + #'AuditResult'{terminationID = '$1', + terminationAuditResult = []}} . +auditOther -> terminationID 'LBRKT' terminationAudit 'RBRKT' : + {auditResult, + #'AuditResult'{terminationID = '$1', + terminationAuditResult = '$3'}} . + +terminationAudit -> auditReturnParameter auditReturnParameterList : + merge_terminationAudit(['$1' |'$2' ]) . + +auditReturnParameterList -> 'COMMA' auditReturnParameter auditReturnParameterList : ['$2' | '$3'] . +auditReturnParameterList -> '$empty' : [] . + +auditReturnParameter -> mediaDescriptor : {mediaDescriptor, '$1'} . +auditReturnParameter -> modemDescriptor : {modemDescriptor, '$1'} . +auditReturnParameter -> muxDescriptor : {muxDescriptor, '$1'} . +auditReturnParameter -> eventsDescriptor : {eventsDescriptor, '$1'} . +auditReturnParameter -> signalsDescriptor : {signalsDescriptor, '$1'} . +auditReturnParameter -> digitMapDescriptor : {digitMapDescriptor, '$1'} . +auditReturnParameter -> observedEventsDescriptor : {observedEventsDescriptor, '$1'} . +auditReturnParameter -> eventBufferDescriptor : {eventBufferDescriptor, '$1'} . +auditReturnParameter -> statisticsDescriptor : {statisticsDescriptor, '$1'} . +auditReturnParameter -> packagesDescriptor : {packagesDescriptor, '$1'} . +auditReturnParameter -> errorDescriptor : {errorDescriptor, '$1'} . +auditReturnParameter -> auditReturnItem : {auditReturnItem, '$1'} . %% IGv11 + +auditDescriptor -> 'AuditToken' 'LBRKT' auditDescriptorBody 'RBRKT' + : #'AuditDescriptor'{auditToken = '$3'} . + +auditDescriptorBody -> auditItem auditItemList : ['$1' | '$2']. +auditDescriptorBody -> '$empty' : asn1_NOVALUE . + +auditItemList -> 'COMMA' auditItem auditItemList : ['$2' | '$3'] . +auditItemList -> '$empty' : [] . + +%% IGv11 - begin +%% +auditReturnItem -> 'MuxToken' : muxToken . +auditReturnItem -> 'ModemToken' : modemToken . +auditReturnItem -> 'MediaToken' : mediaToken . +auditReturnItem -> 'DigitMapToken' : digitMapToken . +auditReturnItem -> 'StatsToken' : statsToken . +auditReturnItem -> 'ObservedEventsToken' : observedEventsToken . +auditReturnItem -> 'PackagesToken' : packagesToken . + +%% at-most-once, and DigitMapToken and PackagesToken are not allowed +%% in AuditCapabilities command +%% +auditItem -> auditReturnItem : '$1' . +auditItem -> 'SignalsToken' : signalsToken . +auditItem -> 'EventBufferToken' : eventBufferToken . +auditItem -> 'EventsToken' : eventsToken . +%% +%% IGv11 - end + +notifyRequest -> 'NotifyToken' 'EQUAL' terminationID + 'LBRKT' notifyRequestBody 'RBRKT' + : make_commandRequest({notifyReq, '$1'}, + setelement(#'NotifyRequest'.terminationID, '$5', ['$3'])) . + +notifyRequestBody -> observedEventsDescriptor + : #'NotifyRequest'{observedEventsDescriptor = '$1'}. +notifyRequestBody -> errorDescriptor + : #'NotifyRequest'{errorDescriptor = '$1'}. + +notifyReply -> 'NotifyToken' 'EQUAL' terminationID notifyReplyBody + : {notifyReply, + #'NotifyReply'{terminationID = ['$3'], + errorDescriptor = '$4'}} . + +notifyReplyBody -> 'LBRKT' errorDescriptor 'RBRKT' : '$2'. +notifyReplyBody -> '$empty' : asn1_NOVALUE . + +serviceChangeRequest -> 'ServiceChangeToken' 'EQUAL' terminationID + 'LBRKT' serviceChangeDescriptor 'RBRKT' + : make_commandRequest({serviceChangeReq, '$1'}, + #'ServiceChangeRequest'{terminationID = ['$3'], + serviceChangeParms = '$5'}) . + +serviceChangeReply -> 'ServiceChangeToken' 'EQUAL' terminationID serviceChangeReplyBody + : {serviceChangeReply, + #'ServiceChangeReply'{terminationID = ['$3'], + serviceChangeResult = '$4'}} . + +serviceChangeReplyBody -> 'LBRKT' errorDescriptor 'RBRKT' + : {errorDescriptor, '$2'} . +serviceChangeReplyBody -> 'LBRKT' serviceChangeReplyDescriptor 'RBRKT' + : {serviceChangeResParms, '$2'} . +serviceChangeReplyBody -> '$empty' : {serviceChangeResParms, #'ServiceChangeResParm'{}}. + +errorDescriptor -> 'ErrorToken' 'EQUAL' errorCode 'LBRKT' errorText 'RBRKT' + : #'ErrorDescriptor'{errorCode = '$3', + errorText = '$5'} . + +errorCode -> safeToken : ensure_uint('$1', 0, 999) . + +errorText -> 'QuotedChars' : value_of('$1') . +errorText -> '$empty' : asn1_NOVALUE . + +transactionID -> safeToken : ensure_uint32('$1') . + +mId -> domainName : '$1' . +mId -> domainAddress : '$1' . +mId -> optSep mtpAddress optSep : '$2' . +mId -> optSep deviceName optSep : '$2' . + +domainName -> 'LESSER' safeToken 'GREATER' 'COLON' portNumber optSep + : ensure_domainName('$2', '$5') . +domainName -> 'LESSER' safeToken 'GREATER' + : ensure_domainName('$2', asn1_NOVALUE) . + +deviceName -> pathName : {deviceName, '$1'} . + +contextID -> safeToken : ensure_contextID('$1') . + +domainAddress -> 'LSBRKT' daddr 'RSBRKT' 'COLON' portNumber optSep + : ensure_domainAddress('$2', '$5') . +domainAddress -> 'LSBRKT' daddr 'RSBRKT' + : ensure_domainAddress('$2', asn1_NOVALUE) . + +daddr -> '$empty' : [] . +daddr -> 'COLON' daddr : [colon| '$2'] . +daddr -> safeToken daddr : ['$1'| '$2'] . + + +portNumber -> safeToken : ensure_uint16('$1') . + +mtpAddress -> 'MtpAddressToken' : ensure_mtpAddress('$1') . + +%% terminationIDList -> LBRKT terminationID *(COMMA terminationID) RBRKT . + +terminationIDList -> 'LBRKT' terminationID terminationIDListRepeat 'RBRKT' + : ['$2' | '$3'] . + +terminationIDListRepeat -> 'COMMA' terminationID terminationIDListRepeat + : ['$2'| '$3'] . +terminationIDListRepeat -> '$empty' : [] . + + +pathName -> safeToken : ensure_pathName('$1') . + +terminationID -> safeToken : ensure_terminationID('$1') . + +mediaDescriptor -> 'MediaToken' 'LBRKT' mediaParm mediaParmList 'RBRKT' + : merge_mediaDescriptor(['$3' | '$4']) . + +mediaParmList -> 'COMMA' mediaParm mediaParmList : ['$2' | '$3'] . +mediaParmList -> '$empty' : [] . + + +%% at-most-once per item +%% using either streamParms or streamDescriptors but not both +mediaParm -> streamParm + : {streamParm, '$1'} . +mediaParm -> streamDescriptor + : {streamDescriptor, '$1'} . +mediaParm -> terminationStateDescriptor + : {termState, '$1'} . + +%% at-most-onc . +%% Specially treated by the scanner. +streamParm -> 'LocalDescriptorToken' : + PGs = ensure_prop_groups('$1'), + {local, #'LocalRemoteDescriptor'{propGrps = PGs} } . +streamParm -> 'RemoteDescriptorToken' : + PGs = ensure_prop_groups('$1'), + {remote, #'LocalRemoteDescriptor'{propGrps = PGs}} . +streamParm -> localControlDescriptor : {control, '$1'} . + +streamDescriptor -> 'StreamToken' 'EQUAL' streamID + 'LBRKT' streamParm streamParmList 'RBRKT' + : #'StreamDescriptor'{streamID = '$3', + streamParms = merge_streamParms(['$5' | '$6'])} . + +streamParmList -> 'COMMA' streamParm streamParmList : ['$2' | '$3'] . +streamParmList -> '$empty' : [] . + +localControlDescriptor -> 'LocalControlToken' 'LBRKT' localParm localParmList 'RBRKT' + : ['$3' | '$4'] . + +localParmList -> 'COMMA' localParm localParmList : ['$2' | '$3'] . +localParmList -> '$empty': [] . + +terminationStateDescriptor -> 'TerminationStateToken' + 'LBRKT' terminationStateParm terminationStateParms 'RBRKT' + : merge_terminationStateDescriptor(['$3' | '$4']) . + +terminationStateParms -> 'COMMA' terminationStateParm terminationStateParms : ['$2' | '$3'] . +terminationStateParms -> '$empty' : [] . + +%% at-most-once per item except for propertyParm +localParm -> 'ReservedGroupToken' 'EQUAL' onOrOff : {group, '$3'} . +localParm -> 'ReservedValueToken' 'EQUAL' onOrOff : {value, '$3'} . +localParm -> 'ModeToken' 'EQUAL' streamModes : {mode, '$3'} . +localParm -> propertyParm : {prop, '$1'} . + +onOrOff -> 'OnToken' : true . +onOrOff -> 'OffToken' : false . + +%% at-most-once +streamModes -> 'SendonlyToken' : sendOnly . +streamModes -> 'RecvonlyToken' : recvOnly . +streamModes -> 'SendrecvToken' : sendRecv . +streamModes -> 'InactiveToken' : inactive . +streamModes -> 'LoopbackToken' : loopBack . + +propertyParm -> pkgdName parmValue : setelement(#'PropertyParm'.name, '$2', '$1') . + +parmValue -> 'EQUAL' alternativeValue : '$2' . + +parmValue -> 'NEQUAL' value + : #'PropertyParm'{value = ['$2'], extraInfo = {relation, unequalTo}} . +parmValue -> 'LESSER' value + : #'PropertyParm'{value = ['$2'], extraInfo = {relation, smallerThan}} . +parmValue -> 'GREATER' value + : #'PropertyParm'{value = ['$2'], extraInfo = {relation, greaterThan}} . + +%% OTP-4013 +%% alternativeValue = ( VALUE / +%% LSBRKT VALUE *(COMMA VALUE) RSBRKT / +%% LSBRKT VALUE COLON VALUE RSBRKT ) / +%% LBRKT VALUE *(COMMA VALUE) RBRKT +alternativeValue -> 'LBRKT' value valueList 'RBRKT' + : #'PropertyParm'{value = ['$2' | '$3'], + extraInfo = {sublist, false}}. % OR + +alternativeValue -> 'LSBRKT' value 'COLON' value 'RSBRKT' + : #'PropertyParm'{value = ['$2', '$4'], + extraInfo = {range, true}}. + +alternativeValue -> 'LSBRKT' value valueList 'RSBRKT' + : #'PropertyParm'{value = ['$2' | '$3'], + extraInfo = {sublist, true}}. % AND + +alternativeValue -> value : #'PropertyParm'{value = ['$1']} . + +valueList -> 'COMMA' value valueList : ['$2' | '$3'] . +valueList -> '$empty' : [] . + + +eventBufferDescriptor -> 'EventBufferToken' : [] . +eventBufferDescriptor -> 'EventBufferToken' 'LBRKT' eventSpec eventSpecList 'RBRKT' + : ['$3' | '$4'] . + +eventSpecList -> 'COMMA' eventSpec eventSpecList : ['$2' | '$3'] . +eventSpecList -> '$empty' : [] . + +eventSpec -> observedEvent : merge_eventSpec('$1') . + +%% at-most-once per item except for propertyParm +terminationStateParm -> serviceStates : {serviceState, '$1'} . +terminationStateParm -> eventBufferControl : {eventBufferControl, '$1'} . +terminationStateParm -> propertyParm : {propertyParm, '$1'} . + +serviceStates -> 'ServiceStatesToken' 'EQUAL' serviceState : '$3' . + +serviceState -> 'TestToken' : test . +serviceState -> 'OutOfSvcToken' : outOfSvc . +serviceState -> 'InSvcToken' : inSvc . + +eventBufferControl -> 'BufferToken' 'EQUAL' eventBufferControlState : '$3' . + +eventBufferControlState -> 'OffToken' : off . +eventBufferControlState -> 'LockStepToken' : lockStep . + +muxDescriptor -> 'MuxToken' 'EQUAL' muxType terminationIDList + : #'MuxDescriptor'{muxType = '$3', + termList = '$4'} . + +muxType -> safeToken : ensure_muxType('$1') . + +streamID -> safeToken : ensure_streamID('$1') . + +pkgdName -> safeToken : ensure_pkgdName('$1') . + +eventsDescriptor -> 'EventsToken' : + #'EventsDescriptor'{requestID = asn1_NOVALUE, + eventList = []} . +eventsDescriptor -> 'EventsToken' 'EQUAL' requestID + 'LBRKT' requestedEvent requestedEvents 'RBRKT' : + #'EventsDescriptor'{requestID = '$3', + eventList = ['$5' | '$6']} . + +requestedEvents -> 'COMMA' requestedEvent requestedEvents : ['$2' | '$3'] . +requestedEvents -> '$empty' : [] . + +requestedEvent -> pkgdName requestedEventBody : + setelement(#'RequestedEvent'.pkgdName, '$2', '$1') . + +requestedEventBody -> 'LBRKT' eventParameter eventParameters 'RBRKT' : + merge_eventParameters(['$2' | '$3']) . +requestedEventBody -> '$empty' : + #'RequestedEvent'{evParList = []} . + +eventParameters -> 'COMMA' eventParameter eventParameters : + ['$2' | '$3'] . +eventParameters -> '$empty' : + [] . + +%% at-most-once each of embedOrKeepActive , eventDM or eventStream +eventParameter -> 'KeepActiveToken' : keepActive . +eventParameter -> embedWithSig : '$1'. +eventParameter -> embedNoSig : '$1'. +eventParameter -> eventDM : '$1'. +eventParameter -> eventStreamOrOther : '$1'. + +embedWithSig -> 'EmbedToken' 'LBRKT' signalsDescriptor + 'COMMA' embedFirst 'RBRKT' : + {embed, '$3', '$5'} . +embedWithSig -> 'EmbedToken' 'LBRKT' signalsDescriptor 'RBRKT' : + {embed, '$3', asn1_NOVALUE} . + +embedNoSig -> 'EmbedToken' 'LBRKT' embedFirst 'RBRKT' : + {embed, asn1_NOVALUE, '$3'} . + +embedFirst -> 'EventsToken' : + #'SecondEventsDescriptor'{requestID = asn1_NOVALUE, + eventList = []} . +embedFirst -> 'EventsToken' 'EQUAL' requestID + 'LBRKT' secondRequestedEvent + secondRequestedEvents 'RBRKT' : + #'SecondEventsDescriptor'{requestID = '$3', + eventList = ['$5' | '$6']} . + +secondRequestedEvents -> 'COMMA' secondRequestedEvent secondRequestedEvents : + ['$2' | '$3'] . +secondRequestedEvents -> '$empty' : [] . + +%% at-most-once of each +secondRequestedEvent -> pkgdName secondRequestedEventBody : + setelement(#'SecondRequestedEvent'.pkgdName, + '$2', '$1') . + +secondRequestedEventBody -> 'LBRKT' secondEventParameter + secondEventParameters 'RBRKT' : + merge_secondEventParameters(['$2' | '$3']) . +secondRequestedEventBody -> '$empty' : + #'SecondRequestedEvent'{evParList = []} . + +secondEventParameters -> 'COMMA' secondEventParameter secondEventParameters : + ['$2' | '$3'] . +secondEventParameters -> '$empty' : [] . + +%% at-most-once each of embedOrKeepActive , eventDM or eventStream +secondEventParameter -> 'KeepActiveToken' : keepActive . +secondEventParameter -> embedSig : '$1' . +secondEventParameter -> eventDM : '$1' . +secondEventParameter -> eventStreamOrOther : '$1' . + +embedSig -> 'EmbedToken' 'LBRKT' signalsDescriptor 'RBRKT' : + {second_embed, '$3'} . + +eventStreamOrOther -> eventParameterName parmValue : + select_stream_or_other('$1', '$2') . + +eventParameterName -> safeToken : + ensure_NAME('$1') . + +%% The DigitMapDescriptorToken is specially treated by the scanner +eventDM -> 'DigitMapDescriptorToken' : ensure_eventDM('$1') . + +%% H248S-IG (IGv11) +signalsDescriptor -> 'SignalsToken' 'LBRKT' signalParm signalParms 'RBRKT' : + ['$3' | '$4'] . +signalsDescriptor -> 'SignalsToken' : + [] . + +signalParms -> 'COMMA' signalParm signalParms : [ '$2' | '$3'] . +signalParms -> '$empty' : [] . + +signalParm -> signalList : {seqSigList, '$1'} . +signalParm -> signalRequest : {signal, '$1'} . + +signalRequest -> signalName 'LBRKT' sigParameter sigParameters 'RBRKT' + : merge_signalRequest('$1', ['$3' | '$4']). +signalRequest -> signalName : merge_signalRequest('$1', []). + +sigParameters -> 'COMMA' sigParameter sigParameters : ['$2' | '$3'] . +sigParameters -> '$empty' : [] . + +%% sigParameter = sigStream / sigSignalType / sigDuration / sigOther +%% / notifyCompletion / KeepActiveToken +%% sigStream = StreamToken EQUAL StreamID +%% sigOther = sigParameterName parmValue +%% sigParameterName = NAME +%% sigSignalType = SignalTypeToken EQUAL signalType +%% signalType = (OnOffToken / TimeOutToken / BriefToken) +%% sigDuration = DurationToken EQUAL UINT16 +%% notifyCompletion = NotifyCompletionToken EQUAL (LBRKT +%% notificationReason *(COMMA notificationReason) RBRKT +%% +%% notificationReason = ( TimeOutToken / InterruptByEventToken +%% / InterruptByNewSignalsDescrToken +%% / OtherReasonToken ) + +sigParameter -> 'StreamToken' 'EQUAL' streamID : {stream, '$3'}. +sigParameter -> 'SignalTypeToken' 'EQUAL' signalType : {signal_type, '$3'} . +sigParameter -> 'DurationToken' 'EQUAL' safeToken : {duration, ensure_uint16('$3')} . +sigParameter -> safeToken parmValue : {other, ensure_NAME('$1'), '$2'}. +sigParameter -> 'NotifyCompletionToken' 'EQUAL' + 'LBRKT' notificationReason notificationReasons 'RBRKT' + : {notify_completion, ['$4' | '$5']} . +sigParameter -> 'KeepActiveToken' : keepActive . + +signalType -> 'OnOffToken' : onOff. +signalType -> 'TimeOutToken' : timeOut. +signalType -> 'BriefToken' : brief. + +notificationReasons -> 'COMMA' notificationReason notificationReasons : ['$2' | '$3'] . +notificationReasons -> '$empty' : [] . + +notificationReason -> 'TimeOutToken' : onTimeOut . +notificationReason -> 'InterruptByEventToken' : onInterruptByEvent . +notificationReason -> 'InterruptByNewSignalsDescrToken' : onInterruptByNewSignalDescr . +notificationReason -> 'OtherReasonToken' : otherReason . + +signalList -> 'SignalListToken' 'EQUAL' signalListId + 'LBRKT' signalListParm signalListParms 'RBRKT' + : #'SeqSigList'{id = ensure_uint16('$3'), + signalList = ['$5' | '$6']} . + +signalListParms -> 'COMMA' signalListParm signalListParms : ['$2' | '$3'] . +signalListParms -> '$empty' : [] . + +signalListId -> safeToken : ensure_uint16('$1') . + +%% exactly once signalType, +%% at most once duration and every signal parameter +signalListParm -> signalRequest : '$1'. + +signalName -> pkgdName : '$1'. + +observedEventsDescriptor -> 'ObservedEventsToken' 'EQUAL' requestID + 'LBRKT' observedEvent observedEvents 'RBRKT' + : #'ObservedEventsDescriptor'{requestId = '$3', + observedEventLst = ['$5' | '$6']} . + +observedEvents -> 'COMMA' observedEvent observedEvents : ['$2' | '$3'] . +observedEvents -> '$empty' : [] . + +%%time per event, because it might be buffered +observedEvent -> observedEventTimeStamp optSep pkgdName observedEventBody : + merge_observed_event('$4', '$3', '$1') . +observedEvent -> pkgdName observedEventBody : + merge_observed_event('$2', '$1', asn1_NOVALUE) . + +observedEventTimeStamp -> timeStamp optSep 'COLON' : '$1' . +observedEventTimeStamp -> '$empty' : asn1_NOVALUE . + +observedEventBody -> 'LBRKT' observedEventParameter observedEventParameters 'RBRKT' + : ['$2' | '$3'] . +observedEventBody -> '$empty' : [] . + +observedEventParameters -> 'COMMA' observedEventParameter observedEventParameters : ['$2' | '$3'] . +observedEventParameters -> '$empty' : [] . + +%%at-most-once eventStream, every eventParameterName at most once +observedEventParameter -> eventStreamOrOther : '$1' . + +requestID -> safeToken : ensure_requestID('$1') . + +modemDescriptor -> 'ModemToken' 'EQUAL' modemType optPropertyParms : + #'ModemDescriptor'{mtl = ['$3'], + mpl = '$4'} . + +%% at-most-once of each modem type exept for extensionParameter +modemDescriptor -> 'ModemToken' 'LSBRKT' modemType modemTypeList 'RSBRKT' + optPropertyParms : + #'ModemDescriptor'{mtl = ['$3' | '$4'], + mpl = '$6'} . + +modemTypeList -> 'COMMA' modemType modemTypeList : ['$2' | '$3'] . +modemTypeList -> '$empty' : [] . + +optPropertyParms -> 'LBRKT' propertyParm propertyParms 'RBRKT' : ['$2' | '$3'] . +optPropertyParms -> '$empty' : [] . + +propertyParms -> 'COMMA' propertyParm propertyParms : ['$2' | '$3'] . +propertyParms -> '$empty' : [] . + +% parmName -> safeToken : ensure_NAME('$1') . + +modemType -> safeToken : ensure_modemType('$1'). + +%% The DigitMapDescriptorToken is specially treated by the scanner +digitMapDescriptor -> 'DigitMapDescriptorToken' : ensure_DMD('$1') . + +%% ; at most of either serviceChangeAddress or serviceChangeMgcId but not both +serviceChangeDescriptor -> 'ServicesToken' + 'LBRKT' serviceChangeParm + serviceChangeParms 'RBRKT' : + merge_ServiceChangeParm(['$3' | '$4']) . + +serviceChangeParms -> 'COMMA' serviceChangeParm serviceChangeParms : + ['$2' | '$3'] . +serviceChangeParms -> '$empty' : [] . + +serviceChangeParm -> serviceChangeMethod : {method, '$1'} . +serviceChangeParm -> serviceChangeReason : {reason, '$1'} . +serviceChangeParm -> serviceChangeDelay : {delay, '$1'} . +serviceChangeParm -> serviceChangeAddress : {address, '$1'} . +serviceChangeParm -> serviceChangeProfile : {profile, '$1'} . +serviceChangeParm -> extension : {extension, '$1'} . +serviceChangeParm -> timeStamp : {time_stamp,'$1'} . +serviceChangeParm -> serviceChangeMgcId : {mgc_id, '$1'} . +serviceChangeParm -> serviceChangeVersion : {version, '$1'} . + +serviceChangeMethod -> 'MethodToken' 'EQUAL' safeToken : ensure_serviceChangeMethod('$3') . + +serviceChangeReason -> 'ReasonToken' 'EQUAL' value : ['$3'] . + +serviceChangeDelay -> 'DelayToken' 'EQUAL' safeToken : ensure_uint32('$3'). + +serviceChangeAddress -> 'ServiceChangeAddressToken' 'EQUAL' mId : '$3' . +serviceChangeAddress -> 'ServiceChangeAddressToken' 'EQUAL' portNumber : {portNumber, '$3'} . + +serviceChangeMgcId -> 'MgcIdToken' 'EQUAL' mId : '$3' . + +serviceChangeProfile -> 'ProfileToken' 'EQUAL' safeToken : ensure_profile('$3'). + +serviceChangeVersion -> 'VersionToken' 'EQUAL' safeToken : ensure_version('$3') . + +extension -> extensionParameter parmValue + : setelement(#'PropertyParm'.name, '$2', '$1') . + +%% at most once. Version is REQUIRED on first ServiceChange response +%% at most of either serviceChangeAddress or serviceChangeMgcId but not both +serviceChangeReplyDescriptor -> 'ServicesToken' + 'LBRKT' servChgReplyParm + servChgReplyParms 'RBRKT' : + merge_ServiceChangeResParm(['$3' | '$4']) . + +servChgReplyParms -> 'COMMA' servChgReplyParm servChgReplyParms : + ['$2' | '$3'] . +servChgReplyParms -> '$empty' : [] . + +servChgReplyParm -> serviceChangeAddress : {address, '$1'} . +servChgReplyParm -> serviceChangeMgcId : {mgc_id, '$1'}. +servChgReplyParm -> serviceChangeProfile : {profile, '$1'} . +servChgReplyParm -> serviceChangeVersion : {version, '$1'}. +servChgReplyParm -> timeStamp : {time_stamp,'$1'}. + +packagesDescriptor -> 'PackagesToken' 'LBRKT' packagesItem packagesItems 'RBRKT' + : ['$3' | '$4'] . + +packagesItems -> 'COMMA' packagesItem packagesItems : ['$2' | '$3'] . +packagesItems -> '$empty' : [] . + +packagesItem -> safeToken : ensure_packagesItem('$1') . + +timeStamp -> TimeStampToken : ensure_timeStamp('$1') . + +statisticsDescriptor -> 'StatsToken' + 'LBRKT' statisticsParameter statisticsParameters 'RBRKT' + : ['$3' | '$4'] . + +statisticsParameters -> 'COMMA' statisticsParameter statisticsParameters : ['$2' | '$3'] . +statisticsParameters -> '$empty' : [] . + +%%at-most-once per item +statisticsParameter -> pkgdName + : #'StatisticsParameter'{statName = '$1', + statValue = asn1_NOVALUE} . +statisticsParameter -> pkgdName 'EQUAL' value + : #'StatisticsParameter'{statName = '$1', + statValue = ['$3']} . + +topologyDescriptor -> 'TopologyToken' 'LBRKT' topologyTriple + topologyTripleList 'RBRKT' : ['$3' | '$4'] . + +terminationA -> terminationID : '$1' . + +terminationB -> terminationID : '$1' . + +topologyTriple -> terminationA 'COMMA' terminationB 'COMMA' + topologyDirection : + #'TopologyRequest'{terminationFrom = '$1', + terminationTo = '$3', + topologyDirection = '$5'} . + +topologyTripleList -> '$empty' : [] . +topologyTripleList -> 'COMMA' topologyTriple topologyTripleList : + ['$2' | '$3'] . + +topologyDirection -> 'BothwayToken' : bothway . +topologyDirection -> 'IsolateToken' : isolate . +topologyDirection -> 'OnewayToken' : oneway . + +priority -> 'PriorityToken' 'EQUAL' safeToken : ensure_uint16('$3') . + +extensionParameter -> safeToken : ensure_extensionParameter('$1') . + +value -> 'QuotedChars' : ensure_value('$1') . +value -> safeToken : ensure_value('$1'). + +safeToken -> safeToken2 : make_safe_token('$1') . + +safeToken2 -> 'SafeChars' : '$1' . +safeToken2 -> 'AddToken' : '$1' . +safeToken2 -> 'AuditToken' : '$1' . +safeToken2 -> 'AuditCapToken' : '$1' . +safeToken2 -> 'AuditValueToken' : '$1' . +safeToken2 -> 'AuthToken' : '$1' . +safeToken2 -> 'BothwayToken' : '$1' . +safeToken2 -> 'BriefToken' : '$1' . +safeToken2 -> 'BufferToken' : '$1' . +safeToken2 -> 'CtxToken' : '$1' . +safeToken2 -> 'ContextAuditToken' : '$1' . +safeToken2 -> 'DigitMapToken' : '$1' . +%% safeToken2 -> 'DigitMapDescriptorToken' : '$1' . +safeToken2 -> 'DiscardToken' : '$1' . +safeToken2 -> 'DisconnectedToken' : '$1' . +safeToken2 -> 'DelayToken' : '$1' . +safeToken2 -> 'DurationToken' : '$1' . +safeToken2 -> 'EmbedToken' : '$1' . +safeToken2 -> 'EmergencyToken' : '$1' . +safeToken2 -> 'ErrorToken' : '$1' . +safeToken2 -> 'EventBufferToken' : '$1' . +safeToken2 -> 'EventsToken' : '$1' . +safeToken2 -> 'FailoverToken' : '$1' . +safeToken2 -> 'ForcedToken' : '$1' . +safeToken2 -> 'GracefulToken' : '$1' . +safeToken2 -> 'H221Token' : '$1' . +safeToken2 -> 'H223Token' : '$1' . +safeToken2 -> 'H226Token' : '$1' . +safeToken2 -> 'HandOffToken' : '$1' . +safeToken2 -> 'ImmAckRequiredToken' : '$1' . +safeToken2 -> 'InactiveToken' : '$1' . +safeToken2 -> 'InterruptByEventToken' : '$1' . +safeToken2 -> 'InterruptByNewSignalsDescrToken' : '$1' . +safeToken2 -> 'IsolateToken' : '$1' . +safeToken2 -> 'InSvcToken' : '$1' . +safeToken2 -> 'KeepActiveToken' : '$1' . +%% safeToken2 -> 'LocalToken' : '$1' . +%% safeToken2 -> 'LocalDescriptorToken' : '$1' . +safeToken2 -> 'LocalControlToken' : '$1' . +safeToken2 -> 'LoopbackToken' : '$1' . +safeToken2 -> 'LockStepToken' : '$1' . +safeToken2 -> 'MediaToken' : '$1' . +%% safeToken2 -> 'MegacopToken' : '$1' . +safeToken2 -> 'MethodToken' : '$1' . +safeToken2 -> 'MgcIdToken' : '$1' . +safeToken2 -> 'ModeToken' : '$1' . +safeToken2 -> 'ModifyToken' : '$1' . +safeToken2 -> 'ModemToken' : '$1' . +safeToken2 -> 'MoveToken' : '$1' . +%% safeToken2 -> 'MtpToken' : '$1' . +%% safeToken2 -> 'MtpAddressToken' : '$1' . +safeToken2 -> 'MuxToken' : '$1' . +safeToken2 -> 'NotifyToken' : '$1' . +safeToken2 -> 'NotifyCompletionToken' : '$1' . +safeToken2 -> 'ObservedEventsToken' : '$1' . +safeToken2 -> 'OnewayToken' : '$1' . +safeToken2 -> 'OffToken' : '$1' . +safeToken2 -> 'OnToken' : '$1' . +safeToken2 -> 'OnOffToken' : '$1' . +safeToken2 -> 'OutOfSvcToken' : '$1' . +safeToken2 -> 'OtherReasonToken' : '$1' . +safeToken2 -> 'PackagesToken' : '$1' . +safeToken2 -> 'PendingToken' : '$1' . +safeToken2 -> 'PriorityToken' : '$1' . +safeToken2 -> 'ProfileToken' : '$1' . +safeToken2 -> 'ReasonToken' : '$1' . +safeToken2 -> 'RecvonlyToken' : '$1' . +safeToken2 -> 'ReplyToken' : '$1' . +safeToken2 -> 'ResponseAckToken' : '$1' . +safeToken2 -> 'RestartToken' : '$1' . +%% safeToken2 -> 'RemoteToken' : '$1' . +%% safeToken2 -> 'RemoteDescriptorToken' : '$1' . +safeToken2 -> 'ReservedGroupToken' : '$1' . +safeToken2 -> 'ReservedValueToken' : '$1' . +safeToken2 -> 'SendonlyToken' : '$1' . +safeToken2 -> 'SendrecvToken' : '$1' . +safeToken2 -> 'ServicesToken' : '$1' . +safeToken2 -> 'ServiceStatesToken' : '$1' . +safeToken2 -> 'ServiceChangeToken' : '$1' . +safeToken2 -> 'ServiceChangeAddressToken' : '$1' . +safeToken2 -> 'SignalListToken' : '$1' . +safeToken2 -> 'SignalsToken' : '$1' . +safeToken2 -> 'SignalTypeToken' : '$1' . +safeToken2 -> 'StatsToken' : '$1' . +safeToken2 -> 'StreamToken' : '$1' . +safeToken2 -> 'SubtractToken' : '$1' . +safeToken2 -> 'SynchISDNToken' : '$1' . +safeToken2 -> 'TerminationStateToken' : '$1' . +safeToken2 -> 'TestToken' : '$1' . +safeToken2 -> 'TimeOutToken' : '$1' . +safeToken2 -> 'TopologyToken' : '$1' . +safeToken2 -> 'TransToken' : '$1' . +safeToken2 -> 'V18Token' : '$1' . +safeToken2 -> 'V22Token' : '$1' . +safeToken2 -> 'V22bisToken' : '$1' . +safeToken2 -> 'V32Token' : '$1' . +safeToken2 -> 'V32bisToken' : '$1' . +safeToken2 -> 'V34Token' : '$1' . +safeToken2 -> 'V76Token' : '$1' . +safeToken2 -> 'V90Token' : '$1' . +safeToken2 -> 'V91Token' : '$1' . +safeToken2 -> 'VersionToken' : '$1' . +%% <OTP-7534> +safeToken2 -> 'AndAUDITSelectToken' : '$1' . % v3 +safeToken2 -> 'BothToken' : '$1' . % v3 +safeToken2 -> 'ContextAttrToken' : '$1' . % v3 +safeToken2 -> 'ContextListToken' : '$1' . % v3 +safeToken2 -> 'DirectionToken' : '$1' . % v3 +safeToken2 -> 'EmergencyOffToken' : '$1' . % v3 +safeToken2 -> 'EmergencyValueToken' : '$1' . % v3 +safeToken2 -> 'ExternalToken' : '$1' . % v3 +safeToken2 -> 'IEPSToken' : '$1' . % v3 +safeToken2 -> 'InternalToken' : '$1' . % v3 +safeToken2 -> 'IntsigDelayToken' : '$1' . % v3 +safeToken2 -> 'IterationToken' : '$1' . % v3 +safeToken2 -> 'MessageSegmentToken' : '$1' . % v3 +safeToken2 -> 'NeverNotifyToken' : '$1' . % v3 +safeToken2 -> 'NotifyImmediateToken' : '$1' . % v3 +safeToken2 -> 'NotifyRegulatedToken' : '$1' . % v3 +safeToken2 -> 'Nx64kToken' : '$1' . % v2 +safeToken2 -> 'OnewayBothToken' : '$1' . % v3 +safeToken2 -> 'OnewayExternalToken' : '$1' . % v3 +safeToken2 -> 'OrAUDITselectToken' : '$1' . % v3 +safeToken2 -> 'RequestIDToken' : '$1' . % v3 +safeToken2 -> 'ResetEventsDescriptorToken' : '$1' . % v3 +safeToken2 -> 'SegmentationCompleteToken' : '$1' . % v3 +safeToken2 -> 'ServiceChangeIncompleteToken' : '$1' . % v3 +%% </OTP-7534> + +Erlang code. + +%% The following directive is needed for (significantly) faster compilation +%% of the generated .erl file by the HiPE compiler. Please do not remove. +-compile([{hipe,[{regalloc,linear_scan}]}]). + +-include("megaco_text_parser_v1.hrl"). + +%%i(F) -> +%% i(F, []). + +%%i(F, A) -> +%% i(get(dbg), F, A). + +%%i(true, F, A) -> +%% io:format("DBG:~p:" ++ F ++ "~n", [?MODULE|A]); +%%i(_, _, _) -> +%% ok. + diff --git a/lib/megaco/src/text/megaco_text_parser_v2.hrl b/lib/megaco/src/text/megaco_text_parser_v2.hrl new file mode 100644 index 0000000000..e968db398d --- /dev/null +++ b/lib/megaco/src/text/megaco_text_parser_v2.hrl @@ -0,0 +1,1643 @@ +%% +%% %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 : Define semantic text parser actions +%%---------------------------------------------------------------------- + + +-include_lib("megaco/include/megaco.hrl"). +-include_lib("megaco/include/megaco_message_v2.hrl"). +-define(encoder_version_pre_prev3c,true). +-include("megaco_text_tokens.hrl"). + +-define(d(F,A), io:format("DBG:"++F++"~n",A)). + +-ifdef(megaco_parser_inline). +-compile({inline,[{make_safe_token,1}]}). +-endif. +make_safe_token(Token) -> + {_TokenTag, Line, Text} = Token, + {safeToken, Line, Text}. + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_value,1}]}). +-endif. +ensure_value(Token) -> + case Token of + {safeToken, _Line, Text} when is_list(Text) -> + Text; % We really should ensure length + {'QuotedChars', _Line, Text} when is_list(Text) -> + Text; % We really should ensure length + Text when is_list(Text) -> + Text % We really should ensure length + end. + +%% NAME = ALPHA *63(ALPHA / DIGIT / "_" ) +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_NAME,1}]}). +-endif. +ensure_NAME(Token) -> + {_TokenTag, _Line, Text} = Token, + Text. %% BUGBUG: ensure length and chars + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_requestID,1}]}). +-endif. +ensure_requestID(Token) -> + case Token of + {safeToken, _Line, "*"} -> + ?megaco_all_request_id; + _ -> + ensure_uint32(Token) + end. + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_streamID,1}]}). +-endif. +ensure_streamID(StreamId) -> + ensure_uint16(StreamId). + +ensure_auth_header(SpiToken, SnToken, AdToken) -> + Spi = ensure_hex(SpiToken, 8, 8), + Sn = ensure_hex(SnToken, 8, 8), + Ad = ensure_hex(AdToken, 24, 64), + #'AuthenticationHeader'{secParmIndex = Spi, seqNum = Sn, ad = Ad}. + +%% The values 0x0, 0xFFFFFFFE and 0xFFFFFFFF are reserved. +%% ContextID = (UINT32 / "*" / "-" / "$") +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_contextID,1}]}). +-endif. +ensure_contextID(Token) -> + {_TokenTag, Line, Text} = Token, + case Text of + "*" -> ?megaco_all_context_id; + "-" -> ?megaco_null_context_id; + "\$" -> ?megaco_choose_context_id; + Int -> + CID = ensure_uint32(Int), + if + (CID =/= 0) andalso + (CID =/= 16#FFFFFFFE) andalso + (CID =/= 16#FFFFFFFF) -> + CID; + true -> + return_error(Line, {bad_ContextID, CID}) + end + end. + +ensure_domainAddress([{_T, _L, _A} = Addr0], Port) -> + Addr = ensure_ip4addr(Addr0), + {ip4Address, #'IP4Address'{address = Addr, portNumber = Port}}; +ensure_domainAddress([colon,colon], Port) -> + Addr = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + {ip6Address, #'IP6Address'{address = Addr, portNumber = Port}}; +ensure_domainAddress(Addr0, Port) -> + Addr = ensure_ip6addr(Addr0), + {ip6Address, #'IP6Address'{address = Addr, portNumber = Port}}. + + +ensure_ip4addr(Token) -> + {_TokenTag, Line, Addr} = Token, + case split_ip4addr_text(Addr, []) of + [T1, T2, T3, T4] -> + %% We optimize by sending only the text part (Addr) of + %% the token to the function. + %% If something is wrong, then we do not get a proper + %% position and therefor we catch and issue the + %% the error again (with the proper line number). + case (catch [ + ensure_uint(T1, 0, 255), + ensure_uint(T2, 0, 255), + ensure_uint(T3, 0, 255), + ensure_uint(T4, 0, 255) + ]) of + A when is_list(A) -> + A; + _ -> + return_error(Line, {bad_IP4address, Addr}) + end; + _ -> + return_error(Line, {bad_IP4address, Addr}) + end. + +split_ip4addr_text([], Acc) -> + [ lists:reverse(Acc) ]; +split_ip4addr_text([$. | Rest], Acc) -> + [ lists:reverse(Acc) | split_ip4addr_text(Rest, []) ]; +split_ip4addr_text([H | T], Acc) -> + split_ip4addr_text(T, [H | Acc]). + + +ensure_ip6addr([colon,colon|T]) -> + [H1|T1] = lists:reverse(T), + case do_ensure_ip6addr(T1, true, [ensure_hex4_or_ip4addr(H1)], 1) of + {true, A} when (length(A) =:= 16) -> + A; + {true, B} when length(B) < 16 -> + lists:duplicate(16 - length(B), 0) ++ B; + {true, C} -> + throw({error, {?MODULE, {bad_mid_ip6addr_length, C}}}) + end; +ensure_ip6addr(L) -> + case lists:reverse(L) of + [colon, colon| T] -> + case do_ensure_ip6addr(T, true, [], 1) of + {true, A} when (length(A) =:= 16) -> + A; + {true, B} when length(B) < 16 -> + B ++ lists:duplicate(16 - length(B), 0); + {true, C} -> + throw({error, {?MODULE, {bad_mid_ip6addr_length, C}}}) + end; + [H|L1] -> % A (last element) could be an ip4 address + case do_ensure_ip6addr(L1,false,[ensure_hex4_or_ip4addr(H)],1) of + {false, A} when (length(A) =:= 16) -> + A; + %% allow a pad even if the address is full (i.e. 16) + {true, B} when length(B) =< 17 -> + do_ensure_ip6addr_padding(B, 0); + {Pad, C} -> + throw({error, {?MODULE, {bad_mid_ip6addr_length, Pad, C}}}) + end + + end. + + +do_ensure_ip6addr([], Pad, Acc, _) -> + {Pad, lists:flatten(Acc)}; +do_ensure_ip6addr([colon,colon|T], false, Acc, Line) -> + do_ensure_ip6addr(T, true, [pad|Acc], Line); +do_ensure_ip6addr([colon,colon|T], true, Acc, Line) -> + return_error(Line, {bad_mid_duplicate_padding, T, Acc}); +do_ensure_ip6addr([colon|T], Pad, Acc, Line) -> + do_ensure_ip6addr(T, Pad, Acc, Line); +do_ensure_ip6addr([{_, Line, _} = A|T], Pad, Acc, _) -> + do_ensure_ip6addr(T, Pad, [ensure_hex4(A)|Acc], Line). + +do_ensure_ip6addr_padding([], _) -> + []; +do_ensure_ip6addr_padding([pad|T], N) -> + lists:duplicate(16 - (N + length(T)), 0) ++ T; +do_ensure_ip6addr_padding([H|T], N) -> + [H|do_ensure_ip6addr_padding(T, N+1)]. + +ensure_hex4_or_ip4addr({TokenTag, Line, Addr} = V) -> + case string:tokens(Addr, [$.]) of + [T1, T2, T3, T4] -> + A1 = ensure_uint({TokenTag, Line, T1}, 0, 255), + A2 = ensure_uint({TokenTag, Line, T2}, 0, 255), + A3 = ensure_uint({TokenTag, Line, T3}, 0, 255), + A4 = ensure_uint({TokenTag, Line, T4}, 0, 255), + [A1, A2, A3, A4]; + _ -> + ensure_hex4(V) + %% %% BMK BMK BMK + %% %% Here we should test for hexseq + %% return_error(Line, {bad_IP4address, Addr}) + end. + +ensure_hex4({_TokenTag, Line, Hex4}) + when length(Hex4) =< 4, length(Hex4) > 0 -> + case (catch do_ensure_hex4(Hex4)) of + IL when is_list(IL) andalso (length(IL) =:= 2) -> + IL; + Error -> + return_error(Line, {bad_hex4, Hex4, Error}) + end. + +do_ensure_hex4([_H1, _H2, _H3, _H4] = H) -> + hex_to_int(H, []); +do_ensure_hex4([H2, H3, H4]) -> + hex_to_int([$0, H2, H3, H4], []); +do_ensure_hex4([H3, H4]) -> + hex_to_int([$0, $0, H3, H4], []); +do_ensure_hex4([H4]) -> + hex_to_int([$0, $0, $0, H4], []). + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_domainName,2}]}). +-endif. +ensure_domainName(Token, Port) -> + {_TokenTag, _Line, Name} = Token, + %% BUGBUG: validate name + {domainName, #'DomainName'{name = Name, portNumber = Port}}. + +%% extensionParameter= "X" ("-" / "+") 1*6(ALPHA / DIGIT) +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_extensionParameter,1}]}). +-endif. +ensure_extensionParameter(Token) -> + {_TokenTag, Line, Text} = Token, + case Text of + [X, S | _Chars] -> + if + (X =/= $X) andalso (X =/= $x) andalso + (S =/= $+) andalso (S =/= $-) -> + return_error(Line, {bad_extension_parameter, Text}); + true -> + {extension_parameter, Text} + end; + _ -> + return_error(Line, {bad_extension_parameter, Text}) + end. + +ensure_message(MegacopToken, MID, Body) -> +%% #'ServiceChangeProfile'{profileName = Name, +%% version = Version} = +%% ensure_profile(MegacopToken), +%% case Name of +%% "megaco" -> +%% #'Message'{version = Version, mId = MID, messageBody = Body}; +%% [$!] -> +%% #'Message'{version = Version, mId = MID, messageBody = Body} +%% end. + {_TokenTag, Line, Text} = MegacopToken, + case split_Megacop(Text, []) of + {Name, Version} -> + Version2 = ensure_version(Version), + case Name of + "megaco" -> + #'Message'{version = Version2, + mId = MID, + messageBody = Body}; + [$!] -> + #'Message'{version = Version2, + mId = MID, + messageBody = Body} + end; + _ -> + return_error(Line, {bad_name_or_version, Text}) + end. + +split_Megacop([], _) -> + error; +split_Megacop([$/ | Version], Acc) -> + {lists:reverse(Acc), Version}; +split_Megacop([H | T], Acc) -> + split_Megacop(T, [H | Acc]). + + +%% Corr1: +%% As of corr 1 ModemDescriptor has been deprecated. +%% and since this functon is only used when creating +%% a ModemDescriptor, iit is removed. +%% modemType = (V32bisToken / V22bisToken / V18Token / +%% V22Token / V32Token / V34Token / V90Token / +%% V91Token / SynchISDNToken / extensionParameter) +%% ensure_modemType({_TokenTag, _Line, Text} = Token) -> +%% case Text of +%% "v32b" -> v32bis; +%% "v22b" -> v22bis; +%% "v18" -> v18; +%% "v22" -> v22; +%% "v32" -> v32; +%% "v34" -> v34; +%% "v90" -> v90; +%% "v91" -> v91; +%% "synchisdn" -> synchISDN; +%% "sn" -> synchISDN; +%% [$x | _] -> ensure_extensionParameter(Token) +%% end. + +%% An mtp address is five octets long +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_mtpAddress,1}]}). +-endif. +ensure_mtpAddress(Token) -> + {_TokenTag, _Line, Addr} = Token, + %% BUGBUG: validate address + {mtpAddress, Addr}. + +%% MuxType = ( H221Token / H223Token / H226Token / V76Token / extensionParameter ) +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_muxType,1}]}). +-endif. +ensure_muxType(Token) -> + {_TokenTag, _Line, Text} = Token, + case Text of + "h221" -> h221; + "h223" -> h223; + "h226" -> h226; + "v76" -> v76; + "nx64k" -> nx64k; % v2 + [$x | _] -> ensure_extensionParameter(Token) + end. + +%% packagesItem = NAME "-" UINT16 +%% NAME = ALPHA *63(ALPHA / DIGIT / "_" ) +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_packagesItem,1}]}). +-endif. +ensure_packagesItem(Token) -> + {_TokenTag, Line, Text} = Token, + case split_packagesItem(Text, []) of + {Name, Version} -> + %% As we don't ensure length of the names, there is no point + %% in doing the ensure_NAME thing... + #'PackagesItem'{packageName = Name, + packageVersion = ensure_uint(Version, 0, 99)}; + _ -> + return_error(Line, {bad_PackagesItem, Text}) + end. + +split_packagesItem([], _) -> + error; +split_packagesItem([$- | Version], Acc) -> + {lists:reverse(Acc), Version}; +split_packagesItem([H|T], Acc) -> + split_packagesItem(T, [H|Acc]). + + +%% pkgdName = (PackageName / "*") SLASH (ItemID / "*" ) +%% PackageName = NAME +%% ItemID = NAME +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_pkgdName,1}]}). +-endif. +ensure_pkgdName(Token) -> + {_TokenTag, Line, Text} = Token, + case ensure_pkgdName(Text, []) of + ok -> + %% As we don't really do any checks on the strings + %% (length or content) there is really no point in + %% "ensuring" the name and item part of the + %% package name + %% ensure_name_or_star(Name), + %% ensure_name_or_star(Item), + Text; + _ -> + return_error(Line, {bad_pkgdName, Text}) + end. + +ensure_pkgdName([], _) -> + error; +ensure_pkgdName([$/ | T], Acc) + when ((length(T) > 0) andalso (length(Acc) > 0)) -> + ok; +ensure_pkgdName([H | T], Acc) -> + ensure_pkgdName(T, [H | Acc]). + + +%% -compile({inline,[{ensure_name_or_star,1}]}). +%% ensure_name_or_star(Val) -> +%% %% case Token of +%% %% {_, _, Name} when Name =:= "*" -> +%% %% Name; +%% %% _ -> +%% %% ensure_NAME(Token) +%% %% end. +%% if +%% Val =:= "*" -> +%% Val; +%% true -> +%% %% as we don't really validate the text part of the token(s), +%% %% we can just return the value assuming it to be correct... +%% Val +%% end. + + +%% v2 - start + +merge_indAudMediaDescriptor({termStateDescr, Val}) -> + #'IndAudMediaDescriptor'{termStateDescr = Val}; +merge_indAudMediaDescriptor({streamParm, Val}) -> + #'IndAudMediaDescriptor'{streams = {oneStream, Val}}; +merge_indAudMediaDescriptor({streamDescr, Val}) -> + #'IndAudMediaDescriptor'{streams = {multiStream, [Val]}}. + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_indAudLocalControlDescriptor,1}]}). +-endif. +merge_indAudLocalControlDescriptor(Parms) -> + do_merge_indAudLocalControlDescriptor(Parms, + #'IndAudLocalControlDescriptor'{}). + +do_merge_indAudLocalControlDescriptor([Parm | Parms], Desc) -> + case Parm of + modeToken when Desc#'IndAudLocalControlDescriptor'.streamMode == asn1_NOVALUE -> + Desc2 = Desc#'IndAudLocalControlDescriptor'{streamMode = 'NULL'}, + do_merge_indAudLocalControlDescriptor(Parms, Desc2); + reservedGroupToken when Desc#'IndAudLocalControlDescriptor'.reserveGroup == asn1_NOVALUE -> + Desc2 = Desc#'IndAudLocalControlDescriptor'{reserveGroup = 'NULL'}, + do_merge_indAudLocalControlDescriptor(Parms, Desc2); + reservedValueToken when Desc#'IndAudLocalControlDescriptor'.reserveValue == asn1_NOVALUE -> + Desc2 = Desc#'IndAudLocalControlDescriptor'{reserveValue = 'NULL'}, + do_merge_indAudLocalControlDescriptor(Parms, Desc2); + {pkgdName, Val} when Desc#'IndAudLocalControlDescriptor'.propertyParms == asn1_NOVALUE -> + PropParms = [#'IndAudPropertyParm'{name = Val}], + Desc2 = Desc#'IndAudLocalControlDescriptor'{propertyParms = PropParms}, + do_merge_indAudLocalControlDescriptor(Parms, Desc2); + {pkgdName, Val} when is_list(Desc#'IndAudLocalControlDescriptor'.propertyParms) -> + PropParms = Desc#'IndAudLocalControlDescriptor'.propertyParms, + PropParms2 = [#'IndAudPropertyParm'{name = Val} | PropParms], + Desc2 = Desc#'IndAudLocalControlDescriptor'{propertyParms = PropParms2}, + do_merge_indAudLocalControlDescriptor(Parms, Desc2) + end; +do_merge_indAudLocalControlDescriptor([], Desc) -> + case Desc#'IndAudLocalControlDescriptor'.propertyParms of + [_ | _] = PropParms -> % List has more then one element + PropParms2= lists:reverse(PropParms), + Desc#'IndAudLocalControlDescriptor'{propertyParms = PropParms2}; + _ -> + Desc + end. + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_indAudLocalParm,1}]}). +-endif. +ensure_indAudLocalParm(Token) -> + case Token of + {safeToken, _Line, "mode"} -> modeToken; + {safeToken, _Line, "mo"} -> modeToken; + {safeToken, _Line, "reservedgroup"} -> reservedGroupToken; + {safeToken, _Line, "rg"} -> reservedGroupToken; + {safeToken, _Line, "reservedvalue"} -> reservedValueToken; + {safeToken, _Line, "rv"} -> reservedValueToken; + PkgdName -> {pkgdName, + ensure_pkgdName(PkgdName)} + end. + +merge_indAudTerminationStateDescriptor({pkgdName, Val}) -> + PropParm = #'IndAudPropertyParm'{name = Val}, + #'IndAudTerminationStateDescriptor'{propertyParms = [PropParm]}; +merge_indAudTerminationStateDescriptor(serviceStatesToken) -> + #'IndAudTerminationStateDescriptor'{serviceState = 'NULL'}; +merge_indAudTerminationStateDescriptor(bufferToken) -> + #'IndAudTerminationStateDescriptor'{eventBufferControl = 'NULL'}. + + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_indAudEventBufferDescriptor,2}]}). +-endif. +merge_indAudEventBufferDescriptor(EventName, SpecParams) -> + IAEBD = #'IndAudEventBufferDescriptor'{eventName = EventName}, + do_merge_indAudEventBufferDescriptor(SpecParams, IAEBD). + +do_merge_indAudEventBufferDescriptor(asn1_NOVALUE, IAEBD) -> + IAEBD; +do_merge_indAudEventBufferDescriptor({streamID, StreamID}, IAEBD) -> + IAEBD#'IndAudEventBufferDescriptor'{streamID = StreamID}; +do_merge_indAudEventBufferDescriptor({eventParameterName, _Name} = EPN, + IAEBD) -> + %% BUGBUG BUGBUG BUGBUG + %% This is an ugly hack to allow the eventParamName which only + %% exists in the text encoding... + IAEBD#'IndAudEventBufferDescriptor'{streamID = EPN}. + + +ensure_indAudSignalListParm(SIG) when is_record(SIG, 'Signal') -> + ensure_indAudSignal(SIG). + +ensure_indAudSignal(#'Signal'{signalName = SignalName, + streamID = asn1_NOVALUE, + sigType = asn1_NOVALUE, + duration = asn1_NOVALUE, + notifyCompletion = asn1_NOVALUE, + keepActive = asn1_NOVALUE, + sigParList = []}) -> + #'IndAudSignal'{signalName = SignalName}. + + +ensure_IADMD({_TokenTag, _Line, + #'DigitMapDescriptor'{digitMapName = Name, + digitMapValue = asn1_NOVALUE}}) -> + #'IndAudDigitMapDescriptor'{digitMapName = Name}. + + +merge_indAudPackagesDescriptor(#'PackagesItem'{packageName = N, + packageVersion = V}) -> + #'IndAudPackagesDescriptor'{packageName = N, + packageVersion = V}. + + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_indAudTerminationStateParm,1}]}). +-endif. +ensure_indAudTerminationStateParm(Token) -> + case Token of + {safeToken, _Line, "servicestates"} -> serviceStatesToken; + {safeToken, _Line, "si"} -> serviceStatesToken; + {safeToken, _Line, "buffer"} -> bufferToken; + {safeToken, _Line, "bf"} -> bufferToken; + PkgdName -> {pkgdName, + ensure_pkgdName(PkgdName)} + end. + + +%% Types modified by v2: + +merge_auditDescriptor([]) -> + #'AuditDescriptor'{}; +merge_auditDescriptor(Tokens) when is_list(Tokens) -> + case lists:keysearch(terminationAudit, 1, Tokens) of + {value, {terminationAudit, TA}} -> + case lists:keydelete(terminationAudit, 1, Tokens) of + [] -> + #'AuditDescriptor'{auditPropertyToken = TA}; + AuditTokens -> + #'AuditDescriptor'{auditToken = AuditTokens, + auditPropertyToken = TA} + end; + false -> + #'AuditDescriptor'{auditToken = Tokens} + end; +merge_auditDescriptor(_) -> + #'AuditDescriptor'{}. + + +%% v2 - end + + + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_ServiceChangeParm,1}]}). +-endif. +merge_ServiceChangeParm(Parms) -> + Required = [serviceChangeReason, serviceChangeMethod], + merge_ServiceChangeParm(Parms, #'ServiceChangeParm'{}, Required). + +merge_ServiceChangeParm([], SCP, []) -> + SCP; + +merge_ServiceChangeParm([], _SCP, Required) -> + exit({missing_required_serviceChangeParm, Required}); + +merge_ServiceChangeParm([{address, Val}|Parms], SCP0, Req) + when ((SCP0#'ServiceChangeParm'.serviceChangeAddress =:= asn1_NOVALUE) + andalso + (SCP0#'ServiceChangeParm'.serviceChangeMgcId =:= asn1_NOVALUE)) -> + SCP = SCP0#'ServiceChangeParm'{serviceChangeAddress = Val}, + merge_ServiceChangeParm(Parms, SCP, Req); +merge_ServiceChangeParm([{address, Val}|_Parms], SCP0, _Req) + when SCP0#'ServiceChangeParm'.serviceChangeAddress == asn1_NOVALUE -> + MgcId = SCP0#'ServiceChangeParm'.serviceChangeMgcId, + exit({not_both_address_mgcid_serviceChangeParm, Val, MgcId}); + +merge_ServiceChangeParm([{mgc_id, Val}|Parms], SCP0, Req) + when ((SCP0#'ServiceChangeParm'.serviceChangeMgcId =:= asn1_NOVALUE) andalso + (SCP0#'ServiceChangeParm'.serviceChangeAddress =:= asn1_NOVALUE)) -> + SCP = SCP0#'ServiceChangeParm'{serviceChangeMgcId = Val}, + merge_ServiceChangeParm(Parms, SCP, Req); +merge_ServiceChangeParm([{mgc_id, Val}|_Parms], SCP0, _Req) + when SCP0#'ServiceChangeParm'.serviceChangeMgcId == asn1_NOVALUE -> + Addr = SCP0#'ServiceChangeParm'.serviceChangeAddress, + exit({not_both_address_mgcid_serviceChangeParm, Val, Addr}); + +merge_ServiceChangeParm([{profile, Val}|Parms], SCP0, Req) + when SCP0#'ServiceChangeParm'.serviceChangeProfile == asn1_NOVALUE -> + SCP = SCP0#'ServiceChangeParm'{serviceChangeProfile = Val}, + merge_ServiceChangeParm(Parms, SCP, Req); + +merge_ServiceChangeParm([{version, Val}|Parms], SCP0, Req) + when SCP0#'ServiceChangeParm'.serviceChangeVersion == asn1_NOVALUE -> + SCP = SCP0#'ServiceChangeParm'{serviceChangeVersion = Val}, + merge_ServiceChangeParm(Parms, SCP, Req); + +%% REQUIRED (i.e. no default value) +merge_ServiceChangeParm([{reason, Val}|Parms], SCP0, Req0) + when SCP0#'ServiceChangeParm'.serviceChangeReason == undefined -> + SCP = SCP0#'ServiceChangeParm'{serviceChangeReason = Val}, + Req = lists:delete(serviceChangeReason, Req0), + merge_ServiceChangeParm(Parms, SCP, Req); + +merge_ServiceChangeParm([{delay, Val}|Parms], SCP0, Req) + when SCP0#'ServiceChangeParm'.serviceChangeDelay == asn1_NOVALUE -> + SCP = SCP0#'ServiceChangeParm'{serviceChangeDelay = Val}, + merge_ServiceChangeParm(Parms, SCP, Req); + +%% REQUIRED (i.e. no default value) +merge_ServiceChangeParm([{method, Val}|Parms], SCP0, Req0) + when SCP0#'ServiceChangeParm'.serviceChangeMethod == undefined -> + SCP = SCP0#'ServiceChangeParm'{serviceChangeMethod = Val}, + Req = lists:delete(serviceChangeMethod, Req0), + merge_ServiceChangeParm(Parms, SCP, Req); + +merge_ServiceChangeParm([{time_stamp, Val}|Parms], SCP0, Req) + when SCP0#'ServiceChangeParm'.timeStamp == asn1_NOVALUE -> + SCP = SCP0#'ServiceChangeParm'{timeStamp = Val}, + merge_ServiceChangeParm(Parms, SCP, Req); + +merge_ServiceChangeParm([{extension, _Val}|Parms], SCP0, Req) -> + merge_ServiceChangeParm(Parms, SCP0, Req); + +%% OTP-5353. +merge_ServiceChangeParm([{audit_item, Val}|Parms], SCP0, Req) + when ((SCP0#'ServiceChangeParm'.serviceChangeInfo =:= asn1_NOVALUE) + andalso is_atom(Val)) -> + SCI = #'AuditDescriptor'{auditToken = [Val]}, + SCP = SCP0#'ServiceChangeParm'{serviceChangeInfo = SCI}, + merge_ServiceChangeParm(Parms, SCP, Req); +merge_ServiceChangeParm([{audit_item, Val}|Parms], SCP0, Req) + when ((SCP0#'ServiceChangeParm'.serviceChangeInfo =:= asn1_NOVALUE) + andalso is_tuple(Val)) -> + SCI = #'AuditDescriptor'{auditPropertyToken = [Val]}, + SCP = SCP0#'ServiceChangeParm'{serviceChangeInfo = SCI}, + merge_ServiceChangeParm(Parms, SCP, Req); +merge_ServiceChangeParm([{audit_item, Val}|Parms], SCP0, Req) + when (is_record(SCP0#'ServiceChangeParm'.serviceChangeInfo, 'AuditDescriptor') + andalso is_atom(Val)) -> + SCI0 = SCP0#'ServiceChangeParm'.serviceChangeInfo, + L = SCI0#'AuditDescriptor'.auditToken, + SCI = SCI0#'AuditDescriptor'{auditToken = [Val|L]}, + SCP = SCP0#'ServiceChangeParm'{serviceChangeInfo = SCI}, + merge_ServiceChangeParm(Parms, SCP, Req); +merge_ServiceChangeParm([{audit_item, Val}|Parms], SCP0, Req) + when (is_record(SCP0#'ServiceChangeParm'.serviceChangeInfo, 'AuditDescriptor') + andalso is_tuple(Val)) -> + SCI0 = SCP0#'ServiceChangeParm'.serviceChangeInfo, + L = SCI0#'AuditDescriptor'.auditPropertyToken, + SCI = SCI0#'AuditDescriptor'{auditPropertyToken = [Val|L]}, + SCP = SCP0#'ServiceChangeParm'{serviceChangeInfo = SCI}, + merge_ServiceChangeParm(Parms, SCP, Req); + +merge_ServiceChangeParm([{Tag, Val}|_Parms], SCP, _Req) -> + Val2 = + case Tag of + address -> + SCP#'ServiceChangeParm'.serviceChangeAddress; + mgc_id -> + SCP#'ServiceChangeParm'.serviceChangeMgcId; + profile -> + SCP#'ServiceChangeParm'.serviceChangeProfile; + version -> + SCP#'ServiceChangeParm'.serviceChangeVersion; + reason -> + SCP#'ServiceChangeParm'.serviceChangeReason; + delay -> + SCP#'ServiceChangeParm'.serviceChangeDelay; + method -> + SCP#'ServiceChangeParm'.serviceChangeMethod; + time_stamp -> + SCP#'ServiceChangeParm'.timeStamp; + audit_item -> + SCP#'ServiceChangeParm'.serviceChangeInfo + end, + exit({at_most_once_serviceChangeParm, {Tag, Val, Val2}}). + + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_ServiceChangeResParm,1}]}). +-endif. +merge_ServiceChangeResParm(Parms) -> + merge_ServiceChangeResParm(Parms, #'ServiceChangeResParm'{}). + +merge_ServiceChangeResParm([], SCRP) -> + SCRP; +merge_ServiceChangeResParm([{address, Val}|Parms], SCRP0) + when SCRP0#'ServiceChangeResParm'.serviceChangeAddress == asn1_NOVALUE, + SCRP0#'ServiceChangeResParm'.serviceChangeMgcId == asn1_NOVALUE -> + SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeAddress = Val}, + merge_ServiceChangeResParm(Parms, SCRP); +merge_ServiceChangeResParm([{address, Val}|_Parms], SCRP0) + when SCRP0#'ServiceChangeResParm'.serviceChangeAddress == asn1_NOVALUE -> + MgcId = SCRP0#'ServiceChangeResParm'.serviceChangeMgcId, + exit({not_both_address_mgcid_servChgReplyParm, Val, MgcId}); + +merge_ServiceChangeResParm([{mgc_id, Val}|Parms], SCRP0) + when SCRP0#'ServiceChangeResParm'.serviceChangeMgcId == asn1_NOVALUE, + SCRP0#'ServiceChangeResParm'.serviceChangeAddress == asn1_NOVALUE -> + SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeMgcId = Val}, + merge_ServiceChangeResParm(Parms, SCRP); +merge_ServiceChangeResParm([{mgc_id, Val}|_Parms], SCRP0) + when SCRP0#'ServiceChangeResParm'.serviceChangeMgcId == asn1_NOVALUE -> + Addr = SCRP0#'ServiceChangeResParm'.serviceChangeAddress, + exit({not_both_address_mgcid_servChgReplyParm, Val, Addr}); + +merge_ServiceChangeResParm([{profile, Val}|Parms], SCRP0) + when SCRP0#'ServiceChangeResParm'.serviceChangeProfile == asn1_NOVALUE -> + SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeProfile = Val}, + merge_ServiceChangeResParm(Parms, SCRP); + +merge_ServiceChangeResParm([{version, Val}|Parms], SCRP0) + when SCRP0#'ServiceChangeResParm'.serviceChangeVersion == asn1_NOVALUE -> + SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeVersion = Val}, + merge_ServiceChangeResParm(Parms, SCRP); + +merge_ServiceChangeResParm([{time_stamp, Val}|Parms], SCRP0) + when SCRP0#'ServiceChangeResParm'.timeStamp == asn1_NOVALUE -> + SCRP = SCRP0#'ServiceChangeResParm'{timeStamp = Val}, + merge_ServiceChangeResParm(Parms, SCRP); + +merge_ServiceChangeResParm([{Tag, Val}|_Parms], SCRP) -> + Val2 = + case Tag of + address -> SCRP#'ServiceChangeResParm'.serviceChangeAddress; + mgc_id -> SCRP#'ServiceChangeResParm'.serviceChangeMgcId; + profile -> SCRP#'ServiceChangeResParm'.serviceChangeProfile; + version -> SCRP#'ServiceChangeResParm'.serviceChangeVersion; + time_stamp -> SCRP#'ServiceChangeResParm'.timeStamp + end, + exit({at_most_once_servChgReplyParm, {Tag, Val, Val2}}). + + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_serviceChangeMethod,1}]}). +-endif. +ensure_serviceChangeMethod(Token) -> + case Token of + {safeToken, _Line, "fl"} -> + failover; + {safeToken, _Line, "failover"} -> + failover; + {safeToken, _Line, "fo"} -> + forced; + {safeToken, _Line, "forced"} -> + forced; + {safeToken, _Line, "gr"} -> + graceful; + {safeToken, _Line, "graceful"} -> + graceful; + {safeToken, _Line, "rs"} -> + restart; + {safeToken, _Line, "restart"} -> + restart; + {safeToken, _Line, "dc"} -> + disconnected; + {safeToken, _Line, "disconnected"} -> + disconnected; + {safeToken, _Line, "ho"} -> + handOff; + {safeToken, _Line, "handoff"} -> + handOff; + {safeToken, Line, Text} -> + return_error(Line, {bad_serviceChangeMethod, Text}) + end. + + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_profile,1}]}). +-endif. +ensure_profile({_TokenTag, Line, Text}) -> + case string:tokens(Text, [$/]) of + [Name, Version] -> + Version2 = ensure_version(Version), + #'ServiceChangeProfile'{profileName = Name, version = Version2}; + _ -> + return_error(Line, {bad_profile, Text}) + end. + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_version,1}]}). +-endif. +ensure_version(Version) -> + ensure_uint(Version, 0, 99). + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_signalRequest,2}]}). +-endif. +merge_signalRequest(SignalName, PropertyParms) -> + Sig = #'Signal'{signalName = SignalName}, + SPL = [], + do_merge_signalRequest(Sig, PropertyParms, SPL). + +do_merge_signalRequest(Sig, [H | T], SPL) -> + case H of + {stream, StreamId} when Sig#'Signal'.streamID == asn1_NOVALUE -> + do_merge_signalRequest(Sig#'Signal'{streamID = StreamId}, T, SPL); + {signal_type, SigType} when Sig#'Signal'.sigType == asn1_NOVALUE -> + do_merge_signalRequest(Sig#'Signal'{sigType = SigType}, T, SPL); + {duration, Duration} when Sig#'Signal'.duration == asn1_NOVALUE -> + do_merge_signalRequest(Sig#'Signal'{duration = Duration}, T, SPL); + {notify_completion, NC} when Sig#'Signal'.notifyCompletion == asn1_NOVALUE -> + do_merge_signalRequest(Sig#'Signal'{notifyCompletion = NC}, T, SPL); + keepActive when Sig#'Signal'.keepActive == asn1_NOVALUE-> + do_merge_signalRequest(Sig#'Signal'{keepActive = true}, T, SPL); + {other, Name, PP} -> + SP = #'SigParameter'{sigParameterName = Name, + value = PP#'PropertyParm'.value, + extraInfo = PP#'PropertyParm'.extraInfo}, + do_merge_signalRequest(Sig, T, [SP | SPL]); + _ -> + return_error(0, {bad_sigParm, H}) + end; +do_merge_signalRequest(Sig, [], SPL) -> + Sig#'Signal'{sigParList = lists:reverse(SPL)} . + +%% eventStream = StreamToken EQUAL StreamID +%% eventOther = eventParameterName parmValue +-ifdef(megaco_parser_inline). +-compile({inline,[{select_stream_or_other,2}]}). +-endif. +select_stream_or_other(EventParameterName, ParmValue) -> + if + (EventParameterName =:= "st") orelse + (EventParameterName =:= "stream") -> + case ParmValue of + #'PropertyParm'{value = [Value]} -> + {stream, ensure_uint16(Value)}; + _ -> + {stream, ensure_uint16(ParmValue)} + end; + true -> + #'PropertyParm'{value = Value} = ParmValue, + EP = #'EventParameter'{eventParameterName = EventParameterName, + value = Value}, + {other, EP} + end. + +%% select_stream_or_other("st", #'PropertyParm'{value = [Value]}) -> +%% {stream, ensure_uint16(Value)}; +%% select_stream_or_other("st", Value) -> +%% {stream, ensure_uint16(Value)}; +%% select_stream_or_other("stream", #'PropertyParm'{value = [Value]}) -> +%% {stream, ensure_uint16(Value)}; +%% select_stream_or_other("stream", Value) -> +%% {stream, ensure_uint16(Value)}; +%% select_stream_or_other(Name, #'PropertyParm'{value = Value}) -> +%% EP = #'EventParameter'{eventParameterName = Name, +%% value = Value}, +%% {other, EP}. + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_eventDM,1}]}). +-endif. +ensure_eventDM(Token) -> + {_TokenTag, Line, DMD} = Token, + if + is_record(DMD, 'DigitMapDescriptor') -> + Name = DMD#'DigitMapDescriptor'.digitMapName, + Val = DMD#'DigitMapDescriptor'.digitMapValue, + if + (Name =:= asn1_NOVALUE) andalso (Val =/= asn1_NOVALUE) -> + {'DigitMapValue', Start, Short, Long, Duration, Body} = Val, + DMV = #'DigitMapValue'{startTimer = Start, + shortTimer = Short, + longTimer = Long, + digitMapBody = Body, + durationTimer = Duration}, + {eventDM, {digitMapValue, DMV}}; + (Name =/= asn1_NOVALUE) andalso (Val =:= asn1_NOVALUE) -> + {eventDM, {digitMapName, Name}}; + true -> + return_error(Line, {bad_eventDM, DMD}) + end; + true -> + return_error(Line, {bad_eventDM, DMD}) + end. + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_DMD,1}]}). +-endif. +ensure_DMD(Token) -> + {_TokenTag, Line, DMD} = Token, + if + is_record(DMD, 'DigitMapDescriptor') -> + Val2 = + case DMD#'DigitMapDescriptor'.digitMapValue of + %% Note that the values of the digitMapBody and + %% durationTimers are swapped by the scanner + %% (this is done because of a problem in the flex scanner). + #'DigitMapValue'{startTimer = asn1_NOVALUE, + shortTimer = asn1_NOVALUE, + longTimer = asn1_NOVALUE, + durationTimer = [], + digitMapBody = asn1_NOVALUE} -> + asn1_NOVALUE; + #'DigitMapValue'{durationTimer = Body, + digitMapBody = Duration} = DMV -> + %% Convert to version 1 DigitMapValue + DMV#'DigitMapValue'{digitMapBody = Body, + durationTimer = Duration}; + Other -> + Other + end, + DMD#'DigitMapDescriptor'{digitMapValue = Val2}; + true -> + return_error(Line, {bad_DigitMapDescriptor, DMD}) + end. + + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_observed_event,3}]}). +-endif. +merge_observed_event(ObservedEvents, EventName, TimeStamp) -> + StreamId = asn1_NOVALUE, + EPL = [], + do_merge_observed_event(ObservedEvents, EventName, TimeStamp, StreamId, EPL). + +do_merge_observed_event([{stream, StreamID} | T], EventName, TimeStamp, asn1_NOVALUE, EPL) -> + do_merge_observed_event(T, EventName, TimeStamp, StreamID, EPL); +do_merge_observed_event([{other, PP} | T], EventName, TimeStamp, StreamID, EPL) -> + do_merge_observed_event(T, EventName, TimeStamp, StreamID, [PP | EPL]); +do_merge_observed_event([], EventName, TimeStamp, StreamID, EPL) -> + #'ObservedEvent'{eventName = EventName, + timeNotation = TimeStamp, + streamID = StreamID, + eventParList = lists:reverse(EPL)}. + +merge_eventSpec(OE) + when is_record(OE, 'ObservedEvent') andalso + (OE#'ObservedEvent'.timeNotation == asn1_NOVALUE) -> + #'EventSpec'{eventName = OE#'ObservedEvent'.eventName, + streamID = OE#'ObservedEvent'.streamID, + eventParList = OE#'ObservedEvent'.eventParList}; +merge_eventSpec(OE) -> + return_error(0, {bad_event_spec, OE}). + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_eventParameters,1}]}). +-endif. +merge_eventParameters(Params) -> + StreamId = asn1_NOVALUE, + EPL = [], + RA = #'RequestedActions'{}, + HasA = no, + do_merge_eventParameters(Params, StreamId, EPL, RA, HasA) . + +do_merge_eventParameters([H | T], StreamId, EPL, RA, HasA) -> + case H of + keepActive when RA#'RequestedActions'.keepActive == asn1_NOVALUE -> + RA2 = RA#'RequestedActions'{keepActive = true}, + do_merge_eventParameters(T, StreamId, EPL, RA2, yes); + {embed, SD, SED} when RA#'RequestedActions'.signalsDescriptor == asn1_NOVALUE -> + RA2 = RA#'RequestedActions'{signalsDescriptor = SD, + secondEvent = SED}, + do_merge_eventParameters(T, StreamId, EPL, RA2, yes); + {eventDM, DM} when RA#'RequestedActions'.eventDM == asn1_NOVALUE -> + RA2 = RA#'RequestedActions'{eventDM = DM}, + do_merge_eventParameters(T, StreamId, EPL, RA2, yes); + {stream, NewStreamId} when StreamId == asn1_NOVALUE -> + do_merge_eventParameters(T, NewStreamId, EPL, RA, HasA); + {other, PP} when is_record(PP, 'PropertyParm') -> + EP = #'EventParameter'{eventParameterName = PP#'PropertyParm'.name, + value = PP#'PropertyParm'.value, + extraInfo = PP#'PropertyParm'.extraInfo}, + do_merge_eventParameters(T, StreamId, [EP | EPL], RA, HasA); + {other, EP} when is_record(EP, 'EventParameter') -> + do_merge_eventParameters(T, StreamId, [EP | EPL], RA, HasA); + _ -> + return_error(0, {bad_eventParameter, H}) + end; +do_merge_eventParameters([], StreamId, EPL, RA, yes) -> + #'RequestedEvent'{streamID = StreamId, + eventAction = RA, + evParList = lists:reverse(EPL)}; +do_merge_eventParameters([], StreamId, EPL, _RA, no) -> + #'RequestedEvent'{streamID = StreamId, + eventAction = asn1_NOVALUE, + evParList = lists:reverse(EPL)}. + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_secondEventParameters,1}]}). +-endif. +merge_secondEventParameters(Params) -> + StreamId = asn1_NOVALUE, + EPL = [], + SRA = #'SecondRequestedActions'{}, + HasA = no, + do_merge_secondEventParameters(Params, StreamId, EPL, SRA, HasA) . + +do_merge_secondEventParameters([H | T], StreamId, EPL, SRA, HasA) -> + case H of + keepActive when SRA#'SecondRequestedActions'.keepActive == asn1_NOVALUE -> + SRA2 = SRA#'SecondRequestedActions'{keepActive = true}, + do_merge_secondEventParameters(T, StreamId, EPL, SRA2, yes); + {second_embed, SD} when SRA#'SecondRequestedActions'.signalsDescriptor == asn1_NOVALUE -> + SRA2 = SRA#'SecondRequestedActions'{signalsDescriptor = SD}, + do_merge_secondEventParameters(T, StreamId, EPL, SRA2, yes); + {eventDM, DM} when SRA#'SecondRequestedActions'.eventDM == asn1_NOVALUE -> + SRA2 = SRA#'SecondRequestedActions'{eventDM = DM}, + do_merge_secondEventParameters(T, StreamId, EPL, SRA2, yes); + {stream, NewStreamId} when StreamId == asn1_NOVALUE -> + do_merge_secondEventParameters(T, NewStreamId, EPL, SRA, HasA); + {other, PP} when is_record(PP, 'PropertyParm') -> + EP = #'EventParameter'{eventParameterName = PP#'PropertyParm'.name, + value = PP#'PropertyParm'.value, + extraInfo = PP#'PropertyParm'.extraInfo}, + do_merge_secondEventParameters(T, StreamId, [EP | EPL], SRA, HasA); + {other, EP} when is_record(EP, 'EventParameter') -> + do_merge_secondEventParameters(T, StreamId, [EP | EPL], SRA, HasA); + _ -> + return_error(0, {bad_secondEventParameter, H}) + end; +do_merge_secondEventParameters([], StreamId, EPL, SRA, yes) -> + #'SecondRequestedEvent'{streamID = StreamId, + eventAction = SRA, + evParList = lists:reverse(EPL)}; +do_merge_secondEventParameters([], StreamId, EPL, _SRA, no) -> + #'SecondRequestedEvent'{streamID = StreamId, + eventAction = asn1_NOVALUE, + evParList = lists:reverse(EPL)}. + +%% terminationID = "ROOT" / pathName / "$" / "*" +%% Total length of pathName must not exceed 64 chars. +%% pathName = ["*"] NAME *("/" / "*"/ ALPHA / DIGIT /"_" / "$" ) +%% ["@" pathDomainName ] +%% ABNF allows two or more consecutive "." although it is meaningless +%% in a path domain name. +%% pathDomainName = (ALPHA / DIGIT / "*" ) +%% *63(ALPHA / DIGIT / "-" / "*" / ".") +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_terminationID,1}]}). +-endif. +ensure_terminationID(Token) -> + {safeToken, _Line, LowerText} = Token, + %% terminationID = "ROOT" / pathName / "$" / "*" + decode_term_id(LowerText, false, [], []). + +decode_term_id([H | T], Wild, Id, Component) -> + case H of + $/ -> decode_term_id(T, Wild, [lists:reverse(Component) | Id], []); + $* -> decode_term_id(T, true, Id, [?megaco_all | Component]); + $$ -> decode_term_id(T, true, Id, [?megaco_choose | Component]); + _ -> decode_term_id(T, Wild, Id, [H | Component]) + end; +decode_term_id([], Wild, Id, Component) -> + Id2 = [lists:reverse(Component) | Id], + #megaco_term_id{contains_wildcards = Wild, id = lists:reverse(Id2)}. + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_pathName,1}]}). +-endif. +ensure_pathName(Token) -> + {_TokenTag, _Line, Text} = Token, + Text. %% BUGBUG: ensure values + +%% TimeStamp = Date "T" Time ; per ISO 8601:1988 +%% Date = 8(DIGIT) ; Date = yyyymmdd +%% Time = 8(DIGIT) ; Time = hhmmssss +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_timeStamp,1}]}). +-endif. +ensure_timeStamp(Token) -> + {'TimeStampToken', Line, Text} = Token, + case string:tokens(Text, [$T, $t]) of + [Date, Time] -> + #'TimeNotation'{date = Date, time = Time}; + _ -> + return_error(Line, {bad_timeStamp, Text}) + end. + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_transactionID,1}]}). +-endif. +ensure_transactionID(TransId) -> + ensure_uint32(TransId). + +%% transactionAck = transactionID / (transactionID "-" transactionID) +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_transactionAck,1}]}). +-endif. +ensure_transactionAck(Tokens) -> + {safeToken, _Line, Text} = Tokens, + ensure_transactionAck2(Text, []). + +ensure_transactionAck2([], Acc) -> + Id = lists:reverse(Acc), + #'TransactionAck'{firstAck = ensure_transactionID(Id)}; +ensure_transactionAck2([$- | Id2], Acc) -> + Id1 = lists:reverse(Acc), + #'TransactionAck'{firstAck = ensure_transactionID(Id1), + lastAck = ensure_transactionID(Id2)}; +ensure_transactionAck2([H|T], Acc) -> + ensure_transactionAck2(T, [H|Acc]). + + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_action_requests,2}]}). +-endif. +merge_action_requests(CtxId, Items) -> + CtxReq = #'ContextRequest'{}, + CtxAuditReq = asn1_NOVALUE, + CmdReq = [], + TopReq = [], + do_merge_action_requests(CtxId, CtxReq, CtxAuditReq, CmdReq, TopReq, Items). + +do_merge_action_requests(CtxId, CtxReq, CtxAuditReq, CmdReq, TopReq, [H | T]) -> + case H of + _ when is_record(H, 'CommandRequest') -> + do_merge_action_requests(CtxId, CtxReq, CtxAuditReq, [H | CmdReq], TopReq, T); + + {priority, Int} when CtxReq#'ContextRequest'.priority == asn1_NOVALUE -> + CtxReq2 = CtxReq#'ContextRequest'{priority = Int}, + do_merge_action_requests(CtxId, CtxReq2, CtxAuditReq, CmdReq, + TopReq, T); + {emergency, Bool} when CtxReq#'ContextRequest'.emergency == asn1_NOVALUE -> + CtxReq2 = CtxReq#'ContextRequest'{emergency = Bool}, + do_merge_action_requests(CtxId, CtxReq2, CtxAuditReq, CmdReq, + TopReq, T); + {topology, Desc} -> + TopReq2 = Desc ++ TopReq, %% OTP-4088 + do_merge_action_requests(CtxId, CtxReq, CtxAuditReq, CmdReq, + TopReq2, T); + + {contextAudit, CAs} -> + CtxAuditReq2 = merge_context_attr_audit_request(CtxAuditReq, CAs), + do_merge_action_requests(CtxId, CtxReq, CtxAuditReq2, CmdReq, + TopReq, T) + + end; +do_merge_action_requests(CtxId, CtxReq, CtxAuditReq, CmdReq, TopReq, []) -> + #'ActionRequest'{contextId = CtxId, + contextRequest = strip_contextRequest(CtxReq, TopReq), + contextAttrAuditReq = strip_contextAttrAuditRequest(CtxAuditReq), + commandRequests = lists:reverse(CmdReq)}. + + +merge_context_attr_audit_request(asn1_NOVALUE, CAs) -> + merge_context_attr_audit_request(#'ContextAttrAuditRequest'{}, CAs); +merge_context_attr_audit_request(CAAR, [H|T]) -> + CAAR2 = + case H of + priorityAudit when CAAR#'ContextAttrAuditRequest'.priority == asn1_NOVALUE -> + CAAR#'ContextAttrAuditRequest'{priority = 'NULL'}; + + priorityAudit -> + Prio = CAAR#'ContextAttrAuditRequest'.priority, + exit({only_once, priorityAudit, Prio}); + + emergencyAudit when CAAR#'ContextAttrAuditRequest'.emergency == asn1_NOVALUE -> + CAAR#'ContextAttrAuditRequest'{emergency = 'NULL'}; + + emergencyAudit -> + Em = CAAR#'ContextAttrAuditRequest'.emergency, + exit({only_once, emergencyAudit, Em}); + + topologyAudit when CAAR#'ContextAttrAuditRequest'.topology == asn1_NOVALUE -> + CAAR#'ContextAttrAuditRequest'{topology = 'NULL'}; + + topologyAudit -> + Top = CAAR#'ContextAttrAuditRequest'.topology, + exit({only_once, topologyAudit, Top}) + + end, + merge_context_attr_audit_request(CAAR2, T); +merge_context_attr_audit_request(CAAR, []) -> + CAAR. + +%% OTP-5085: +%% In order to solve a problem in the parser, the error descriptor +%% has been put last in the non-empty commandReplyList, if it is not +%% asn1_NOVALUE +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_action_reply,1}]}). +-endif. +merge_action_reply(ReplyList) -> + CtxReq = #'ContextRequest'{}, + TopReq = [], + CmdList = [], + case lists:reverse(ReplyList) of + [ED|RL2] when is_record(ED, 'ErrorDescriptor') -> + AR = do_merge_action_reply(lists:reverse(RL2), + CtxReq, TopReq, CmdList), + AR#'ActionReply'{errorDescriptor = ED}; + _ -> + do_merge_action_reply(ReplyList, CtxReq, TopReq, CmdList) + end. + +do_merge_action_reply([H | T], CtxReq, TopReq, CmdList) -> + case H of + {command, Cmd} -> + do_merge_action_reply(T, CtxReq, TopReq, [Cmd | CmdList]); + {context, Ctx} -> + case Ctx of + {priority, Int} when CtxReq#'ContextRequest'.priority == asn1_NOVALUE -> + CtxReq2 = CtxReq#'ContextRequest'{priority = Int}, + do_merge_action_reply(T, CtxReq2, TopReq, CmdList); + {emergency, Bool} when CtxReq#'ContextRequest'.emergency == asn1_NOVALUE -> + CtxReq2 = CtxReq#'ContextRequest'{emergency = Bool}, + do_merge_action_reply(T, CtxReq2, TopReq, CmdList); + {topology, Desc} -> + TopReq2 = Desc ++ TopReq, %% OTP-4088 + do_merge_action_reply(T, CtxReq, TopReq2, CmdList) + end + end; +do_merge_action_reply([], CtxReq, TopReq, CmdList) -> + #'ActionReply'{contextReply = strip_contextRequest(CtxReq, TopReq), + commandReply = lists:reverse(CmdList)}. + +strip_contextRequest(R, TopReq) + when ((R#'ContextRequest'.priority =:= asn1_NOVALUE) andalso + (R#'ContextRequest'.emergency =:= asn1_NOVALUE) andalso + (TopReq =:= [])) -> + asn1_NOVALUE; +strip_contextRequest(R, []) -> + R#'ContextRequest'{topologyReq = asn1_NOVALUE}; +strip_contextRequest(R, TopReq) -> + R#'ContextRequest'{topologyReq = TopReq}. %% OTP-4088 + + +strip_contextAttrAuditRequest(R) + when ((R#'ContextAttrAuditRequest'.priority =:= asn1_NOVALUE) andalso + (R#'ContextAttrAuditRequest'.emergency =:= asn1_NOVALUE) andalso + (R#'ContextAttrAuditRequest'.topology =:= asn1_NOVALUE)) -> + asn1_NOVALUE; +strip_contextAttrAuditRequest(R) -> + R. + +merge_AmmRequest_descriptors([], Acc) -> + lists:reverse(Acc); +merge_AmmRequest_descriptors([{_, deprecated}|Descs], Acc) -> + merge_AmmRequest_descriptors(Descs, Acc); +merge_AmmRequest_descriptors([Desc|Descs], Acc) -> + merge_AmmRequest_descriptors(Descs, [Desc|Acc]). + +make_commandRequest({CmdTag, {_TokenTag, _Line, Text}}, Cmd) -> + Req = #'CommandRequest'{command = {CmdTag, Cmd}}, + case Text of + [$w, $- | _] -> + Req#'CommandRequest'{wildcardReturn = 'NULL'}; + [$o, $-, $w, $- | _] -> + Req#'CommandRequest'{optional = 'NULL', wildcardReturn = 'NULL'}; + [$o, $- | _] -> + Req#'CommandRequest'{optional = 'NULL'}; + _ -> + Req + end. + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_terminationAudit,1}]}). +-endif. +merge_terminationAudit(AuditReturnParameters) -> + lists:reverse(do_merge_terminationAudit(AuditReturnParameters, [], [])). + +do_merge_terminationAudit([H| T], ARPs, AuditItems) -> + case H of + {auditReturnItem, AuditItem} -> + do_merge_terminationAudit(T, ARPs, [AuditItem | AuditItems]); + AuditReturnParameter -> + do_merge_terminationAudit(T, [AuditReturnParameter | ARPs], AuditItems) + end; +do_merge_terminationAudit([], AuditReturnParameters, []) -> + AuditReturnParameters; +do_merge_terminationAudit([], AuditReturnParameters, AuditItems) -> + AuditDescriptor = #'AuditDescriptor'{auditToken = AuditItems}, + AuditReturnParameter = {emptyDescriptors, AuditDescriptor}, + [AuditReturnParameter | AuditReturnParameters]. + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_mediaDescriptor,1}]}). +-endif. +merge_mediaDescriptor(MediaParms) -> + do_merge_mediaDescriptor(MediaParms, asn1_NOVALUE, [], []). + +do_merge_mediaDescriptor([H | T], TS, One, Multi) -> + case H of + {streamParm, Parm} when Multi =:= [] -> + do_merge_mediaDescriptor(T, TS, [Parm | One], Multi); + {streamDescriptor, Desc} when One =:= [] -> + do_merge_mediaDescriptor(T, TS, One, [Desc | Multi]); + {termState, TS2} when TS =:= asn1_NOVALUE -> + do_merge_mediaDescriptor(T, TS2, One, Multi); + _ -> + return_error(0, {bad_merge_mediaDescriptor, [H, TS, One, Multi]}) + end; +do_merge_mediaDescriptor([], TS, One, Multi) -> + if + (One =:= []) -> + if (Multi =:= []) -> + #'MediaDescriptor'{streams = asn1_NOVALUE, + termStateDescr = TS}; + true -> % (Multi =/= []) + Streams = {multiStream, lists:reverse(Multi)}, + #'MediaDescriptor'{streams = Streams, + termStateDescr = TS} + end; + true -> % (One =/= []) + if + (Multi =:= []) -> + Streams = {oneStream, merge_streamParms(One)}, + #'MediaDescriptor'{streams = Streams, + termStateDescr = TS}; + true -> % (Multi =/= []) + return_error(0, + {bad_merge_mediaDescriptor, [TS, One, Multi]}) + end + end. + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_streamParms,1}]}). +-endif. +merge_streamParms(TaggedStreamParms) -> + SP = #'StreamParms'{}, + do_merge_streamParms(TaggedStreamParms, SP). + +do_merge_streamParms([{Tag, D} | T] = All, SP) -> + case Tag of + local when SP#'StreamParms'.localDescriptor =:= asn1_NOVALUE -> + do_merge_streamParms(T, SP#'StreamParms'{localDescriptor = D}); + remote when SP#'StreamParms'.remoteDescriptor =:= asn1_NOVALUE -> + do_merge_streamParms(T, SP#'StreamParms'{remoteDescriptor = D}); + control -> + LCD = + case SP#'StreamParms'.localControlDescriptor of + asn1_NOVALUE -> + #'LocalControlDescriptor'{propertyParms = []}; + PrevLCD -> + PrevLCD + end, + LCD2 = do_merge_control_streamParms(D, LCD), + do_merge_streamParms(T, SP#'StreamParms'{localControlDescriptor = LCD2}); + _ -> + return_error(0, {do_merge_streamParms, [All, SP]}) + end; +do_merge_streamParms([], SP) + when is_record(SP#'StreamParms'.localControlDescriptor, + 'LocalControlDescriptor') -> + LCD = SP#'StreamParms'.localControlDescriptor, + PP = LCD#'LocalControlDescriptor'.propertyParms, + LCD2 = LCD#'LocalControlDescriptor'{propertyParms = lists:reverse(PP)}, + SP#'StreamParms'{localControlDescriptor = LCD2}; +do_merge_streamParms([], SP) -> + SP. + + +do_merge_control_streamParms([{SubTag, SD} | T] = All, LCD) -> + case SubTag of + group when LCD#'LocalControlDescriptor'.reserveGroup =:= asn1_NOVALUE -> + LCD2 = LCD#'LocalControlDescriptor'{reserveGroup = SD}, + do_merge_control_streamParms(T, LCD2); + value when LCD#'LocalControlDescriptor'.reserveValue =:= asn1_NOVALUE -> + LCD2 = LCD#'LocalControlDescriptor'{reserveValue = SD}, + do_merge_control_streamParms(T, LCD2); + mode when LCD#'LocalControlDescriptor'.streamMode =:= asn1_NOVALUE -> + LCD2 = LCD#'LocalControlDescriptor'{streamMode = SD}, + do_merge_control_streamParms(T, LCD2); + prop -> + PP = LCD#'LocalControlDescriptor'.propertyParms, + LCD2 = LCD#'LocalControlDescriptor'{propertyParms = [SD | PP]}, + do_merge_control_streamParms(T, LCD2); + _ -> + return_error(0, {do_merge_control_streamParms, [All, LCD]}) + end; +do_merge_control_streamParms([], LCD) -> + LCD. + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_terminationStateDescriptor,1}]}). +-endif. +merge_terminationStateDescriptor(Parms) -> + TSD = #'TerminationStateDescriptor'{propertyParms = []}, + do_merge_terminationStateDescriptor(Parms, TSD). + +do_merge_terminationStateDescriptor([{Tag, Val} | T], TSD) -> + case Tag of + serviceState when TSD#'TerminationStateDescriptor'.serviceState =:= asn1_NOVALUE -> + TSD2 = TSD#'TerminationStateDescriptor'{serviceState = Val}, + do_merge_terminationStateDescriptor(T, TSD2); + eventBufferControl when TSD#'TerminationStateDescriptor'.eventBufferControl =:= asn1_NOVALUE-> + TSD2 = TSD#'TerminationStateDescriptor'{eventBufferControl = Val}, + do_merge_terminationStateDescriptor(T, TSD2); + propertyParm -> + PP = TSD#'TerminationStateDescriptor'.propertyParms, + TSD2 = TSD#'TerminationStateDescriptor'{propertyParms = [Val | PP]}, + do_merge_terminationStateDescriptor(T, TSD2) + end; +do_merge_terminationStateDescriptor([], TSD) -> + PP = TSD#'TerminationStateDescriptor'.propertyParms, + TSD#'TerminationStateDescriptor'{propertyParms = lists:reverse(PP)}. + +-ifdef(megaco_nscanner_props). + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_prop_groups,1}]}). +-endif. +ensure_prop_groups(Token) -> + {_TokenTag, _Line, Text} = Token, + Group = [], + Groups = [], + parse_prop_name(Text, Group, Groups). + +parse_prop_name([Char | Rest] = All, Group, Groups) -> + if + ?white_space(Char) -> + parse_prop_name(Rest, Group, Groups); + ?end_of_line(Char) -> + parse_prop_name(Rest, Group, Groups); + true -> + Name = [], + do_parse_prop_name(All, Name, Group, Groups) + end; +parse_prop_name([] = All, Group, Groups) -> + Name = [], + do_parse_prop_name(All, Name, Group, Groups). + +do_parse_prop_name([Char | Rest], Name, Group, Groups) + when (Char =:= $=) andalso (Name =/= []) -> + %% Now we have a complete name + if + (Name =:= "v") andalso (Group =/= []) -> + %% v= is a property group delimiter, + %% lets create yet another property group. + Groups2 = [lists:reverse(Group) | Groups], + Group2 = [], + parse_prop_value(Rest, Name, Group2, Groups2); + true -> + %% Use current property group + parse_prop_value(Rest, Name, Group, Groups) + end; +do_parse_prop_name([Char | Rest], Name, Group, Groups) -> + case ?classify_char4(Char) of + safe_char_upper -> + do_parse_prop_name(Rest, [Char | Name], Group, Groups); + safe_char -> + do_parse_prop_name(Rest, [Char | Name], Group, Groups); + _ -> + return_error(0, {bad_prop_name, lists:reverse(Name), Char}) + end; +do_parse_prop_name([], [], [], Groups) -> + lists:reverse(Groups); +do_parse_prop_name([], [], Group, Groups) -> + Group2 = lists:reverse(Group), + lists:reverse([Group2 | Groups]); +do_parse_prop_name([], Name, Group, Groups) when Name =/= [] -> + %% Assume end of line + Value = [], + PP = make_prop_parm(Name, Value), + Group2 = lists:reverse([PP | Group]), + lists:reverse([Group2 | Groups]). + +-ifdef(megaco_parser_inline). +-compile({inline,[{parse_prop_value,4}]}). +-endif. +parse_prop_value(Chars, Name, Group, Groups) -> + Value = [], + do_parse_prop_value(Chars, Name, Value, Group, Groups). + +do_parse_prop_value([Char | Rest], Name, Value, Group, Groups) -> + if + ?end_of_line(Char) -> + %% Now we have a complete "name=value" pair + PP = make_prop_parm(Name, Value), + parse_prop_name(Rest, [PP | Group], Groups); + true -> + do_parse_prop_value(Rest, Name, [Char | Value], Group, Groups) + end; +do_parse_prop_value([], Name, Value, Group, Groups) -> + %% Assume end of line + PP = make_prop_parm(Name, Value), + Group2 = lists:reverse([PP | Group]), + lists:reverse([Group2 | Groups]). + +-ifdef(megaco_parser_inline). +-compile({inline,[{make_prop_parm,2}]}). +-endif. +make_prop_parm(Name, Value) -> + #'PropertyParm'{name = lists:reverse(Name), + value = [lists:reverse(Value)]}. + +-else. % -ifdef(megaco_nscanner_props). + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_prop_groups,1}]}). +-endif. +ensure_prop_groups(Token) -> + {_TokenTag, _Line, Groups} = Token, + Groups. + +%% -ifdef(megaco_parser_inline). +%% -compile({inline,[{do_ensure_prop_groups,1}]}). +%% -endif. +%% do_ensure_prop_groups(Groups) when is_list(Groups) -> +%% [ensure_prop_group(Group) || Group <- Groups]; +%% do_ensure_prop_groups(BadGroups) -> +%% throw({error, {?MODULE, {bad_property_groups, BadGroups}}}). + +%% -ifdef(megaco_parser_inline). +%% -compile({inline,[{ensure_prop_group,1}]}). +%% -endif. +%% ensure_prop_group(Group) when is_list(Group) -> +%% [ensure_prop_parm(PropParm) || PropParm <- Group]; +%% ensure_prop_group(BadGroup) -> +%% throw({error, {?MODULE, {bad_property_group, BadGroup}}}). + +%% -ifdef(megaco_parser_inline). +%% -compile({inline,[{ensure_prop_parm,1}]}). +%% -endif. +%% ensure_prop_parm(#property_parm{name = Name, +%% value = Value}) -> +%% #'PropertyParm'{name = Name, +%% value = Value}; +%% ensure_prop_parm(PP) when is_record(PP, 'PropertyParm') -> +%% PP; +%% ensure_prop_parm(BadPropParm) -> +%% throw({error, {?MODULE, {bad_property_parm, BadPropParm}}}). + +-endif. % -ifdef(megaco_nscanner_props). + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_uint,3}]}). +-endif. +ensure_uint(Token, Min, Max) -> + case Token of + {_TokenTag, Line, Val} when is_integer(Val) -> + ensure_uint(Val, Min, Max, Line); + {_TokenTag, Line, Text} -> + case (catch list_to_integer(Text)) of + {'EXIT', _} -> + return_error(Line, {not_an_integer, Text}); + Val when is_integer(Val) -> + ensure_uint(Val, Min, Max, Line) + end; + Val when is_integer(Val) -> + ensure_uint(Val, Min, Max, 0); + Text -> + case (catch list_to_integer(Text)) of + {'EXIT', _} -> + return_error(0, {not_an_integer, Text}); + Val when is_integer(Val) -> + ensure_uint(Val, Min, Max, 0) + end + end. + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_uint,4}]}). +-endif. +ensure_uint(Val, Min, Max, Line) -> + if + is_integer(Min) andalso (Val >= Min) -> + if + is_integer(Max) andalso (Val =< Max) -> + Val; + Max =:= infinity -> + Val; + true -> + return_error(Line, {too_large_integer, Val, Max}) + end; + true -> + return_error(Line, {too_small_integer, Val, Min}) + end. + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_uint16,1}]}). +-endif. +ensure_uint16(Int) -> + ensure_uint(Int, 0, 65535). + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_uint32,1}]}). +-endif. +ensure_uint32(Int) -> + ensure_uint(Int, 0, 4294967295) . + +%% OTP-4710 +ensure_hex({_TokenTag, _Line, [$0, $x |Chars]}, Min, Max) -> + ensure_uint(length(Chars), Min, Max), + hex_to_int(Chars, []); +ensure_hex({_TokenTag, _Line, [$0, $X |Chars]}, Min, Max) -> + ensure_uint(length(Chars), Min, Max), + hex_to_int(Chars, []); +ensure_hex([$0, $x |Chars], Min, Max) -> + ensure_uint(length(Chars), Min, Max), + hex_to_int(Chars, []); +ensure_hex([$0, $X |Chars], Min, Max) -> + ensure_uint(length(Chars), Min, Max), + hex_to_int(Chars, []). + +%% OTP-4710 +hex_to_int([], Acc) -> + lists:reverse(Acc); +hex_to_int([Char1,Char2|Tail], Acc) -> + Int1 = hchar_to_int(Char1), + Int2 = hchar_to_int(Char2), + Val = Int2 bor (Int1 bsl 4), + hex_to_int(Tail, [Val| Acc]); +hex_to_int([Char], Acc) -> + Int = hchar_to_int(Char), + lists:reverse([Int|Acc]). + +hchar_to_int(Char) when ($0 =< Char) andalso (Char =< $9) -> + Char - $0; +hchar_to_int(Char) when ($A =< Char) andalso (Char =< $F) -> + Char - $A + 10; % OTP-4710 +hchar_to_int(Char) when ($a =< Char) andalso (Char =< $f) -> + Char - $a + 10. % OTP-4710 + +-ifdef(megaco_parser_inline). +-compile({inline,[{value_of,1}]}). +-endif. +value_of(Token) -> + {_TokenTag, _Line, Text} = Token, + Text. + + +% d(F) -> +% d(F, []). + +% d(F, A) -> +% d(get(dbg), F, A). + +% d(true, F, A) -> +% io:format("~p:" ++ F ++ "~n", [?MODULE|A]); +% d(_, _, _) -> +% ok. + diff --git a/lib/megaco/src/text/megaco_text_parser_v2.yrl b/lib/megaco/src/text/megaco_text_parser_v2.yrl new file mode 100644 index 0000000000..8152cc4e9b --- /dev/null +++ b/lib/megaco/src/text/megaco_text_parser_v2.yrl @@ -0,0 +1,1538 @@ +%% +%% %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: YECC grammar for text encoding of Megaco/H.248 +%%---------------------------------------------------------------------- + +%%---------------------------------------------------------------------- +%% Annex B TEXT ENCODING OF THE PROTOCOL (NORMATIVE) +%% +%% B.1 Coding of wildcards +%% +%% In a text encoding of the protocol, while TerminationIDs are +%% arbitrary, by judicious choice of names, the wildcard character, "*" +%% may be made more useful. When the wildcard character is encountered, +%% it will "match" all TerminationIDs having the same previous and +%% following characters (if appropriate). For example, if there were +%% TerminationIDs of R13/3/1, R13/3/2 and R13/3/3, the TerminationID +%% R13/3/* would match all of them. There are some circumstances where +%% ALL Terminations must be referred to. The TerminationID "*" suffices, +%% and is referred to as ALL. The CHOOSE TerminationID "$" may be used to +%% signal to the MG that it has to create an ephemeral Termination or +%% select an idle physical Termination. +%% +%% B.2 ABNF specification +%% +%% The protocol syntax is presented in ABNF according to RFC2234. The +%% protocol is not case sensitive. Identifiers are not case sensitive. +%%---------------------------------------------------------------------- + +%%---------------------------------------------------------------------- +%% Number of expected shift/reduce warnings +%% This is ugly but... +%%---------------------------------------------------------------------- + +Expect 135. + + +%%---------------------------------------------------------------------- +%% Non-terminals +%%---------------------------------------------------------------------- + +Nonterminals + + actionReply + actionReplyBody + actionReplyList + actionRequest + actionRequestItem + actionRequestItems + actionRequestList + alternativeValue + ammParameter + ammParameters + ammRequest + ammRequestBody + ammToken + ammsReply + ammsReplyBody + ammsToken + auditDescriptor + auditDescriptorBody + auditItem + auditItemList + auditOther + auditReply + auditRequest + auditReturnItem + auditReturnParameter + auditReturnParameterList + authenticationHeader + commandReply + commandReplyList + commandRequest + contextAudit + contextAuditProperties + contextAuditProperty + contextID + contextProperty + contextTerminationAudit + daddr + deviceName + digitMapDescriptor + domainAddress + domainName + embedFirst + embedNoSig + embedSig + embedWithSig + errorCode + errorDescriptor + errorText + eventBufferControl + eventBufferControlState + eventBufferDescriptor + eventDM + eventParameter + eventParameterName + eventParameters + eventSpec + eventSpecList + eventStream + eventStreamOrOther + eventsDescriptor + extension + extensionParameter + + %% v2 - start + indAudauditReturnParameter + indAuddigitMapDescriptor + indAudeventBufferDescriptor + indAudeventSpec + indAudeventSpecParameter + %% indAudeventSpecParameterList + indAudeventsDescriptor + indAudlocalControlDescriptor + indAudlocalParm + indAudlocalParmList + indAudmediaDescriptor + indAudmediaParm + %% indAudmediaParmList + indAudpackagesDescriptor + indAudrequestedEvent + indAudsignalsDescriptor + indAudsignalList + %% indAudsignalListParm + indAudsignalParm + %% indAudsignalRequest + indAudstreamDescriptor + indAudstreamParm + indAudstatisticsDescriptor + indAudterminationAudit + indAudterminationAuditList + indAudterminationStateDescriptor + indAudterminationStateParm + %% indAudterminationStateParmList + optIndAudeventSpecParameter + optIndAudsignalParm + %% v2 - end + + + localControlDescriptor + localParm + localParmList + mId + mediaDescriptor + mediaParm + mediaParmList + megacoMessage + message + messageBody + modemDescriptor % Deprecated as of Corr 1 + modemType % Deprecated as of Corr 1 + modemTypeList % Deprecated as of Corr 1 + mtpAddress + muxDescriptor + muxType + notificationReason + notificationReasons + notifyReply + notifyReplyBody + notifyRequest + notifyRequestBody + observedEvent + observedEventBody + observedEventParameter + observedEventParameters + % observedEventTimeStamp + observedEvents + observedEventsDescriptor + onOrOff + optAuditDescriptor + optImmAckRequired + optPropertyParms + optSep + packagesDescriptor + packagesItem + packagesItems + %% parmName + parmValue + pathName + pkgdName + portNumber + priority + propertyParm + propertyParms + requestID + requestedEvent + requestedEventBody + requestedEvents + safeToken + safeToken2 + secondEventParameter + secondEventParameters + secondRequestedEvent + secondRequestedEventBody + secondRequestedEvents + servChgReplyParm + servChgReplyParms + serviceChangeAddress + serviceChangeDelay + serviceChangeDescriptor + serviceChangeMethod + serviceChangeMgcId + serviceChangeParm + serviceChangeParms + serviceChangeProfile + serviceChangeReason + serviceChangeReply + serviceChangeReplyBody + serviceChangeReplyDescriptor + serviceChangeRequest + serviceChangeVersion + serviceState + serviceStates + sigParameter + sigParameters + signalList + signalListId + signalListParm + signalListParms + signalName + signalParm + signalParms + signalRequest + signalsDescriptor + signalType + statisticsDescriptor + statisticsParameter + statisticsParameters + streamDescriptor + streamID + streamModes + streamParm + streamParmList + subtractRequest + terminationA + terminationAudit + terminationB + terminationID + terminationIDList + terminationIDListRepeat + terminationStateDescriptor + terminationStateParm + terminationStateParms + timeStamp + topologyDescriptor + topologyDirection + topologyTriple + topologyTripleList + transactionAck + transactionAckList + transactionID + transactionItem + transactionList + transactionPending + transactionReply + transactionReplyBody + transactionRequest + transactionResponseAck + value + valueList + +. + +%%---------------------------------------------------------------------- +%% Terminals +%%---------------------------------------------------------------------- + +Terminals + + 'AddToken' + 'AuditCapToken' + 'AuditToken' + 'AuditValueToken' + 'AuthToken' + 'BothwayToken' + 'BriefToken' + 'BufferToken' + 'COLON' + 'COMMA' + %% 'ContextAttrToken' % OTP-7138: See OTP-7534 below + 'ContextAuditToken' + 'CtxToken' + 'DelayToken' + 'DigitMapToken' + 'DigitMapDescriptorToken' + 'DiscardToken' + 'DisconnectedToken' + 'DurationToken' + 'EQUAL' + 'EmbedToken' + 'EmergencyToken' + 'EmergencyOffToken' + 'ErrorToken' + 'EventBufferToken' + 'EventsToken' + 'FailoverToken' + 'ForcedToken' + 'GREATER' + 'GracefulToken' + 'H221Token' + 'H223Token' + 'H226Token' + 'HandOffToken' + 'ImmAckRequiredToken' + 'InSvcToken' + 'InactiveToken' + %% 'IndAudTerminationAuditToken' %% testing fix... + 'InterruptByEventToken' + 'InterruptByNewSignalsDescrToken' + 'IsolateToken' + 'KeepActiveToken' + 'LBRKT' + 'LESSER' + 'LSBRKT' + 'LocalControlToken' + 'LocalDescriptorToken' + 'LockStepToken' + 'LoopbackToken' + 'MediaToken' + %% 'MegacopToken' + 'MethodToken' + 'MgcIdToken' + 'ModeToken' + 'ModemToken' + 'ModifyToken' + 'MoveToken' + 'MtpAddressToken' + 'MuxToken' + 'NEQUAL' + 'NotifyCompletionToken' + 'NotifyToken' + 'Nx64kToken' %% v2 + 'ObservedEventsToken' + 'OffToken' + 'OnToken' + 'OnOffToken' + 'OnewayToken' + 'OtherReasonToken' + 'OutOfSvcToken' + 'PackagesToken' + 'PendingToken' + 'PriorityToken' + 'ProfileToken' + 'QuotedChars' + 'RBRKT' + 'RSBRKT' + 'ReasonToken' + 'RecvonlyToken' + 'RemoteDescriptorToken' + 'ReplyToken' + 'ReservedGroupToken' + 'ReservedValueToken' + 'ResponseAckToken' + 'RestartToken' + 'SEP' + 'SafeChars' + 'SendonlyToken' + 'SendrecvToken' + 'ServiceChangeAddressToken' + 'ServiceChangeToken' + 'ServiceStatesToken' + 'ServicesToken' + 'SignalListToken' + 'SignalTypeToken' + 'SignalsToken' + 'StatsToken' + 'StreamToken' + 'SubtractToken' + 'SynchISDNToken' + 'TerminationStateToken' + 'TestToken' + 'TimeOutToken' + 'TimeStampToken' + 'TopologyToken' + 'TransToken' + 'V18Token' + 'V22Token' + 'V22bisToken' + 'V32Token' + 'V32bisToken' + 'V34Token' + 'V76Token' + 'V90Token' + 'V91Token' + 'VersionToken' + 'AndAUDITSelectToken' %% OTP-7534: v3-fix + 'BothToken' %% OTP-7534: v3-fix + 'ContextAttrToken' %% OTP-7534: v3-fix + 'ContextListToken' %% OTP-7534: v3-fix + 'DirectionToken' %% OTP-7534: v3-fix + %% 'EmergencyOffToken' %% OTP-7534: v3-fix + 'EmergencyValueToken' %% OTP-7534: v3-fix + 'ExternalToken' %% OTP-7534: v3-fix + 'IEPSToken' %% OTP-7534: v3-fix + 'IntsigDelayToken' %% OTP-7534: v3-fix + 'InternalToken' %% OTP-7534: v3-fix + 'IterationToken' %% OTP-7534: v3-fix + 'MessageSegmentToken' %% OTP-7534: v3-fix + 'NeverNotifyToken' %% OTP-7534: v3-fix + 'NotifyImmediateToken' %% OTP-7534: v3-fix + 'NotifyRegulatedToken' %% OTP-7534: v3-fix + 'OnewayBothToken' %% OTP-7534: v3-fix + 'OnewayExternalToken' %% OTP-7534: v3-fix + 'OrAUDITselectToken' %% OTP-7534: v3-fix + 'RequestIDToken' %% OTP-7534: v3-fix + 'ResetEventsDescriptorToken' %% OTP-7534: v3-fix + 'SegmentationCompleteToken' %% OTP-7534: v3-fix + 'ServiceChangeIncompleteToken' %% OTP-7534: v3-fix + endOfMessage + +. + +%%---------------------------------------------------------------------- +%% Root symbol +%%---------------------------------------------------------------------- + +Rootsymbol megacoMessage. + +%%---------------------------------------------------------------------- +%% The grammar +%%---------------------------------------------------------------------- + +%% megacoMessage = LWSP [authenticationHeader SEP ] message +%% authenticationHeader = AuthToken EQUAL SecurityParmIndex COLON +%% SequenceNum COLON AuthData +%% +%% SecurityParmIndex = "0x" 8(HEXDIG) +%% SequenceNum = "0x" 8(HEXDIG) +%% AuthData = "0x" 24*64(HEXDIG) +%% message = MegacopToken SLASH version SEP mId SEP messageBody +%% version = 1*2(DIGIT) . + +megacoMessage -> optSep authenticationHeader message endOfMessage + : #'MegacoMessage'{authHeader = '$2', mess = '$3'} . + +optSep -> 'SEP' : sep . +optSep -> '$empty' : no_sep . + +authenticationHeader -> 'AuthToken' 'EQUAL' safeToken 'COLON' + safeToken 'COLON' safeToken optSep + : ensure_auth_header('$3', '$5', '$7') . +authenticationHeader -> '$empty' : asn1_NOVALUE . + +message -> safeToken mId messageBody : ensure_message('$1', '$2', '$3') . + +messageBody -> errorDescriptor : {messageError, '$1'} . +messageBody -> transactionList : {transactions, '$1'} . + +transactionList -> transactionItem : ['$1'] . +transactionList -> transactionItem transactionList : ['$1' | '$2'] . + +transactionItem -> transactionRequest : {transactionRequest, '$1'} . +transactionItem -> transactionReply : {transactionReply, '$1'}. +transactionItem -> transactionPending : {transactionPending, '$1'} . +transactionItem -> transactionResponseAck : {transactionResponseAck, '$1'} . + +transactionResponseAck -> 'ResponseAckToken' + 'LBRKT' transactionAck transactionAckList 'RBRKT' : ['$3' | '$4'] . + +transactionAckList -> 'COMMA' transactionAck transactionAckList : ['$2' | '$3'] . +transactionAckList -> '$empty' : [] . + +transactionAck -> safeToken : ensure_transactionAck('$1') . + +transactionPending -> 'PendingToken' 'EQUAL' transactionID 'LBRKT' 'RBRKT' + : #'TransactionPending'{transactionId = ensure_transactionID('$3') } . + +%% OTP-4359: We have the first two rule's in order to be able +%% to handle chapter 8.1.1 in RFC3525 +transactionRequest -> 'TransToken' + 'LBRKT' actionRequest actionRequestList 'RBRKT' + : #'TransactionRequest'{transactionId = asn1_NOVALUE, + actions = ['$3' | '$4']} . +transactionRequest -> 'TransToken' 'EQUAL' + 'LBRKT' actionRequest actionRequestList 'RBRKT' + : #'TransactionRequest'{transactionId = asn1_NOVALUE, + actions = ['$4' | '$5']} . +transactionRequest -> 'TransToken' 'EQUAL' transactionID + 'LBRKT' actionRequest actionRequestList 'RBRKT' + : #'TransactionRequest'{transactionId = ensure_transactionID('$3'), + actions = ['$5' | '$6']} . + +actionRequestList -> 'COMMA' actionRequest actionRequestList : ['$2' | '$3'] . +actionRequestList -> '$empty' : [] . + +actionRequest -> 'CtxToken' 'EQUAL' contextID + 'LBRKT' actionRequestItem actionRequestItems 'RBRKT' + : merge_action_requests('$3', ['$5' | '$6']) . + +actionRequestItems -> 'COMMA' actionRequestItem actionRequestItems : ['$2' | '$3'] . +actionRequestItems -> '$empty' : [] . + +actionRequestItem -> contextProperty : '$1' . +actionRequestItem -> contextAudit : '$1' . +actionRequestItem -> commandRequest : '$1' . + +%% at-most-once +contextProperty -> topologyDescriptor : {topology, '$1'}. +contextProperty -> priority : {priority, '$1'}. +contextProperty -> 'EmergencyToken' : {emergency, true}. +contextProperty -> 'EmergencyOffToken' : {emergency, false}. + +contextAudit -> 'ContextAuditToken' + 'LBRKT' contextAuditProperty contextAuditProperties 'RBRKT' + : {contextAudit, ['$3' | '$4']} . + +contextAuditProperties -> 'COMMA' contextAuditProperty contextAuditProperties + : ['$2' | '$3'] . +contextAuditProperties -> '$empty' : [] . + +%% at-most-once . +contextAuditProperty -> 'TopologyToken' : topologyAudit . +contextAuditProperty -> 'EmergencyToken' : emergencyAudit . +contextAuditProperty -> 'PriorityToken' : priorityAudit . + +commandRequest -> ammRequest : '$1'. +commandRequest -> subtractRequest : '$1'. +commandRequest -> auditRequest : '$1'. +commandRequest -> notifyRequest : '$1'. +commandRequest -> serviceChangeRequest : '$1'. + +transactionReply -> 'ReplyToken' 'EQUAL' transactionID + 'LBRKT' + optImmAckRequired transactionReplyBody + 'RBRKT' + : #'TransactionReply'{transactionId = '$3', + immAckRequired = '$5', + transactionResult = '$6'} . + +optImmAckRequired -> 'ImmAckRequiredToken' 'COMMA' : 'NULL' . +optImmAckRequired -> '$empty' : asn1_NOVALUE . + +transactionReplyBody -> errorDescriptor : {transactionError, '$1'} . +transactionReplyBody -> actionReply actionReplyList : {actionReplies, ['$1' | '$2']} . + +actionReplyList -> 'COMMA' actionReply actionReplyList : ['$2' | '$3'] . +actionReplyList -> '$empty' : [] . + +actionReply -> 'CtxToken' 'EQUAL' contextID + 'LBRKT' actionReplyBody 'RBRKT' : + setelement(#'ActionReply'.contextId, '$5', '$3') . + +actionReplyBody -> errorDescriptor : + #'ActionReply'{errorDescriptor = '$1'} . +actionReplyBody -> commandReply commandReplyList : + merge_action_reply(['$1' | '$2']) . + +commandReply -> serviceChangeReply : {command, '$1'} . +commandReply -> auditReply : {command, '$1'} . +commandReply -> ammsReply : {command, '$1'} . +commandReply -> notifyReply : {command, '$1'} . +commandReply -> contextProperty : {context, '$1'} . + +%% OTP-5085 +%% This ugly thing is to fool the parser. The errorDescriptor does not +%% realy belong here. The merge_action_reply will remove it and put it +%% in it's right place later. +commandReplyList -> 'COMMA' errorDescriptor : + ['$2'] . +commandReplyList -> 'COMMA' commandReply commandReplyList : + ['$2' | '$3'] . +commandReplyList -> '$empty' : [] . + +%Add Move and Modify have the same request parameter +ammRequest -> ammToken 'EQUAL' terminationID ammRequestBody : + Descs = merge_AmmRequest_descriptors('$4', []), + make_commandRequest('$1', + #'AmmRequest'{terminationID = ['$3'], + descriptors = Descs}) . + +ammToken -> 'AddToken' : {addReq, '$1'} . +ammToken -> 'MoveToken' : {moveReq, '$1'} . +ammToken -> 'ModifyToken' : {modReq, '$1'} . + +ammRequestBody -> 'LBRKT' ammParameter ammParameters 'RBRKT' : ['$2' | '$3'] . +ammRequestBody -> '$empty' : [] . + +ammParameters -> 'COMMA' ammParameter ammParameters : ['$2' | '$3'] . +ammParameters -> '$empty' : [] . + +%at-most-once +ammParameter -> mediaDescriptor : {mediaDescriptor, '$1'}. +ammParameter -> modemDescriptor : {modemDescriptor, deprecated}. +ammParameter -> muxDescriptor : {muxDescriptor, '$1'}. +ammParameter -> eventsDescriptor : {eventsDescriptor, '$1'}. +ammParameter -> eventBufferDescriptor : {eventBufferDescriptor, '$1'}. +ammParameter -> signalsDescriptor : {signalsDescriptor, '$1'}. +ammParameter -> digitMapDescriptor : {digitMapDescriptor, '$1'}. +ammParameter -> auditDescriptor : {auditDescriptor, '$1'}. + +ammsReply -> ammsToken 'EQUAL' terminationID ammsReplyBody + : {'$1', #'AmmsReply'{terminationID = ['$3'], + terminationAudit = '$4'}} . + +ammsToken -> 'AddToken' : addReply . +ammsToken -> 'MoveToken' : moveReply . +ammsToken -> 'ModifyToken' : modReply . +ammsToken -> 'SubtractToken' : subtractReply . + +ammsReplyBody -> 'LBRKT' terminationAudit 'RBRKT' : '$2' . +ammsReplyBody -> '$empty' : asn1_NOVALUE . + +subtractRequest -> 'SubtractToken' 'EQUAL' terminationID optAuditDescriptor + : make_commandRequest({subtractReq, '$1'}, + #'SubtractRequest'{terminationID = ['$3'], + auditDescriptor = '$4'}) . + + +optAuditDescriptor -> 'LBRKT' auditDescriptor 'RBRKT' : '$2'. +optAuditDescriptor -> '$empty' : asn1_NOVALUE . + +auditRequest -> 'AuditValueToken' 'EQUAL' + terminationID optAuditDescriptor : + make_commandRequest({auditValueRequest, '$1'}, + #'AuditRequest'{terminationID = '$3', + auditDescriptor = '$4'}) . +auditRequest -> 'AuditCapToken' 'EQUAL' + terminationID optAuditDescriptor : + make_commandRequest({auditCapRequest, '$1'}, + #'AuditRequest'{terminationID = '$3', + auditDescriptor = '$4'}) . + +auditReply -> 'AuditValueToken' 'EQUAL' 'CtxToken' contextTerminationAudit + : {auditValueReply, '$4'} . +auditReply -> 'AuditCapToken' 'EQUAL' 'CtxToken' contextTerminationAudit + : {auditCapReply, '$4'} . +auditReply -> 'AuditValueToken' 'EQUAL' auditOther + : {auditValueReply, '$3'} . +auditReply -> 'AuditCapToken' 'EQUAL' auditOther + : {auditCapReply, '$3'} . + +contextTerminationAudit -> terminationIDList : {contextAuditResult, '$1'} . +contextTerminationAudit -> 'LBRKT' errorDescriptor 'RBRKT' : {contextAuditResult, '$2'} . + +auditOther -> terminationID : + {auditResult, + #'AuditResult'{terminationID = '$1', + terminationAuditResult = []}} . +auditOther -> terminationID 'LBRKT' terminationAudit 'RBRKT' : + {auditResult, + #'AuditResult'{terminationID = '$1', + terminationAuditResult = '$3'}} . + + +terminationAudit -> auditReturnParameter auditReturnParameterList : + merge_terminationAudit(['$1' |'$2' ]) . + +auditReturnParameterList -> 'COMMA' auditReturnParameter auditReturnParameterList : ['$2' | '$3'] . +auditReturnParameterList -> '$empty' : [] . + +auditReturnParameter -> mediaDescriptor : {mediaDescriptor, '$1'} . +auditReturnParameter -> modemDescriptor. +auditReturnParameter -> muxDescriptor : {muxDescriptor, '$1'} . +auditReturnParameter -> eventsDescriptor : {eventsDescriptor, '$1'} . +auditReturnParameter -> signalsDescriptor : {signalsDescriptor, '$1'} . +auditReturnParameter -> digitMapDescriptor : {digitMapDescriptor, '$1'} . +auditReturnParameter -> observedEventsDescriptor : {observedEventsDescriptor, '$1'} . +auditReturnParameter -> eventBufferDescriptor : {eventBufferDescriptor, '$1'} . +auditReturnParameter -> statisticsDescriptor : {statisticsDescriptor, '$1'} . +auditReturnParameter -> packagesDescriptor : {packagesDescriptor, '$1'} . +auditReturnParameter -> errorDescriptor : {errorDescriptor, '$1'} . +auditReturnParameter -> auditReturnItem : {auditReturnItem, '$1'} . + +auditDescriptor -> 'AuditToken' 'LBRKT' auditDescriptorBody 'RBRKT' : + merge_auditDescriptor('$3') . + +auditDescriptorBody -> auditItem auditItemList : ['$1' | '$2']. +auditDescriptorBody -> '$empty' : asn1_NOVALUE . + +auditItemList -> 'COMMA' auditItem auditItemList : ['$2' | '$3'] . +auditItemList -> '$empty' : [] . + +%% IGv11 - begin +%% +auditReturnItem -> 'MuxToken' : muxToken . +auditReturnItem -> 'ModemToken' : modemToken . +auditReturnItem -> 'MediaToken' : mediaToken . +auditReturnItem -> 'DigitMapToken' : digitMapToken . +auditReturnItem -> 'StatsToken' : statsToken . +auditReturnItem -> 'ObservedEventsToken' : observedEventsToken . +auditReturnItem -> 'PackagesToken' : packagesToken . + +%% at-most-once, and DigitMapToken and PackagesToken are not allowed +%% in AuditCapabilities command +auditItem -> auditReturnItem : '$1' . +auditItem -> 'SignalsToken' : signalsToken. +auditItem -> 'EventBufferToken' : eventBufferToken. +auditItem -> 'EventsToken' : eventsToken . +auditItem -> indAudterminationAudit : {terminationAudit, '$1'} . % v2 +%% +%% IGv11 - end + + +%% v2 - start +%% +indAudterminationAudit -> indAudauditReturnParameter + indAudterminationAuditList + : ['$1' | '$2'] . + +% testing fix... +% indAudterminationAudit -> 'IndAudTerminationAuditToken' +% indAudauditReturnParameter +% indAudterminationAuditList +% : ['$2' | '$3'] . + +indAudterminationAuditList -> 'COMMA' indAudauditReturnParameter + indAudterminationAuditList + : ['$2' | '$3'] . +indAudterminationAuditList -> '$empty' : [] . + +indAudauditReturnParameter -> indAudmediaDescriptor + : {indAudMediaDescriptor, '$1'} . +indAudauditReturnParameter -> indAudeventsDescriptor + : {indAudEventsDescriptor, '$1'} . +indAudauditReturnParameter -> indAudsignalsDescriptor + : {indAudSignalsDescriptor, '$1'} . +indAudauditReturnParameter -> indAuddigitMapDescriptor + : {indAudDigitMapDescriptor, '$1'} . +indAudauditReturnParameter -> indAudeventBufferDescriptor + : {indAudEventBufferDescriptor, '$1'} . +indAudauditReturnParameter -> indAudstatisticsDescriptor + : {indAudStatisticsDescriptor, '$1'} . +indAudauditReturnParameter -> indAudpackagesDescriptor + : {indAudPackagesDescriptor, '$1'} . + + +indAudmediaDescriptor -> 'MediaToken' 'LBRKT' + indAudmediaParm 'RBRKT' + : merge_indAudMediaDescriptor('$3') . + +%% at-most-once per item +%% and either streamParm or streamDescriptor but not both +%% <rambling> +%% This is solved in another way in text than in binary :( +%% Instead of having a list of indAudmediaParm we put this +%% stuff in the indAudterminationAuditList with several +%% indAudmediaDescriptor's. +%% </rambling> +%% + +indAudmediaParm -> indAudstreamParm : {streamParm, '$1'} . +indAudmediaParm -> indAudstreamDescriptor : {streamDescr, '$1'} . +indAudmediaParm -> indAudterminationStateDescriptor : {termStateDescr, '$1'} . + +%% at-most-once +indAudstreamParm -> indAudlocalControlDescriptor + : #'IndAudStreamParms'{localControlDescriptor = '$1'} . + +indAudstreamDescriptor -> 'StreamToken' 'EQUAL' streamID + 'LBRKT' indAudstreamParm 'RBRKT' + : #'IndAudStreamDescriptor'{streamID = '$3', + streamParms = '$5'} . + + +indAudlocalControlDescriptor -> 'LocalControlToken' + 'LBRKT' indAudlocalParm indAudlocalParmList 'RBRKT' : + merge_indAudLocalControlDescriptor(['$3'| '$4']) . + +indAudlocalParmList -> 'COMMA' indAudlocalParm indAudlocalParmList : ['$2'| '$3'] . +indAudlocalParmList -> '$empty' : [] . + +%% at-most-once per item +%% +indAudlocalParm -> safeToken : ensure_indAudLocalParm('$1') . + +indAudterminationStateDescriptor -> 'TerminationStateToken' + 'LBRKT' indAudterminationStateParm 'RBRKT' + : + merge_indAudTerminationStateDescriptor('$3') . + +%% at-most-once per item +%% + +indAudterminationStateParm -> safeToken : + ensure_indAudTerminationStateParm('$1') . + +indAudeventBufferDescriptor -> 'EventBufferToken' + 'LBRKT' indAudeventSpec 'RBRKT' : '$3' . + +indAudeventSpec -> pkgdName optIndAudeventSpecParameter + : merge_indAudEventBufferDescriptor('$1','$2') . + +optIndAudeventSpecParameter -> 'LBRKT' indAudeventSpecParameter 'RBRKT' + : '$2' . +optIndAudeventSpecParameter -> '$empty' : asn1_NOVALUE . + + +indAudeventSpecParameter -> eventStream : {streamID, '$1'} . +indAudeventSpecParameter -> eventParameterName : {eventParameterName, '$1'} . + +indAudeventsDescriptor -> 'EventsToken' 'EQUAL' requestID + 'LBRKT' indAudrequestedEvent 'RBRKT' + : #'IndAudEventsDescriptor'{requestID = '$3', + pkgdName = '$5'} . + +indAudrequestedEvent -> pkgdName : '$1' . + + +indAudsignalsDescriptor -> 'SignalsToken' optIndAudsignalParm : '$2' . + + +optIndAudsignalParm -> 'LBRKT' 'RBRKT' : asn1_NOVALUE . +optIndAudsignalParm -> 'LBRKT' indAudsignalParm 'RBRKT' : '$2' . + +indAudsignalParm -> indAudsignalList : {seqSigList, '$1'} . +indAudsignalParm -> signalRequest : {signal, ensure_indAudSignal('$1')} . + +indAudsignalList -> 'SignalListToken' 'EQUAL' signalListId + 'LBRKT' signalListParm 'RBRKT' : + #'IndAudSeqSigList'{id = ensure_uint16('$3'), + signalList = + ensure_indAudSignalListParm('$5')} . + + +%% The DigitMapDescriptorToken is specially treated by the scanner +indAuddigitMapDescriptor -> 'DigitMapDescriptorToken' : + ensure_IADMD('$1') . + +indAudstatisticsDescriptor -> 'StatsToken' 'LBRKT' pkgdName 'RBRKT' : + #'IndAudStatisticsDescriptor'{statName = '$3'} . + +indAudpackagesDescriptor -> 'PackagesToken' 'LBRKT' packagesItem 'RBRKT' + : merge_indAudPackagesDescriptor('$3') . + +eventStream -> 'StreamToken' 'EQUAL' streamID : '$3' . + + +%% +%% v2 - end + +notifyRequest -> 'NotifyToken' 'EQUAL' terminationID + 'LBRKT' notifyRequestBody 'RBRKT' + : make_commandRequest({notifyReq, '$1'}, + setelement(#'NotifyRequest'.terminationID, '$5', ['$3'])) . + +notifyRequestBody -> observedEventsDescriptor + : #'NotifyRequest'{observedEventsDescriptor = '$1'}. +notifyRequestBody -> errorDescriptor + : #'NotifyRequest'{errorDescriptor = '$1'}. + +notifyReply -> 'NotifyToken' 'EQUAL' terminationID notifyReplyBody + : {notifyReply, + #'NotifyReply'{terminationID = ['$3'], + errorDescriptor = '$4'}} . + +notifyReplyBody -> 'LBRKT' errorDescriptor 'RBRKT' : '$2'. +notifyReplyBody -> '$empty' : asn1_NOVALUE . + +serviceChangeRequest -> 'ServiceChangeToken' 'EQUAL' terminationID + 'LBRKT' serviceChangeDescriptor 'RBRKT' + : make_commandRequest({serviceChangeReq, '$1'}, + #'ServiceChangeRequest'{terminationID = ['$3'], + serviceChangeParms = '$5'}) . + +serviceChangeReply -> 'ServiceChangeToken' 'EQUAL' terminationID serviceChangeReplyBody + : {serviceChangeReply, + #'ServiceChangeReply'{terminationID = ['$3'], + serviceChangeResult = '$4'}} . + +serviceChangeReplyBody -> 'LBRKT' errorDescriptor 'RBRKT' + : {errorDescriptor, '$2'} . +serviceChangeReplyBody -> 'LBRKT' serviceChangeReplyDescriptor 'RBRKT' + : {serviceChangeResParms, '$2'} . +serviceChangeReplyBody -> '$empty' : {serviceChangeResParms, #'ServiceChangeResParm'{}}. + +errorDescriptor -> 'ErrorToken' 'EQUAL' errorCode 'LBRKT' errorText 'RBRKT' + : #'ErrorDescriptor'{errorCode = '$3', + errorText = '$5'} . + +errorCode -> safeToken : ensure_uint('$1', 0, 999) . + +errorText -> 'QuotedChars' : value_of('$1') . +errorText -> '$empty' : asn1_NOVALUE . + +transactionID -> safeToken : ensure_uint32('$1') . + +mId -> domainName : '$1' . +mId -> domainAddress : '$1' . +mId -> optSep mtpAddress optSep : '$2' . +mId -> optSep deviceName optSep : '$2' . + +domainName -> 'LESSER' safeToken 'GREATER' 'COLON' portNumber optSep + : ensure_domainName('$2', '$5') . +domainName -> 'LESSER' safeToken 'GREATER' + : ensure_domainName('$2', asn1_NOVALUE) . + +deviceName -> pathName : {deviceName, '$1'} . + +%% '-' is used for NULL context +contextID -> safeToken : ensure_contextID('$1') . + +domainAddress -> 'LSBRKT' daddr 'RSBRKT' 'COLON' portNumber optSep + : ensure_domainAddress('$2', '$5') . +domainAddress -> 'LSBRKT' daddr 'RSBRKT' + : ensure_domainAddress('$2', asn1_NOVALUE) . + +daddr -> '$empty' : [] . +daddr -> 'COLON' daddr : [colon| '$2'] . +daddr -> safeToken daddr : ['$1'| '$2'] . + + +portNumber -> safeToken : ensure_uint16('$1') . + +mtpAddress -> 'MtpAddressToken' : ensure_mtpAddress('$1') . + +%% terminationIDList -> LBRKT terminationID *(COMMA terminationID) RBRKT . + +terminationIDList -> 'LBRKT' terminationID terminationIDListRepeat 'RBRKT' + : ['$2' | '$3'] . + +terminationIDListRepeat -> 'COMMA' terminationID terminationIDListRepeat + : ['$2'| '$3'] . +terminationIDListRepeat -> '$empty' : [] . + + +pathName -> safeToken : ensure_pathName('$1') . + +terminationID -> safeToken : ensure_terminationID('$1') . + +mediaDescriptor -> 'MediaToken' 'LBRKT' mediaParm mediaParmList 'RBRKT' + : merge_mediaDescriptor(['$3' | '$4']) . + +mediaParmList -> 'COMMA' mediaParm mediaParmList : ['$2' | '$3'] . +mediaParmList -> '$empty' : [] . + + +%% at-most-once per item +%% using either streamParms or streamDescriptors but not both +mediaParm -> streamParm + : {streamParm, '$1'} . +mediaParm -> streamDescriptor + : {streamDescriptor, '$1'} . +mediaParm -> terminationStateDescriptor + : {termState, '$1'} . + +%% at-most-onc . +%% Specially treated by the scanner. +streamParm -> 'LocalDescriptorToken' : + PGs = ensure_prop_groups('$1'), + {local, #'LocalRemoteDescriptor'{propGrps = PGs}} . +streamParm -> 'RemoteDescriptorToken' : + PGs = ensure_prop_groups('$1'), + {remote, #'LocalRemoteDescriptor'{propGrps = PGs}} . +streamParm -> localControlDescriptor : {control, '$1'} . + +streamDescriptor -> 'StreamToken' 'EQUAL' streamID + 'LBRKT' streamParm streamParmList 'RBRKT' + : #'StreamDescriptor'{streamID = '$3', + streamParms = merge_streamParms(['$5' | '$6'])} . + +streamParmList -> 'COMMA' streamParm streamParmList : ['$2' | '$3'] . +streamParmList -> '$empty' : [] . + +localControlDescriptor -> 'LocalControlToken' 'LBRKT' localParm localParmList 'RBRKT' + : ['$3' | '$4'] . + +localParmList -> 'COMMA' localParm localParmList : ['$2' | '$3'] . +localParmList -> '$empty': [] . + +terminationStateDescriptor -> 'TerminationStateToken' + 'LBRKT' terminationStateParm terminationStateParms 'RBRKT' + : merge_terminationStateDescriptor(['$3' | '$4']) . + +terminationStateParms -> 'COMMA' terminationStateParm terminationStateParms : ['$2' | '$3'] . +terminationStateParms -> '$empty' : [] . + +%% at-most-once per item except for propertyParm +localParm -> 'ReservedGroupToken' 'EQUAL' onOrOff : {group, '$3'} . +localParm -> 'ReservedValueToken' 'EQUAL' onOrOff : {value, '$3'} . +localParm -> 'ModeToken' 'EQUAL' streamModes : {mode, '$3'} . +localParm -> propertyParm : {prop, '$1'} . + +onOrOff -> 'OnToken' : true . +onOrOff -> 'OffToken' : false . + +%% at-most-once +streamModes -> 'SendonlyToken' : sendOnly . +streamModes -> 'RecvonlyToken' : recvOnly . +streamModes -> 'SendrecvToken' : sendRecv . +streamModes -> 'InactiveToken' : inactive . +streamModes -> 'LoopbackToken' : loopBack . + +propertyParm -> pkgdName parmValue : + setelement(#'PropertyParm'.name, '$2', '$1') . + +parmValue -> 'EQUAL' alternativeValue : + '$2' . + +parmValue -> 'NEQUAL' value : + #'PropertyParm'{value = ['$2'], + extraInfo = {relation, unequalTo}} . +parmValue -> 'LESSER' value : + #'PropertyParm'{value = ['$2'], + extraInfo = {relation, smallerThan}} . +parmValue -> 'GREATER' value : + #'PropertyParm'{value = ['$2'], + extraInfo = {relation, greaterThan}} . + +%% OTP-4013 +%% alternativeValue = ( VALUE / +%% LSBRKT VALUE *(COMMA VALUE) RSBRKT / +%% LSBRKT VALUE COLON VALUE RSBRKT ) / +%% LBRKT VALUE *(COMMA VALUE) RBRKT +alternativeValue -> 'LBRKT' value valueList 'RBRKT' : + #'PropertyParm'{value = ['$2' | '$3'], + extraInfo = {sublist, false}}. % OR + +alternativeValue -> 'LSBRKT' value 'COLON' value 'RSBRKT' : + #'PropertyParm'{value = ['$2', '$4'], + extraInfo = {range, true}}. + +alternativeValue -> 'LSBRKT' value valueList 'RSBRKT' : + #'PropertyParm'{value = ['$2' | '$3'], + extraInfo = {sublist, true}}. % AND + +alternativeValue -> value : + #'PropertyParm'{value = ['$1']} . + +valueList -> 'COMMA' value valueList : ['$2' | '$3'] . +valueList -> '$empty' : [] . + + +eventBufferDescriptor -> 'EventBufferToken' : [] . +eventBufferDescriptor -> 'EventBufferToken' 'LBRKT' eventSpec eventSpecList 'RBRKT' + : ['$3' | '$4'] . + +eventSpecList -> 'COMMA' eventSpec eventSpecList : ['$2' | '$3'] . +eventSpecList -> '$empty' : [] . + +eventSpec -> observedEvent : merge_eventSpec('$1') . + +%% at-most-once per item except for propertyParm +terminationStateParm -> serviceStates : {serviceState, '$1'} . +terminationStateParm -> eventBufferControl : {eventBufferControl, '$1'} . +terminationStateParm -> propertyParm : {propertyParm, '$1'} . + +serviceStates -> 'ServiceStatesToken' 'EQUAL' serviceState : '$3' . + +serviceState -> 'TestToken' : test . +serviceState -> 'OutOfSvcToken' : outOfSvc . +serviceState -> 'InSvcToken' : inSvc . + +eventBufferControl -> 'BufferToken' 'EQUAL' eventBufferControlState : '$3' . + +eventBufferControlState -> 'OffToken' : off . +eventBufferControlState -> 'LockStepToken' : lockStep . + +muxDescriptor -> 'MuxToken' 'EQUAL' muxType terminationIDList : + #'MuxDescriptor'{muxType = '$3', + termList = '$4'} . + +muxType -> safeToken : ensure_muxType('$1') . + +streamID -> safeToken : ensure_streamID('$1') . + +pkgdName -> safeToken : ensure_pkgdName('$1') . + +eventsDescriptor -> 'EventsToken' : + #'EventsDescriptor'{requestID = asn1_NOVALUE, + eventList = []} . +eventsDescriptor -> 'EventsToken' 'EQUAL' requestID + 'LBRKT' requestedEvent requestedEvents 'RBRKT' : + #'EventsDescriptor'{requestID = '$3', + eventList = ['$5' | '$6']} . + +requestedEvents -> 'COMMA' requestedEvent requestedEvents : ['$2' | '$3'] . +requestedEvents -> '$empty' : [] . + +requestedEvent -> pkgdName requestedEventBody : + setelement(#'RequestedEvent'.pkgdName, '$2', '$1') . + +requestedEventBody -> 'LBRKT' eventParameter eventParameters 'RBRKT' : + merge_eventParameters(['$2' | '$3']) . +requestedEventBody -> '$empty' : #'RequestedEvent'{evParList = []} . + +eventParameters -> 'COMMA' eventParameter eventParameters : + ['$2' | '$3'] . +eventParameters -> '$empty' : [] . + +%% at-most-once each of embedOrKeepActive , eventDM or eventStream +eventParameter -> 'KeepActiveToken' : keepActive . +eventParameter -> embedWithSig : '$1'. +eventParameter -> embedNoSig : '$1'. +eventParameter -> eventDM : '$1'. +eventParameter -> eventStreamOrOther : '$1'. + +embedWithSig -> 'EmbedToken' 'LBRKT' signalsDescriptor + 'COMMA' embedFirst 'RBRKT' + : {embed, '$3', '$5'} . +embedWithSig -> 'EmbedToken' 'LBRKT' signalsDescriptor 'RBRKT' + : {embed, '$3', asn1_NOVALUE} . + +embedNoSig -> 'EmbedToken' 'LBRKT' embedFirst 'RBRKT' + : {embed, asn1_NOVALUE, '$3'} . + +embedFirst -> 'EventsToken' : + #'SecondEventsDescriptor'{requestID = asn1_NOVALUE, + eventList = []} . +embedFirst -> 'EventsToken' 'EQUAL' requestID + 'LBRKT' secondRequestedEvent secondRequestedEvents 'RBRKT' : + #'SecondEventsDescriptor'{requestID = '$3', + eventList = ['$5' | '$6']} . + +secondRequestedEvents -> 'COMMA' secondRequestedEvent secondRequestedEvents : ['$2' | '$3'] . +secondRequestedEvents -> '$empty' : [] . + +%% at-most-once of each +secondRequestedEvent -> pkgdName secondRequestedEventBody + : setelement(#'SecondRequestedEvent'.pkgdName, '$2', '$1') . + +secondRequestedEventBody -> 'LBRKT' secondEventParameter secondEventParameters 'RBRKT' + : merge_secondEventParameters(['$2' | '$3']) . +secondRequestedEventBody -> '$empty' : #'SecondRequestedEvent'{evParList = []} . + +secondEventParameters -> 'COMMA' secondEventParameter secondEventParameters : ['$2' | '$3'] . +secondEventParameters -> '$empty' : [] . + +%% at-most-once each of embedOrKeepActive , eventDM or eventStream +secondEventParameter -> 'KeepActiveToken' : keepActive . +secondEventParameter -> embedSig : '$1' . +secondEventParameter -> eventDM : '$1' . +secondEventParameter -> eventStreamOrOther : '$1' . + +embedSig -> 'EmbedToken' 'LBRKT' signalsDescriptor 'RBRKT' + : {second_embed, '$3'} . + +eventStreamOrOther -> eventParameterName parmValue : + select_stream_or_other('$1', '$2') . + +eventParameterName -> safeToken : ensure_NAME('$1') . + +%% The DigitMapDescriptorToken is specially treated by the scanner +eventDM -> 'DigitMapDescriptorToken' : + ensure_eventDM('$1') . + +%% H248S-IG (IGv11) +signalsDescriptor -> 'SignalsToken' 'LBRKT' signalParm signalParms 'RBRKT' : + ['$3' | '$4'] . +signalsDescriptor -> 'SignalsToken' : [] . + +signalParms -> 'COMMA' signalParm signalParms : [ '$2' | '$3'] . +signalParms -> '$empty' : [] . + +signalParm -> signalList : {seqSigList, '$1'} . +signalParm -> signalRequest : {signal, '$1'} . + +signalRequest -> signalName 'LBRKT' sigParameter sigParameters 'RBRKT' + : merge_signalRequest('$1', ['$3' | '$4']). +signalRequest -> signalName : merge_signalRequest('$1', []). + +sigParameters -> 'COMMA' sigParameter sigParameters : ['$2' | '$3'] . +sigParameters -> '$empty' : [] . + +%% sigParameter = sigStream / sigSignalType / sigDuration / sigOther +%% / notifyCompletion / KeepActiveToken +%% sigStream = StreamToken EQUAL StreamID +%% sigOther = sigParameterName parmValue +%% sigParameterName = NAME +%% sigSignalType = SignalTypeToken EQUAL signalType +%% signalType = (OnOffToken / TimeOutToken / BriefToken) +%% sigDuration = DurationToken EQUAL UINT16 +%% notifyCompletion = NotifyCompletionToken EQUAL (LBRKT +%% notificationReason *(COMMA notificationReason) RBRKT +%% +%% notificationReason = ( TimeOutToken / InterruptByEventToken +%% / InterruptByNewSignalsDescrToken +%% / OtherReasonToken ) + +sigParameter -> 'StreamToken' 'EQUAL' streamID : {stream, '$3'}. +sigParameter -> 'SignalTypeToken' 'EQUAL' signalType : {signal_type, '$3'} . +sigParameter -> 'DurationToken' 'EQUAL' safeToken : {duration, ensure_uint16('$3')} . +sigParameter -> safeToken parmValue : {other, ensure_NAME('$1'), '$2'}. +sigParameter -> 'NotifyCompletionToken' 'EQUAL' + 'LBRKT' notificationReason notificationReasons 'RBRKT' + : {notify_completion, ['$4' | '$5']} . +sigParameter -> 'KeepActiveToken' : keepActive . + +signalType -> 'OnOffToken' : onOff. +signalType -> 'TimeOutToken' : timeOut. +signalType -> 'BriefToken' : brief. + +notificationReasons -> 'COMMA' notificationReason notificationReasons : ['$2' | '$3'] . +notificationReasons -> '$empty' : [] . + +notificationReason -> 'TimeOutToken' : onTimeOut . +notificationReason -> 'InterruptByEventToken' : onInterruptByEvent . +notificationReason -> 'InterruptByNewSignalsDescrToken' : onInterruptByNewSignalDescr . +notificationReason -> 'OtherReasonToken' : otherReason . + +signalList -> 'SignalListToken' 'EQUAL' signalListId + 'LBRKT' signalListParm signalListParms 'RBRKT' + : #'SeqSigList'{id = ensure_uint16('$3'), + signalList = ['$5' | '$6']} . + +signalListParms -> 'COMMA' signalListParm signalListParms : + ['$2' | '$3'] . +signalListParms -> '$empty' : [] . + +signalListId -> safeToken : ensure_uint16('$1') . + +%% exactly once signalType, +%% at most once duration and every signal parameter +signalListParm -> signalRequest : '$1'. + +signalName -> pkgdName : '$1'. + +observedEventsDescriptor -> 'ObservedEventsToken' 'EQUAL' requestID + 'LBRKT' observedEvent observedEvents 'RBRKT' + : #'ObservedEventsDescriptor'{requestId = '$3', + observedEventLst = ['$5' | '$6']} . + +observedEvents -> 'COMMA' observedEvent observedEvents : ['$2' | '$3'] . +observedEvents -> '$empty' : [] . + +%%time per event, because it might be buffered + +observedEvent -> timeStamp optSep 'COLON' optSep pkgdName observedEventBody : + merge_observed_event('$6', '$5', '$1') . +observedEvent -> optSep pkgdName observedEventBody : + merge_observed_event('$3', '$2', asn1_NOVALUE) . + +observedEventBody -> 'LBRKT' observedEventParameter + observedEventParameters 'RBRKT' + : ['$2' | '$3'] . +observedEventBody -> '$empty' : [] . + +observedEventParameters -> 'COMMA' observedEventParameter observedEventParameters : ['$2' | '$3'] . +observedEventParameters -> '$empty' : [] . + +%%at-most-once eventStream, every eventParameterName at most once +observedEventParameter -> eventStreamOrOther : '$1' . + +requestID -> safeToken : ensure_requestID('$1') . + +%% Deprecated as of Corr 1 +modemDescriptor -> 'ModemToken' 'EQUAL' modemType optPropertyParms . +modemDescriptor -> 'ModemToken' 'LSBRKT' modemType modemTypeList 'RSBRKT' + optPropertyParms. +modemTypeList -> 'COMMA' modemType modemTypeList. +modemTypeList -> '$empty'. +modemType -> safeToken. + +optPropertyParms -> 'LBRKT' propertyParm propertyParms 'RBRKT' : + ['$2' | '$3'] . +optPropertyParms -> '$empty' : [] . + +propertyParms -> 'COMMA' propertyParm propertyParms : ['$2' | '$3'] . +propertyParms -> '$empty' : [] . + +% parmName -> safeToken : ensure_NAME('$1') . + +%% The DigitMapDescriptorToken is specially treated by the scanner +digitMapDescriptor -> 'DigitMapDescriptorToken' : + ensure_DMD('$1') . + +%% each parameter at-most-once, except auditItem +%% at most one of either serviceChangeAddress or serviceChangeMgcId but +%% not both. serviceChangeMethod and serviceChangeReason are REQUIRED +serviceChangeDescriptor -> 'ServicesToken' + 'LBRKT' serviceChangeParm + serviceChangeParms 'RBRKT' : + merge_ServiceChangeParm(['$3' | '$4']) . + +serviceChangeParms -> 'COMMA' serviceChangeParm serviceChangeParms : + ['$2' | '$3'] . +serviceChangeParms -> '$empty' : [] . + +serviceChangeParm -> serviceChangeMethod : {method, '$1'} . +serviceChangeParm -> serviceChangeReason : {reason, '$1'} . +serviceChangeParm -> serviceChangeDelay : {delay, '$1'} . +serviceChangeParm -> serviceChangeAddress : {address, '$1'} . +serviceChangeParm -> serviceChangeProfile : {profile, '$1'} . +serviceChangeParm -> extension : {extension, '$1'} . +serviceChangeParm -> timeStamp : {time_stamp, '$1'} . +serviceChangeParm -> serviceChangeMgcId : {mgc_id, '$1'} . +serviceChangeParm -> serviceChangeVersion : {version, '$1'} . +serviceChangeParm -> auditItem : {audit_item, '$1'} . % v2 + +serviceChangeMethod -> 'MethodToken' 'EQUAL' safeToken : ensure_serviceChangeMethod('$3') . + +serviceChangeReason -> 'ReasonToken' 'EQUAL' value : ['$3'] . + +serviceChangeDelay -> 'DelayToken' 'EQUAL' safeToken : ensure_uint32('$3'). + +serviceChangeAddress -> 'ServiceChangeAddressToken' 'EQUAL' mId : '$3' . +serviceChangeAddress -> 'ServiceChangeAddressToken' 'EQUAL' portNumber : + {portNumber, '$3'} . + +serviceChangeMgcId -> 'MgcIdToken' 'EQUAL' mId : '$3' . + +serviceChangeProfile -> 'ProfileToken' 'EQUAL' safeToken : ensure_profile('$3'). + +serviceChangeVersion -> 'VersionToken' 'EQUAL' safeToken : ensure_version('$3') . + +extension -> extensionParameter parmValue + : setelement(#'PropertyParm'.name, '$2', '$1') . + +%% at most once. Version is REQUIRED on first ServiceChange response +%% at most of either serviceChangeAddress or serviceChangeMgcId but not both +serviceChangeReplyDescriptor -> 'ServicesToken' + 'LBRKT' servChgReplyParm + servChgReplyParms 'RBRKT' : + merge_ServiceChangeResParm(['$3' | '$4']) . + +servChgReplyParms -> 'COMMA' servChgReplyParm servChgReplyParms : + ['$2' | '$3'] . +servChgReplyParms -> '$empty' : [] . + +servChgReplyParm -> serviceChangeAddress : {address, '$1'} . +servChgReplyParm -> serviceChangeMgcId : {mgc_id, '$1'} . +servChgReplyParm -> serviceChangeProfile : {profile, '$1'} . +servChgReplyParm -> serviceChangeVersion : {version, '$1'} . +servChgReplyParm -> timeStamp : {time_stamp,'$1'} . + +packagesDescriptor -> 'PackagesToken' 'LBRKT' packagesItem packagesItems 'RBRKT' + : ['$3' | '$4'] . + +packagesItems -> 'COMMA' packagesItem packagesItems : ['$2' | '$3'] . +packagesItems -> '$empty' : [] . + +packagesItem -> safeToken : ensure_packagesItem('$1') . + +timeStamp -> TimeStampToken : ensure_timeStamp('$1') . + +statisticsDescriptor -> 'StatsToken' + 'LBRKT' statisticsParameter statisticsParameters 'RBRKT' + : ['$3' | '$4'] . + +statisticsParameters -> 'COMMA' statisticsParameter statisticsParameters : ['$2' | '$3'] . +statisticsParameters -> '$empty' : [] . + +%%at-most-once per item +statisticsParameter -> pkgdName + : #'StatisticsParameter'{statName = '$1', + statValue = asn1_NOVALUE} . +statisticsParameter -> pkgdName 'EQUAL' value + : #'StatisticsParameter'{statName = '$1', + statValue = ['$3']} . + +topologyDescriptor -> 'TopologyToken' 'LBRKT' topologyTriple + topologyTripleList 'RBRKT' : ['$3' | '$4'] . + +terminationA -> terminationID : '$1' . + +terminationB -> terminationID : '$1' . + +topologyTriple -> terminationA 'COMMA' terminationB 'COMMA' + topologyDirection 'COMMA' eventStream : + #'TopologyRequest'{terminationFrom = '$1', + terminationTo = '$3', + topologyDirection = '$5', + streamID = '$7'} . +topologyTriple -> terminationA 'COMMA' terminationB 'COMMA' + topologyDirection : + #'TopologyRequest'{terminationFrom = '$1', + terminationTo = '$3', + topologyDirection = '$5'} . + +topologyTripleList -> '$empty' : [] . +topologyTripleList -> 'COMMA' topologyTriple topologyTripleList : + ['$2' | '$3'] . + +topologyDirection -> 'BothwayToken' : bothway . +topologyDirection -> 'IsolateToken' : isolate . +topologyDirection -> 'OnewayToken' : oneway . + +priority -> 'PriorityToken' 'EQUAL' safeToken : ensure_uint16('$3') . + +extensionParameter -> safeToken : ensure_extensionParameter('$1') . + +value -> 'QuotedChars' : + ensure_value('$1') . +value -> safeToken : + ensure_value('$1'). + +safeToken -> safeToken2 : make_safe_token('$1') . + +safeToken2 -> 'SafeChars' : '$1' . +safeToken2 -> 'AddToken' : '$1' . +safeToken2 -> 'AuditToken' : '$1' . +safeToken2 -> 'AuditCapToken' : '$1' . +safeToken2 -> 'AuditValueToken' : '$1' . +safeToken2 -> 'AuthToken' : '$1' . +safeToken2 -> 'BothwayToken' : '$1' . +safeToken2 -> 'BriefToken' : '$1' . +safeToken2 -> 'BufferToken' : '$1' . +safeToken2 -> 'CtxToken' : '$1' . +%% safeToken2 -> 'ContextAttrToken' : '$1' . +safeToken2 -> 'ContextAuditToken' : '$1' . +%% v2-safeToken2 -> 'DigitMapToken' : '$1' . +%% safeToken2 -> 'DigitMapDescriptorToken' : '$1' . +safeToken2 -> 'DiscardToken' : '$1' . +safeToken2 -> 'DisconnectedToken' : '$1' . +safeToken2 -> 'DelayToken' : '$1' . +safeToken2 -> 'DurationToken' : '$1' . +safeToken2 -> 'EmbedToken' : '$1' . +safeToken2 -> 'EmergencyToken' : '$1' . +safeToken2 -> 'EmergencyOffToken' : '$1' . +safeToken2 -> 'ErrorToken' : '$1' . +%% v2-safeToken2 -> 'EventBufferToken' : '$1' . +%% v2-safeToken2 -> 'EventsToken' : '$1' . +safeToken2 -> 'FailoverToken' : '$1' . +safeToken2 -> 'ForcedToken' : '$1' . +safeToken2 -> 'GracefulToken' : '$1' . +safeToken2 -> 'H221Token' : '$1' . +safeToken2 -> 'H223Token' : '$1' . +safeToken2 -> 'H226Token' : '$1' . +safeToken2 -> 'HandOffToken' : '$1' . +safeToken2 -> 'ImmAckRequiredToken' : '$1' . +safeToken2 -> 'InactiveToken' : '$1' . +safeToken2 -> 'InterruptByEventToken' : '$1' . +safeToken2 -> 'InterruptByNewSignalsDescrToken' : '$1' . +safeToken2 -> 'IsolateToken' : '$1' . +safeToken2 -> 'InSvcToken' : '$1' . +safeToken2 -> 'KeepActiveToken' : '$1' . +%% safeToken2 -> 'LocalToken' : '$1' . +%% safeToken2 -> 'LocalDescriptorToken' : '$1' . +safeToken2 -> 'LocalControlToken' : '$1' . +safeToken2 -> 'LoopbackToken' : '$1' . +safeToken2 -> 'LockStepToken' : '$1' . +%% v2-safeToken2 -> 'MediaToken' : '$1' . +%% safeToken2 -> 'MegacopToken' : '$1' . +safeToken2 -> 'MethodToken' : '$1' . +safeToken2 -> 'MgcIdToken' : '$1' . +safeToken2 -> 'ModeToken' : '$1' . +safeToken2 -> 'ModifyToken' : '$1' . +%% v2-safeToken2 -> 'ModemToken' : '$1' . +safeToken2 -> 'MoveToken' : '$1' . +%% safeToken2 -> 'MtpToken' : '$1' . +%% safeToken2 -> 'MtpAddressToken' : '$1' . +%% v2-safeToken2 -> 'MuxToken' : '$1' . +safeToken2 -> 'NotifyToken' : '$1' . +safeToken2 -> 'NotifyCompletionToken' : '$1' . +safeToken2 -> 'Nx64kToken' : '$1' . +%% v2-safeToken2 -> 'ObservedEventsToken' : '$1' . +safeToken2 -> 'OnewayToken' : '$1' . +safeToken2 -> 'OffToken' : '$1' . +safeToken2 -> 'OnToken' : '$1' . +safeToken2 -> 'OnOffToken' : '$1' . +safeToken2 -> 'OutOfSvcToken' : '$1' . +safeToken2 -> 'OtherReasonToken' : '$1' . +%% v2-safeToken2 -> 'PackagesToken' : '$1' . +safeToken2 -> 'PendingToken' : '$1' . +safeToken2 -> 'PriorityToken' : '$1' . +safeToken2 -> 'ProfileToken' : '$1' . +safeToken2 -> 'ReasonToken' : '$1' . +safeToken2 -> 'RecvonlyToken' : '$1' . +safeToken2 -> 'ReplyToken' : '$1' . +safeToken2 -> 'ResponseAckToken' : '$1' . +safeToken2 -> 'RestartToken' : '$1' . +%% safeToken2 -> 'RemoteToken' : '$1' . +%% safeToken2 -> 'RemoteDescriptorToken' : '$1' . +safeToken2 -> 'ReservedGroupToken' : '$1' . +safeToken2 -> 'ReservedValueToken' : '$1' . +safeToken2 -> 'SendonlyToken' : '$1' . +safeToken2 -> 'SendrecvToken' : '$1' . +safeToken2 -> 'ServicesToken' : '$1' . +safeToken2 -> 'ServiceStatesToken' : '$1' . +safeToken2 -> 'ServiceChangeToken' : '$1' . +safeToken2 -> 'ServiceChangeAddressToken' : '$1' . +safeToken2 -> 'SignalListToken' : '$1' . +%% v2-safeToken2 -> 'SignalsToken' : '$1' . +safeToken2 -> 'SignalTypeToken' : '$1' . +%% v2-safeToken2 -> 'StatsToken' : '$1' . +safeToken2 -> 'StreamToken' : '$1' . +safeToken2 -> 'SubtractToken' : '$1' . +safeToken2 -> 'SynchISDNToken' : '$1' . +safeToken2 -> 'TerminationStateToken' : '$1' . +safeToken2 -> 'TestToken' : '$1' . +safeToken2 -> 'TimeOutToken' : '$1' . +safeToken2 -> 'TimeStampToken' : '$1' . +safeToken2 -> 'TopologyToken' : '$1' . +safeToken2 -> 'TransToken' : '$1' . +safeToken2 -> 'V18Token' : '$1' . +safeToken2 -> 'V22Token' : '$1' . +safeToken2 -> 'V22bisToken' : '$1' . +safeToken2 -> 'V32Token' : '$1' . +safeToken2 -> 'V32bisToken' : '$1' . +safeToken2 -> 'V34Token' : '$1' . +safeToken2 -> 'V76Token' : '$1' . +safeToken2 -> 'V90Token' : '$1' . +safeToken2 -> 'V91Token' : '$1' . +safeToken2 -> 'VersionToken' : '$1' . +%% <OTP-7534> +safeToken2 -> 'AndAUDITSelectToken' : '$1' . +safeToken2 -> 'BothToken' : '$1' . +safeToken2 -> 'ContextAttrToken' : '$1' . +safeToken2 -> 'ContextListToken' : '$1' . +safeToken2 -> 'DirectionToken' : '$1' . +%% safeToken2 -> 'EmergencyOffToken' : '$1' . +safeToken2 -> 'EmergencyValueToken' : '$1' . +safeToken2 -> 'ExternalToken' : '$1' . +safeToken2 -> 'IEPSToken' : '$1' . +safeToken2 -> 'InternalToken' : '$1' . +safeToken2 -> 'IntsigDelayToken' : '$1' . +safeToken2 -> 'IterationToken' : '$1' . +safeToken2 -> 'MessageSegmentToken' : '$1' . +safeToken2 -> 'NeverNotifyToken' : '$1' . +safeToken2 -> 'NotifyImmediateToken' : '$1' . +safeToken2 -> 'NotifyRegulatedToken' : '$1' . +safeToken2 -> 'OnewayBothToken' : '$1' . +safeToken2 -> 'OnewayExternalToken' : '$1' . +safeToken2 -> 'OrAUDITselectToken' : '$1' . +safeToken2 -> 'RequestIDToken' : '$1' . +safeToken2 -> 'ResetEventsDescriptorToken' : '$1' . +safeToken2 -> 'SegmentationCompleteToken' : '$1' . +safeToken2 -> 'ServiceChangeIncompleteToken' : '$1' . +%% </OTP-7534> + + +Erlang code. + +%% The following directive is needed for (significantly) faster compilation +%% of the generated .erl file by the HiPE compiler. Please do not remove. +-compile([{hipe,[{regalloc,linear_scan}]}]). + +-include("megaco_text_parser_v2.hrl"). + + diff --git a/lib/megaco/src/text/megaco_text_parser_v3.hrl b/lib/megaco/src/text/megaco_text_parser_v3.hrl new file mode 100644 index 0000000000..9f68fb6127 --- /dev/null +++ b/lib/megaco/src/text/megaco_text_parser_v3.hrl @@ -0,0 +1,2002 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2005-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 : Define semantic text parser actions +%%---------------------------------------------------------------------- + + +-include_lib("megaco/include/megaco.hrl"). +-include_lib("megaco/include/megaco_message_v3.hrl"). +-include("megaco_text_tokens.hrl"). + +-ifdef(megaco_parser_inline). +-compile({inline,[{make_safe_token,1}]}). +-endif. +make_safe_token(Token) -> + {_TokenTag, Line, Text} = Token, + {safeToken, Line, Text}. + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_value,1}]}). +-endif. +ensure_value(Token) -> + case Token of + {safeToken, _Line, Text} when is_list(Text) -> + Text; % We really should ensure length + {'QuotedChars', _Line, Text} when is_list(Text) -> + Text; % We really should ensure length + Text when is_list(Text) -> + Text % We really should ensure length + end. + +%% NAME = ALPHA *63(ALPHA / DIGIT / "_" ) +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_NAME,1}]}). +-endif. +ensure_NAME(Token) -> + {_TokenTag, _Line, Text} = Token, + Text. %% BUGBUG: ensure length and chars + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_requestID,1}]}). +-endif. +ensure_requestID(Token) -> + case Token of + {safeToken, _Line, "*"} -> + ?megaco_all_request_id; + _ -> + ensure_uint32(Token) + end. + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_streamID,1}]}). +-endif. +ensure_streamID(StreamId) -> + ensure_uint16(StreamId). + +ensure_auth_header(SpiToken, SnToken, AdToken) -> + Spi = ensure_hex(SpiToken, 8, 8), + Sn = ensure_hex(SnToken, 8, 8), + Ad = ensure_hex(AdToken, 24, 64), + #'AuthenticationHeader'{secParmIndex = Spi, seqNum = Sn, ad = Ad}. + +%% ContextID = (UINT32 / "*" / "-" / "$") +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_contextID,1}]}). +-endif. +ensure_contextID(Token) -> + {_TokenTag, Line, Text} = Token, + case Text of + "*" -> ?megaco_all_context_id; + "-" -> ?megaco_null_context_id; + "\$" -> ?megaco_choose_context_id; + Int -> + CID = ensure_uint32(Int), + if + (CID =/= 0) andalso + (CID =/= 16#FFFFFFFE) andalso + (CID =/= 16#FFFFFFFF) -> + CID; + true -> + return_error(Line, {bad_ContextID, CID}) + end + end. + +ensure_domainAddress([{_T, _L, _A} = Addr0], Port) -> + Addr = ensure_ip4addr(Addr0), + {ip4Address, #'IP4Address'{address = Addr, portNumber = Port}}; +ensure_domainAddress([colon,colon], Port) -> + Addr = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + {ip6Address, #'IP6Address'{address = Addr, portNumber = Port}}; +ensure_domainAddress(Addr0, Port) -> + Addr = ensure_ip6addr(Addr0), + {ip6Address, #'IP6Address'{address = Addr, portNumber = Port}}. + + +ensure_ip4addr(Token) -> + {_TokenTag, Line, Addr} = Token, + case split_ip4addr_text(Addr, []) of + [T1, T2, T3, T4] -> + %% We optimize by sending only the text part (Addr) of + %% the token to the function. + %% If something is wrong, then we do not get a proper + %% position and therefor we catch and sendissue the + %% the error again (with the proper line number). + case (catch [ + ensure_uint(T1, 0, 255), + ensure_uint(T2, 0, 255), + ensure_uint(T3, 0, 255), + ensure_uint(T4, 0, 255) + ]) of + A when is_list(A) -> + A; + _ -> + return_error(Line, {bad_IP4address, Addr}) + end; + _ -> + return_error(Line, {bad_IP4address, Addr}) + end. + +split_ip4addr_text([], Acc) -> + [ lists:reverse(Acc) ]; +split_ip4addr_text([$. | Rest], Acc) -> + [ lists:reverse(Acc) | split_ip4addr_text(Rest, []) ]; +split_ip4addr_text([H | T], Acc) -> + split_ip4addr_text(T, [H | Acc]). + + +ensure_ip6addr([colon,colon|T]) -> + [H1|T1] = lists:reverse(T), + case do_ensure_ip6addr(T1, true, [ensure_hex4_or_ip4addr(H1)], 1) of + {true, A} when length(A) =:= 16 -> + A; + {true, B} when length(B) < 16 -> + lists:duplicate(16 - length(B), 0) ++ B; + {true, C} -> + throw({error, {?MODULE, {bad_mid_ip6addr_length, C}}}) + end; +ensure_ip6addr(L) -> + case lists:reverse(L) of + [colon, colon| T] -> + case do_ensure_ip6addr(T, true, [], 1) of + {true, A} when length(A) =:= 16 -> + A; + {true, B} when length(B) < 16 -> + B ++ lists:duplicate(16 - length(B), 0); + {true, C} -> + throw({error, {?MODULE, {bad_mid_ip6addr_length, C}}}) + end; + [H|L1] -> % A (last element) could be an ip4 address + case do_ensure_ip6addr(L1,false,[ensure_hex4_or_ip4addr(H)],1) of + {false, A} when length(A) =:= 16 -> + A; + %% allow a pad even if the address is full (i.e. 16) + {true, B} when length(B) =< 17 -> + do_ensure_ip6addr_padding(B, 0); + {Pad, C} -> + throw({error, {?MODULE, {bad_mid_ip6addr_length, Pad, C}}}) + end + + end. + + +do_ensure_ip6addr([], Pad, Acc, _) -> + {Pad, lists:flatten(Acc)}; +do_ensure_ip6addr([colon,colon|T], false, Acc, Line) -> + do_ensure_ip6addr(T, true, [pad|Acc], Line); +do_ensure_ip6addr([colon,colon|T], true, Acc, Line) -> + return_error(Line, {bad_mid_duplicate_padding, T, Acc}); +do_ensure_ip6addr([colon|T], Pad, Acc, Line) -> + do_ensure_ip6addr(T, Pad, Acc, Line); +do_ensure_ip6addr([{_, Line, _} = A|T], Pad, Acc, _) -> + do_ensure_ip6addr(T, Pad, [ensure_hex4(A)|Acc], Line). + +do_ensure_ip6addr_padding([], _) -> + []; +do_ensure_ip6addr_padding([pad|T], N) -> + lists:duplicate(16 - (N + length(T)), 0) ++ T; +do_ensure_ip6addr_padding([H|T], N) -> + [H|do_ensure_ip6addr_padding(T, N+1)]. + +ensure_hex4_or_ip4addr({TokenTag, Line, Addr} = V) -> + case string:tokens(Addr, [$.]) of + [T1, T2, T3, T4] -> + A1 = ensure_uint({TokenTag, Line, T1}, 0, 255), + A2 = ensure_uint({TokenTag, Line, T2}, 0, 255), + A3 = ensure_uint({TokenTag, Line, T3}, 0, 255), + A4 = ensure_uint({TokenTag, Line, T4}, 0, 255), + [A1, A2, A3, A4]; + _ -> + ensure_hex4(V) + %% %% BMK BMK BMK + %% %% Here we should test for hexseq + %% return_error(Line, {bad_IP4address, Addr}) + end. + +ensure_hex4({_TokenTag, Line, Hex4}) + when (length(Hex4) =< 4) andalso (length(Hex4) > 0) -> + case (catch do_ensure_hex4(Hex4)) of + IL when is_list(IL) andalso (length(IL) =:= 2) -> + IL; + Error -> + return_error(Line, {bad_hex4, Hex4, Error}) + end. + +do_ensure_hex4([_H1, _H2, _H3, _H4] = H) -> + hex_to_int(H, []); +do_ensure_hex4([H2, H3, H4]) -> + hex_to_int([$0, H2, H3, H4], []); +do_ensure_hex4([H3, H4]) -> + hex_to_int([$0, $0, H3, H4], []); +do_ensure_hex4([H4]) -> + hex_to_int([$0, $0, $0, H4], []). + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_domainName,2}]}). +-endif. +ensure_domainName(Token, Port) -> + {_TokenTag, _Line, Name} = Token, + %% BUGBUG: we should really validate name + {domainName, #'DomainName'{name = Name, portNumber = Port}}. + +%% extensionParameter= "X" ("-" / "+") 1*6(ALPHA / DIGIT) +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_extensionParameter,1}]}). +-endif. +ensure_extensionParameter(Token) -> + {_TokenTag, Line, Text} = Token, + case Text of + [X, S | _Chars] -> + if + (X =/= $X) andalso (X =/= $x) andalso + (S =/= $+) andalso (S =/= $-) -> + return_error(Line, {bad_extension_parameter, Text}); + true -> + {extension_parameter, Text} + end; + _ -> + return_error(Line, {bad_extension_parameter, Text}) + end. + +ensure_message(MegacopToken, MID, Body) -> +%% #'ServiceChangeProfile'{profileName = Name, +%% version = Version} = +%% ensure_profile(MegacopToken), +%% case Name of +%% "megaco" -> +%% #'Message'{version = Version, mId = MID, messageBody = Body}; +%% [$!] -> +%% #'Message'{version = Version, mId = MID, messageBody = Body} +%% end. + {_TokenTag, Line, Text} = MegacopToken, + case split_Megacop(Text, []) of + {Name, Version} -> + Version2 = ensure_version(Version), + case Name of + "megaco" -> + #'Message'{version = Version2, + mId = MID, + messageBody = Body}; + [$!] -> + #'Message'{version = Version2, + mId = MID, + messageBody = Body} + end; + _ -> + return_error(Line, {bad_name_or_version, Text}) + end. + +split_Megacop([], _) -> + error; +split_Megacop([$/ | Version], Acc) -> + {lists:reverse(Acc), Version}; +split_Megacop([H | T], Acc) -> + split_Megacop(T, [H | Acc]). + + +%% Corr1: +%% As of corr 1 ModemDescriptor has been deprecated. +%% and since this functon is only used when creating +%% a ModemDescriptor, iit is removed. +%% modemType = (V32bisToken / V22bisToken / V18Token / +%% V22Token / V32Token / V34Token / V90Token / +%% V91Token / SynchISDNToken / extensionParameter) +%% ensure_modemType({_TokenTag, _Line, Text} = Token) -> +%% case Text of +%% "v32b" -> v32bis; +%% "v22b" -> v22bis; +%% "v18" -> v18; +%% "v22" -> v22; +%% "v32" -> v32; +%% "v34" -> v34; +%% "v90" -> v90; +%% "v91" -> v91; +%% "synchisdn" -> synchISDN; +%% "sn" -> synchISDN; +%% [$x | _] -> ensure_extensionParameter(Token) +%% end. + +%% An mtp address is five octets long +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_mtpAddress,1}]}). +-endif. +ensure_mtpAddress(Token) -> + {_TokenTag, _Line, Addr} = Token, + %% BUGBUG: validate address + {mtpAddress, Addr}. + +%% MuxType = ( H221Token / H223Token / H226Token / V76Token / extensionParameter ) +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_muxType,1}]}). +-endif. +ensure_muxType(Token) -> + {_TokenTag, _Line, Text} = Token, + case Text of + "h221" -> h221; + "h223" -> h223; + "h226" -> h226; + "v76" -> v76; + "nx64k" -> nx64k; % v2 + [$x | _] -> ensure_extensionParameter(Token) + end. + +%% packagesItem = NAME "-" UINT16 +%% NAME = ALPHA *63(ALPHA / DIGIT / "_" ) +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_packagesItem,1}]}). +-endif. +ensure_packagesItem(Token) -> + {_TokenTag, Line, Text} = Token, + case split_packagesItem(Text, []) of + {Name, Version} -> + %% As we don't ensure length of the names, there is no point + %% in doing the ensure_NAME thing... + #'PackagesItem'{packageName = Name, + packageVersion = ensure_uint(Version, 0, 99)}; + _ -> + return_error(Line, {bad_PackagesItem, Text}) + end. + +split_packagesItem([], _) -> + error; +split_packagesItem([$- | Version], Acc) -> + {lists:reverse(Acc), Version}; +split_packagesItem([H|T], Acc) -> + split_packagesItem(T, [H|Acc]). + + +%% pkgdName = (PackageName / "*") SLASH (ItemID / "*" ) +%% PackageName = NAME +%% ItemID = NAME +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_pkgdName,1}]}). +-endif. +ensure_pkgdName(Token) -> + {_TokenTag, Line, Text} = Token, + case ensure_pkgdName(Text, []) of + ok -> + %% As we don't really do any checks on the strings + %% (length or content) there is really no point in + %% "ensuring" the name and item part of the + %% package name + %% ensure_name_or_star(Name), + %% ensure_name_or_star(Item), + Text; + _ -> + return_error(Line, {bad_pkgdName, Text}) + end. + +ensure_pkgdName([], _) -> + error; +ensure_pkgdName([$/ | T], Acc) + when ((length(T) > 0) andalso (length(Acc) > 0)) -> + ok; +ensure_pkgdName([H | T], Acc) -> + ensure_pkgdName(T, [H | Acc]). + + +%% -compile({inline,[{ensure_name_or_star,1}]}). +%% ensure_name_or_star(Val) -> +%% %% case Token of +%% %% {_, _, Name} when Name =:= "*" -> +%% %% Name; +%% %% _ -> +%% %% ensure_NAME(Token) +%% %% end. +%% if +%% Val =:= "*" -> +%% Val; +%% true -> +%% %% as we don't really validate the text part of the token(s), +%% %% we can just return the value assuming it to be correct... +%% Val +%% end. + + +%% v2 - start + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_indAudMediaDescriptor,1}]}). +-endif. +merge_indAudMediaDescriptor(Vals) -> + merge_indAudMediaDescriptor(Vals, #'IndAudMediaDescriptor'{}). + +merge_indAudMediaDescriptor( + [], #'IndAudMediaDescriptor'{streams = Streams1} = D) -> + Streams2 = + case Streams1 of + {multiStream, Descs} -> + {multiStream, lists:reverse(Descs)}; + _ -> + Streams1 + end, + D#'IndAudMediaDescriptor'{streams = Streams2}; +merge_indAudMediaDescriptor([{termStateDescr, Val}|Vals], D) + when D#'IndAudMediaDescriptor'.termStateDescr =:= asn1_NOVALUE -> + D2 = #'IndAudMediaDescriptor'{termStateDescr = Val}, + merge_indAudMediaDescriptor(Vals, D2); +merge_indAudMediaDescriptor([{streamParm, Val}|Vals], D) + when D#'IndAudMediaDescriptor'.streams =:= asn1_NOVALUE -> + D2 = #'IndAudMediaDescriptor'{streams = {oneStream, Val}}, + merge_indAudMediaDescriptor(Vals, D2); +merge_indAudMediaDescriptor([{streamDescr, Val}|Vals], D) + when D#'IndAudMediaDescriptor'.streams =:= asn1_NOVALUE -> + D2 = #'IndAudMediaDescriptor'{streams = {multiStream, [Val]}}, + merge_indAudMediaDescriptor(Vals, D2); +merge_indAudMediaDescriptor([{streamDescr, Val}|Vals], + #'IndAudMediaDescriptor'{streams = Streams1} = D1) -> + Streams2 = + case Streams1 of + {multiStream, Descs} -> + {multiStream, [Val|Descs]}; + _ -> + return_error(0, {bad_IndAudMediaDescriptor_streamDescr, + Val, Streams1}) + end, + D2 = D1#'IndAudMediaDescriptor'{streams = Streams2}, + merge_indAudMediaDescriptor(Vals, D2); +merge_indAudMediaDescriptor([{Tag, Val}|_], D) -> + case Tag of + termStateDescr -> + return_error(0, {bad_IndAudMediaDescriptor_termStateDescr, + Val, D#'IndAudMediaDescriptor'.termStateDescr}); + streamParm -> + return_error(0, {bad_IndAudMediaDescriptor_streamParm, + Val, D#'IndAudMediaDescriptor'.streams}); + streamDescr -> + return_error(0, {bad_IndAudMediaDescriptor_streamDescr, + Val, D#'IndAudMediaDescriptor'.streams}); + _ -> + return_error(0, {bad_IndAudMediaDescriptor_tag, Tag, Val}) + end. + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_indAudLocalControlDescriptor,1}]}). +-endif. +merge_indAudLocalControlDescriptor(Parms) -> + merge_indAudLocalControlDescriptor(Parms, + #'IndAudLocalControlDescriptor'{}, + asn1_NOVALUE). + +merge_indAudLocalControlDescriptor([modeToken | Parms], D, PP) + when (D#'IndAudLocalControlDescriptor'.streamMode =:= asn1_NOVALUE) andalso + (D#'IndAudLocalControlDescriptor'.streamModeSel =:= asn1_NOVALUE) -> + D2 = D#'IndAudLocalControlDescriptor'{streamMode = 'NULL'}, + merge_indAudLocalControlDescriptor(Parms, D2, PP); + +merge_indAudLocalControlDescriptor([modeToken | Parms], D, PP) + when (D#'IndAudLocalControlDescriptor'.streamMode =:= asn1_NOVALUE) -> + merge_indAudLocalControlDescriptor(Parms, D, PP); + +merge_indAudLocalControlDescriptor([{mode, Val} | Parms], D, PP) + when (D#'IndAudLocalControlDescriptor'.streamMode =:= asn1_NOVALUE) andalso + (D#'IndAudLocalControlDescriptor'.streamModeSel =:= asn1_NOVALUE) -> + D2 = + case Val of + {equal, Val2} -> + D#'IndAudLocalControlDescriptor'{streamModeSel = Val2}; + {inequal, Val2} -> + D#'IndAudLocalControlDescriptor'{streamModeSel = Val2} + end, + merge_indAudLocalControlDescriptor(Parms, D2, PP); + +merge_indAudLocalControlDescriptor([{mode, Val} | Parms], D, PP) + when (D#'IndAudLocalControlDescriptor'.streamModeSel =:= asn1_NOVALUE) -> + D2 = + case Val of + {equal, Val2} -> + D#'IndAudLocalControlDescriptor'{streamMode = asn1_NOVALUE, + streamModeSel = Val2}; + {inequal, Val2} -> + D#'IndAudLocalControlDescriptor'{streamMode = asn1_NOVALUE, + streamModeSel = Val2} + end, + merge_indAudLocalControlDescriptor(Parms, D2, PP); + +merge_indAudLocalControlDescriptor([reservedGroupToken | Parms], D, PP) + when D#'IndAudLocalControlDescriptor'.reserveGroup =:= asn1_NOVALUE -> + D2 = D#'IndAudLocalControlDescriptor'{reserveGroup = 'NULL'}, + merge_indAudLocalControlDescriptor(Parms, D2, PP); + +merge_indAudLocalControlDescriptor([reservedValueToken | Parms], D, PP) + when D#'IndAudLocalControlDescriptor'.reserveValue =:= asn1_NOVALUE -> + D2 = D#'IndAudLocalControlDescriptor'{reserveValue = 'NULL'}, + merge_indAudLocalControlDescriptor(Parms, D2, PP); + +%% This is really wierd in the standard, so at this point this is the +%% best I can do... BUGBUG BUGBUG BUGBUG +%% +merge_indAudLocalControlDescriptor([{name, Val} | Parms], D, asn1_NOVALUE) -> + PP = #'IndAudPropertyParm'{name = Val}, + merge_indAudLocalControlDescriptor(Parms, D, PP); + +merge_indAudLocalControlDescriptor([{name, Val} | Parms], D, PP) + when D#'IndAudLocalControlDescriptor'.propertyParms =:= asn1_NOVALUE -> + D2 = D#'IndAudLocalControlDescriptor'{propertyParms = [PP]}, + PP2 = #'IndAudPropertyParm'{name = Val}, + merge_indAudLocalControlDescriptor(Parms, D2, PP2); + +merge_indAudLocalControlDescriptor([{name, Val} | Parms], D, PP) -> + PPs = D#'IndAudLocalControlDescriptor'.propertyParms, + D2 = D#'IndAudLocalControlDescriptor'{propertyParms = [PP|PPs]}, + PP2 = #'IndAudPropertyParm'{name = Val}, + merge_indAudLocalControlDescriptor(Parms, D2, PP2); + +%% BUGBUG BUGBUG I cannot construct a proper IndAudPropertyParm with +%% just the prop (the mandatory name part is missing), so for now I +%% assume that it this has been used, then the name part +%% (pkgdName) must precide it? +merge_indAudLocalControlDescriptor([{prop, Val} | Parms], D, PP) + when (PP =/= asn1_NOVALUE) andalso + (D#'IndAudLocalControlDescriptor'.propertyParms =:= asn1_NOVALUE) -> + PP2 = PP#'IndAudPropertyParm'{propertyParms = Val}, + D2 = D#'IndAudLocalControlDescriptor'{propertyParms = [PP2]}, + merge_indAudLocalControlDescriptor(Parms, D2, asn1_NOVALUE); + +merge_indAudLocalControlDescriptor([{prop, Val} | Parms], D, PP) + when (PP =/= asn1_NOVALUE) andalso + is_list(D#'IndAudLocalControlDescriptor'.propertyParms) -> + PPs = D#'IndAudLocalControlDescriptor'.propertyParms, + PP2 = PP#'IndAudPropertyParm'{propertyParms = Val}, + D2 = D#'IndAudLocalControlDescriptor'{propertyParms = [PP2|PPs]}, + merge_indAudLocalControlDescriptor(Parms, D2, asn1_NOVALUE); + +merge_indAudLocalControlDescriptor([H | _T], _D, _PP) -> + return_error(0, {bad_indAudLocalControlDescriptor_parm, H}); + +merge_indAudLocalControlDescriptor([], D, asn1_NOVALUE) + when D#'IndAudLocalControlDescriptor'.propertyParms =:= asn1_NOVALUE -> + D; +merge_indAudLocalControlDescriptor([], D, asn1_NOVALUE) -> + PPs = D#'IndAudLocalControlDescriptor'.propertyParms, + PropParms2 = lists:reverse(PPs), + D#'IndAudLocalControlDescriptor'{propertyParms = PropParms2}; +merge_indAudLocalControlDescriptor([], D, PP) + when D#'IndAudLocalControlDescriptor'.propertyParms =:= asn1_NOVALUE -> + D#'IndAudLocalControlDescriptor'{propertyParms = [PP]}; +merge_indAudLocalControlDescriptor([], D, PP) -> + PPs = D#'IndAudLocalControlDescriptor'.propertyParms, + PPs2 = lists:reverse([PP|PPs]), + D#'IndAudLocalControlDescriptor'{propertyParms = PPs2}. + + +merge_indAudTerminationStateDescriptor({name, Val}) -> + PropParm = #'IndAudPropertyParm'{name = Val}, + #'IndAudTerminationStateDescriptor'{propertyParms = [PropParm]}; +%% BUGBUG BUGBUG BUGBUG +merge_indAudTerminationStateDescriptor({prop, Val}) -> + exit({incomplete_propertyParm_in_indAudTerminationStateDescriptor, Val}); +merge_indAudTerminationStateDescriptor(serviceStatesToken) -> + #'IndAudTerminationStateDescriptor'{serviceState = 'NULL'}; +merge_indAudTerminationStateDescriptor({serviceStates, {equal, Val}}) -> + #'IndAudTerminationStateDescriptor'{serviceStateSel = Val}; +merge_indAudTerminationStateDescriptor({serviceStates, {inequal, Val}}) -> + #'IndAudTerminationStateDescriptor'{serviceStateSel = Val}; +merge_indAudTerminationStateDescriptor(bufferToken) -> + #'IndAudTerminationStateDescriptor'{eventBufferControl = 'NULL'}. + + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_indAudEventBufferDescriptor,2}]}). +-endif. +merge_indAudEventBufferDescriptor(EventName, SpecParams) -> + IAEBD = #'IndAudEventBufferDescriptor'{eventName = EventName}, + do_merge_indAudEventBufferDescriptor(SpecParams, IAEBD). + +do_merge_indAudEventBufferDescriptor(asn1_NOVALUE, IAEBD) -> + IAEBD; +do_merge_indAudEventBufferDescriptor({streamID, StreamID}, IAEBD) -> + IAEBD#'IndAudEventBufferDescriptor'{streamID = StreamID}; +do_merge_indAudEventBufferDescriptor({eventParameterName, _Name} = EPN, + IAEBD) -> + %% BUGBUG BUGBUG BUGBUG + %% This is an ugly hack to allow the eventParamName which only + %% exists in the text encoding... + IAEBD#'IndAudEventBufferDescriptor'{streamID = EPN}. + + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_indAudSignalListParm,1}]}). +-endif. +ensure_indAudSignalListParm(SIG) -> + if + is_record(SIG, 'Signal') -> + ensure_indAudSignal(SIG); + true -> + return_error(0, {bad_Signal, SIG}) + end. + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_indAudSignal,1}]}). +-endif. +ensure_indAudSignal(Sig) -> + #'Signal'{signalName = SignalName, + streamID = SID, + sigType = asn1_NOVALUE, + duration = asn1_NOVALUE, + notifyCompletion = asn1_NOVALUE, + keepActive = asn1_NOVALUE, + sigParList = [], + requestID = RID} = Sig, + #'IndAudSignal'{signalName = SignalName, + streamID = SID, + signalRequestID = RID}. + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_IADMD,1}]}). +-endif. +ensure_IADMD(Token) -> + {_TokenTag, _Line, DMD} = Token, + #'DigitMapDescriptor'{digitMapName = Name, + digitMapValue = asn1_NOVALUE} = DMD, + #'IndAudDigitMapDescriptor'{digitMapName = Name}. + + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_indAudPackagesDescriptor,1}]}). +-endif. +merge_indAudPackagesDescriptor(Pkgs) -> + #'PackagesItem'{packageName = N, + packageVersion = V} = Pkgs, + #'IndAudPackagesDescriptor'{packageName = N, + packageVersion = V}. + + +%% ensure_indAudTerminationStateParm(Token) -> +%% case Token of +%% {safeToken, _Line, "servicestates"} -> serviceStatesToken; +%% {safeToken, _Line, "si"} -> serviceStatesToken; +%% {safeToken, _Line, "buffer"} -> bufferToken; +%% {safeToken, _Line, "bf"} -> bufferToken; +%% PkgdName -> {pkgdName, +%% ensure_pkgdName(PkgdName)} +%% end. + + +%% Types modified by v2: + +merge_auditDescriptor([]) -> + #'AuditDescriptor'{}; +merge_auditDescriptor(Tokens) when is_list(Tokens) -> + case lists:keysearch(terminationAudit, 1, Tokens) of + {value, {terminationAudit, TA}} -> + case lists:keydelete(terminationAudit, 1, Tokens) of + [] -> + #'AuditDescriptor'{auditPropertyToken = TA}; + AuditTokens -> + #'AuditDescriptor'{auditToken = AuditTokens, + auditPropertyToken = TA} + end; + false -> + #'AuditDescriptor'{auditToken = Tokens} + end; +merge_auditDescriptor(_) -> + #'AuditDescriptor'{}. + + +%% v2 - end + + + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_ServiceChangeParm,1}]}). +-endif. +merge_ServiceChangeParm(Parms) -> + Required = [serviceChangeReason, serviceChangeMethod], + merge_ServiceChangeParm(Parms, #'ServiceChangeParm'{}, Required). + +merge_ServiceChangeParm([], SCP, []) -> + SCP; + +merge_ServiceChangeParm([], _SCP, Required) -> + exit({missing_required_serviceChangeParm, Required}); + +merge_ServiceChangeParm([{address, Val}|Parms], SCP0, Req) + when (SCP0#'ServiceChangeParm'.serviceChangeAddress =:= asn1_NOVALUE) andalso + (SCP0#'ServiceChangeParm'.serviceChangeMgcId =:= asn1_NOVALUE) -> + SCP = SCP0#'ServiceChangeParm'{serviceChangeAddress = Val}, + merge_ServiceChangeParm(Parms, SCP, Req); +merge_ServiceChangeParm([{address, Val}|_Parms], SCP0, _Req) + when SCP0#'ServiceChangeParm'.serviceChangeAddress =:= asn1_NOVALUE -> + MgcId = SCP0#'ServiceChangeParm'.serviceChangeMgcId, + exit({not_both_address_mgcid_serviceChangeParm, Val, MgcId}); + +merge_ServiceChangeParm([{mgc_id, Val}|Parms], SCP0, Req) + when (SCP0#'ServiceChangeParm'.serviceChangeMgcId =:= asn1_NOVALUE) andalso + (SCP0#'ServiceChangeParm'.serviceChangeAddress =:= asn1_NOVALUE) -> + SCP = SCP0#'ServiceChangeParm'{serviceChangeMgcId = Val}, + merge_ServiceChangeParm(Parms, SCP, Req); +merge_ServiceChangeParm([{mgc_id, Val}|_Parms], SCP0, _Req) + when SCP0#'ServiceChangeParm'.serviceChangeMgcId =:= asn1_NOVALUE -> + Addr = SCP0#'ServiceChangeParm'.serviceChangeAddress, + exit({not_both_address_mgcid_serviceChangeParm, Val, Addr}); + +merge_ServiceChangeParm([{profile, Val}|Parms], SCP0, Req) + when SCP0#'ServiceChangeParm'.serviceChangeProfile =:= asn1_NOVALUE -> + SCP = SCP0#'ServiceChangeParm'{serviceChangeProfile = Val}, + merge_ServiceChangeParm(Parms, SCP, Req); + +merge_ServiceChangeParm([{version, Val}|Parms], SCP0, Req) + when SCP0#'ServiceChangeParm'.serviceChangeVersion =:= asn1_NOVALUE -> + SCP = SCP0#'ServiceChangeParm'{serviceChangeVersion = Val}, + merge_ServiceChangeParm(Parms, SCP, Req); + +%% REQUIRED (i.e. no default value) +merge_ServiceChangeParm([{reason, Val}|Parms], SCP0, Req0) + when SCP0#'ServiceChangeParm'.serviceChangeReason =:= undefined -> + SCP = SCP0#'ServiceChangeParm'{serviceChangeReason = Val}, + Req = lists:delete(serviceChangeReason, Req0), + merge_ServiceChangeParm(Parms, SCP, Req); + +merge_ServiceChangeParm([{delay, Val}|Parms], SCP0, Req) + when SCP0#'ServiceChangeParm'.serviceChangeDelay =:= asn1_NOVALUE -> + SCP = SCP0#'ServiceChangeParm'{serviceChangeDelay = Val}, + merge_ServiceChangeParm(Parms, SCP, Req); + +%% REQUIRED (i.e. no default value) +merge_ServiceChangeParm([{method, Val}|Parms], SCP0, Req0) + when SCP0#'ServiceChangeParm'.serviceChangeMethod =:= undefined -> + SCP = SCP0#'ServiceChangeParm'{serviceChangeMethod = Val}, + Req = lists:delete(serviceChangeMethod, Req0), + merge_ServiceChangeParm(Parms, SCP, Req); + +merge_ServiceChangeParm([{time_stamp, Val}|Parms], SCP0, Req) + when SCP0#'ServiceChangeParm'.timeStamp =:= asn1_NOVALUE -> + SCP = SCP0#'ServiceChangeParm'{timeStamp = Val}, + merge_ServiceChangeParm(Parms, SCP, Req); + +merge_ServiceChangeParm([{extension, _Val}|Parms], SCP0, Req) -> + merge_ServiceChangeParm(Parms, SCP0, Req); + +merge_ServiceChangeParm([{audit_item, Val}|Parms], SCP0, Req) + when (SCP0#'ServiceChangeParm'.serviceChangeInfo =:= asn1_NOVALUE) andalso + is_atom(Val) -> + SCI = #'AuditDescriptor'{auditToken = [Val]}, + SCP = SCP0#'ServiceChangeParm'{serviceChangeInfo = SCI}, + merge_ServiceChangeParm(Parms, SCP, Req); +merge_ServiceChangeParm([{audit_item, Val}|Parms], SCP0, Req) + when (SCP0#'ServiceChangeParm'.serviceChangeInfo =:= asn1_NOVALUE) andalso + is_tuple(Val) -> + SCI = #'AuditDescriptor'{auditPropertyToken = [Val]}, + SCP = SCP0#'ServiceChangeParm'{serviceChangeInfo = SCI}, + merge_ServiceChangeParm(Parms, SCP, Req); +merge_ServiceChangeParm([{audit_item, Val}|Parms], SCP0, Req) + when is_record(SCP0#'ServiceChangeParm'.serviceChangeInfo, 'AuditDescriptor') andalso + is_atom(Val) -> + SCI0 = SCP0#'ServiceChangeParm'.serviceChangeInfo, + L = SCI0#'AuditDescriptor'.auditToken, + SCI = SCI0#'AuditDescriptor'{auditToken = [Val|L]}, + SCP = SCP0#'ServiceChangeParm'{serviceChangeInfo = SCI}, + merge_ServiceChangeParm(Parms, SCP, Req); +merge_ServiceChangeParm([{audit_item, Val}|Parms], SCP0, Req) + when is_record(SCP0#'ServiceChangeParm'.serviceChangeInfo, 'AuditDescriptor') andalso + is_tuple(Val) -> + SCI0 = SCP0#'ServiceChangeParm'.serviceChangeInfo, + L = SCI0#'AuditDescriptor'.auditPropertyToken, + SCI = SCI0#'AuditDescriptor'{auditPropertyToken = [Val|L]}, + SCP = SCP0#'ServiceChangeParm'{serviceChangeInfo = SCI}, + merge_ServiceChangeParm(Parms, SCP, Req); + +merge_ServiceChangeParm([incomplete|Parms], SCP0, Req) + when SCP0#'ServiceChangeParm'.serviceChangeIncompleteFlag =:= asn1_NOVALUE -> + SCP = SCP0#'ServiceChangeParm'{serviceChangeIncompleteFlag = 'NULL'}, + merge_ServiceChangeParm(Parms, SCP, Req); + +merge_ServiceChangeParm([{Tag, Val}|_Parms], SCP, _Req) -> + Val2 = + case Tag of + address -> + SCP#'ServiceChangeParm'.serviceChangeAddress; + mgc_id -> + SCP#'ServiceChangeParm'.serviceChangeMgcId; + profile -> + SCP#'ServiceChangeParm'.serviceChangeProfile; + version -> + SCP#'ServiceChangeParm'.serviceChangeVersion; + reason -> + SCP#'ServiceChangeParm'.serviceChangeReason; + delay -> + SCP#'ServiceChangeParm'.serviceChangeDelay; + method -> + SCP#'ServiceChangeParm'.serviceChangeMethod; + time_stamp -> + SCP#'ServiceChangeParm'.timeStamp; + audit_item -> + SCP#'ServiceChangeParm'.serviceChangeInfo + end, + exit({at_most_once_serviceChangeParm, {Tag, Val, Val2}}); +merge_ServiceChangeParm([Parm|_Parms], SCP, _Req) -> + Parm2 = + case Parm of + incomplete -> + SCP#'ServiceChangeParm'.serviceChangeIncompleteFlag + end, + exit({at_most_once_serviceChangeParm, {Parm, Parm2}}). + + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_ServiceChangeResParm,1}]}). +-endif. +merge_ServiceChangeResParm(Parms) -> + merge_ServiceChangeResParm(Parms, #'ServiceChangeResParm'{}). + +merge_ServiceChangeResParm([], SCRP) -> + SCRP; +merge_ServiceChangeResParm([{address, Val}|Parms], SCRP0) + when (SCRP0#'ServiceChangeResParm'.serviceChangeAddress =:= asn1_NOVALUE) andalso + (SCRP0#'ServiceChangeResParm'.serviceChangeMgcId =:= asn1_NOVALUE) -> + SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeAddress = Val}, + merge_ServiceChangeResParm(Parms, SCRP); +merge_ServiceChangeResParm([{address, Val}|_Parms], SCRP0) + when SCRP0#'ServiceChangeResParm'.serviceChangeAddress =:= asn1_NOVALUE -> + MgcId = SCRP0#'ServiceChangeResParm'.serviceChangeMgcId, + exit({not_both_address_mgcid_servChgReplyParm, Val, MgcId}); + +merge_ServiceChangeResParm([{mgc_id, Val}|Parms], SCRP0) + when (SCRP0#'ServiceChangeResParm'.serviceChangeMgcId =:= asn1_NOVALUE) andalso + (SCRP0#'ServiceChangeResParm'.serviceChangeAddress =:= asn1_NOVALUE) -> + SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeMgcId = Val}, + merge_ServiceChangeResParm(Parms, SCRP); +merge_ServiceChangeResParm([{mgc_id, Val}|_Parms], SCRP0) + when SCRP0#'ServiceChangeResParm'.serviceChangeMgcId =:= asn1_NOVALUE -> + Addr = SCRP0#'ServiceChangeResParm'.serviceChangeAddress, + exit({not_both_address_mgcid_servChgReplyParm, Val, Addr}); + +merge_ServiceChangeResParm([{profile, Val}|Parms], SCRP0) + when SCRP0#'ServiceChangeResParm'.serviceChangeProfile =:= asn1_NOVALUE -> + SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeProfile = Val}, + merge_ServiceChangeResParm(Parms, SCRP); + +merge_ServiceChangeResParm([{version, Val}|Parms], SCRP0) + when SCRP0#'ServiceChangeResParm'.serviceChangeVersion =:= asn1_NOVALUE -> + SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeVersion = Val}, + merge_ServiceChangeResParm(Parms, SCRP); + +merge_ServiceChangeResParm([{time_stamp, Val}|Parms], SCRP0) + when SCRP0#'ServiceChangeResParm'.timeStamp =:= asn1_NOVALUE -> + SCRP = SCRP0#'ServiceChangeResParm'{timeStamp = Val}, + merge_ServiceChangeResParm(Parms, SCRP); + +merge_ServiceChangeResParm([{Tag, Val}|_Parms], SCRP) -> + Val2 = + case Tag of + address -> SCRP#'ServiceChangeResParm'.serviceChangeAddress; + mgc_id -> SCRP#'ServiceChangeResParm'.serviceChangeMgcId; + profile -> SCRP#'ServiceChangeResParm'.serviceChangeProfile; + version -> SCRP#'ServiceChangeResParm'.serviceChangeVersion; + time_stamp -> SCRP#'ServiceChangeResParm'.timeStamp + end, + exit({at_most_once_servChgReplyParm, {Tag, Val, Val2}}). + + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_serviceChangeMethod,1}]}). +-endif. +ensure_serviceChangeMethod(Token) -> + case Token of + {safeToken, _Line, "fl"} -> + failover; + {safeToken, _Line, "failover"} -> + failover; + {safeToken, _Line, "fo"} -> + forced; + {safeToken, _Line, "forced"} -> + forced; + {safeToken, _Line, "gr"} -> + graceful; + {safeToken, _Line, "graceful"} -> + graceful; + {safeToken, _Line, "rs"} -> + restart; + {safeToken, _Line, "restart"} -> + restart; + {safeToken, _Line, "dc"} -> + disconnected; + {safeToken, _Line, "disconnected"} -> + disconnected; + {safeToken, _Line, "ho"} -> + handOff; + {safeToken, _Line, "handoff"} -> + handOff; + {safeToken, Line, Text} -> + return_error(Line, {bad_serviceChangeMethod, Text}) + end. + + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_topologyDescriptor,1}]}). +-endif. +merge_topologyDescriptor(Components) -> + merge_topologyDescriptor(Components, #'TopologyRequest'{}, []). + +merge_topologyDescriptor([], TR, TRs) -> + lists:reverse([ensure_TopologyRequest(TR)|TRs]); +merge_topologyDescriptor( + [{tid, From}|Comps], + #'TopologyRequest'{terminationFrom = undefined} = TR1, TRs) -> + TR2 = TR1#'TopologyRequest'{terminationFrom = From}, + merge_topologyDescriptor(Comps, TR2, TRs); +merge_topologyDescriptor( + [{tid, To}|Comps], + #'TopologyRequest'{terminationTo = undefined} = TR1, + TRs) -> + TR2 = TR1#'TopologyRequest'{terminationTo = To}, + merge_topologyDescriptor(Comps, TR2, TRs); +merge_topologyDescriptor([{tid, From}|Comps], TR1, TRs) -> + TR2 = #'TopologyRequest'{terminationFrom = From}, + merge_topologyDescriptor(Comps, TR2, [TR1 | TRs]); +merge_topologyDescriptor([{direction, Dir}|Comps], TR1, TRs) -> + TR2 = TR1#'TopologyRequest'{topologyDirection = Dir}, + merge_topologyDescriptor(Comps, TR2, TRs); +merge_topologyDescriptor([{sid, SID}|Comps], TR1, TRs) -> + TR2 = TR1#'TopologyRequest'{streamID = SID}, + merge_topologyDescriptor(Comps, TR2, TRs); +merge_topologyDescriptor( + [{direction_ext, EDir}|Comps], + #'TopologyRequest'{topologyDirection = asn1_NOVALUE} = TR1, TRs) -> + TR2 = TR1#'TopologyRequest'{topologyDirection = oneway, + topologyDirectionExtension = EDir}, + merge_topologyDescriptor(Comps, TR2, TRs); +merge_topologyDescriptor([{direction_ext, EDir}|Comps], TR1, TRs) -> + TR2 = TR1#'TopologyRequest'{topologyDirectionExtension = EDir}, + merge_topologyDescriptor(Comps, TR2, TRs); +merge_topologyDescriptor(Comps, TR, TRs) -> + return_error(0, {bad_topologyDescriptor, Comps, TR, TRs}). + + +ensure_TopologyRequest(#'TopologyRequest'{terminationFrom = From, + terminationTo = To, + topologyDirection = Dir} = R) + when (From =/= asn1_NOVALUE) andalso + (To =/= asn1_NOVALUE) andalso + (Dir =/= asn1_NOVALUE) -> + R; +ensure_TopologyRequest(R) -> + return_error(0, {bad_TopologyRequest, R}). + + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_profile,1}]}). +-endif. +ensure_profile(Token) -> + {_TokenTag, Line, Text} = Token, + case string:tokens(Text, [$/]) of + [Name, Version] -> + Version2 = ensure_version(Version), + #'ServiceChangeProfile'{profileName = Name, version = Version2}; + _ -> + return_error(Line, {bad_profile, Text}) + end. + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_version,1}]}). +-endif. +ensure_version(Version) -> + ensure_uint(Version, 0, 99). + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_signalRequest,2}]}). +-endif. +merge_signalRequest(SignalName, PropertyParms) -> + Sig = #'Signal'{signalName = SignalName}, + SPL = [], + do_merge_signalRequest(Sig, PropertyParms, SPL). + +do_merge_signalRequest(Sig, [H | T], SPL) -> + case H of + {stream, SID} when Sig#'Signal'.streamID =:= asn1_NOVALUE -> + do_merge_signalRequest(Sig#'Signal'{streamID = SID}, T, SPL); + {signal_type, SigType} when Sig#'Signal'.sigType =:= asn1_NOVALUE -> + do_merge_signalRequest(Sig#'Signal'{sigType = SigType}, T, SPL); + {duration, Duration} when Sig#'Signal'.duration =:= asn1_NOVALUE -> + do_merge_signalRequest(Sig#'Signal'{duration = Duration}, T, SPL); + {notify_completion, NC} when Sig#'Signal'.notifyCompletion =:= asn1_NOVALUE -> + do_merge_signalRequest(Sig#'Signal'{notifyCompletion = NC}, T, SPL); + keepActive when Sig#'Signal'.keepActive =:= asn1_NOVALUE -> + do_merge_signalRequest(Sig#'Signal'{keepActive = true}, T, SPL); + {other, Name, PP} -> + SP = #'SigParameter'{sigParameterName = Name, + value = PP#'PropertyParm'.value, + extraInfo = PP#'PropertyParm'.extraInfo}, + do_merge_signalRequest(Sig, T, [SP | SPL]); + {direction, Dir} when Sig#'Signal'.direction =:= asn1_NOVALUE -> + do_merge_signalRequest(Sig#'Signal'{direction = Dir}, T, SPL); + {requestId, RID} when Sig#'Signal'.requestID =:= asn1_NOVALUE -> + do_merge_signalRequest(Sig#'Signal'{requestID = RID}, T, SPL); + {intersigDelay, ISD} when Sig#'Signal'.intersigDelay =:= asn1_NOVALUE -> + do_merge_signalRequest(Sig#'Signal'{intersigDelay = ISD}, T, SPL); + _ -> + return_error(0, {bad_sigParm, H}) + end; +do_merge_signalRequest(Sig, [], SPL) -> + Sig#'Signal'{sigParList = lists:reverse(SPL)} . + +%% eventStream = StreamToken EQUAL StreamID +%% eventOther = eventParameterName parmValue +-ifdef(megaco_parser_inline). +-compile({inline,[{select_stream_or_other,2}]}). +-endif. +select_stream_or_other(EventParameterName, ParmValue) -> + if + (EventParameterName =:= "st") orelse + (EventParameterName =:= "stream") -> + case ParmValue of + #'PropertyParm'{value = [Value]} -> + {stream, ensure_uint16(Value)}; + _ -> + {stream, ensure_uint16(ParmValue)} + end; + true -> + #'PropertyParm'{value = Value} = ParmValue, + EP = #'EventParameter'{eventParameterName = EventParameterName, + value = Value}, + {other, EP} + end. + +%% select_stream_or_other("st", #'PropertyParm'{value = [Value]}) -> +%% {stream, ensure_uint16(Value)}; +%% select_stream_or_other("st", Value) -> +%% {stream, ensure_uint16(Value)}; +%% select_stream_or_other("stream", #'PropertyParm'{value = [Value]}) -> +%% {stream, ensure_uint16(Value)}; +%% select_stream_or_other("stream", Value) -> +%% {stream, ensure_uint16(Value)}; +%% select_stream_or_other(Name, #'PropertyParm'{value = Value}) -> +%% EP = #'EventParameter'{eventParameterName = Name, +%% value = Value}, +%% {other, EP}. + + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_eventDM,1}]}). +-endif. +ensure_eventDM(Token) -> + {_TokenTag, Line, DMD} = Token, + if + is_record(DMD, 'DigitMapDescriptor') -> + Name = DMD#'DigitMapDescriptor'.digitMapName, + Val = DMD#'DigitMapDescriptor'.digitMapValue, + if + (Name =:= asn1_NOVALUE) andalso (Val =/= asn1_NOVALUE) -> + {'DigitMapValue', Start, Short, Long, Duration, Body} = Val, + DMV = #'DigitMapValue'{startTimer = Start, + shortTimer = Short, + longTimer = Long, + digitMapBody = Body, + durationTimer = Duration}, + {eventDM, {digitMapValue, DMV}}; + (Name =/= asn1_NOVALUE) andalso (Val =:= asn1_NOVALUE) -> + {eventDM, {digitMapName, Name}}; + true -> + return_error(Line, {bad_eventDM, DMD}) + end; + true -> + return_error(Line, {bad_eventDM, DMD}) + end. + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_DMD,1}]}). +-endif. +ensure_DMD(Token) -> + {_TokenTag, Line, DMD} = Token, + if + is_record(DMD, 'DigitMapDescriptor') -> + Val2 = + case DMD#'DigitMapDescriptor'.digitMapValue of + %% Note that the values of the digitMapBody and + %% durationTimers are swapped by the scanner + %% (this is done because of a problem in the flex scanner). + #'DigitMapValue'{startTimer = asn1_NOVALUE, + shortTimer = asn1_NOVALUE, + longTimer = asn1_NOVALUE, + durationTimer = [], + digitMapBody = asn1_NOVALUE} -> + asn1_NOVALUE; + #'DigitMapValue'{durationTimer = Body, + digitMapBody = Duration} = DMV -> + %% Convert to version 1 DigitMapValue + DMV#'DigitMapValue'{digitMapBody = Body, + durationTimer = Duration}; + Other -> + Other + end, + DMD#'DigitMapDescriptor'{digitMapValue = Val2}; + true -> + return_error(Line, {bad_DigitMapDescriptor, DMD}) + end. + + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_observed_event,3}]}). +-endif. +merge_observed_event(ObservedEvents, EventName, TimeStamp) -> + StreamId = asn1_NOVALUE, + EPL = [], + do_merge_observed_event(ObservedEvents, EventName, TimeStamp, StreamId, EPL). + +do_merge_observed_event([{stream, StreamID} | T], EventName, TimeStamp, asn1_NOVALUE, EPL) -> + do_merge_observed_event(T, EventName, TimeStamp, StreamID, EPL); +do_merge_observed_event([{other, PP} | T], EventName, TimeStamp, StreamID, EPL) -> + do_merge_observed_event(T, EventName, TimeStamp, StreamID, [PP | EPL]); +do_merge_observed_event([], EventName, TimeStamp, StreamID, EPL) -> + #'ObservedEvent'{eventName = EventName, + timeNotation = TimeStamp, + streamID = StreamID, + eventParList = lists:reverse(EPL)}. + +merge_eventSpec(OE) + when is_record(OE, 'ObservedEvent') andalso + (OE#'ObservedEvent'.timeNotation =:= asn1_NOVALUE) -> + #'EventSpec'{eventName = OE#'ObservedEvent'.eventName, + streamID = OE#'ObservedEvent'.streamID, + eventParList = OE#'ObservedEvent'.eventParList}; +merge_eventSpec(OE) -> + return_error(0, {bad_event_spec, OE}). + +make_RegulatedEmbeddedDescriptor({embed, SD, SED}) -> + #'RegulatedEmbeddedDescriptor'{secondEvent = SED, + signalsDescriptor = SD}. + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_eventParameters,1}]}). +-endif. +merge_eventParameters(Params) -> + SID = asn1_NOVALUE, + EPL = [], + RA = #'RequestedActions'{}, + HasA = no, + do_merge_eventParameters(Params, SID, EPL, RA, HasA) . + +do_merge_eventParameters([H | T], SID, EPL, RA, HasA) -> + case H of + keepActive when RA#'RequestedActions'.keepActive =:= asn1_NOVALUE -> + RA2 = RA#'RequestedActions'{keepActive = true}, + do_merge_eventParameters(T, SID, EPL, RA2, yes); + resetEventsDescriptor when RA#'RequestedActions'.resetEventsDescriptor =:= asn1_NOVALUE -> + RA2 = RA#'RequestedActions'{resetEventsDescriptor = 'NULL'}, + do_merge_eventParameters(T, SID, EPL, RA2, yes); + {embed, SD, SED} when RA#'RequestedActions'.signalsDescriptor =:= asn1_NOVALUE -> + RA2 = RA#'RequestedActions'{signalsDescriptor = SD, + secondEvent = SED}, + do_merge_eventParameters(T, SID, EPL, RA2, yes); + {eventDM, DM} when RA#'RequestedActions'.eventDM =:= asn1_NOVALUE -> + RA2 = RA#'RequestedActions'{eventDM = DM}, + do_merge_eventParameters(T, SID, EPL, RA2, yes); + {stream, NewSID} when SID =:= asn1_NOVALUE -> + do_merge_eventParameters(T, NewSID, EPL, RA, HasA); + {other, PP} when is_record(PP, 'PropertyParm') -> + EP = #'EventParameter'{eventParameterName = PP#'PropertyParm'.name, + value = PP#'PropertyParm'.value, + extraInfo = PP#'PropertyParm'.extraInfo}, + do_merge_eventParameters(T, SID, [EP | EPL], RA, HasA); + {other, EP} when is_record(EP, 'EventParameter') -> + do_merge_eventParameters(T, SID, [EP | EPL], RA, HasA); + {notifyBehaviour, NB} when RA#'RequestedActions'.notifyBehaviour =:= asn1_NOVALUE -> + RA2 = RA#'RequestedActions'{notifyBehaviour = NB}, + do_merge_eventParameters(T, SID, EPL, RA2, yes); + _ -> + return_error(0, {bad_eventParameter, H}) + end; +do_merge_eventParameters([], SID, EPL, RA, yes) -> + #'RequestedEvent'{streamID = SID, + eventAction = RA, + evParList = lists:reverse(EPL)}; +do_merge_eventParameters([], SID, EPL, _RA, no) -> + #'RequestedEvent'{streamID = SID, + eventAction = asn1_NOVALUE, + evParList = lists:reverse(EPL)}. + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_secondEventParameters,1}]}). +-endif. +merge_secondEventParameters(Params) -> + SID = asn1_NOVALUE, + EPL = [], + SRA = #'SecondRequestedActions'{}, + HasA = no, + do_merge_secondEventParameters(Params, SID, EPL, SRA, HasA) . + +do_merge_secondEventParameters([H | T], SID, EPL, SRA, HasA) -> + case H of + keepActive when SRA#'SecondRequestedActions'.keepActive =:= asn1_NOVALUE -> + SRA2 = SRA#'SecondRequestedActions'{keepActive = true}, + do_merge_secondEventParameters(T, SID, EPL, SRA2, yes); + resetEventsDescriptor when SRA#'SecondRequestedActions'.resetEventsDescriptor =:= asn1_NOVALUE -> + SRA2 = SRA#'SecondRequestedActions'{resetEventsDescriptor = 'NULL'}, + do_merge_secondEventParameters(T, SID, EPL, SRA2, yes); + {second_embed, SD} when SRA#'SecondRequestedActions'.signalsDescriptor =:= asn1_NOVALUE -> + SRA2 = SRA#'SecondRequestedActions'{signalsDescriptor = SD}, + do_merge_secondEventParameters(T, SID, EPL, SRA2, yes); + {eventDM, DM} when SRA#'SecondRequestedActions'.eventDM =:= asn1_NOVALUE -> + SRA2 = SRA#'SecondRequestedActions'{eventDM = DM}, + do_merge_secondEventParameters(T, SID, EPL, SRA2, yes); + {stream, NewSID} when SID =:= asn1_NOVALUE -> + do_merge_secondEventParameters(T, NewSID, EPL, SRA, HasA); + {other, PP} when is_record(PP, 'PropertyParm') -> + EP = #'EventParameter'{eventParameterName = PP#'PropertyParm'.name, + value = PP#'PropertyParm'.value, + extraInfo = PP#'PropertyParm'.extraInfo}, + do_merge_secondEventParameters(T, SID, [EP | EPL], SRA, HasA); + {other, EP} when is_record(EP, 'EventParameter') -> + do_merge_secondEventParameters(T, SID, [EP | EPL], SRA, HasA); + {notifyBehaviour, NB} when SRA#'SecondRequestedActions'.notifyBehaviour =:= asn1_NOVALUE -> + SRA2 = SRA#'SecondRequestedActions'{notifyBehaviour = NB}, + do_merge_secondEventParameters(T, SID, EPL, SRA2, yes); + _ -> + return_error(0, {bad_secondEventParameter, H}) + end; +do_merge_secondEventParameters([], SID, EPL, SRA, yes) -> + #'SecondRequestedEvent'{streamID = SID, + eventAction = SRA, + evParList = lists:reverse(EPL)}; +do_merge_secondEventParameters([], SID, EPL, _SRA, no) -> + #'SecondRequestedEvent'{streamID = SID, + eventAction = asn1_NOVALUE, + evParList = lists:reverse(EPL)}. + +%% terminationID = "ROOT" / pathName / "$" / "*" +%% Total length of pathName must not exceed 64 chars. +%% pathName = ["*"] NAME *("/" / "*"/ ALPHA / DIGIT /"_" / "$" ) +%% ["@" pathDomainName ] +%% ABNF allows two or more consecutive "." although it is meaningless +%% in a path domain name. +%% pathDomainName = (ALPHA / DIGIT / "*" ) +%% *63(ALPHA / DIGIT / "-" / "*" / ".") +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_terminationID,1}]}). +-endif. +ensure_terminationID(Token) -> + {safeToken, _Line, LowerText} = Token, + %% terminationID = "ROOT" / pathName / "$" / "*" + decode_term_id(LowerText, false, [], []). + +decode_term_id([H | T], Wild, Id, Component) -> + case H of + $/ -> decode_term_id(T, Wild, [lists:reverse(Component) | Id], []); + $* -> decode_term_id(T, true, Id, [?megaco_all | Component]); + $$ -> decode_term_id(T, true, Id, [?megaco_choose | Component]); + _ -> decode_term_id(T, Wild, Id, [H | Component]) + end; +decode_term_id([], Wild, Id, Component) -> + Id2 = [lists:reverse(Component) | Id], + #megaco_term_id{contains_wildcards = Wild, id = lists:reverse(Id2)}. + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_pathName,1}]}). +-endif. +ensure_pathName(Token) -> + {_TokenTag, _Line, Text} = Token, + Text. %% BUGBUG: ensure values + +%% TimeStamp = Date "T" Time ; per ISO 8601:1988 +%% Date = 8(DIGIT) ; Date = yyyymmdd +%% Time = 8(DIGIT) ; Time = hhmmssss +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_timeStamp,1}]}). +-endif. +ensure_timeStamp(Token) -> + {'TimeStampToken', Line, Text} = Token, + case string:tokens(Text, [$T, $t]) of + [Date, Time] -> + #'TimeNotation'{date = Date, time = Time}; + _ -> + return_error(Line, {bad_timeStamp, Text}) + end. + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_transactionID,1}]}). +-endif. +ensure_transactionID(TransId) -> + ensure_uint32(TransId). + +make_transactionID_and_segment_info({TokenTag, Line, Text}) -> + case string:tokens(Text, [$/]) of + [TidText, SegNoText, SegComplText] -> + Tid = ensure_uint32({TokenTag, Line, TidText}), + SegNo = ensure_uint16({TokenTag, Line, SegNoText}), + ensure_segmentationComplete({TokenTag, Line, SegComplText}), + {Tid, SegNo, 'NULL'}; + [TidText, SegNoText] -> + Tid = ensure_uint32({TokenTag, Line, TidText}), + SegNo = ensure_uint16({TokenTag, Line, SegNoText}), + {Tid, SegNo}; + [TidText] -> + ensure_uint32({TokenTag, Line, TidText}) + end. + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_segmentationComplete,1}]}). +-endif. +ensure_segmentationComplete(Token) -> + {_TokenTag, Line, Text} = Token, + if + (Text =:= "end") orelse (Text =:= "&") -> + ok; + true -> + return_error(Line, {invalid_segmentationCompleteToken, Text}) + end. + +make_TransactionReply({Tid, SegNo, 'NULL'}, IAR, Res) -> + #'TransactionReply'{transactionId = Tid, + immAckRequired = IAR, + transactionResult = Res, + segmentNumber = SegNo, + segmentationComplete = 'NULL'}; +make_TransactionReply({Tid, SegNo}, IAR, Res) -> + #'TransactionReply'{transactionId = Tid, + immAckRequired = IAR, + transactionResult = Res, + segmentNumber = SegNo}; +make_TransactionReply(Tid, IAR, Res) -> + #'TransactionReply'{transactionId = Tid, + immAckRequired = IAR, + transactionResult = Res}. + +make_SegmentReply({Tid, SegNo, 'NULL'}) -> + #'SegmentReply'{transactionId = Tid, + segmentNumber = SegNo, + segmentationComplete = 'NULL'}; +make_SegmentReply({Tid, SegNo}) -> + #'SegmentReply'{transactionId = Tid, + segmentNumber = SegNo}. + + +%% transactionAck = transactionID / (transactionID "-" transactionID) +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_transactionAck,1}]}). +-endif. +ensure_transactionAck(Tokens) -> + {safeToken, _Line, Text} = Tokens, + case string:tokens(Text, [$-]) of + [Id] -> + #'TransactionAck'{firstAck = ensure_transactionID(Id)}; + [Id, Id2] -> + #'TransactionAck'{firstAck = ensure_transactionID(Id), + lastAck = ensure_transactionID(Id2)} + end. + +merge_context_request(asn1_NOVALUE, Prop) -> + merge_context_request(#'ContextRequest'{}, Prop); + +merge_context_request(#'ContextRequest'{priority = asn1_NOVALUE} = CR, + {priority, Int}) -> + CR#'ContextRequest'{priority = Int}; + +merge_context_request(#'ContextRequest'{emergency = asn1_NOVALUE} = CR, + {emergency, Bool}) -> + CR#'ContextRequest'{emergency = Bool}; + +merge_context_request(#'ContextRequest'{topologyReq = asn1_NOVALUE} = CR, + {topology, Desc}) -> + CR#'ContextRequest'{topologyReq = Desc}; + +merge_context_request(#'ContextRequest'{iepscallind = asn1_NOVALUE} = CR, + {iepsCallind, Ind}) -> + CR#'ContextRequest'{iepscallind = Ind}; + +merge_context_request(#'ContextRequest'{contextProp = asn1_NOVALUE} = CR, + {contextProp, Props}) -> + CR#'ContextRequest'{contextProp = Props}; + +merge_context_request(#'ContextRequest'{contextList = asn1_NOVALUE} = CR, + {contextList, IDs}) -> + CR#'ContextRequest'{contextList = IDs}; + +merge_context_request(CR, {Tag, Val}) -> + Val2 = + case Tag of + priority -> CR#'ContextRequest'.priority; + emergency -> CR#'ContextRequest'.emergency; + topology -> CR#'ContextRequest'.topologyReq; + iepsCallind -> CR#'ContextRequest'.iepscallind; + contextProp -> CR#'ContextRequest'.contextProp; + contextList -> CR#'ContextRequest'.contextList + end, + exit({at_most_once_contextProperty, {Tag, Val, Val2}}). + + +merge_context_attr_audit_request( + #'ContextAttrAuditRequest'{contextPropAud = asn1_NOVALUE} = CAAR, []) -> + + CAAR; +merge_context_attr_audit_request( + #'ContextAttrAuditRequest'{contextPropAud = CPA} = CAAR, []) -> + + CAAR#'ContextAttrAuditRequest'{contextPropAud = lists:reverse(CPA)}; +merge_context_attr_audit_request(CAAR, [H|T]) -> + case H of + priorityAudit when CAAR#'ContextAttrAuditRequest'.priority =:= asn1_NOVALUE -> + CAAR2 = CAAR#'ContextAttrAuditRequest'{priority = 'NULL'}, + merge_context_attr_audit_request(CAAR2, T); + + emergencyAudit when CAAR#'ContextAttrAuditRequest'.emergency =:= asn1_NOVALUE -> + CAAR2 = CAAR#'ContextAttrAuditRequest'{emergency = 'NULL'}, + merge_context_attr_audit_request(CAAR2, T); + + topologyAudit when CAAR#'ContextAttrAuditRequest'.topology =:= asn1_NOVALUE -> + CAAR2 = CAAR#'ContextAttrAuditRequest'{topology = 'NULL'}, + merge_context_attr_audit_request(CAAR2, T); + + iepsCallind when CAAR#'ContextAttrAuditRequest'.iepscallind =:= asn1_NOVALUE -> + CAAR2 = CAAR#'ContextAttrAuditRequest'{iepscallind = 'NULL'}, + merge_context_attr_audit_request(CAAR2, T); + + {prop, Name} when CAAR#'ContextAttrAuditRequest'.contextPropAud =:= asn1_NOVALUE -> + CPA = [#'IndAudPropertyParm'{name = Name}], + CAAR2 = CAAR#'ContextAttrAuditRequest'{contextPropAud = CPA}, + merge_context_attr_audit_request(CAAR2, T); + + {prop, Name} -> + CPA = CAAR#'ContextAttrAuditRequest'.contextPropAud, + CPA2 = [#'IndAudPropertyParm'{name = Name}|CPA], + CAAR2 = CAAR#'ContextAttrAuditRequest'{contextPropAud = CPA2}, + merge_context_attr_audit_request(CAAR2, T); + + {select_prio, Prio} when CAAR#'ContextAttrAuditRequest'.selectpriority =:= asn1_NOVALUE -> + CAAR2 = CAAR#'ContextAttrAuditRequest'{selectpriority = Prio}, + merge_context_attr_audit_request(CAAR2, T); + + {select_emergency, EV} when CAAR#'ContextAttrAuditRequest'.selectemergency =:= asn1_NOVALUE -> + CAAR2 = CAAR#'ContextAttrAuditRequest'{selectemergency = EV}, + merge_context_attr_audit_request(CAAR2, T); + + {select_ieps, IV} when CAAR#'ContextAttrAuditRequest'.selectiepscallind =:= asn1_NOVALUE -> + CAAR2 = CAAR#'ContextAttrAuditRequest'{selectiepscallind = IV}, + merge_context_attr_audit_request(CAAR2, T); + + {select_logic, SL} when CAAR#'ContextAttrAuditRequest'.selectLogic =:= asn1_NOVALUE -> + CAAR2 = CAAR#'ContextAttrAuditRequest'{selectLogic = SL}, + merge_context_attr_audit_request(CAAR2, T); + + %% BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG + %% + %% For some strange reason, contextAttrDescriptor was added + %% to contextAuditSelector. But there is no place for this + %% info in the ContextAttrAuditRequest. Since contextAttrDescriptor + %% can also be found in contextProperty (which correspond to + %% ContextRequest), the question is if this info should go there + %% or if we shall just drop it. For now we drop it. + %% + {contextProp, _PPs} -> + merge_context_attr_audit_request(CAAR, T); + + {contextList, _IDs} -> + merge_context_attr_audit_request(CAAR, T); + + _ -> + exit({unexpected_contextAttrAudit_item, H}) + + end. + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_action_request,2}]}). +-endif. +merge_action_request(CtxId, Items) -> + do_merge_action_request(Items, [], asn1_NOVALUE, asn1_NOVALUE, CtxId). + +do_merge_action_request([H|T], CmdReqs, CtxReq, CtxAuditReq, CtxId) -> + case H of + {commandRequest, CmdReq} -> + do_merge_action_request(T, [CmdReq|CmdReqs], + CtxReq, CtxAuditReq, CtxId); + + {contextProp, ContextProp} -> + do_merge_action_request(T, CmdReqs, + merge_context_request(CtxReq, ContextProp), + CtxAuditReq, CtxId); + + {contextAudit, ContextAuditReq} when CtxAuditReq =:= asn1_NOVALUE -> + do_merge_action_request(T, CmdReqs, + CtxReq, ContextAuditReq, CtxId) + end; +do_merge_action_request([], CmdReqs, CtxReq, CtxAuditReq, CtxId) -> + #'ActionRequest'{contextId = CtxId, + contextRequest = strip_ContextRequest(CtxReq), + contextAttrAuditReq = strip_ContextAttrAuditRequest(CtxAuditReq), + commandRequests = lists:reverse(CmdReqs)}. + + +%% OTP-5085: +%% In order to solve a problem in the parser, the error descriptor +%% has been put last in the non-empty commandReplyList, if it is not +%% asn1_NOVALUE +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_action_reply,1}]}). +-endif. +merge_action_reply(Items) -> + do_merge_action_reply(Items, asn1_NOVALUE, asn1_NOVALUE, []). + +do_merge_action_reply([], Err, Ctx, Cmds) -> + #'ActionReply'{errorDescriptor = Err, + contextReply = strip_ContextRequest(Ctx), + commandReply = lists:reverse(Cmds)}; +do_merge_action_reply([H|T], Err0, CR, Cmds) -> + case H of + {error, Err1} when Err0 =:= asn1_NOVALUE -> + do_merge_action_reply(T, Err1, CR, Cmds); + {command, Cmd} -> + do_merge_action_reply(T, Err0, CR, [Cmd | Cmds]); + {context, CtxProp} -> + do_merge_action_reply(T, Err0, + merge_context_request(CR, CtxProp), Cmds) + end. + +merge_auditOther([TID], TAR) -> + {auditResult, + #'AuditResult'{terminationID = TID, + terminationAuditResult = TAR}}; +merge_auditOther(TIDs, TAR) -> + {auditResultTermList, + #'TermListAuditResult'{terminationIDList = TIDs, + terminationAuditResult = TAR}}. + +strip_ContextRequest(#'ContextRequest'{priority = asn1_NOVALUE, + emergency = asn1_NOVALUE, + topologyReq = asn1_NOVALUE, + iepscallind = asn1_NOVALUE, + contextProp = asn1_NOVALUE, + contextList = asn1_NOVALUE}) -> + asn1_NOVALUE; +strip_ContextRequest(#'ContextRequest'{priority = asn1_NOVALUE, + emergency = asn1_NOVALUE, + topologyReq = asn1_NOVALUE, + iepscallind = asn1_NOVALUE, + contextProp = [], + contextList = asn1_NOVALUE}) -> + asn1_NOVALUE; +%% strip_ContextRequest(asn1_NOVALUE) -> +%% asn1_NOVALUE; +strip_ContextRequest(R) -> + R. + +strip_ContextAttrAuditRequest( + #'ContextAttrAuditRequest'{priority = asn1_NOVALUE, + emergency = asn1_NOVALUE, + topology = asn1_NOVALUE, + iepscallind = asn1_NOVALUE, + contextPropAud = asn1_NOVALUE, + selectpriority = asn1_NOVALUE, + selectemergency = asn1_NOVALUE, + selectiepscallind = asn1_NOVALUE, + selectLogic = asn1_NOVALUE}) -> + asn1_NOVALUE; +strip_ContextAttrAuditRequest( + #'ContextAttrAuditRequest'{priority = asn1_NOVALUE, + emergency = asn1_NOVALUE, + topology = asn1_NOVALUE, + iepscallind = asn1_NOVALUE, + contextPropAud = [], + selectpriority = asn1_NOVALUE, + selectemergency = asn1_NOVALUE, + selectiepscallind = asn1_NOVALUE, + selectLogic = asn1_NOVALUE}) -> + asn1_NOVALUE; +strip_ContextAttrAuditRequest(R) -> + R. + +merge_AmmRequest_descriptors([], Acc) -> + lists:reverse(Acc); +merge_AmmRequest_descriptors([{_, deprecated}|Descs], Acc) -> + merge_AmmRequest_descriptors(Descs, Acc); +merge_AmmRequest_descriptors([Desc|Descs], Acc) -> + merge_AmmRequest_descriptors(Descs, [Desc|Acc]). + +make_auditRequest([TID], AD) -> + #'AuditRequest'{terminationID = TID, + auditDescriptor = AD}; +make_auditRequest([TID|_] = TIDList, AD) -> + #'AuditRequest'{terminationID = TID, + auditDescriptor = AD, + terminationIDList = TIDList}. + +make_commandRequest({CmdTag, {_TokenTag, _Line, Text}}, Cmd) -> + Req = #'CommandRequest'{command = {CmdTag, Cmd}}, + case Text of + [$w, $- | _] -> + Req#'CommandRequest'{wildcardReturn = 'NULL'}; + [$o, $-, $w, $- | _] -> + Req#'CommandRequest'{optional = 'NULL', wildcardReturn = 'NULL'}; + [$o, $- | _] -> + Req#'CommandRequest'{optional = 'NULL'}; + _ -> + Req + end. + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_terminationAudit,1}]}). +-endif. +merge_terminationAudit(AuditReturnParameters) -> + lists:reverse(do_merge_terminationAudit(AuditReturnParameters, [], [])). + +do_merge_terminationAudit([H| T], ARPs, AuditItems) -> + case H of + {auditReturnItem, AuditItem} -> + do_merge_terminationAudit(T, ARPs, [AuditItem | AuditItems]); + AuditReturnParameter -> + do_merge_terminationAudit(T, [AuditReturnParameter | ARPs], AuditItems) + end; +do_merge_terminationAudit([], AuditReturnParameters, []) -> + AuditReturnParameters; +do_merge_terminationAudit([], AuditReturnParameters, AuditItems) -> + AuditDescriptor = #'AuditDescriptor'{auditToken = AuditItems}, + AuditReturnParameter = {emptyDescriptors, AuditDescriptor}, + [AuditReturnParameter | AuditReturnParameters]. + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_mediaDescriptor,1}]}). +-endif. +merge_mediaDescriptor(MediaParms) -> + do_merge_mediaDescriptor(MediaParms, asn1_NOVALUE, [], []). + +do_merge_mediaDescriptor([H | T], TS, One, Multi) -> + case H of + {streamParm, Parm} when Multi =:= [] -> + do_merge_mediaDescriptor(T, TS, [Parm | One], Multi); + {streamDescriptor, Desc} when One =:= [] -> + do_merge_mediaDescriptor(T, TS, One, [Desc | Multi]); + {termState, TS2} when TS =:= asn1_NOVALUE -> + do_merge_mediaDescriptor(T, TS2, One, Multi); + _ -> + return_error(0, {bad_merge_mediaDescriptor, [H, TS, One, Multi]}) + end; +do_merge_mediaDescriptor([], TS, One, Multi) -> + if + (One =:= []) -> + if (Multi =:= []) -> + #'MediaDescriptor'{streams = asn1_NOVALUE, + termStateDescr = TS}; + true -> % (Multi =/= []) + Streams = {multiStream, lists:reverse(Multi)}, + #'MediaDescriptor'{streams = Streams, + termStateDescr = TS} + end; + true -> % (One =/= []) + if + (Multi =:= []) -> + Streams = {oneStream, merge_streamParms(One)}, + #'MediaDescriptor'{streams = Streams, + termStateDescr = TS}; + true -> % (Multi =/= []) + return_error(0, + {bad_merge_mediaDescriptor, [TS, One, Multi]}) + end + end. + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_streamParms,1}]}). +-endif. +merge_streamParms(TaggedStreamParms) -> + SP = #'StreamParms'{}, + do_merge_streamParms(TaggedStreamParms, SP). + +do_merge_streamParms([{Tag, D} | T] = All, SP) -> + case Tag of + local when SP#'StreamParms'.localDescriptor =:= asn1_NOVALUE -> + do_merge_streamParms(T, SP#'StreamParms'{localDescriptor = D}); + remote when SP#'StreamParms'.remoteDescriptor =:= asn1_NOVALUE -> + do_merge_streamParms(T, SP#'StreamParms'{remoteDescriptor = D}); + control -> + LCD = + case SP#'StreamParms'.localControlDescriptor of + asn1_NOVALUE -> + #'LocalControlDescriptor'{propertyParms = []}; + PrevLCD -> + PrevLCD + end, + LCD2 = do_merge_control_streamParms(D, LCD), + do_merge_streamParms(T, SP#'StreamParms'{localControlDescriptor = LCD2}); + statistics when SP#'StreamParms'.statisticsDescriptor =:= asn1_NOVALUE -> + do_merge_streamParms(T, SP#'StreamParms'{statisticsDescriptor = D}); + _ -> + return_error(0, {do_merge_streamParms, [All, SP]}) + end; +do_merge_streamParms([], SP) + when is_record(SP#'StreamParms'.localControlDescriptor, 'LocalControlDescriptor') -> + LCD = SP#'StreamParms'.localControlDescriptor, + PP = LCD#'LocalControlDescriptor'.propertyParms, + LCD2 = LCD#'LocalControlDescriptor'{propertyParms = lists:reverse(PP)}, + SP#'StreamParms'{localControlDescriptor = LCD2}; +do_merge_streamParms([], SP) -> + SP. + + +do_merge_control_streamParms([{SubTag, SD} | T] = All, LCD) -> + case SubTag of + group when LCD#'LocalControlDescriptor'.reserveGroup =:= asn1_NOVALUE -> + LCD2 = LCD#'LocalControlDescriptor'{reserveGroup = SD}, + do_merge_control_streamParms(T, LCD2); + value when LCD#'LocalControlDescriptor'.reserveValue =:= asn1_NOVALUE -> + LCD2 = LCD#'LocalControlDescriptor'{reserveValue = SD}, + do_merge_control_streamParms(T, LCD2); + mode when LCD#'LocalControlDescriptor'.streamMode =:= asn1_NOVALUE -> + LCD2 = LCD#'LocalControlDescriptor'{streamMode = SD}, + do_merge_control_streamParms(T, LCD2); + prop -> + PP = LCD#'LocalControlDescriptor'.propertyParms, + LCD2 = LCD#'LocalControlDescriptor'{propertyParms = [SD | PP]}, + do_merge_control_streamParms(T, LCD2); + _ -> + return_error(0, {do_merge_control_streamParms, [All, LCD]}) + end; +do_merge_control_streamParms([], LCD) -> + LCD. + +-ifdef(megaco_parser_inline). +-compile({inline,[{merge_terminationStateDescriptor,1}]}). +-endif. +merge_terminationStateDescriptor(Parms) -> + TSD = #'TerminationStateDescriptor'{propertyParms = []}, + do_merge_terminationStateDescriptor(Parms, TSD). + +do_merge_terminationStateDescriptor([{Tag, Val} | T], TSD) -> + case Tag of + serviceState when TSD#'TerminationStateDescriptor'.serviceState =:= asn1_NOVALUE -> + TSD2 = TSD#'TerminationStateDescriptor'{serviceState = Val}, + do_merge_terminationStateDescriptor(T, TSD2); + eventBufferControl when TSD#'TerminationStateDescriptor'.eventBufferControl =:= asn1_NOVALUE-> + TSD2 = TSD#'TerminationStateDescriptor'{eventBufferControl = Val}, + do_merge_terminationStateDescriptor(T, TSD2); + propertyParm -> + PP = TSD#'TerminationStateDescriptor'.propertyParms, + TSD2 = TSD#'TerminationStateDescriptor'{propertyParms = [Val | PP]}, + do_merge_terminationStateDescriptor(T, TSD2) + end; +do_merge_terminationStateDescriptor([], TSD) -> + PP = TSD#'TerminationStateDescriptor'.propertyParms, + TSD#'TerminationStateDescriptor'{propertyParms = lists:reverse(PP)}. + +-ifdef(megaco_nscanner_props). + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_prop_groups,1}]}). +-endif. +ensure_prop_groups(Token) -> + {_TokenTag, _Line, Text} = Token, + Group = [], + Groups = [], + parse_prop_name(Text, Group, Groups). + +parse_prop_name([Char | Rest] = All, Group, Groups) -> + if + ?white_space(Char) -> + parse_prop_name(Rest, Group, Groups); + ?end_of_line(Char) -> + parse_prop_name(Rest, Group, Groups); + true -> + Name = [], + do_parse_prop_name(All, Name, Group, Groups) + end; +parse_prop_name([] = All, Group, Groups) -> + Name = [], + do_parse_prop_name(All, Name, Group, Groups). + +do_parse_prop_name([Char | Rest], Name, Group, Groups) + when (Char =:= $=) andalso (Name =/= []) -> + %% Now we have a complete name + if + (Name =:= "v") andalso (Group =/= []) -> + %% v= is a property group delimiter, + %% lets create yet another property group. + Groups2 = [lists:reverse(Group) | Groups], + Group2 = [], + parse_prop_value(Rest, Name, Group2, Groups2); + true -> + %% Use current property group + parse_prop_value(Rest, Name, Group, Groups) + end; +do_parse_prop_name([Char | Rest], Name, Group, Groups) -> + case ?classify_char4(Char) of + safe_char_upper -> + do_parse_prop_name(Rest, [Char | Name], Group, Groups); + safe_char -> + do_parse_prop_name(Rest, [Char | Name], Group, Groups); + _ -> + return_error(0, {bad_prop_name, lists:reverse(Name), Char}) + end; +do_parse_prop_name([], [], [], Groups) -> + lists:reverse(Groups); +do_parse_prop_name([], [], Group, Groups) -> + Group2 = lists:reverse(Group), + lists:reverse([Group2 | Groups]); +do_parse_prop_name([], Name, Group, Groups) when Name =/= [] -> + %% Assume end of line + Value = [], + PP = make_prop_parm(Name, Value), + Group2 = lists:reverse([PP | Group]), + lists:reverse([Group2 | Groups]). + +-ifdef(megaco_parser_inline). +-compile({inline,[{parse_prop_value,4}]}). +-endif. +parse_prop_value(Chars, Name, Group, Groups) -> + Value = [], + do_parse_prop_value(Chars, Name, Value, Group, Groups). + +do_parse_prop_value([Char | Rest], Name, Value, Group, Groups) -> + if + ?end_of_line(Char) -> + %% Now we have a complete "name=value" pair + PP = make_prop_parm(Name, Value), + parse_prop_name(Rest, [PP | Group], Groups); + true -> + do_parse_prop_value(Rest, Name, [Char | Value], Group, Groups) + end; +do_parse_prop_value([], Name, Value, Group, Groups) -> + %% Assume end of line + PP = make_prop_parm(Name, Value), + Group2 = lists:reverse([PP | Group]), + lists:reverse([Group2 | Groups]). + +-ifdef(megaco_parser_inline). +-compile({inline,[{make_prop_parm,2}]}). +-endif. +make_prop_parm(Name, Value) -> + #'PropertyParm'{name = lists:reverse(Name), + value = [lists:reverse(Value)]}. + +-else. % -ifdef(megaco_nscanner_props). + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_prop_groups,1}]}). +-endif. +ensure_prop_groups(Token) -> + {_TokenTag, _Line, Groups} = Token, + Groups. + +%% -ifdef(megaco_parser_inline). +%% -compile({inline,[{do_ensure_prop_groups,1}]}). +%% -endif. +%% do_ensure_prop_groups(Groups) when is_list(Groups) -> +%% [ensure_prop_group(Group) || Group <- Groups]; +%% do_ensure_prop_groups(BadGroups) -> +%% throw({error, {?MODULE, {bad_property_groups, BadGroups}}}). + +%% -ifdef(megaco_parser_inline). +%% -compile({inline,[{ensure_prop_group,1}]}). +%% -endif. +%% ensure_prop_group(Group) when is_list(Group) -> +%% [ensure_prop_parm(PropParm) || PropParm <- Group]; +%% ensure_prop_group(BadGroup) -> +%% throw({error, {?MODULE, {bad_property_group, BadGroup}}}). + +%% -ifdef(megaco_parser_inline). +%% -compile({inline,[{ensure_prop_parm,1}]}). +%% -endif. +%% ensure_prop_parm(#property_parm{name = Name, +%% value = Value}) -> +%% #'PropertyParm'{name = Name, +%% value = Value}; +%% ensure_prop_parm(PP) when is_record(PP, 'PropertyParm') -> +%% PP; +%% ensure_prop_parm(BadPropParm) -> +%% throw({error, {?MODULE, {bad_property_parm, BadPropParm}}}). + +-endif. % -ifdef(megaco_nscanner_props). + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_uint,3}]}). +-endif. +ensure_uint(Token, Min, Max) -> + case Token of + {_TokenTag, Line, Val} when is_integer(Val) -> + ensure_uint(Val, Min, Max, Line); + {_TokenTag, Line, Text} -> + case (catch list_to_integer(Text)) of + {'EXIT', _} -> + return_error(Line, {not_an_integer, Text}); + Val when is_integer(Val) -> + ensure_uint(Val, Min, Max, Line) + end; + Val when is_integer(Val) -> + ensure_uint(Val, Min, Max, 0); + Text -> + case (catch list_to_integer(Text)) of + {'EXIT', _} -> + return_error(0, {not_an_integer, Text}); + Val when is_integer(Val) -> + ensure_uint(Val, Min, Max, 0) + end + end. + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_uint,4}]}). +-endif. +ensure_uint(Val, Min, Max, Line) -> + if + is_integer(Min) andalso (Val >= Min) -> + if + is_integer(Max) andalso (Val =< Max) -> + Val; + Max =:= infinity -> + Val; + true -> + return_error(Line, {too_large_integer, Val, Max}) + end; + true -> + return_error(Line, {too_small_integer, Val, Min}) + end. + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_uint16,1}]}). +-endif. +ensure_uint16(Int) -> + ensure_uint(Int, 0, 65535). + +-ifdef(megaco_parser_inline). +-compile({inline,[{ensure_uint32,1}]}). +-endif. +ensure_uint32(Int) -> + ensure_uint(Int, 0, 4294967295) . + +%% OTP-4710 +ensure_hex({_TokenTag, _Line, [$0, $x |Chars]}, Min, Max) -> + ensure_uint(length(Chars), Min, Max), + hex_to_int(Chars, []); +ensure_hex({_TokenTag, _Line, [$0, $X |Chars]}, Min, Max) -> + ensure_uint(length(Chars), Min, Max), + hex_to_int(Chars, []); +ensure_hex([$0, $x |Chars], Min, Max) -> + ensure_uint(length(Chars), Min, Max), + hex_to_int(Chars, []); +ensure_hex([$0, $X |Chars], Min, Max) -> + ensure_uint(length(Chars), Min, Max), + hex_to_int(Chars, []). + +%% OTP-4710 +hex_to_int([], Acc) -> + lists:reverse(Acc); +hex_to_int([Char1,Char2|Tail], Acc) -> + Int1 = hchar_to_int(Char1), + Int2 = hchar_to_int(Char2), + Val = Int2 bor (Int1 bsl 4), + hex_to_int(Tail, [Val| Acc]); +hex_to_int([Char], Acc) -> + Int = hchar_to_int(Char), + lists:reverse([Int|Acc]). + +hchar_to_int(Char) when ($0 =< Char) andalso (Char =< $9) -> + Char - $0; +hchar_to_int(Char) when ($A =< Char) andalso (Char =< $F) -> + Char - $A + 10; % OTP-4710 +hchar_to_int(Char) when ($a =< Char) andalso (Char =< $f) -> + Char - $a + 10. % OTP-4710 + +-ifdef(megaco_parser_inline). +-compile({inline,[{value_of,1}]}). +-endif. +value_of(Token) -> + {_TokenTag, _Line, Text} = Token, + Text. + + +%% ------------------------------------------------------------------- + +%% d(F) -> +%% d(F,[]). +%% d(F, A) -> +%% %% d(true, F, A). +%% d(get(dbg), F, A). + +%% d(true, F, A) -> +%% io:format("DBG:~w:" ++ F ++ "~n", [?MODULE | A]); +%% d(_, _, _) -> +%% ok. + diff --git a/lib/megaco/src/text/megaco_text_parser_v3.yrl b/lib/megaco/src/text/megaco_text_parser_v3.yrl new file mode 100644 index 0000000000..d400a93c66 --- /dev/null +++ b/lib/megaco/src/text/megaco_text_parser_v3.yrl @@ -0,0 +1,1680 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2005-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: YECC grammar for text encoding of Megaco/H.248 +%%---------------------------------------------------------------------- + +%%---------------------------------------------------------------------- +%% Annex B TEXT ENCODING OF THE PROTOCOL (NORMATIVE) +%% +%% B.1 Coding of wildcards +%% +%% In a text encoding of the protocol, while TerminationIDs are +%% arbitrary, by judicious choice of names, the wildcard character, "*" +%% may be made more useful. When the wildcard character is encountered, +%% it will "match" all TerminationIDs having the same previous and +%% following characters (if appropriate). For example, if there were +%% TerminationIDs of R13/3/1, R13/3/2 and R13/3/3, the TerminationID +%% R13/3/* would match all of them. There are some circumstances where +%% ALL Terminations must be referred to. The TerminationID "*" suffices, +%% and is referred to as ALL. The CHOOSE TerminationID "$" may be used to +%% signal to the MG that it has to create an ephemeral Termination or +%% select an idle physical Termination. +%% +%% B.2 ABNF specification +%% +%% The protocol syntax is presented in ABNF according to RFC2234. The +%% protocol is not case sensitive. Identifiers are not case sensitive. +%% +%% NOTE 1 - This syntax specification does not enforce all restrictions +%% on element inclusions and values. Some additional +%% restrictions are stated in comments and other restrictions +%% appear in the text of this Recommendation. These additional +%% restrictions are part of the protocol even though not +%% enforced by this Recommendation. +%% NOTE 2 - The syntax is context-dependent. For example, "Add" can be +%% the AddToken or a NAME depending on the context in which it +%% occurs. +%% +%% Everything in the ABNF and text encoding is case insensitive. This +%% includes TerminationIDs, digitmap Ids etc. SDP is case sensitive as +%% per RFC 2327. +%% +%%---------------------------------------------------------------------- + +%%---------------------------------------------------------------------- +%% Number of expected shift/reduce warnings +%% This is ugly but... +%%---------------------------------------------------------------------- + +Expect 91. + + +%%---------------------------------------------------------------------- +%% Non-terminals +%%---------------------------------------------------------------------- + +Nonterminals + + actionReply + actionReplyBody + actionReplyList + actionRequest + actionRequestBody + actionRequestItem + actionRequestItems + actionRequestList + alternativeValue + ammParameter + ammParameters + ammRequest + ammRequestBody + ammToken + ammsReply + ammsReplyBody + ammsToken + auditDescriptor + auditDescriptorBody + auditItem + auditItemList + auditOther + auditReply + auditRequest + auditReturnItem + auditReturnParameter + auditReturnParameterList + auditSelectLogic %% v3 + authenticationHeader + commandReplyList + commandReplys %% v3 + commandRequest + contextAttrDescriptor %% v3 + contextAudit + contextAuditProperties + contextAuditProperty + contextAuditSelector %% v3 + contextID + contextIdList %% v3 + contextIDs %% v3 +%% contextProperties %% v3 + contextProperty +%% contextPropertyList + contextTerminationAudit + daddr + deviceName + digitMapDescriptor + direction %% v3 + domainAddress + domainName + embedFirst + embedNoSig + embedSig + embedWithSig + emergencyValue %% v3 + errorCode + errorDescriptor + errorText + eventBufferControl + eventBufferControlValue %% v3 + eventBufferDescriptor + eventDM + eventParameter + eventParameterName + eventParameters + eventSpec + eventSpecList + eventStream + eventStreamOrOther + eventsDescriptor + extension + extensionParameter + + iaServiceStates %% v3 + iepsValue + + %% v2 - start + indAudauditReturnParameter + indAuddigitMapDescriptor + indAudeventBufferDescriptor + indAudeventSpec + indAudeventSpecParameter + %% indAudeventSpecParameterList + indAudeventsDescriptor + indAudlocalControlDescriptor + indAudlocalParm + indAudlocalParmList + indAudmediaDescriptor + indAudmediaParm + indAudmediaParms %% v3 + %% indAudmediaParmList + indAudpackagesDescriptor + indAudrequestedEvent + indAudsignalsDescriptor + indAudsignalList + %% indAudsignalListParm + indAudsignalParm + %% indAudsignalRequest + indAudstreamDescriptor + indAudstreamParm + indAudstatisticsDescriptor + indAudterminationAudit + indAudterminationAuditList + indAudterminationStateDescriptor + indAudterminationStateParm + %% indAudterminationStateParmList + optIndAudeventSpecParameter + optIndAudsignalParm + %% v2 - end + + indAudcontextAttrDescriptor %% v3 + + localControlDescriptor + localParm + localParmList + mId + mediaDescriptor + mediaParm + mediaParmList + megacoMessage + message + messageBody + modemDescriptor % Deprecated as of Corr 1 + modemType % Deprecated as of Corr 1 + modemTypeList % Deprecated as of Corr 1 + mtpAddress + muxDescriptor + muxType + notificationReason + notificationReasons + notifyBehaviour %% v3 + notifyRegulated %% v3 + notifyReply + notifyReplyBody + notifyRequest + notifyRequestBody + observedEvent + observedEventBody + observedEventParameter + observedEventParameters + % observedEventTimeStamp + observedEvents + observedEventsDescriptor + onOrOff + optAuditDescriptor + optImmAckRequired + optPropertyParms + optSep + packagesDescriptor + packagesItem + packagesItems + %% parmName + parmValue + pathName + pkgdName + portNumber + priority + propertyParm + propertyParms + propertyParmList + requestID + requestedEvent + requestedEventBody + requestedEvents + safeToken + safeToken2 + secondEventParameter + secondEventParameters + secondRequestedEvent + secondRequestedEventBody + secondRequestedEvents + segmentReply %% v3 + %% segmentNumber %% v3 + servChgReplyParm + servChgReplyParms + serviceChangeAddress + serviceChangeDelay + serviceChangeDescriptor + serviceChangeMethod + serviceChangeMgcId + serviceChangeParm + serviceChangeParms + serviceChangeProfile + serviceChangeReason + serviceChangeReply + serviceChangeReplyBody + serviceChangeReplyDescriptor + serviceChangeRequest + serviceChangeVersion + serviceStates + serviceStatesValue %% v3 + sigParameter + sigParameters + signalList + signalListId + signalListParm + signalListParms + signalName + signalParm + signalParms + signalRequest + signalsDescriptor + signalType + statisticsDescriptor + statisticsParameter + statisticsParameters + streamDescriptor + streamID + streamModes + streamParm + streamParmList + subtractRequest + termIDList %% v3 + terminationAudit + terminationID + terminationIDList + terminationIDListRepeat + terminationStateDescriptor + terminationStateParm + terminationStateParms + timeStamp + topologyDescriptor + topologyDirection + topologyDescComp + topologyDescCompList + transactionAck + transactionAckList + transactionID + transactionID_and_segment_info + transactionItem + transactionList + transactionPending + transactionReply + transactionReplyBody + transactionRequest + transactionResponseAck + value + valueList + +. + +%%---------------------------------------------------------------------- +%% Terminals +%%---------------------------------------------------------------------- + +Terminals + + 'AddToken' + 'AndAUDITselectToken' %% v3 + 'AuditCapToken' + 'AuditToken' + 'AuditValueToken' + 'AuthToken' + 'BothToken' %% v3 + 'BothwayToken' + 'BriefToken' + 'BufferToken' + 'COLON' + 'COMMA' + 'ContextAttrToken' %% v3 + 'ContextAuditToken' + 'ContextListToken' %% v3 + 'CtxToken' + 'DelayToken' + 'DigitMapToken' + 'DigitMapDescriptorToken' + 'DirectionToken' %% v3 + 'DiscardToken' + 'DisconnectedToken' + 'DurationToken' + 'EQUAL' + 'EmbedToken' + 'EmergencyToken' + 'EmergencyOffToken' + 'EmergencyValueToken' %% v3 + 'ErrorToken' + 'EventBufferToken' + 'EventsToken' + 'ExternalToken' %% v3 + 'FailoverToken' + 'ForcedToken' + 'GREATER' + 'GracefulToken' + 'H221Token' + 'H223Token' + 'H226Token' + 'HandOffToken' + 'IEPSToken' %% v3 + 'ImmAckRequiredToken' + 'INEQUAL' %% v3 + 'InSvcToken' + 'InactiveToken' + 'InternalToken' %% v3 + 'InterruptByEventToken' + 'InterruptByNewSignalsDescrToken' + 'IntsigDelayToken' %% v3 + 'IsolateToken' + 'IterationToken' %% v3 + 'KeepActiveToken' + 'LBRKT' + 'LESSER' + 'LSBRKT' + 'LocalControlToken' + 'LocalDescriptorToken' + 'LockStepToken' + 'LoopbackToken' + 'MediaToken' + %% 'MegacopToken' + 'MessageSegmentToken' + 'MethodToken' + 'MgcIdToken' + 'ModeToken' + 'ModemToken' + 'ModifyToken' + 'MoveToken' + 'MtpAddressToken' + 'MuxToken' + 'NEQUAL' + 'NeverNotifyToken' %% v3 + 'NotifyCompletionToken' + 'NotifyImmediateToken' %% v3 + 'NotifyRegulatedToken' %% v3 + 'NotifyToken' + 'Nx64Token' %% v2 + 'ObservedEventsToken' + 'OffToken' + 'OnToken' + 'OnOffToken' + 'OnewayToken' + 'OnewayExternalToken' %% v3 + 'OnewayBothToken' %% v3 + 'OrAUDITselectToken' %% v3 + 'OtherReasonToken' + 'OutOfSvcToken' + 'PackagesToken' + 'PendingToken' + 'PriorityToken' + 'ProfileToken' + 'QuotedChars' + 'RBRKT' + 'RSBRKT' + 'ReasonToken' + 'RecvonlyToken' + 'RemoteDescriptorToken' + 'ReplyToken' + 'RequestIDToken' %% v3 + 'ReservedGroupToken' + 'ReservedValueToken' + 'ResetEventsDescriptorToken' %% v3 + 'ResponseAckToken' + 'RestartToken' + 'SEP' + 'SafeChars' + %% 'SegmentationCompleteToken' + 'SendonlyToken' + 'SendrecvToken' + 'ServiceChangeAddressToken' + 'ServiceChangeToken' + 'ServiceChangeIncompleteToken' + 'ServiceStatesToken' + 'ServicesToken' + 'SignalListToken' + 'SignalTypeToken' + 'SignalsToken' + %% 'SLASH' + 'StatsToken' + 'StreamToken' + 'SubtractToken' + 'SynchISDNToken' + 'TerminationStateToken' + 'TestToken' + 'TimeOutToken' + 'TimeStampToken' + 'TopologyToken' + 'TransToken' + 'V18Token' + 'V22Token' + 'V22bisToken' + 'V32Token' + 'V32bisToken' + 'V34Token' + 'V76Token' + 'V90Token' + 'V91Token' + 'VersionToken' + endOfMessage + +. + +%%---------------------------------------------------------------------- +%% Root symbol +%%---------------------------------------------------------------------- + +Rootsymbol megacoMessage. + +%%---------------------------------------------------------------------- +%% The grammar +%%---------------------------------------------------------------------- + +%% megacoMessage = LWSP [authenticationHeader SEP ] message +%% authenticationHeader = AuthToken EQUAL SecurityParmIndex COLON +%% SequenceNum COLON AuthData +%% +%% SecurityParmIndex = "0x" 8(HEXDIG) +%% SequenceNum = "0x" 8(HEXDIG) +%% AuthData = "0x" 24*64(HEXDIG) +%% message = MegacopToken SLASH version SEP mId SEP messageBody +%% version = 1*2(DIGIT) . + +megacoMessage -> optSep authenticationHeader message endOfMessage + : #'MegacoMessage'{authHeader = '$2', mess = '$3'} . + +optSep -> 'SEP' : sep . +optSep -> '$empty' : no_sep . + +authenticationHeader -> 'AuthToken' 'EQUAL' safeToken 'COLON' + safeToken 'COLON' safeToken optSep + : ensure_auth_header('$3', '$5', '$7') . +authenticationHeader -> '$empty' : asn1_NOVALUE . + +message -> safeToken mId messageBody : + ensure_message('$1', '$2', '$3') . + +messageBody -> errorDescriptor : {messageError, '$1'} . +messageBody -> transactionList : {transactions, '$1'} . + +transactionList -> transactionItem : ['$1'] . +transactionList -> transactionItem transactionList : ['$1' | '$2'] . + +transactionItem -> transactionRequest : {transactionRequest, '$1'} . +transactionItem -> transactionReply : {transactionReply, '$1'}. +transactionItem -> transactionPending : {transactionPending, '$1'} . +transactionItem -> transactionResponseAck : {transactionResponseAck, '$1'} . +transactionItem -> segmentReply : {segmentReply, '$1'} . + +transactionResponseAck -> 'ResponseAckToken' + 'LBRKT' transactionAck + transactionAckList 'RBRKT' : ['$3' | '$4'] . + +transactionAckList -> 'COMMA' transactionAck + transactionAckList : ['$2' | '$3'] . +transactionAckList -> '$empty' : [] . + +transactionAck -> safeToken : ensure_transactionAck('$1') . + +transactionPending -> 'PendingToken' 'EQUAL' transactionID 'LBRKT' 'RBRKT' : + #'TransactionPending'{transactionId = ensure_transactionID('$3') } . + +transactionRequest -> 'TransToken' 'LBRKT' actionRequest + actionRequestList 'RBRKT' : + #'TransactionRequest'{transactionId = asn1_NOVALUE, + actions = ['$3' | '$4']} . +transactionRequest -> 'TransToken' 'EQUAL' 'LBRKT' actionRequest + actionRequestList 'RBRKT' : + #'TransactionRequest'{transactionId = asn1_NOVALUE, + actions = ['$4' | '$5']} . +transactionRequest -> 'TransToken' 'EQUAL' transactionID + 'LBRKT' actionRequest actionRequestList 'RBRKT' : + #'TransactionRequest'{transactionId = ensure_transactionID('$3'), + actions = ['$5' | '$6']} . + +actionRequestList -> 'COMMA' actionRequest actionRequestList : ['$2' | '$3'] . +actionRequestList -> '$empty' : [] . + +%% actionRequest = CtxToken EQUAL ContextID LBRKT ((contextRequest +%% [COMMA commandRequestList]) / +%% commandRequestList) RBRKT +%% contextRequest = ((contextProperties [COMMA contextAudit]) / +%% contextAudit) +%% contextProperties = contextProperty *(COMMA contextProperty) + +actionRequest -> 'CtxToken' 'EQUAL' contextID + 'LBRKT' actionRequestBody 'RBRKT' : + merge_action_request('$3', '$5') . + +actionRequestBody -> actionRequestItem actionRequestItems : ['$1' | '$2'] . + +actionRequestItems -> 'COMMA' actionRequestItem + actionRequestItems : ['$2' | '$3'] . +actionRequestItems -> '$empty' : [] . + +actionRequestItem -> contextProperty : {contextProp, '$1'} . +actionRequestItem -> contextAudit : {contextAudit, '$1'} . +actionRequestItem -> commandRequest : {commandRequest, '$1'} . + + +%% at-most-once (presumebly in contextProperties) +contextProperty -> topologyDescriptor : {topology, '$1'}. +contextProperty -> priority : {priority, '$1'}. +contextProperty -> 'EmergencyToken' : {emergency, true}. +contextProperty -> 'EmergencyOffToken' : {emergency, false}. +contextProperty -> iepsValue : {iepsCallind, '$1'} . +contextProperty -> contextAttrDescriptor : '$1' . + +contextAttrDescriptor -> 'ContextAttrToken' 'LBRKT' propertyParms 'RBRKT' : + {contextProp, '$3'}. +contextAttrDescriptor -> 'ContextAttrToken' 'LBRKT' contextIdList 'RBRKT' : + {contextList, '$3'}. + +contextIdList -> 'ContextListToken' 'EQUAL' + 'LBRKT' contextID contextIDs 'RBRKT' : ['$4' | '$5'] . + +contextIDs -> 'COMMA' contextID contextIDs : ['$2' | '$3'] . +contextIDs -> '$empty' : [] . + +contextAudit -> 'ContextAuditToken' 'LBRKT' + indAudcontextAttrDescriptor 'RBRKT' : + merge_context_attr_audit_request( + #'ContextAttrAuditRequest'{}, '$3') . +contextAudit -> 'ContextAuditToken' 'LBRKT' + contextAuditProperty contextAuditProperties 'RBRKT' : + merge_context_attr_audit_request( + #'ContextAttrAuditRequest'{}, ['$3' | '$4']) . + +indAudcontextAttrDescriptor -> 'ContextAttrToken' + 'LBRKT' contextAuditProperty + contextAuditProperties 'RBRKT' + : ['$3' | '$4'] . + +contextAuditProperties -> 'COMMA' contextAuditProperty contextAuditProperties + : ['$2' | '$3'] . +contextAuditProperties -> '$empty' : [] . + +%% at-most-once except contextAuditSelector. +contextAuditProperty -> 'TopologyToken' : topologyAudit . +contextAuditProperty -> 'EmergencyToken' : emergencyAudit . +contextAuditProperty -> 'PriorityToken' : priorityAudit . +contextAuditProperty -> 'IEPSToken' : iepsCallind . +contextAuditProperty -> pkgdName : {prop, '$1'} . +contextAuditProperty -> contextAuditSelector : '$1' . + +%% at-most-once +contextAuditSelector -> priority : {select_prio, '$1'} . +contextAuditSelector -> emergencyValue : {select_emergency, '$1'} . +contextAuditSelector -> iepsValue : {select_ieps, '$1'} . +contextAuditSelector -> auditSelectLogic : {select_logic, '$1'} . +contextAuditSelector -> contextAttrDescriptor : '$1' . + +auditSelectLogic -> 'AndAUDITselectToken' : {andAUDITSelect, 'NULL'} . +auditSelectLogic -> 'OrAUDITselectToken' : {orAUDITSelect, 'NULL'} . + +commandRequest -> ammRequest : '$1'. +commandRequest -> subtractRequest : '$1'. +commandRequest -> auditRequest : '$1'. +commandRequest -> notifyRequest : '$1'. +commandRequest -> serviceChangeRequest : '$1'. + +transactionReply -> 'ReplyToken' 'EQUAL' transactionID_and_segment_info + 'LBRKT' + optImmAckRequired transactionReplyBody + 'RBRKT' : + make_TransactionReply('$3', '$5', '$6') . + +segmentReply -> 'MessageSegmentToken' 'EQUAL' + transactionID_and_segment_info : + make_SegmentReply('$3') . + +%% segmentNumber -> safeToken : ensure_uint16('$1') . + +optImmAckRequired -> 'ImmAckRequiredToken' 'COMMA' : 'NULL' . +optImmAckRequired -> '$empty' : asn1_NOVALUE . + +transactionReplyBody -> errorDescriptor : {transactionError, '$1'} . +transactionReplyBody -> actionReply actionReplyList : {actionReplies, ['$1' | '$2']} . + +actionReplyList -> 'COMMA' actionReply actionReplyList : ['$2' | '$3'] . +actionReplyList -> '$empty' : [] . + +actionReply -> 'CtxToken' 'EQUAL' contextID + 'LBRKT' actionReplyBody 'RBRKT' : + setelement(#'ActionReply'.contextId, '$5', '$3') . +actionReply -> 'CtxToken' 'EQUAL' contextID : + #'ActionReply'{contextId = '$3'} . + +actionReplyBody -> errorDescriptor : + #'ActionReply'{errorDescriptor = '$1'} . +actionReplyBody -> commandReplys commandReplyList : + merge_action_reply(['$1' | '$2']) . + +%% OTP-5085 +%% This ugly thing is to fool the parser. The errorDescriptor does not +%% realy belong here. The merge_action_reply will remove it and put it +%% in it's right place later. +commandReplyList -> 'COMMA' errorDescriptor : + [{error, '$2'}] . +commandReplyList -> 'COMMA' commandReplys commandReplyList : + ['$2' | '$3'] . +commandReplyList -> '$empty' : [] . + +commandReplys -> serviceChangeReply : {command, '$1'} . +commandReplys -> auditReply : {command, '$1'} . +commandReplys -> ammsReply : {command, '$1'} . +commandReplys -> notifyReply : {command, '$1'} . +commandReplys -> contextProperty : {context, '$1'} . + +%Add Move and Modify have the same request parameter +ammRequest -> ammToken 'EQUAL' termIDList ammRequestBody : + Descs = merge_AmmRequest_descriptors('$4', []), + make_commandRequest('$1', + #'AmmRequest'{terminationID = '$3', + descriptors = Descs}) . + +ammToken -> 'AddToken' : {addReq, '$1'} . +ammToken -> 'MoveToken' : {moveReq, '$1'} . +ammToken -> 'ModifyToken' : {modReq, '$1'} . + +ammRequestBody -> 'LBRKT' ammParameter ammParameters 'RBRKT' : ['$2' | '$3'] . +ammRequestBody -> '$empty' : [] . + +ammParameters -> 'COMMA' ammParameter ammParameters : ['$2' | '$3'] . +ammParameters -> '$empty' : [] . + +%at-most-once +ammParameter -> mediaDescriptor : {mediaDescriptor, '$1'}. +ammParameter -> modemDescriptor : {modemDescriptor, deprecated}. +ammParameter -> muxDescriptor : {muxDescriptor, '$1'}. +ammParameter -> eventsDescriptor : {eventsDescriptor, '$1'}. +ammParameter -> eventBufferDescriptor : {eventBufferDescriptor, '$1'}. +ammParameter -> signalsDescriptor : {signalsDescriptor, '$1'}. +ammParameter -> digitMapDescriptor : {digitMapDescriptor, '$1'}. +ammParameter -> auditDescriptor : {auditDescriptor, '$1'}. +ammParameter -> statisticsDescriptor : {statisticsDescriptor, '$1'}. + +ammsReply -> ammsToken 'EQUAL' termIDList ammsReplyBody + : {'$1', #'AmmsReply'{terminationID = '$3', + terminationAudit = '$4'}} . + +ammsToken -> 'AddToken' : addReply . +ammsToken -> 'MoveToken' : moveReply . +ammsToken -> 'ModifyToken' : modReply . +ammsToken -> 'SubtractToken' : subtractReply . + +ammsReplyBody -> 'LBRKT' terminationAudit 'RBRKT' : '$2' . +ammsReplyBody -> '$empty' : asn1_NOVALUE . + +subtractRequest -> 'SubtractToken' 'EQUAL' termIDList optAuditDescriptor : + SR = #'SubtractRequest'{terminationID = '$3', + auditDescriptor = '$4'}, + make_commandRequest({subtractReq, '$1'}, SR) . + + +optAuditDescriptor -> 'LBRKT' auditDescriptor 'RBRKT' : '$2'. +optAuditDescriptor -> '$empty' : asn1_NOVALUE . + +auditRequest -> 'AuditValueToken' 'EQUAL' termIDList optAuditDescriptor : + make_commandRequest({auditValueRequest, '$1'}, + make_auditRequest('$3', '$4')) . +auditRequest -> 'AuditCapToken' 'EQUAL' termIDList optAuditDescriptor : + make_commandRequest({auditCapRequest, '$1'}, + make_auditRequest('$3', '$4')) . + +auditReply -> 'AuditValueToken' 'EQUAL' 'CtxToken' contextTerminationAudit : + {auditValueReply, '$4'} . +auditReply -> 'AuditCapToken' 'EQUAL' 'CtxToken' contextTerminationAudit : + {auditCapReply, '$4'} . +auditReply -> 'AuditValueToken' 'EQUAL' auditOther : + {auditValueReply, '$3'} . +auditReply -> 'AuditCapToken' 'EQUAL' auditOther : + {auditCapReply, '$3'} . + +contextTerminationAudit -> terminationIDList : + {contextAuditResult, '$1'} . +contextTerminationAudit -> 'LBRKT' errorDescriptor 'RBRKT' : + {error, '$2'} . + +auditOther -> termIDList : + merge_auditOther('$1', []) . +auditOther -> termIDList 'LBRKT' terminationAudit 'RBRKT' : + merge_auditOther('$1', '$3') . + + +terminationAudit -> auditReturnParameter auditReturnParameterList : + merge_terminationAudit(['$1' |'$2' ]) . + +auditReturnParameterList -> 'COMMA' auditReturnParameter auditReturnParameterList : ['$2' | '$3'] . +auditReturnParameterList -> '$empty' : [] . + +auditReturnParameter -> mediaDescriptor : {mediaDescriptor, '$1'} . +auditReturnParameter -> modemDescriptor. +auditReturnParameter -> muxDescriptor : {muxDescriptor, '$1'} . +auditReturnParameter -> eventsDescriptor : {eventsDescriptor, '$1'} . +auditReturnParameter -> signalsDescriptor : {signalsDescriptor, '$1'} . +auditReturnParameter -> digitMapDescriptor : {digitMapDescriptor, '$1'} . +auditReturnParameter -> observedEventsDescriptor : {observedEventsDescriptor, '$1'} . +auditReturnParameter -> eventBufferDescriptor : {eventBufferDescriptor, '$1'} . +auditReturnParameter -> statisticsDescriptor : {statisticsDescriptor, '$1'} . +auditReturnParameter -> packagesDescriptor : {packagesDescriptor, '$1'} . +auditReturnParameter -> errorDescriptor : {errorDescriptor, '$1'} . +auditReturnParameter -> auditReturnItem : {auditReturnItem, '$1'} . + +auditDescriptor -> 'AuditToken' 'LBRKT' auditDescriptorBody 'RBRKT' : + merge_auditDescriptor('$3') . + +auditDescriptorBody -> auditItem auditItemList : ['$1' | '$2']. +auditDescriptorBody -> '$empty' : asn1_NOVALUE . + +auditItemList -> 'COMMA' auditItem auditItemList : ['$2' | '$3'] . +auditItemList -> '$empty' : [] . + +%% IGv11 - begin +%% +auditReturnItem -> 'MuxToken' : muxToken . +auditReturnItem -> 'ModemToken' : modemToken . +auditReturnItem -> 'MediaToken' : mediaToken . +auditReturnItem -> 'DigitMapToken' : digitMapToken . +auditReturnItem -> 'StatsToken' : statsToken . +auditReturnItem -> 'ObservedEventsToken' : observedEventsToken . +auditReturnItem -> 'PackagesToken' : packagesToken . + +%% at-most-once, and DigitMapToken and PackagesToken are not allowed +%% in AuditCapabilities command +auditItem -> auditReturnItem : '$1' . +auditItem -> 'SignalsToken' : signalsToken. +auditItem -> 'EventBufferToken' : eventBufferToken. +auditItem -> 'EventsToken' : eventsToken . +auditItem -> indAudterminationAudit : {terminationAudit, '$1'} . % v2 +%% +%% IGv11 - end + + +%% v2 - start +%% +indAudterminationAudit -> indAudauditReturnParameter + indAudterminationAuditList + : ['$1' | '$2'] . + +indAudterminationAuditList -> 'COMMA' indAudauditReturnParameter + indAudterminationAuditList + : ['$2' | '$3'] . +indAudterminationAuditList -> '$empty' : [] . + +indAudauditReturnParameter -> indAudmediaDescriptor + : {indAudMediaDescriptor, '$1'} . +indAudauditReturnParameter -> indAudeventsDescriptor + : {indAudEventsDescriptor, '$1'} . +indAudauditReturnParameter -> indAudsignalsDescriptor + : {indAudSignalsDescriptor, '$1'} . +indAudauditReturnParameter -> indAuddigitMapDescriptor + : {indAudDigitMapDescriptor, '$1'} . +indAudauditReturnParameter -> indAudeventBufferDescriptor + : {indAudEventBufferDescriptor, '$1'} . +indAudauditReturnParameter -> indAudstatisticsDescriptor + : {indAudStatisticsDescriptor, '$1'} . +indAudauditReturnParameter -> indAudpackagesDescriptor + : {indAudPackagesDescriptor, '$1'} . + + +indAudmediaDescriptor -> 'MediaToken' 'LBRKT' + indAudmediaParm indAudmediaParms 'RBRKT' + : merge_indAudMediaDescriptor(['$3'|'$4']) . + +%% at-most-once per item +%% and either streamParm or streamDescriptor but not both +%% + +indAudmediaParm -> indAudstreamParm : {streamParm, '$1'} . +indAudmediaParm -> indAudstreamDescriptor : {streamDescr, '$1'} . +indAudmediaParm -> indAudterminationStateDescriptor : {termStateDescr, '$1'} . + +indAudmediaParms -> 'COMMA' indAudmediaParm indAudmediaParms : ['$2' | '$3'] . +indAudmediaParms -> '$empty' : [] . + +%% at-most-once +indAudstreamParm -> 'RemoteDescriptorToken' : + RD = ensure_prop_groups('$1'), + #'IndAudStreamParms'{remoteDescriptor = RD} . +indAudstreamParm -> 'LocalDescriptorToken' : + LD = ensure_prop_groups('$1'), + #'IndAudStreamParms'{localDescriptor = LD} . +indAudstreamParm -> indAudlocalControlDescriptor : + #'IndAudStreamParms'{localControlDescriptor = '$1'} . +indAudstreamParm -> indAudstatisticsDescriptor : + #'IndAudStreamParms'{statisticsDescriptor = '$1'} . + +indAudstreamDescriptor -> 'StreamToken' 'EQUAL' streamID + 'LBRKT' indAudstreamParm 'RBRKT' + : #'IndAudStreamDescriptor'{streamID = '$3', + streamParms = '$5'} . + + +indAudlocalControlDescriptor -> 'LocalControlToken' + 'LBRKT' indAudlocalParm + indAudlocalParmList 'RBRKT' : + merge_indAudLocalControlDescriptor(['$3' | '$4']) . + +indAudlocalParmList -> 'COMMA' indAudlocalParm + indAudlocalParmList : ['$2' | '$3'] . +indAudlocalParmList -> '$empty' : [] . + +%% at-most-once per item +%% +%% propertyparm and streamModes are used only to specify audit selection +%% criteria. AND/OR selection logic is specified at context level. +%% +indAudlocalParm -> 'ReservedGroupToken' : reservedGroupToken . +indAudlocalParm -> 'ReservedValueToken' : reservedValueToken . +indAudlocalParm -> 'ModeToken' : modeToken . +indAudlocalParm -> 'ModeToken' 'EQUAL' streamModes : {mode, {equal, '$3'}} . +indAudlocalParm -> 'ModeToken' 'INEQUAL' streamModes : {mode, {inequal,'$3'}} . +indAudlocalParm -> propertyParm : {prop, '$1'} . +indAudlocalParm -> pkgdName : {name, '$1'} . + +indAudterminationStateDescriptor -> 'TerminationStateToken' + 'LBRKT' indAudterminationStateParm 'RBRKT' + : + merge_indAudTerminationStateDescriptor('$3') . + +%% at-most-once per item +%% + +%% at-most-once per item except for propertyParm +indAudterminationStateParm -> iaServiceStates : '$1' . +indAudterminationStateParm -> 'BufferToken' : bufferToken . +indAudterminationStateParm -> propertyParm : {prop, '$1'} . +indAudterminationStateParm -> pkgdName : {name, '$1'} . + +iaServiceStates -> 'ServiceStatesToken' : + serviceStatesToken . +iaServiceStates -> 'ServiceStatesToken' 'EQUAL' serviceStatesValue : + {serviceStates, {equal, '$3'}} . +iaServiceStates -> 'ServiceStatesToken' 'INEQUAL' serviceStatesValue : + {serviceStates, {inequal, '$3'}} . + +indAudeventBufferDescriptor -> 'EventBufferToken' + 'LBRKT' indAudeventSpec 'RBRKT' : '$3' . + +indAudeventSpec -> pkgdName optIndAudeventSpecParameter + : merge_indAudEventBufferDescriptor('$1','$2') . + +optIndAudeventSpecParameter -> 'LBRKT' indAudeventSpecParameter 'RBRKT' + : '$2' . +optIndAudeventSpecParameter -> '$empty' : asn1_NOVALUE . + + +indAudeventSpecParameter -> eventStream : {streamID, '$1'} . +indAudeventSpecParameter -> eventParameterName : {eventParameterName, '$1'} . + +indAudeventsDescriptor -> 'EventsToken' 'LBRKT' indAudrequestedEvent 'RBRKT' : + #'IndAudEventsDescriptor'{pkgdName = '$3'} . +indAudeventsDescriptor -> 'EventsToken' 'EQUAL' requestID + 'LBRKT' indAudrequestedEvent 'RBRKT' : + #'IndAudEventsDescriptor'{requestID = '$3', + pkgdName = '$5'} . + +indAudrequestedEvent -> pkgdName : '$1' . + + +indAudsignalsDescriptor -> 'SignalsToken' optIndAudsignalParm : '$2' . + + +optIndAudsignalParm -> 'LBRKT' 'RBRKT' : asn1_NOVALUE . +optIndAudsignalParm -> 'LBRKT' indAudsignalParm 'RBRKT' : '$2' . + +indAudsignalParm -> indAudsignalList : {seqSigList, '$1'} . +indAudsignalParm -> signalRequest : {signal, ensure_indAudSignal('$1')} . + +indAudsignalList -> 'SignalListToken' 'EQUAL' signalListId : + #'IndAudSeqSigList'{id = ensure_uint16('$3')} . +indAudsignalList -> 'SignalListToken' 'EQUAL' signalListId + 'LBRKT' signalListParm 'RBRKT' : + #'IndAudSeqSigList'{id = ensure_uint16('$3'), + signalList = + ensure_indAudSignalListParm('$5')} . + + +%% The DigitMapDescriptorToken is specially treated by the scanner +indAuddigitMapDescriptor -> 'DigitMapDescriptorToken' : + ensure_IADMD('$1') . + +indAudstatisticsDescriptor -> 'StatsToken' 'LBRKT' pkgdName 'RBRKT' : + #'IndAudStatisticsDescriptor'{statName = '$3'} . + +indAudpackagesDescriptor -> 'PackagesToken' 'LBRKT' packagesItem 'RBRKT' + : merge_indAudPackagesDescriptor('$3') . + +eventStream -> 'StreamToken' 'EQUAL' streamID : '$3' . + + +%% +%% v2 - end + +notifyRequest -> 'NotifyToken' 'EQUAL' termIDList + 'LBRKT' notifyRequestBody 'RBRKT' : + NR = setelement(#'NotifyRequest'.terminationID, + '$5', '$3'), + make_commandRequest({notifyReq, '$1'}, NR) . + +notifyRequestBody -> observedEventsDescriptor : + #'NotifyRequest'{observedEventsDescriptor = '$1'}. +notifyRequestBody -> errorDescriptor : + #'NotifyRequest'{errorDescriptor = '$1'}. + +notifyReply -> 'NotifyToken' 'EQUAL' termIDList notifyReplyBody : + {notifyReply, #'NotifyReply'{terminationID = '$3', + errorDescriptor = '$4'}} . + +notifyReplyBody -> 'LBRKT' errorDescriptor 'RBRKT' : '$2'. +notifyReplyBody -> '$empty' : asn1_NOVALUE . + +serviceChangeRequest -> 'ServiceChangeToken' 'EQUAL' termIDList + 'LBRKT' serviceChangeDescriptor 'RBRKT' : + make_commandRequest({serviceChangeReq, '$1'}, + #'ServiceChangeRequest'{terminationID = '$3', + serviceChangeParms = '$5'}) . + +serviceChangeReply -> 'ServiceChangeToken' 'EQUAL' termIDList + serviceChangeReplyBody : + {serviceChangeReply, + #'ServiceChangeReply'{terminationID = '$3', + serviceChangeResult = '$4'}} . + +serviceChangeReplyBody -> 'LBRKT' errorDescriptor 'RBRKT' : + {errorDescriptor, '$2'} . +serviceChangeReplyBody -> 'LBRKT' serviceChangeReplyDescriptor 'RBRKT' : + {serviceChangeResParms, '$2'} . +serviceChangeReplyBody -> '$empty' : + {serviceChangeResParms, #'ServiceChangeResParm'{}}. + +errorDescriptor -> 'ErrorToken' 'EQUAL' errorCode 'LBRKT' + errorText 'RBRKT' : + #'ErrorDescriptor'{errorCode = '$3', + errorText = '$5'} . + +errorCode -> safeToken : ensure_uint('$1', 0, 999) . + +errorText -> 'QuotedChars' : value_of('$1') . +errorText -> '$empty' : asn1_NOVALUE . + +transactionID -> safeToken : ensure_uint32('$1') . +transactionID_and_segment_info -> safeToken : + make_transactionID_and_segment_info('$1') . + +mId -> domainName : '$1' . +mId -> domainAddress : '$1' . +mId -> optSep mtpAddress optSep : '$2' . +mId -> optSep deviceName optSep : '$2' . + +domainName -> 'LESSER' safeToken 'GREATER' 'COLON' portNumber optSep + : ensure_domainName('$2', '$5') . +domainName -> 'LESSER' safeToken 'GREATER' + : ensure_domainName('$2', asn1_NOVALUE) . + +deviceName -> pathName : {deviceName, '$1'} . + +%% '-' is used for NULL context +contextID -> safeToken : ensure_contextID('$1') . + +domainAddress -> 'LSBRKT' daddr 'RSBRKT' 'COLON' portNumber optSep + : ensure_domainAddress('$2', '$5') . +domainAddress -> 'LSBRKT' daddr 'RSBRKT' + : ensure_domainAddress('$2', asn1_NOVALUE) . + +daddr -> '$empty' : [] . +daddr -> 'COLON' daddr : [colon| '$2'] . +daddr -> safeToken daddr : ['$1'| '$2'] . + + +portNumber -> safeToken : ensure_uint16('$1') . + +mtpAddress -> 'MtpAddressToken' : ensure_mtpAddress('$1') . + +termIDList -> terminationID : ['$1'] . +termIDList -> LSBRKT terminationID terminationIDListRepeat RSBRKT : + ['$2' | '$3'] . + +terminationIDList -> 'LBRKT' terminationID terminationIDListRepeat 'RBRKT' : + ['$2' | '$3'] . + +terminationIDListRepeat -> 'COMMA' terminationID terminationIDListRepeat : + ['$2'| '$3'] . +terminationIDListRepeat -> '$empty' : [] . + + +pathName -> safeToken : ensure_pathName('$1') . + +terminationID -> safeToken : ensure_terminationID('$1') . + +mediaDescriptor -> 'MediaToken' 'LBRKT' mediaParm mediaParmList 'RBRKT' + : merge_mediaDescriptor(['$3' | '$4']) . + +mediaParmList -> 'COMMA' mediaParm mediaParmList : ['$2' | '$3'] . +mediaParmList -> '$empty' : [] . + + +%% at-most-once per item +%% using either streamParms or streamDescriptors but not both +mediaParm -> streamParm + : {streamParm, '$1'} . +mediaParm -> streamDescriptor + : {streamDescriptor, '$1'} . +mediaParm -> terminationStateDescriptor + : {termState, '$1'} . + +%% at-most-once . +%% Specially treated by the scanner. +streamParm -> 'LocalDescriptorToken' : + PGs = ensure_prop_groups('$1'), + {local, #'LocalRemoteDescriptor'{propGrps = PGs}} . +streamParm -> 'RemoteDescriptorToken' : + PGs = ensure_prop_groups('$1'), + {remote, #'LocalRemoteDescriptor'{propGrps = PGs}} . +streamParm -> localControlDescriptor : {control, '$1'} . +streamParm -> statisticsDescriptor : {statistics, '$1'} . + +streamDescriptor -> 'StreamToken' 'EQUAL' streamID + 'LBRKT' streamParm streamParmList 'RBRKT' + : #'StreamDescriptor'{streamID = '$3', + streamParms = merge_streamParms(['$5' | '$6'])} . + +streamParmList -> 'COMMA' streamParm streamParmList : ['$2' | '$3'] . +streamParmList -> '$empty' : [] . + +localControlDescriptor -> 'LocalControlToken' 'LBRKT' localParm localParmList 'RBRKT' + : ['$3' | '$4'] . + +localParmList -> 'COMMA' localParm localParmList : ['$2' | '$3'] . +localParmList -> '$empty': [] . + +terminationStateDescriptor -> 'TerminationStateToken' + 'LBRKT' terminationStateParm + terminationStateParms 'RBRKT' + : merge_terminationStateDescriptor(['$3' | '$4']) . + +terminationStateParms -> 'COMMA' terminationStateParm terminationStateParms : ['$2' | '$3'] . +terminationStateParms -> '$empty' : [] . + +%% at-most-once per item except for propertyParm +localParm -> 'ReservedGroupToken' 'EQUAL' onOrOff : {group, '$3'} . +localParm -> 'ReservedValueToken' 'EQUAL' onOrOff : {value, '$3'} . +localParm -> 'ModeToken' 'EQUAL' streamModes : {mode, '$3'} . +localParm -> propertyParm : {prop, '$1'} . + +onOrOff -> 'OnToken' : true . +onOrOff -> 'OffToken' : false . + +%% at-most-once +streamModes -> 'SendonlyToken' : sendOnly . +streamModes -> 'RecvonlyToken' : recvOnly . +streamModes -> 'SendrecvToken' : sendRecv . +streamModes -> 'InactiveToken' : inactive . +streamModes -> 'LoopbackToken' : loopBack . + +propertyParm -> pkgdName parmValue : + setelement(#'PropertyParm'.name, '$2', '$1') . + +parmValue -> 'EQUAL' alternativeValue : + '$2' . + +parmValue -> 'NEQUAL' value : + #'PropertyParm'{value = ['$2'], + extraInfo = {relation, unequalTo}} . +parmValue -> 'LESSER' value : + #'PropertyParm'{value = ['$2'], + extraInfo = {relation, smallerThan}} . +parmValue -> 'GREATER' value : + #'PropertyParm'{value = ['$2'], + extraInfo = {relation, greaterThan}} . + +%% OTP-4013 +%% alternativeValue = ( VALUE / +%% LSBRKT VALUE *(COMMA VALUE) RSBRKT / +%% LSBRKT VALUE COLON VALUE RSBRKT ) / +%% LBRKT VALUE *(COMMA VALUE) RBRKT +alternativeValue -> 'LBRKT' value valueList 'RBRKT' + : #'PropertyParm'{value = ['$2' | '$3'], + extraInfo = {sublist, false}}. % OR + +alternativeValue -> 'LSBRKT' value 'COLON' value 'RSBRKT' + : #'PropertyParm'{value = ['$2', '$4'], + extraInfo = {range, true}}. + +alternativeValue -> 'LSBRKT' value valueList 'RSBRKT' + : #'PropertyParm'{value = ['$2' | '$3'], + extraInfo = {sublist, true}}. % AND + +alternativeValue -> value : + #'PropertyParm'{value = ['$1']} . + +valueList -> 'COMMA' value valueList : ['$2' | '$3'] . +valueList -> '$empty' : [] . + + +eventBufferDescriptor -> 'EventBufferToken' : [] . +eventBufferDescriptor -> 'EventBufferToken' 'LBRKT' eventSpec + eventSpecList 'RBRKT' : + ['$3' | '$4'] . + +eventSpecList -> 'COMMA' eventSpec eventSpecList : ['$2' | '$3'] . +eventSpecList -> '$empty' : [] . + +eventSpec -> observedEvent : merge_eventSpec('$1') . + +%% at-most-once per item except for propertyParm +terminationStateParm -> serviceStates : {serviceState, '$1'} . +terminationStateParm -> eventBufferControl : {eventBufferControl, '$1'} . +terminationStateParm -> propertyParm : {propertyParm, '$1'} . + +serviceStates -> 'ServiceStatesToken' 'EQUAL' serviceStatesValue : '$3'. + +serviceStatesValue -> 'TestToken' : test . +serviceStatesValue -> 'OutOfSvcToken' : outOfSvc . +serviceStatesValue -> 'InSvcToken' : inSvc . + +eventBufferControl -> 'BufferToken' 'EQUAL' eventBufferControlValue : '$3' . + +eventBufferControlValue -> 'OffToken' : off . +eventBufferControlValue -> 'LockStepToken' : lockStep . + +muxDescriptor -> 'MuxToken' 'EQUAL' muxType terminationIDList : + #'MuxDescriptor'{muxType = '$3', + termList = '$4'} . + +muxType -> safeToken : ensure_muxType('$1') . + +streamID -> safeToken : ensure_streamID('$1') . + +pkgdName -> safeToken : ensure_pkgdName('$1') . + +eventsDescriptor -> 'EventsToken' : + #'EventsDescriptor'{requestID = asn1_NOVALUE, + eventList = []} . +eventsDescriptor -> 'EventsToken' 'EQUAL' requestID + 'LBRKT' requestedEvent requestedEvents 'RBRKT' : + #'EventsDescriptor'{requestID = '$3', + eventList = ['$5' | '$6']} . + +requestedEvents -> 'COMMA' requestedEvent requestedEvents : ['$2' | '$3'] . +requestedEvents -> '$empty' : [] . + +requestedEvent -> pkgdName requestedEventBody : + setelement(#'RequestedEvent'.pkgdName, '$2', '$1') . + +requestedEventBody -> 'LBRKT' eventParameter eventParameters 'RBRKT' : + merge_eventParameters(['$2' | '$3']) . +requestedEventBody -> '$empty' : #'RequestedEvent'{evParList = []} . + + +notifyRegulated -> 'NotifyRegulatedToken' : + #'RegulatedEmbeddedDescriptor'{} . +notifyRegulated -> 'NotifyRegulatedToken' 'LBRKT' embedWithSig 'RBRKT' : + make_RegulatedEmbeddedDescriptor('$3') . +notifyRegulated -> 'NotifyRegulatedToken' 'LBRKT' embedNoSig 'RBRKT' : + make_RegulatedEmbeddedDescriptor('$3') . + +notifyBehaviour -> 'NotifyImmediateToken' : {notifyImmediate, 'NULL'} . +notifyBehaviour -> 'NeverNotifyToken' : {neverNotify, 'NULL'} . +notifyBehaviour -> notifyRegulated : {notifyRegulated, '$1'} . + +eventParameters -> 'COMMA' eventParameter eventParameters : + ['$2' | '$3'] . +eventParameters -> '$empty' : [] . + +%% at-most-once each of embedOrKeepActive , eventDM or eventStream +eventParameter -> 'KeepActiveToken' : keepActive . +eventParameter -> embedWithSig : '$1'. +eventParameter -> embedNoSig : '$1'. +eventParameter -> eventDM : '$1'. +eventParameter -> eventStreamOrOther : '$1'. +eventParameter -> notifyBehaviour : {notifyBehaviour, '$1'}. +eventParameter -> 'ResetEventsDescriptorToken' : resetEventsDescriptor . + +embedWithSig -> 'EmbedToken' 'LBRKT' signalsDescriptor + 'COMMA' embedFirst 'RBRKT' + : {embed, '$3', '$5'} . +embedWithSig -> 'EmbedToken' 'LBRKT' signalsDescriptor 'RBRKT' + : {embed, '$3', asn1_NOVALUE} . + +embedNoSig -> 'EmbedToken' 'LBRKT' embedFirst 'RBRKT' + : {embed, asn1_NOVALUE, '$3'} . + +embedFirst -> 'EventsToken' : + #'SecondEventsDescriptor'{requestID = asn1_NOVALUE, + eventList = []} . +embedFirst -> 'EventsToken' 'EQUAL' requestID + 'LBRKT' secondRequestedEvent secondRequestedEvents 'RBRKT' : + #'SecondEventsDescriptor'{requestID = '$3', + eventList = ['$5' | '$6']} . + +secondRequestedEvents -> 'COMMA' secondRequestedEvent secondRequestedEvents : ['$2' | '$3'] . +secondRequestedEvents -> '$empty' : [] . + +%% at-most-once of each +secondRequestedEvent -> pkgdName secondRequestedEventBody + : setelement(#'SecondRequestedEvent'.pkgdName, '$2', '$1') . + +secondRequestedEventBody -> 'LBRKT' secondEventParameter secondEventParameters 'RBRKT' + : merge_secondEventParameters(['$2' | '$3']) . +secondRequestedEventBody -> '$empty' : #'SecondRequestedEvent'{evParList = []} . + +secondEventParameters -> 'COMMA' secondEventParameter secondEventParameters : ['$2' | '$3'] . +secondEventParameters -> '$empty' : [] . + +%% at-most-once each of embedOrKeepActive , eventDM or eventStream +secondEventParameter -> 'KeepActiveToken' : keepActive . +secondEventParameter -> embedSig : '$1' . +secondEventParameter -> eventDM : '$1' . +secondEventParameter -> eventStreamOrOther : '$1' . +secondEventParameter -> notifyBehaviour : {notifyBehaviour, '$1'}. +secondEventParameter -> 'ResetEventsDescriptorToken' : resetEventsDescriptor . + +embedSig -> 'EmbedToken' 'LBRKT' signalsDescriptor 'RBRKT' + : {second_embed, '$3'} . + +eventStreamOrOther -> eventParameterName parmValue : + select_stream_or_other('$1', '$2') . + +eventParameterName -> safeToken : ensure_NAME('$1') . + +%% The DigitMapDescriptorToken is specially treated by the scanner +eventDM -> 'DigitMapDescriptorToken' : + ensure_eventDM('$1') . + +%% H248S-IG (IGv11) +signalsDescriptor -> 'SignalsToken' 'LBRKT' signalParm signalParms 'RBRKT' : + ['$3' | '$4'] . +signalsDescriptor -> 'SignalsToken' : [] . + +signalParms -> 'COMMA' signalParm signalParms : [ '$2' | '$3'] . +signalParms -> '$empty' : [] . + +signalParm -> signalList : {seqSigList, '$1'} . +signalParm -> signalRequest : {signal, '$1'} . + +signalRequest -> signalName 'LBRKT' sigParameter sigParameters 'RBRKT' + : merge_signalRequest('$1', ['$3' | '$4']). +signalRequest -> signalName : merge_signalRequest('$1', []). + +sigParameters -> 'COMMA' sigParameter sigParameters : ['$2' | '$3'] . +sigParameters -> '$empty' : [] . + +%% sigParameter = sigStream / sigSignalType / sigDuration / sigOther / +%% notifyCompletion / KeepActiveToken / +%% direction / sigRequestID +%% sigStream = StreamToken EQUAL StreamID +%% sigOther = sigParameterName parmValue +%% sigParameterName = NAME +%% sigSignalType = SignalTypeToken EQUAL signalType +%% signalType = (OnOffToken / TimeOutToken / BriefToken) +%% sigDuration = DurationToken EQUAL UINT16 +%% notifyCompletion = NotifyCompletionToken EQUAL (LBRKT +%% notificationReason *(COMMA notificationReason) +%% RBRKT) +%% +%% notificationReason = ( TimeOutToken / InterruptByEventToken / +%% InterruptByNewSignalsDescrToken / +%% OtherReasonToken ) +%% sigDirection = DirectionToken EQUAL direction +%% sigRequestID = RequestIDToken EQUAL RequestID +%% sigIntsigDelay = IntsigDelayToken EQUAL UINT16 + +sigParameter -> 'StreamToken' 'EQUAL' streamID : + {stream, '$3'}. +sigParameter -> 'SignalTypeToken' 'EQUAL' signalType : + {signal_type, '$3'} . +sigParameter -> 'DurationToken' 'EQUAL' safeToken : + {duration, ensure_uint16('$3')} . +sigParameter -> 'NotifyCompletionToken' 'EQUAL' + 'LBRKT' notificationReason notificationReasons 'RBRKT' : + {notify_completion, ['$4' | '$5']} . +sigParameter -> 'KeepActiveToken' : keepActive . +sigParameter -> 'DirectionToken' 'EQUAL' direction : + {direction, '$3'} . +sigParameter -> 'RequestIDToken' 'EQUAL' requestID : + {requestId, '$3'} . +sigParameter -> 'IntsigDelayToken' 'EQUAL' safeToken : + {intersigDelay, ensure_uint16('$3')} . +sigParameter -> safeToken parmValue : + {other, ensure_NAME('$1'), '$2'}. + +signalType -> 'OnOffToken' : onOff. +signalType -> 'TimeOutToken' : timeOut. +signalType -> 'BriefToken' : brief. + +direction -> 'ExternalToken' : external . +direction -> 'InternalToken' : internal . +direction -> 'BothToken' : both . + +notificationReasons -> 'COMMA' notificationReason notificationReasons : ['$2' | '$3'] . +notificationReasons -> '$empty' : [] . + +notificationReason -> 'TimeOutToken' : onTimeOut . +notificationReason -> 'InterruptByEventToken' : onInterruptByEvent . +notificationReason -> 'InterruptByNewSignalsDescrToken' : onInterruptByNewSignalDescr . +notificationReason -> 'OtherReasonToken' : otherReason . +notificationReason -> 'IterationToken' : iteration . + +signalList -> 'SignalListToken' 'EQUAL' signalListId + 'LBRKT' signalListParm signalListParms 'RBRKT' + : #'SeqSigList'{id = ensure_uint16('$3'), + signalList = ['$5' | '$6']} . + +signalListParms -> 'COMMA' signalListParm signalListParms : + ['$2' | '$3'] . +signalListParms -> '$empty' : [] . + +signalListId -> safeToken : ensure_uint16('$1') . + +%% exactly once signalType, +%% at most once duration and every signal parameter +signalListParm -> signalRequest : '$1'. + +signalName -> pkgdName : '$1'. + +observedEventsDescriptor -> 'ObservedEventsToken' 'EQUAL' requestID + 'LBRKT' observedEvent observedEvents 'RBRKT' + : #'ObservedEventsDescriptor'{requestId = '$3', + observedEventLst = ['$5' | '$6']} . + +observedEvents -> 'COMMA' observedEvent observedEvents : ['$2' | '$3'] . +observedEvents -> '$empty' : [] . + +%%time per event, because it might be buffered + +observedEvent -> timeStamp optSep 'COLON' optSep pkgdName observedEventBody : + merge_observed_event('$6', '$5', '$1') . +observedEvent -> optSep pkgdName observedEventBody : + merge_observed_event('$3', '$2', asn1_NOVALUE) . + +observedEventBody -> 'LBRKT' observedEventParameter + observedEventParameters 'RBRKT' + : ['$2' | '$3'] . +observedEventBody -> '$empty' : [] . + +observedEventParameters -> 'COMMA' observedEventParameter observedEventParameters : ['$2' | '$3'] . +observedEventParameters -> '$empty' : [] . + +%%at-most-once eventStream, every eventParameterName at most once +observedEventParameter -> eventStreamOrOther : '$1' . + +requestID -> safeToken : ensure_requestID('$1') . + +%% Deprecated as of Corr 1 +modemDescriptor -> 'ModemToken' 'EQUAL' modemType optPropertyParms . +modemDescriptor -> 'ModemToken' 'LSBRKT' modemType modemTypeList 'RSBRKT' + optPropertyParms. +modemTypeList -> 'COMMA' modemType modemTypeList. +modemTypeList -> '$empty'. +modemType -> safeToken. + +optPropertyParms -> 'LBRKT' propertyParm propertyParmList 'RBRKT' : + ['$2' | '$3'] . +optPropertyParms -> '$empty' : [] . + +propertyParms -> propertyParm propertyParmList : ['$1' | '$2'] . +propertyParmList -> 'COMMA' propertyParm propertyParmList : ['$2' | '$3'] . +propertyParmList -> '$empty' : [] . + +% parmName -> safeToken : ensure_NAME('$1') . + +%% The DigitMapDescriptorToken is specially treated by the scanner +digitMapDescriptor -> 'DigitMapDescriptorToken' : + ensure_DMD('$1') . + +%% each parameter at-most-once, except auditItem +%% at most one of either serviceChangeAddress or serviceChangeMgcId but +%% not both. serviceChangeMethod and serviceChangeReason are REQUIRED +serviceChangeDescriptor -> 'ServicesToken' + 'LBRKT' serviceChangeParm + serviceChangeParms 'RBRKT' : + merge_ServiceChangeParm(['$3' | '$4']) . + +serviceChangeParms -> 'COMMA' serviceChangeParm serviceChangeParms : + ['$2' | '$3'] . +serviceChangeParms -> '$empty' : [] . + +serviceChangeParm -> serviceChangeMethod : {method, '$1'} . +serviceChangeParm -> serviceChangeReason : {reason, '$1'} . +serviceChangeParm -> serviceChangeDelay : {delay, '$1'} . +serviceChangeParm -> serviceChangeAddress : {address, '$1'} . +serviceChangeParm -> serviceChangeProfile : {profile, '$1'} . +serviceChangeParm -> extension : {extension, '$1'} . +serviceChangeParm -> timeStamp : {time_stamp, '$1'} . +serviceChangeParm -> serviceChangeMgcId : {mgc_id, '$1'} . +serviceChangeParm -> serviceChangeVersion : {version, '$1'} . +serviceChangeParm -> 'ServiceChangeIncompleteToken' : incomplete . % v3 +serviceChangeParm -> auditItem : {audit_item, '$1'} . % v2 + +serviceChangeMethod -> 'MethodToken' 'EQUAL' safeToken : + ensure_serviceChangeMethod('$3') . + +serviceChangeReason -> 'ReasonToken' 'EQUAL' value : ['$3'] . + +serviceChangeDelay -> 'DelayToken' 'EQUAL' safeToken : ensure_uint32('$3'). + +serviceChangeAddress -> 'ServiceChangeAddressToken' 'EQUAL' mId : '$3' . +serviceChangeAddress -> 'ServiceChangeAddressToken' 'EQUAL' portNumber : + {portNumber, '$3'} . + +serviceChangeMgcId -> 'MgcIdToken' 'EQUAL' mId : '$3' . + +serviceChangeProfile -> 'ProfileToken' 'EQUAL' safeToken : ensure_profile('$3'). + +serviceChangeVersion -> 'VersionToken' 'EQUAL' safeToken : ensure_version('$3') . + +extension -> extensionParameter parmValue + : setelement(#'PropertyParm'.name, '$2', '$1') . + +%% at most once. Version is REQUIRED on first ServiceChange response +%% at most of either serviceChangeAddress or serviceChangeMgcId but not both +serviceChangeReplyDescriptor -> 'ServicesToken' + 'LBRKT' servChgReplyParm + servChgReplyParms 'RBRKT' : + merge_ServiceChangeResParm(['$3' | '$4']) . + +servChgReplyParms -> 'COMMA' servChgReplyParm servChgReplyParms : + ['$2' | '$3'] . +servChgReplyParms -> '$empty' : [] . + +servChgReplyParm -> serviceChangeAddress : {address, '$1'} . +servChgReplyParm -> serviceChangeMgcId : {mgc_id, '$1'} . +servChgReplyParm -> serviceChangeProfile : {profile, '$1'} . +servChgReplyParm -> serviceChangeVersion : {version, '$1'} . +servChgReplyParm -> timeStamp : {time_stamp,'$1'} . + +packagesDescriptor -> 'PackagesToken' 'LBRKT' packagesItem + packagesItems 'RBRKT' + : ['$3' | '$4'] . + +packagesItems -> 'COMMA' packagesItem packagesItems : ['$2' | '$3'] . +packagesItems -> '$empty' : [] . + +packagesItem -> safeToken : ensure_packagesItem('$1') . + +timeStamp -> TimeStampToken : ensure_timeStamp('$1') . + +statisticsDescriptor -> 'StatsToken' + 'LBRKT' statisticsParameter + statisticsParameters 'RBRKT' + : ['$3' | '$4'] . + +statisticsParameters -> 'COMMA' statisticsParameter statisticsParameters : ['$2' | '$3'] . +statisticsParameters -> '$empty' : [] . + +%%at-most-once per item +statisticsParameter -> pkgdName : + #'StatisticsParameter'{statName = '$1', + statValue = asn1_NOVALUE} . +statisticsParameter -> pkgdName 'EQUAL' value : + #'StatisticsParameter'{statName = '$1', + statValue = ['$3']} . +statisticsParameter -> pkgdName 'EQUAL' 'LSBRKT' value valueList 'RSBRKT' : + #'StatisticsParameter'{statName = '$1', + statValue = ['$4' | '$5']} . + + +topologyDescriptor -> 'TopologyToken' 'LBRKT' + topologyDescComp topologyDescCompList 'RBRKT' : + merge_topologyDescriptor(['$3' | '$4']) . + +topologyDescComp -> terminationID : {tid, '$1'} . +topologyDescComp -> eventStream : {sid, '$1'} . +topologyDescComp -> topologyDirection : '$1' . + +topologyDescCompList -> '$empty' : [] . +topologyDescCompList -> 'COMMA' topologyDescComp topologyDescCompList : + ['$2' | '$3'] . + +topologyDirection -> 'BothwayToken' : {direction, bothway} . +topologyDirection -> 'IsolateToken' : {direction, isolate} . +topologyDirection -> 'OnewayToken' : {direction, oneway} . +topologyDirection -> 'OnewayExternalToken' : {direction_ext, onewayexternal} . +topologyDirection -> 'OnewayBothToken' : {direction_ext, onewayboth} . + +iepsValue -> 'IEPSToken' 'EQUAL' onOrOff : '$3' . + +emergencyValue -> 'EmergencyValueToken' 'EQUAL' 'EmergencyToken' : true . +emergencyValue -> 'EmergencyValueToken' 'EQUAL' 'EmergencyOffToken' : false . + +priority -> 'PriorityToken' 'EQUAL' safeToken : ensure_uint16('$3') . + +extensionParameter -> safeToken : ensure_extensionParameter('$1') . + +value -> 'QuotedChars' : ensure_value('$1') . +value -> safeToken : ensure_value('$1'). + +safeToken -> safeToken2 : make_safe_token('$1') . + +safeToken2 -> 'SafeChars' : '$1' . +%% BMK BMK safeToken2 -> 'AddToken' : '$1' . +safeToken2 -> 'AuditToken' : '$1' . +safeToken2 -> 'AuditCapToken' : '$1' . +safeToken2 -> 'AuditValueToken' : '$1' . +safeToken2 -> 'AuthToken' : '$1' . +safeToken2 -> 'BothToken' : '$1' . % v3 +%% v3-safeToken2 -> 'BothwayToken' : '$1' . +safeToken2 -> 'BriefToken' : '$1' . +%% v3-safeToken2 -> 'BufferToken' : '$1' . +safeToken2 -> 'CtxToken' : '$1' . +%% v3-safeToken2 -> 'ContextAttrToken' : '$1' . % v3 +safeToken2 -> 'ContextAuditToken' : '$1' . +%% v3-safeToken2 -> 'ContextListToken' : '$1' . % v3 +%% v2-safeToken2 -> 'DigitMapToken' : '$1' . +%% safeToken2 -> 'DigitMapDescriptorToken' : '$1' . +%% v3- +safeToken2 -> 'DirectionToken' : '$1' . % v3 +safeToken2 -> 'DiscardToken' : '$1' . +safeToken2 -> 'DisconnectedToken' : '$1' . +safeToken2 -> 'DelayToken' : '$1' . +safeToken2 -> 'DurationToken' : '$1' . +safeToken2 -> 'EmbedToken' : '$1' . +%% BMK BMK safeToken2 -> 'EmergencyToken' : '$1' . +%% BMK BMK safeToken2 -> 'EmergencyOffToken' : '$1' . +safeToken2 -> 'ErrorToken' : '$1' . +%% v2-safeToken2 -> 'EventBufferToken' : '$1' . +%% v2-safeToken2 -> 'EventsToken' : '$1' . +%% v3-safeToken2 -> 'ExternalToken' : '$1' . % v3 +safeToken2 -> 'FailoverToken' : '$1' . +safeToken2 -> 'ForcedToken' : '$1' . +safeToken2 -> 'GracefulToken' : '$1' . +safeToken2 -> 'H221Token' : '$1' . +safeToken2 -> 'H223Token' : '$1' . +safeToken2 -> 'H226Token' : '$1' . +safeToken2 -> 'HandOffToken' : '$1' . +%% v3-safeToken2 -> 'IEPSToken' : '$1' . % v3 +safeToken2 -> 'ImmAckRequiredToken' : '$1' . +safeToken2 -> 'InactiveToken' : '$1' . +%% v3-safeToken2 -> 'InternalToken' : '$1' . % v3 +safeToken2 -> 'InterruptByEventToken' : '$1' . +safeToken2 -> 'InterruptByNewSignalsDescrToken' : '$1' . +%% v3-safeToken2 -> 'IsolateToken' : '$1' . +safeToken2 -> 'InSvcToken' : '$1' . +safeToken2 -> 'KeepActiveToken' : '$1' . +%% safeToken2 -> 'LocalToken' : '$1' . +%% safeToken2 -> 'LocalDescriptorToken' : '$1' . +safeToken2 -> 'LocalControlToken' : '$1' . +safeToken2 -> 'LoopbackToken' : '$1' . +safeToken2 -> 'LockStepToken' : '$1' . +%% v2-safeToken2 -> 'MediaToken' : '$1' . +%% safeToken2 -> 'MegacopToken' : '$1' . +safeToken2 -> 'MethodToken' : '$1' . +safeToken2 -> 'MgcIdToken' : '$1' . +%% v3-safeToken2 -> 'ModeToken' : '$1' . +%% BMK BMK safeToken2 -> 'ModifyToken' : '$1' . +%% v2-safeToken2 -> 'ModemToken' : '$1' . +%% BMK BMK safeToken2 -> 'MoveToken' : '$1' . +%% safeToken2 -> 'MtpToken' : '$1' . +%% safeToken2 -> 'MtpAddressToken' : '$1' . +%% v2-safeToken2 -> 'MuxToken' : '$1' . +safeToken2 -> 'NotifyToken' : '$1' . +safeToken2 -> 'NotifyCompletionToken' : '$1' . +safeToken2 -> 'Nx64Token' : '$1' . +%% v2-safeToken2 -> 'ObservedEventsToken' : '$1' . +%% v3-safeToken2 -> 'OnewayToken' : '$1' . +%% v3-safeToken2 -> 'OnewayExternalToken' : '$1' . +%% v3-safeToken2 -> 'OnewayBothToken' : '$1' . +safeToken2 -> 'OffToken' : '$1' . +safeToken2 -> 'OnToken' : '$1' . +safeToken2 -> 'OnOffToken' : '$1' . +safeToken2 -> 'OutOfSvcToken' : '$1' . +safeToken2 -> 'OtherReasonToken' : '$1' . +%% v2-safeToken2 -> 'PackagesToken' : '$1' . +safeToken2 -> 'PendingToken' : '$1' . +%% BMK BMK safeToken2 -> 'PriorityToken' : '$1' . +safeToken2 -> 'ProfileToken' : '$1' . +safeToken2 -> 'ReasonToken' : '$1' . +safeToken2 -> 'RecvonlyToken' : '$1' . +safeToken2 -> 'ReplyToken' : '$1' . +%% v3- +safeToken2 -> 'RequestIDToken' : '$1' . % v3 +safeToken2 -> 'ResponseAckToken' : '$1' . +safeToken2 -> 'RestartToken' : '$1' . +%% safeToken2 -> 'RemoteToken' : '$1' . +%% safeToken2 -> 'RemoteDescriptorToken' : '$1' . +%% v3-safeToken2 -> 'ReservedGroupToken' : '$1' . +%% v3-safeToken2 -> 'ReservedValueToken' : '$1' . +safeToken2 -> 'SendonlyToken' : '$1' . +safeToken2 -> 'SendrecvToken' : '$1' . +safeToken2 -> 'ServicesToken' : '$1' . +%% v3-safeToken2 -> 'ServiceStatesToken' : '$1' . +safeToken2 -> 'ServiceChangeToken' : '$1' . +%% v3-safeToken2 -> 'ServiceChangeIncompleteToken' : '$1' . % v3 +safeToken2 -> 'ServiceChangeAddressToken' : '$1' . +safeToken2 -> 'SignalListToken' : '$1' . +%% v2-safeToken2 -> 'SignalsToken' : '$1' . +safeToken2 -> 'SignalTypeToken' : '$1' . +%% v2-safeToken2 -> 'StatsToken' : '$1' . +safeToken2 -> 'StreamToken' : '$1' . +%% BMK BMK safeToken2 -> 'SubtractToken' : '$1' . +safeToken2 -> 'SynchISDNToken' : '$1' . +safeToken2 -> 'TerminationStateToken' : '$1' . +safeToken2 -> 'TestToken' : '$1' . +safeToken2 -> 'TimeOutToken' : '$1' . +%% BMK BMK safeToken2 -> 'TopologyToken' : '$1' . +safeToken2 -> 'TransToken' : '$1' . +safeToken2 -> 'V18Token' : '$1' . +safeToken2 -> 'V22Token' : '$1' . +safeToken2 -> 'V22bisToken' : '$1' . +safeToken2 -> 'V32Token' : '$1' . +safeToken2 -> 'V32bisToken' : '$1' . +safeToken2 -> 'V34Token' : '$1' . +safeToken2 -> 'V76Token' : '$1' . +safeToken2 -> 'V90Token' : '$1' . +safeToken2 -> 'V91Token' : '$1' . +safeToken2 -> 'VersionToken' : '$1' . + +Erlang code. + +%% The following directive is needed for (significantly) faster compilation +%% of the generated .erl file by the HiPE compiler. Please do not remove. +-compile([{hipe,[{regalloc,linear_scan}]}]). + +-include("megaco_text_parser_v3.hrl"). + + diff --git a/lib/megaco/src/text/megaco_text_scanner.erl b/lib/megaco/src/text/megaco_text_scanner.erl new file mode 100644 index 0000000000..8559941e5f --- /dev/null +++ b/lib/megaco/src/text/megaco_text_scanner.erl @@ -0,0 +1,869 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2000-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 : Scanner for text encoded Megaco/H.248 messages +%%---------------------------------------------------------------------- + +-module('megaco_text_scanner'). + +-export([scan/1, skip_sep_chars/2]). + +-include_lib("megaco/include/megaco.hrl"). +-include_lib("megaco/src/engine/megaco_message_internal.hrl"). +-include("megaco_text_tokens.hrl"). + +-define(LOWER1(Char), + if + (Char >= $A) andalso (Char =< $Z) -> + Char - ($A - $a); + true -> + Char + end). + +%% This is used when we _know_ it to be upper case +-define(LOWER2(Char), Char - ($A - $a)). + +scan(Bin) when is_binary(Bin) -> + Chars = erlang:binary_to_list(Bin), + tokens1(Chars, 1, []); +scan(Chars) when is_list(Chars) -> + tokens1(Chars, 1, []). + +%% As long as we dont know the version, we will loop in this function +tokens1(Chars, Line, Acc) -> + case any_chars(Chars, Line, 1) of + {token, Token, [], LatestLine} -> + %% We got to the end without actually getting a version token. + Tokens = [{endOfMessage, LatestLine, endOfMessage}, Token | Acc], + {error, no_version_found, lists:reverse(Tokens), Line}; + + %% -- Version token for version 1 -- + {token, {'SafeChars',_,"!/1"} = Token, Rest, LatestLine} -> + tokens2(Rest, LatestLine, 1, [Token | Acc]); + + {token, {'SafeChars',_,"megaco/1"} = Token, Rest, LatestLine} -> + tokens2(Rest, LatestLine, 1, [Token | Acc]); + + + %% -- Version token for version 2 -- + {token, {'SafeChars',_,"!/2"} = Token, Rest, LatestLine} -> + tokens2(Rest, LatestLine, 2, [Token | Acc]); + + {token, {'SafeChars',_,"megaco/2"} = Token, Rest, LatestLine} -> + tokens2(Rest, LatestLine, 2, [Token | Acc]); + + + %% -- Version token for version 3 -- + {token, {'SafeChars',_,"!/3"} = Token, Rest, LatestLine} -> + tokens2(Rest, LatestLine, 3, [Token | Acc]); + + {token, {'SafeChars',_,"megaco/3"} = Token, Rest, LatestLine} -> + tokens2(Rest, LatestLine, 3, [Token | Acc]); + + + %% -- Version token for version X -- + {token, {'SafeChars',_,[$!,$/| Vstr]} = Token, Rest, LatestLine} -> + case guess_version(Vstr) of + {ok, V} -> + tokens2(Rest, LatestLine, V, [Token | Acc]); + {error, Reason} -> + {error, Reason, LatestLine} + end; + + {token, {'SafeChars',_,[$m,$e,$g,$a,$c,$o,$/|Vstr]} = Token, Rest, LatestLine} -> + case guess_version(Vstr) of + {ok, V} -> + tokens2(Rest, LatestLine, V, [Token | Acc]); + {error, Reason} -> + {error, Reason, LatestLine} + end; + + %% -- Other tokens -- + {token, Token, Rest, LatestLine} -> + tokens1(Rest, LatestLine, [Token | Acc]); + + {bad_token, Token, _Rest, _LatestLine} -> + {error, {bad_token, [Token, Acc]}, Line} + end. + +tokens2(Chars, Line0, Version, Tokens0) -> + case tokens3(Chars, Line0, Tokens0, Version) of + {ok, Tokens, Line} -> + {ok, Tokens, Version, Line}; + Error -> + Error + end. + +tokens3(Chars, Line, Acc, Version) -> + %% d("tokens2 -> entry with" + %% "~n Chars: ~s" + %% "~n Line: ~p", [Chars, Line]), + case any_chars(Chars, Line, Version) of + {token, Token, [], LatestLine} -> + %% d("tokens2 -> Token: ~n~p", [Token]), + Tokens = [{endOfMessage, LatestLine, endOfMessage}, Token | Acc], + {ok, lists:reverse(Tokens), Line}; + + {token, Token, Rest, LatestLine} -> + %% d("tokens2 -> Token: ~n~p", [Token]), + tokens3(Rest, LatestLine, [Token | Acc], Version); + + {bad_token, Token, _Rest, _LatestLine} -> + {error, {bad_token, [Token, Acc]}, Line} + end. + + +guess_version([C]) when (48 =< C) and (C =< 57) -> + {ok, C-48}; +guess_version(Str) when is_list(Str) -> + case (catch list_to_integer(Str)) of + I when is_integer(I) -> + {ok, I}; + _ -> + {error, {invalid_version, Str}} + end. + + +%% Returns {token, Token, Rest, LatestLine} +%% Returns {bad_token, Token, Rest, LatestLine} +any_chars([Char | Rest], Line, Version) -> + case ?classify_char(Char) of + safe_char_upper -> + safe_chars(Rest, [Char], [?LOWER2(Char)], Line, Version); + safe_char -> + safe_chars(Rest, [Char], [Char], Line, Version); + rest_char -> + case Char of + ?SemiColonToken -> + comment_chars(Rest, Line); + _ -> + rest_chars(Rest, [Char], Line) + end; + double_quote -> + quoted_chars(Rest, [], Line); + white_space -> + sep_chars(Rest, Line); + end_of_line -> + sep_chars(Rest, Line); + bad_char -> + %% {bad_token, {'SEP', Line, Char}, Rest, Line} + {bad_token, {'AnyChars', Line, Char}, Rest, Line} + end; +any_chars([] = All, Line, _Version) -> + {token, {'SEP', Line, end_of_input}, All, Line}. + +comment_chars([Char | Rest], Line) -> + case ?classify_char(Char) of + safe_char_upper -> + comment_chars(Rest, Line); + safe_char -> + comment_chars(Rest, Line); + rest_char -> + comment_chars(Rest, Line); + white_space -> + comment_chars(Rest, Line); + end_of_line -> + sep_chars(Rest, Line); + _ when Char =:= 22 -> + comment_chars(Rest, Line); + _ -> + %% {bad_token, {'SEP', Line, Char}, Rest, Line} + {bad_token, {'CommentChars', Line, Char}, Rest, Line} + end; +comment_chars([] = All, Line) -> + {token, {'SEP', Line}, All, Line}. + +sep_chars([Char | Rest] = All, Line) -> + case ?classify_char(Char) of + safe_char_upper -> + {token, {'SEP', Line}, All, Line}; + safe_char -> + {token, {'SEP', Line}, All, Line}; + rest_char when Char =:= ?SemiColonToken -> + comment_chars(Rest, Line); + rest_char -> + rest_chars(Rest, [Char], Line); + white_space -> + sep_chars(Rest, Line); + end_of_line -> + sep_chars(Rest, Line + 1); + _ -> + %% {bad_token, {'SEP', Line, Char}, Rest, Line} + {bad_token, {'SepChars', Line, Char}, Rest, Line} + end; +sep_chars([] = All, Line) -> + {token, {'SEP', Line}, All, Line}. + +rest_chars(Rest, [?ColonToken], Line) -> + {token, {'COLON', Line}, Rest, Line}; +rest_chars(Rest, [AccChar], Line) -> + TokenTag = + case AccChar of + ?EqualToken -> 'EQUAL'; + ?NequalToken -> 'NEQUAL'; + ?LesserToken -> 'LESSER'; + ?GreaterToken -> 'GREATER'; + ?LbrktToken -> 'LBRKT'; + ?RbrktToken -> 'RBRKT'; + ?LsbrktToken -> 'LSBRKT'; + ?RsbrktToken -> 'RSBRKT'; + ?LparToken -> 'LPAR'; + ?RparToken -> 'RPAR'; + ?VbarToken -> 'VBAR'; + ?CommaToken -> 'COMMA' + end, + {Rest2, Line2} = skip_sep_chars(Rest, Line), + {token, {TokenTag, Line}, Rest2, Line2}. + +skip_sep_chars([Char | Rest] = All, Line) -> + case ?classify_char2(Char) of + rest_char when Char =:= ?SemiColonToken -> + skip_comment_chars(Rest, Line); + white_space -> + skip_sep_chars(Rest, Line); + end_of_line -> + skip_sep_chars(Rest, Line + 1); + _ -> + {All, Line} + end; +skip_sep_chars([] = All, Line) -> + {All, Line}. + +skip_comment_chars([Char | Rest] = All, Line) -> + case ?classify_char(Char) of + safe_char_upper -> + skip_comment_chars(Rest, Line); + safe_char -> + skip_comment_chars(Rest, Line); + rest_char -> + skip_comment_chars(Rest, Line); + double_quote -> + skip_comment_chars(Rest, Line); + white_space -> + skip_comment_chars(Rest, Line); + end_of_line -> + skip_sep_chars(Rest, Line + 1); + _ -> + {All, Line} + end; +skip_comment_chars([] = All, Line) -> + {All, Line}. + +quoted_chars([Char | Rest], Acc, Line) -> + case ?classify_char(Char) of + safe_char_upper -> + quoted_chars(Rest, [Char | Acc], Line); + safe_char -> + quoted_chars(Rest, [Char | Acc], Line); + rest_char -> + quoted_chars(Rest, [Char | Acc], Line); + white_space -> + quoted_chars(Rest, [Char | Acc], Line); + double_quote -> + {token, {'QuotedChars', Line, lists:reverse(Acc)}, Rest, Line}; + _ -> + {bad_token, {'QuotedChars', Line, Char}, Rest, Line} + end; +quoted_chars([] = All, _Acc, Line) -> + {bad_token, {'QuotedChars', Line, end_of_input}, All, Line}. + +safe_chars([Char | Rest] = All, Acc, LowerAcc, Line, Version) -> + %% d("safe_chars -> entry with" + %% "~n Char: ~p" + %% "~n LowerAcc: ~p", [Char, LowerAcc]), + case ?classify_char3(Char) of + safe_char_upper -> + safe_chars(Rest, [Char | Acc], + [?LOWER2(Char) | LowerAcc], Line, Version); + safe_char -> + safe_chars(Rest, [Char | Acc], [Char | LowerAcc], Line, Version); + _ -> + LowerSafeChars = lists:reverse(LowerAcc), + TokenTag = select_token(LowerSafeChars, Version), + SafeChars = lists:reverse(Acc), + case TokenTag of + 'MtpToken' -> + %% 'MtpToken' 'LBRKT' OctetString 'RBRKT' + special_chars(All, LowerSafeChars, Line, TokenTag); + 'LocalToken' -> + %% 'LocalToken' 'LBRKT' OctetString 'RBRKT' + special_chars(All, SafeChars, Line, TokenTag); + 'RemoteToken' -> + %% 'RemoteToken' 'LBRKT' OctetString 'RBRKT' + special_chars(All, SafeChars, Line, TokenTag); + 'DigitMapToken' -> + %% 'DigitMapToken' + %% 'DigitMapToken' 'EQUAL' Name + %% 'DigitMapToken' 'EQUAL' Name 'LBRKT' Value 'RBRKT' + %% 'DigitMapToken' 'EQUAL' 'LBRKT' Value 'RBRKT' + %% 'DigitMapToken' 'LBRKT' Value 'RBRKT' + special_chars(All, LowerSafeChars, Line, TokenTag); + _ -> + {token, {TokenTag, Line, LowerSafeChars}, All, Line} + end + end; +safe_chars([] = All, _Acc, LowerAcc, Line, Version) -> + LowerSafeChars = lists:reverse(LowerAcc), + TokenTag = select_token(LowerSafeChars, Version), + %%SafeChars = lists:reverse(Acc), + {token, {TokenTag, Line, LowerSafeChars}, All, Line}. + +collect_safe_chars([Char | Rest] = All, LowerAcc) -> + case ?classify_char3(Char) of + safe_char_upper -> + collect_safe_chars(Rest, [?LOWER2(Char) | LowerAcc]); + safe_char -> + collect_safe_chars(Rest, [Char | LowerAcc]); + _ -> + {All, lists:reverse(LowerAcc)} + end; +collect_safe_chars([] = Rest, LowerAcc) -> + {Rest, lists:reverse(LowerAcc)}. + +special_chars(All, SafeChars, Line, TokenTag) -> + {Rest, Line2} = skip_sep_chars(All, Line), + case Rest of + [?LbrktToken | Rest2] -> + {token, {'OctetString', _, OctetString}, Rest4, Line4} = + octet_string(Rest2, Line2), + case Rest4 of + [?RbrktToken | Rest6] -> + Token = + case TokenTag of + 'MtpToken' -> + %% 'MtpToken' 'LBRKT' OctetString 'RBRKT' + {'MtpAddressToken', Line, OctetString}; + 'LocalToken' -> + %% 'LocalToken' 'LBRKT' OctetString 'RBRKT' + PGs = property_groups(OctetString), + {'LocalDescriptorToken', Line, PGs}; + 'RemoteToken' -> + %% 'RemoteToken' 'LBRKT' OctetString 'RBRKT' + PGs = property_groups(OctetString), + {'RemoteDescriptorToken', Line, PGs}; + 'DigitMapToken' -> + %% 'DigitMapToken' 'LBRKT' OctetString 'RBRKT' + DMV = digit_map_value(OctetString), + DMD = #'DigitMapDescriptor'{digitMapValue = DMV}, + {'DigitMapDescriptorToken', Line, DMD} + end, + {token, Token, Rest6, Line4}; + _ when TokenTag =:= 'DigitMapToken' -> + %% 'DigitMapToken' + {token, {'DigitMapToken', Line, SafeChars}, All, Line}; + _ -> + {token, {'SafeChars', Line, SafeChars}, All, Line} + end; + [?EqualToken | Rest2] when TokenTag =:= 'DigitMapToken' -> + {Rest3, Line3} = skip_sep_chars(Rest2, Line2), + {Rest4, DigitMapName} = collect_safe_chars(Rest3, []), + {Rest6, Line6, DMD} = + if + DigitMapName =:= [] -> + {Rest3, Line3, #'DigitMapDescriptor'{}}; + true -> + {Rest5, Line5} = skip_sep_chars(Rest4, Line3), + {Rest5, Line5, #'DigitMapDescriptor'{digitMapName = DigitMapName}} + end, + case Rest6 of + [?LbrktToken | Rest7] -> + {token, {'OctetString', _, OctetString}, Rest8, Line8} = + octet_string(Rest7, Line6), + case Rest8 of + [?RbrktToken | Rest10] -> + %% 'DigitMapToken' 'EQUAL' 'LBRKT' OctetString 'RBRKT' + %% 'DigitMapToken' 'EQUAL' Name 'LBRKT' OctetString 'RBRKT' + {Rest11, Line11} = skip_sep_chars(Rest10, Line8), + DMV = digit_map_value(OctetString), + DMD2 = DMD#'DigitMapDescriptor'{digitMapValue = DMV}, + {token, {'DigitMapDescriptorToken', Line, DMD2}, Rest11, Line11}; + _ when DMD#'DigitMapDescriptor'.digitMapName /= asn1_NOVALUE -> + %% 'DigitMapToken' 'EQUAL' Name + {token, {'DigitMapDescriptorToken', Line, DMD}, Rest4, Line3}; + _ -> + %% 'DigitMapToken' + {token, {'DigitMapToken', Line, SafeChars}, All, Line} + end; + _ when DMD#'DigitMapDescriptor'.digitMapName /= asn1_NOVALUE -> + %% 'DigitMapToken' 'EQUAL' Name + {token, {'DigitMapDescriptorToken', Line, DMD}, Rest4, Line3}; + _ -> + %% 'DigitMapToken' + {token, {'DigitMapToken', Line, SafeChars}, All, Line} + end; + _ when TokenTag =:= 'DigitMapToken' -> + %% 'DigitMapToken' + {token, {'DigitMapToken', Line, SafeChars}, All, Line}; + _ -> + %% 'DigitMapToken' + {token, {'SafeChars', Line, SafeChars}, All, Line} + end. + +octet_string(Chars, Line) -> + {Chars2, Line2} = skip_sep_chars(Chars, Line), + Acc = [], + {Rest, RevChars, RestLine} = octet_string(Chars2, Acc, Line2), + {RevChars2, _} = skip_sep_chars(RevChars, RestLine), + OctetString = lists:reverse(RevChars2), + {token, {'OctetString', Line, OctetString}, Rest, RestLine}. + + +octet_string([Char | Rest] = All, Acc, Line) -> + if + (Char =:= ?CrToken) -> + octet_string(Rest, [Char | Acc], Line + 1); + (Char =:= ?LfToken) -> + octet_string(Rest, [Char | Acc], Line + 1); + (Char >= 8#1) andalso (Char =< 8#174) -> + octet_string(Rest, [Char | Acc], Line); + (Char >= 8#176) andalso (Char =< 8#377) -> + octet_string(Rest, [Char | Acc], Line); + (Char =:= ?BackslashToken) -> + case Rest of + [?RbrktToken | _Rest2] -> + %% OTP-4357 + octet_string(Rest, + [?RbrktToken, ?BackslashToken | Acc], Line); + _ -> + octet_string(Rest, [Char | Acc], Line) + end; + true -> + {All, Acc, Line} + end; +octet_string([] = All, Acc, Line) -> + {All, Acc, Line}. + + +%% digitMapValue = ["T" COLON Timer COMMA] +%% ["S" COLON Timer COMMA] +%% ["L" COLON Timer COMMA] +%% ["Z" COLON Timer COMMA] digitMap +digit_map_value(Chars) -> + digit_map_value(Chars, #'DigitMapValue'{}). + +%% NOTE: The swap of the digitMapBody and the durationTimer is +%% intentional. The reason is a problem with the flex scanner. +%% Hopefully this is temporary... +%% The values are swapped back later by the parser... +digit_map_value([Char, ?ColonToken | Rest] = All, DMV) -> + case ?LOWER1(Char) of + $t -> digit_map_timer(All, Rest, #'DigitMapValue'.startTimer, DMV); + $s -> digit_map_timer(All, Rest, #'DigitMapValue'.shortTimer, DMV); + $l -> digit_map_timer(All, Rest, #'DigitMapValue'.longTimer, DMV); +% $z -> digit_map_timer(All, Rest, #'DigitMapValue'.durationTimer, DMV); +% _ -> DMV#'DigitMapValue'{digitMapBody = All} + $z -> digit_map_timer(All, Rest, #'DigitMapValue'.digitMapBody, DMV); + _ -> DMV#'DigitMapValue'{durationTimer = All} + end; +digit_map_value(Chars, DMV) -> + DMV#'DigitMapValue'{durationTimer = Chars}. + +digit_map_timer(All, Chars, TimerPos, DMV) -> + {Rest, Digits} = collect_safe_chars(Chars, []), + {Rest2, _} = skip_sep_chars(Rest, 0), + case {Rest2, catch list_to_integer(Digits)} of + {[?CommaToken | Rest3], Int} when is_integer(Int) andalso + (Int >= 0) andalso + (element(TimerPos, DMV) =:= asn1_NOVALUE) -> + {Rest4, _} = skip_sep_chars(Rest3, 0), + DMV2 = setelement(TimerPos, DMV, Int), + digit_map_value(Rest4, DMV2); + _ -> + DMV#'DigitMapValue'{digitMapBody = All} + end. + +%% ============================================================================ +%% <prev-parser-stuff> +%% +%% This stuff was originally in the parser(s), but was, +%% for performance reasons, moved to the scanner(s). This +%% scanner does not make it faster, but the flex scanner +%% does, which is why the move was made. +%% + +property_groups(OctetString) -> + Group = [], + Groups = [], + property_name(OctetString, Group, Groups). + +property_name([Char | Rest] = All, Group, Groups) -> + if + ?white_space(Char) -> + property_name(Rest, Group, Groups); + ?end_of_line(Char) -> + property_name(Rest, Group, Groups); + true -> + Name = [], + do_property_name(All, Name, Group, Groups) + end; +property_name([] = All, Group, Groups) -> + Name = [], + do_property_name(All, Name, Group, Groups). + +do_property_name([Char | Rest], Name, Group, Groups) + when (Char =:= $=) andalso (Name =/= []) -> + %% Now we have a complete name + if + (Name =:= "v") andalso (Group =/= []) -> + %% v= is a property group delimiter, + %% lets create yet another property group. + Groups2 = [lists:reverse(Group) | Groups], + Group2 = [], + property_value(Rest, Name, Group2, Groups2); + true -> + %% Use current property group + property_value(Rest, Name, Group, Groups) + end; +do_property_name([Char | Rest], Name, Group, Groups) -> + case ?classify_char4(Char) of + safe_char_upper -> + do_property_name(Rest, [Char | Name], Group, Groups); + safe_char -> + do_property_name(Rest, [Char | Name], Group, Groups); + _ -> + throw({error, {bad_prop_name, lists:reverse(Name), Char}}) + end; +do_property_name([], [], [], Groups) -> + lists:reverse(Groups); +do_property_name([], [], Group, Groups) -> + Group2 = lists:reverse(Group), + lists:reverse([Group2 | Groups]); +do_property_name([], Name, Group, Groups) when Name =/= [] -> + %% Assume end of line + Value = [], + PP = make_property_parm(Name, Value), + Group2 = lists:reverse([PP | Group]), + lists:reverse([Group2 | Groups]). + +-ifdef(megaco_scanner_inline). +-compile({inline,[{property_value,4}]}). +-endif. +property_value(Chars, Name, Group, Groups) -> + Value = [], + do_property_value(Chars, Name, Value, Group, Groups). + +do_property_value([Char | Rest], Name, Value, Group, Groups) -> + if + ?end_of_line(Char) -> + %% Now we have a complete "name=value" pair + PP = make_property_parm(Name, Value), + property_name(Rest, [PP | Group], Groups); + true -> + do_property_value(Rest, Name, [Char | Value], Group, Groups) + end; +do_property_value([], Name, Value, Group, Groups) -> + %% Assume end of line + PP = make_property_parm(Name, Value), + Group2 = lists:reverse([PP | Group]), + lists:reverse([Group2 | Groups]). + +-ifdef(megaco_scanner_inline). +-compile({inline,[{make_property_parm,2}]}). +-endif. +make_property_parm(Name, Value) -> + %% Record name, name field, value field, extraInfo field + {'PropertyParm', + lists:reverse(Name), + [lists:reverse(Value)], + asn1_NOVALUE}. + + +%% </prev-parser-stuff> +%% =========================================================================== + +select_token([$o, $- | LowerText], Version) -> + select_token(LowerText, Version); +select_token([$w, $- | LowerText], Version) -> + select_token(LowerText, Version); +select_token(LowerText, Version) -> + case LowerText of + "add" -> 'AddToken'; + "a" -> 'AddToken'; + "andlgc" when (Version >= 3) -> 'AndAUDITSelectToken'; % v3 + "audit" -> 'AuditToken'; + "at" -> 'AuditToken'; + "auditcapability" -> 'AuditCapToken'; + "ac" -> 'AuditCapToken'; + "auditvalue" -> 'AuditValueToken'; + "av" -> 'AuditValueToken'; + "authentication" -> 'AuthToken'; + "au" -> 'AuthToken'; + "both" when (Version >= 3) -> 'BothToken'; % v3 + "b" when (Version >= 3) -> 'BothToken'; % v3 + "bothway" -> 'BothwayToken'; + "bw" -> 'BothwayToken'; + "brief" -> 'BriefToken'; + "br" -> 'BriefToken'; + "buffer" -> 'BufferToken'; + "bf" -> 'BufferToken'; + "context" -> 'CtxToken'; + "c" -> 'CtxToken'; + "contextattr" when (Version >= 3) -> 'ContextAttrToken'; % v3 + "ct" when (Version >= 3) -> 'ContextAttrToken'; % v3 + "contextlist" when (Version >= 3) -> 'ContextListToken'; % v3 + "clt" when (Version >= 3) -> 'ContextListToken'; % v3 + "contextaudit" -> 'ContextAuditToken'; + "ca" -> 'ContextAuditToken'; + "digitmap" -> 'DigitMapToken'; + "dm" -> 'DigitMapToken'; + "spadirection" when (Version >= 3) -> 'DirectionToken'; % v3 + "direction" when (Version >= 3) -> 'DirectionToken'; % v3 (pre-v3a/v3b) + "spadi" when (Version >= 3) -> 'DirectionToken'; % v3 + "di" when (Version >= 3) -> 'DirectionToken'; % v3 (pre-v3a/v3b) + "discard" -> 'DiscardToken'; + "ds" -> 'DiscardToken'; + "disconnected" -> 'DisconnectedToken'; + "dc" -> 'DisconnectedToken'; + "delay" -> 'DelayToken'; + "dl" -> 'DelayToken'; + "delete" -> 'DeleteToken'; + "de" -> 'DeleteToken'; + "duration" -> 'DurationToken'; + "dr" -> 'DurationToken'; + "embed" -> 'EmbedToken'; + "em" -> 'EmbedToken'; + "emergency" -> 'EmergencyToken'; + "eg" -> 'EmergencyToken'; + "emergencyofftoken" -> 'EmergencyOffToken'; + "emergencyoff" when (Version >= 3) -> 'EmergencyOffToken'; % v3 (as of prev3c) + "ego" -> 'EmergencyOffToken'; + "emergencyvalue" when (Version >= 3) -> 'EmergencyValueToken'; % v3 + "egv" when (Version >= 3) -> 'EmergencyValueToken'; % v3 + "error" -> 'ErrorToken'; + "er" -> 'ErrorToken'; + "eventbuffer" -> 'EventBufferToken'; + "eb" -> 'EventBufferToken'; + "events" -> 'EventsToken'; + "e" -> 'EventsToken'; + "external" when (Version >= 3) -> 'ExternalToken'; % v3 + "ex" when (Version >= 3) -> 'ExternalToken'; % v3 + "failover" -> 'FailoverToken'; + "fl" -> 'FailoverToken'; + "forced" -> 'ForcedToken'; + "fo" -> 'ForcedToken'; + "graceful" -> 'GracefulToken'; + "gr" -> 'GracefulToken'; + "h221" -> 'H221Token'; + "h223" -> 'H223Token'; + "h226" -> 'H226Token'; + "handoff" -> 'HandOffToken'; + "ho" -> 'HandOffToken'; + "iepscall" when (Version >= 3) -> 'IEPSToken'; % v3 + "ieps" when (Version >= 3) -> 'IEPSToken'; % v3 + "inactive" -> 'InactiveToken'; + "in" -> 'InactiveToken'; + "internal" when (Version >= 3) -> 'InternalToken'; % v3 + "it" when (Version >= 3) -> 'InternalToken'; % v3 + "immackrequired" -> 'ImmAckRequiredToken'; + "ia" -> 'ImmAckRequiredToken'; + "inservice" -> 'InSvcToken'; + "intersignal" when (Version >= 3) -> 'IntsigDelayToken'; % v3 + "spais" when (Version >= 3) -> 'IntsigDelayToken'; % v3 + "intbyevent" -> 'InterruptByEventToken'; + "ibe" -> 'InterruptByEventToken'; + "intbysigdescr" -> 'InterruptByNewSignalsDescrToken'; + "ibs" -> 'InterruptByNewSignalsDescrToken'; + "iv" -> 'InSvcToken'; + "isolate" -> 'IsolateToken'; + "is" -> 'IsolateToken'; + "iterationtoken" when (Version >= 3) -> 'IterationToken'; % v3 + "ir" when (Version >= 3) -> 'IterationToken'; % v3 + "keepactive" -> 'KeepActiveToken'; + "ka" -> 'KeepActiveToken'; + "local" -> 'LocalToken'; + "l" -> 'LocalToken'; + "localcontrol" -> 'LocalControlToken'; + "lockstep" -> 'LockStepToken'; + "sp" -> 'LockStepToken'; + "o" -> 'LocalControlToken'; + "loopback" -> 'LoopbackToken'; + "lb" -> 'LoopbackToken'; + "media" -> 'MediaToken'; + "m" -> 'MediaToken'; + %% "megaco" -> 'MegacopToken'; + %% "!" -> 'megacoptoken'; + "segment" when (Version >= 3) -> 'MessageSegmentToken'; % v3 + "sm" when (Version >= 3) -> 'MessageSegmentToken'; % v3 + "method" -> 'MethodToken'; + "mt" -> 'MethodToken'; + "mtp" -> 'MtpToken'; + "mgcidtotry" -> 'MgcIdToken'; + "mg" -> 'MgcIdToken'; + "mode" -> 'ModeToken'; + "mo" -> 'ModeToken'; + "modify" -> 'ModifyToken'; + "mf" -> 'ModifyToken'; + "modem" -> 'ModemToken'; + "md" -> 'ModemToken'; + "move" -> 'MoveToken'; + "mv" -> 'MoveToken'; + "mux" -> 'MuxToken'; + "mx" -> 'MuxToken'; + "nevernotify" when (Version >= 3) -> 'NeverNotifyToken'; % v3 + "nbnn" when (Version >= 3) -> 'NeverNotifyToken'; % v3 + "notify" -> 'NotifyToken'; + "n" -> 'NotifyToken'; + "notifycompletion" -> 'NotifyCompletionToken'; + "nc" -> 'NotifyCompletionToken'; + "immediatenotify" when (Version >= 3) -> 'NotifyImmediateToken'; % v3 + "nbin" when (Version >= 3) -> 'NotifyImmediateToken'; % v3 + "regulatednotify" when (Version >= 3) -> 'NotifyRegulatedToken'; % v3 + "nbrn" when (Version >= 3) -> 'NotifyRegulatedToken'; % v3 + "nx64kservice" when (Version >= 2) -> 'Nx64kToken'; % v2 + "n64" when (Version >= 2) -> 'Nx64kToken'; % v2 + "observedevents" -> 'ObservedEventsToken'; + "oe" -> 'ObservedEventsToken'; + "oneway" -> 'OnewayToken'; + "ow" -> 'OnewayToken'; + "onewayboth" when (Version >= 3) -> 'OnewayBothToken'; % v3 + "owb" when (Version >= 3) -> 'OnewayBothToken'; % v3 + "onewayexternal" when (Version >= 3) -> 'OnewayExternalToken'; % v3 + "owe" when (Version >= 3) -> 'OnewayExternalToken'; % v3 + "off" -> 'OffToken'; + "on" -> 'OnToken'; + "onoff" -> 'OnOffToken'; + "oo" -> 'OnOffToken'; + "orlgc" when (Version >= 3) -> 'OrAUDITselectToken'; % v3 + "otherreason" -> 'OtherReasonToken'; + "or" -> 'OtherReasonToken'; + "outofservice" -> 'OutOfSvcToken'; + "os" -> 'OutOfSvcToken'; + "packages" -> 'PackagesToken'; + "pg" -> 'PackagesToken'; + "pending" -> 'PendingToken'; + "pn" -> 'PendingToken'; + "priority" -> 'PriorityToken'; + "pr" -> 'PriorityToken'; + "profile" -> 'ProfileToken'; + "pf" -> 'ProfileToken'; + "reason" -> 'ReasonToken'; + "re" -> 'ReasonToken'; + "receiveonly" -> 'RecvonlyToken'; + "requestid" when (Version >= 3) -> 'RequestIDToken'; % v3 + "rq" when (Version >= 3) -> 'RequestIDToken'; % v3 + "rc" -> 'RecvonlyToken'; + "reply" -> 'ReplyToken'; + "p" -> 'ReplyToken'; + "reseteventsdescriptor" when (Version >= 3) -> 'ResetEventsDescriptorToken'; % v3 + "rse" when (Version >= 3) -> 'ResetEventsDescriptorToken'; % v3 + "transactionresponseack"-> 'ResponseAckToken'; + "k" -> 'ResponseAckToken'; + "restart" -> 'RestartToken'; + "rs" -> 'RestartToken'; + "remote" -> 'RemoteToken'; + "r" -> 'RemoteToken'; + "sparequestid" -> 'RequestIDToken'; + "sparq" -> 'RequestIDToken'; + "reservedgroup" -> 'ReservedGroupToken'; + "rg" -> 'ReservedGroupToken'; + "reservedvalue" -> 'ReservedValueToken'; + "rv" -> 'ReservedValueToken'; + "end" when (Version >= 3) -> 'SegmentationCompleteToken'; % v3 + "&" when (Version >= 3) -> 'SegmentationCompleteToken'; % v3 + "sendonly" -> 'SendonlyToken'; + "so" -> 'SendonlyToken'; + "sendreceive" -> 'SendrecvToken'; + "sr" -> 'SendrecvToken'; + "services" -> 'ServicesToken'; + "sv" -> 'ServicesToken'; + "servicestates" -> 'ServiceStatesToken'; + "si" -> 'ServiceStatesToken'; + "servicechange" -> 'ServiceChangeToken'; + "sc" -> 'ServiceChangeToken'; + "servicechangeaddress" -> 'ServiceChangeAddressToken'; + "ad" -> 'ServiceChangeAddressToken'; + "servicechangeinc" when (Version >= 3) -> 'ServiceChangeIncompleteToken'; % v3 + "sic" when (Version >= 3) -> 'ServiceChangeIncompleteToken'; % v3 + "signallist" -> 'SignalListToken'; + "sl" -> 'SignalListToken'; + "signals" -> 'SignalsToken'; + "sg" -> 'SignalsToken'; + "signaltype" -> 'SignalTypeToken'; + "sy" -> 'SignalTypeToken'; + "statistics" -> 'StatsToken'; + "sa" -> 'StatsToken'; + "stream" -> 'StreamToken'; + "st" -> 'StreamToken'; + "subtract" -> 'SubtractToken'; + "s" -> 'SubtractToken'; + "synchisdn" -> 'SynchISDNToken'; + "sn" -> 'SynchISDNToken'; + "terminationstate" -> 'TerminationStateToken'; + "ts" -> 'TerminationStateToken'; + "test" -> 'TestToken'; + "te" -> 'TestToken'; + "timeout" -> 'TimeOutToken'; + "to" -> 'TimeOutToken'; + "topology" -> 'TopologyToken'; + "tp" -> 'TopologyToken'; + "transaction" -> 'TransToken'; + "t" -> 'TransToken'; + "v18" -> 'V18Token'; + "v22" -> 'V22Token'; + "v22b" -> 'V22bisToken'; + "v32" -> 'V32Token'; + "v32b" -> 'V32bisToken'; + "v34" -> 'V34Token'; + "v76" -> 'V76Token'; + "v90" -> 'V90Token'; + "v91" -> 'V91Token'; + "version" -> 'VersionToken'; + "v" -> 'VersionToken'; + [_,_,_,_,_,_,_,_,$t,_,_,_,_,_,_,_,_] -> % Could be a time-stamp + [D1,D2,D3,D4,D5,D6,D7,D8,_,T1,T2,T3,T4,T5,T6,T7,T8] = LowerText, + select_TimeStampToken(D1,D2,D3,D4,D5,D6,D7,D8, + T1,T2,T3,T4,T5,T6,T7,T8); + _ -> 'SafeChars' + end. + +select_TimeStampToken(D1,D2,D3,D4,D5,D6,D7,D8, + T1,T2,T3,T4,T5,T6,T7,T8) + when ($0 =< D1) andalso (D1 =< $9) andalso + ($0 =< D2) andalso (D2 =< $9) andalso + ($0 =< D3) andalso (D3 =< $9) andalso + ($0 =< D4) andalso (D4 =< $9) andalso + ($0 =< D5) andalso (D5 =< $9) andalso + ($0 =< D6) andalso (D6 =< $9) andalso + ($0 =< D7) andalso (D7 =< $9) andalso + ($0 =< D8) andalso (D8 =< $9) andalso + ($0 =< T1) andalso (T1 =< $9) andalso + ($0 =< T2) andalso (T2 =< $9) andalso + ($0 =< T3) andalso (T3 =< $9) andalso + ($0 =< T4) andalso (T4 =< $9) andalso + ($0 =< T5) andalso (T5 =< $9) andalso + ($0 =< T6) andalso (T6 =< $9) andalso + ($0 =< T7) andalso (T7 =< $9) andalso + ($0 =< T8) andalso (T8 =< $9) -> + 'TimeStampToken'; +select_TimeStampToken(_D1,_D2,_D3,_D4,_D5,_D6,_D7,_D8, + _T1,_T2,_T3,_T4,_T5,_T6,_T7,_T8) -> + 'SafeChars'. + + +%% d(F) -> +%% d(F, []). + +%% d(F, A) -> +%% d(get(dbg), F, A). + +%% d(true, F, A) -> +%% io:format("DBG:~p:" ++ F ++ "~n", [?MODULE|A]); +%% d(_, _, _) -> +%% ok. diff --git a/lib/megaco/src/text/megaco_text_tokens.hrl b/lib/megaco/src/text/megaco_text_tokens.hrl new file mode 100644 index 0000000000..14f59c3f06 --- /dev/null +++ b/lib/megaco/src/text/megaco_text_tokens.hrl @@ -0,0 +1,475 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2000-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: Define of tokens used in text encoding of Megaco/H.248 +%%---------------------------------------------------------------------- + +%%---------------------------------------------------------------------- +%% Adding a new token requires changes in the following files: +%% +%% megaco_text_tokens.hrl +%% megaco_text_gen.hrl +%% megaco_compact_text_encoder.erl +%% megaco_pretty_text_encoder.erl +%% megaco_text_scanner.erl +%% megaco_text_parser.yrl (safeToken rule, make_safe_token/1, actual rule) +%% +%% Plus regeneration the ASN.1 related files including +%% manual patches +%%---------------------------------------------------------------------- + +%%---------------------------------------------------------------------- +%% Special records +%%---------------------------------------------------------------------- + +-record(property_parm, + { + name, + value, + extraInfo = asn1_NOVALUE + }). + + + +%%---------------------------------------------------------------------- +%% Special characters +%%---------------------------------------------------------------------- + +-define(EqualToken, 16#3d). +-define(ColonToken, 16#3a). +-define(LbrktToken, 16#7b). +-define(RbrktToken, 16#7d). +-define(LsbrktToken, $[). +-define(RsbrktToken, $]). +-define(CommaToken, 16#2c). +-define(DotToken, 16#2e). +-define(SlashToken, 16#2f). +-define(DoubleQuoteToken, 16#22). +-define(SpToken, 16#20). +-define(HtabToken, 16#09). +-define(CrToken, 16#0d). +-define(LfToken, 16#0a). + +-define(SemiColonToken, $;). +-define(NequalToken, $#). +-define(GreaterToken, $>). +-define(LesserToken, $<). +-define(BackslashToken, $\\). +-define(LparToken, $(). +-define(RparToken, $)). +-define(VbarToken, $|). + +%%---------------------------------------------------------------------- +%% Pretty version of tokens +%%---------------------------------------------------------------------- + +-define(PrettyAddToken , "Add" ). +-define(PrettyAndAUDITSelectToken , "ANSLgc" ). +-define(PrettyAuditToken , "Audit" ). +-define(PrettyAuditCapToken , "AuditCapability" ). +-define(PrettyAuditValueToken , "AuditValue" ). +-define(PrettyAuthToken , "Authentication" ). +-define(PrettyBothToken , "Both" ). % v3 +-define(PrettyBothwayToken , "Bothway" ). +-define(PrettyBriefToken , "Brief" ). +-define(PrettyBufferToken , "Buffer" ). +-define(PrettyCtxToken , "Context" ). +-define(PrettyContextAuditToken , "ContextAudit" ). +-define(PrettyContextAttrToken , "ContextAttr" ). % v3 +-define(PrettyContextListToken , "ContextList" ). % v3 +-define(PrettyDigitMapToken , "DigitMap" ). +-ifdef(encoder_version_pre_prev3c). +-define(PrettyDirectionToken , "Direction" ). % v3 +-else. +-define(PrettyDirectionToken , "SPADirection" ). % v3 +-endif. +-define(PrettyDiscardToken , "Discard" ). +-define(PrettyDisconnectedToken , "Disconnected" ). +-define(PrettyDelayToken , "Delay" ). +-define(PrettyDurationToken , "Duration" ). +-define(PrettyEmbedToken , "Embed" ). +-define(PrettyEmergencyToken , "Emergency" ). +-ifdef(encoder_version_pre_prev3c). +-define(PrettyEmergencyOffToken , "EmergencyOffToken" ). % v2 +-else. +-define(PrettyEmergencyOffToken , "EmergencyOff" ). % v3 +-endif. +-define(PrettyEmergencyValueToken , "EmergencyValue" ). % v3 +-define(PrettyErrorToken , "Error" ). +-define(PrettyEventBufferToken , "EventBuffer" ). +-define(PrettyEventsToken , "Events" ). +-define(PrettyExternalToken , "External" ). % v3 +-define(PrettyFailoverToken , "Failover" ). +-define(PrettyForcedToken , "Forced" ). +-define(PrettyGracefulToken , "Graceful" ). +-define(PrettyH221Token , "H221" ). +-define(PrettyH223Token , "H223" ). +-define(PrettyH226Token , "H226" ). +-define(PrettyHandOffToken , "HandOff" ). +-define(PrettyIEPSToken , "IEPSCall" ). % v3 +-define(PrettyImmAckRequiredToken , "ImmAckRequired" ). +-define(PrettyInactiveToken , "Inactive" ). +-define(PrettyInternalToken , "Internal" ). % v3 +-define(PrettyIntsigDelayToken , "Intersignal" ). % v3 +-define(PrettyInterruptByEventToken , "IntByEvent" ). +-define(PrettyInterruptByNewSignalsDescrToken, "IntBySigDescr" ). +-define(PrettyIsolateToken , "Isolate" ). +-define(PrettyInSvcToken , "InService" ). +-define(PrettyIterationToken , "Iteration" ). % v3 +-define(PrettyKeepActiveToken , "KeepActive" ). +-define(PrettyLocalToken , "Local" ). +-define(PrettyLocalControlToken , "LocalControl" ). +-define(PrettyLockStepToken , "LockStep" ). +-define(PrettyLoopbackToken , "Loopback" ). +-define(PrettyMediaToken , "Media" ). +-define(PrettyMegacopToken , "MEGACO" ). +-define(PrettyMessageSegmentToken , "Segment" ). % v3 +-define(PrettyMethodToken , "Method" ). +-define(PrettyMgcIdToken , "MgcIdToTry" ). +-define(PrettyModeToken , "Mode" ). +-define(PrettyModifyToken , "Modify" ). +-define(PrettyModemToken , "Modem" ). +-define(PrettyMoveToken , "Move" ). +-define(PrettyMtpToken , "MTP" ). +-define(PrettyMuxToken , "Mux" ). +-define(PrettyNeverNotifyToken , "NeverNotify" ). % v3 +-define(PrettyNotifyToken , "Notify" ). +-define(PrettyNotifyCompletionToken , "NotifyCompletion" ). +-define(PrettyNotifyImmediateToken , "ImmediateNotify" ). % v3 +-define(PrettyNotifyRegulatedToken , "RegulatedNotify" ). % v3 +-define(PrettyNx64kToken , "Nx64Kservice" ). +-define(PrettyObservedEventsToken , "ObservedEvents" ). +-define(PrettyOffToken , "OFF" ). +-define(PrettyOnewayToken , "Oneway" ). +-define(PrettyOnewayBothToken , "OnewayBoth" ). % v3 +-define(PrettyOnewayExternalToken , "OnewayExternal" ). % v3 +-define(PrettyOnOffToken , "OnOff" ). +-define(PrettyOrAUDITselectToken , "ORLgc" ). % v3 +-define(PrettyOnToken , "ON" ). +-define(PrettyOtherReasonToken , "OtherReason" ). +-define(PrettyOutOfSvcToken , "OutOfService" ). +-define(PrettyPackagesToken , "Packages" ). +-define(PrettyPendingToken , "Pending" ). +-define(PrettyPriorityToken , "Priority" ). +-define(PrettyProfileToken , "Profile" ). +-define(PrettyReasonToken , "Reason" ). +-define(PrettyRecvonlyToken , "ReceiveOnly" ). +-define(PrettyReplyToken , "Reply" ). +-define(PrettyResetEventsDescriptorToken , "ResetEventsDescriptor" ). % v3 +-define(PrettyRestartToken , "Restart" ). +-define(PrettyRemoteToken , "Remote" ). +-ifdef(encoder_version_pre_prev3c). +-define(PrettyRequestIDToken , "RequestID" ). % v3 +-else. +-define(PrettyRequestIDToken , "SPARequestID" ). % v3 +-endif. +-define(PrettyReservedGroupToken , "ReservedGroup" ). +-define(PrettyReservedValueToken , "ReservedValue" ). +-define(PrettySegmentationCompleteToken , "END" ). % v3 +-define(PrettySendonlyToken , "SendOnly" ). +-define(PrettySendrecvToken , "SendReceive" ). +-define(PrettyServicesToken , "Services" ). +-define(PrettyServiceStatesToken , "ServiceStates" ). +-define(PrettyServiceChangeToken , "ServiceChange" ). +-define(PrettyServiceChangeAddressToken , "ServiceChangeAddress" ). +-define(PrettyServiceChangeIncompleteToken , "ServiceChangeInc" ). % v3 +-define(PrettySignalListToken , "SignalList" ). +-define(PrettySignalsToken , "Signals" ). +-define(PrettySignalTypeToken , "SignalType" ). +-define(PrettyStatsToken , "Statistics" ). +-define(PrettyStreamToken , "Stream" ). +-define(PrettySubtractToken , "Subtract" ). +-define(PrettySynchISDNToken , "SynchISDN" ). +-define(PrettyTerminationStateToken , "TerminationState" ). +-define(PrettyTestToken , "Test" ). +-define(PrettyTimeOutToken , "TimeOut" ). +-define(PrettyTopologyToken , "Topology" ). +-define(PrettyTransToken , "Transaction" ). +-define(PrettyResponseAckToken , "TransactionResponseAck"). +-define(PrettyV18Token , "V18" ). +-define(PrettyV22Token , "V22" ). +-define(PrettyV22bisToken , "V22b" ). +-define(PrettyV32Token , "V32" ). +-define(PrettyV32bisToken , "V32b" ). +-define(PrettyV34Token , "V34" ). +-define(PrettyV76Token , "V76" ). +-define(PrettyV90Token , "V90" ). +-define(PrettyV91Token , "V91" ). +-define(PrettyVersionToken , "Version" ). + +%%---------------------------------------------------------------------- +%% Compact version of tokens +%%---------------------------------------------------------------------- + +-define(CompactAddToken , "A" ). +-define(CompactAndAUDITSelectToken , "ANSLgc" ). +-define(CompactAuditToken , "AT" ). +-define(CompactAuditCapToken , "AC" ). +-define(CompactAuditValueToken , "AV" ). +-define(CompactAuthToken , "AU" ). +-define(CompactBothToken , "B" ). % v3 +-define(CompactBothwayToken , "BW" ). +-define(CompactBriefToken , "BR" ). +-define(CompactBufferToken , "BF" ). +-define(CompactCtxToken , "C" ). +-define(CompactContextAuditToken , "CA" ). +-define(CompactContextAttrToken , "CT" ). % v3 +-define(CompactContextListToken , "CLT" ). % v3 +-define(CompactDigitMapToken , "DM" ). +-ifdef(encoder_version_pre_prev3c). +-define(CompactDirectionToken , "DI" ). % v3 +-else. +-define(CompactDirectionToken , "SPADI" ). % v3 +-endif. +-define(CompactDiscardToken , "DS" ). +-define(CompactDisconnectedToken , "DC" ). +-define(CompactDelayToken , "DL" ). +-define(CompactDurationToken , "DR" ). +-define(CompactEmbedToken , "EM" ). +-define(CompactEmergencyToken , "EG" ). +-define(CompactEmergencyOffToken , "EGO" ). +-define(CompactEmergencyValueToken , "EGV" ). % v3 +-define(CompactErrorToken , "ER" ). +-define(CompactEventBufferToken , "EB" ). +-define(CompactEventsToken , "E" ). +-define(CompactExternalToken , "EX" ). % v3 +-define(CompactFailoverToken , "FL" ). +-define(CompactForcedToken , "FO" ). +-define(CompactGracefulToken , "GR" ). +-define(CompactH221Token , ?PrettyH221Token ). +-define(CompactH223Token , ?PrettyH223Token ). +-define(CompactH226Token , ?PrettyH226Token ). +-define(CompactHandOffToken , "HO" ). +-define(CompactIEPSToken , "IEPS" ). % v3 +-define(CompactImmAckRequiredToken , "IA" ). +-define(CompactInactiveToken , "IN" ). +-define(CompactInternalToken , "IT" ). % v3 +-define(CompactIntsigDelayToken , "SPAIS" ). % v3 +-define(CompactInterruptByEventToken , "IBE" ). +-define(CompactInterruptByNewSignalsDescrToken, "IBS" ). +-define(CompactIsolateToken , "IS" ). +-define(CompactInSvcToken , "IV" ). +-define(CompactIterationToken , "IR" ). % v3 +-define(CompactKeepActiveToken , "KA" ). +-define(CompactLocalToken , "L" ). +-define(CompactLocalControlToken , "O" ). +-define(CompactLockStepToken , "SP" ). +-define(CompactLoopbackToken , "LB" ). +-define(CompactMediaToken , "M" ). +-define(CompactMegacopToken , "!" ). +-define(CompactMessageSegmentToken , "SM" ). % v3 +-define(CompactMethodToken , "MT" ). +-define(CompactMgcIdToken , "MG" ). +-define(CompactModeToken , "MO" ). +-define(CompactModifyToken , "MF" ). +-define(CompactModemToken , "MD" ). +-define(CompactMoveToken , "MV" ). +-define(CompactMtpToken , ?PrettyMtpToken ). +-define(CompactMuxToken , "MX" ). +-define(CompactNeverNotifyToken , "NBNN" ). % v3 +-define(CompactNotifyToken , "N" ). +-define(CompactNotifyCompletionToken , "NC" ). +-define(CompactNotifyImmediateToken , "NBIN" ). % v3 +-define(CompactNotifyRegulatedToken , "NBRN" ). % v3 +-define(CompactNx64kToken , "N64" ). +-define(CompactObservedEventsToken , "OE" ). +-define(CompactOffToken , "OFF" ). +-define(CompactOnewayToken , "OW" ). +-define(CompactOnewayBothToken , "OWB" ). % v3 +-define(CompactOnewayExternalToken , "OWE" ). % v3 +-define(CompactOnOffToken , "OO" ). +-define(CompactOrAUDITselectToken , "ORLgc" ). % v3 +-define(CompactOnToken , "ON" ). +-define(CompactOtherReasonToken , "OR" ). +-define(CompactOutOfSvcToken , "OS" ). +-define(CompactPackagesToken , "PG" ). +-define(CompactPendingToken , "PN" ). +-define(CompactPriorityToken , "PR" ). +-define(CompactProfileToken , "PF" ). +-define(CompactReasonToken , "RE" ). +-define(CompactRecvonlyToken , "RC" ). +-define(CompactReplyToken , "P" ). +-define(CompactResetEventsDescriptorToken , "RSE" ). % v3 +-define(CompactRestartToken , "RS" ). +-define(CompactRemoteToken , "R" ). +-ifdef(encoder_version_pre_prev3c). +-define(CompactRequestIDToken , "RQ" ). % v3 +-else. +-define(CompactRequestIDToken , "SPARQ" ). % v3 +-endif. +-define(CompactReservedGroupToken , "RG" ). +-define(CompactReservedValueToken , "RV" ). +-define(CompactSegmentationCompleteToken , "&" ). % v3 +-define(CompactSendonlyToken , "SO" ). +-define(CompactSendrecvToken , "SR" ). +-define(CompactServicesToken , "SV" ). +-define(CompactServiceStatesToken , "SI" ). +-define(CompactServiceChangeToken , "SC" ). +-define(CompactServiceChangeAddressToken , "AD" ). +-define(CompactServiceChangeIncompleteToken , "SIC" ). % v3 +-define(CompactSignalListToken , "SL" ). +-define(CompactSignalsToken , "SG" ). +-define(CompactSignalTypeToken , "SY" ). +-define(CompactStatsToken , "SA" ). +-define(CompactStreamToken , "ST" ). +-define(CompactSubtractToken , "S" ). +-define(CompactSynchISDNToken , "SN" ). +-define(CompactTerminationStateToken , "TS" ). +-define(CompactTestToken , "TE" ). +-define(CompactTimeOutToken , "TO" ). +-define(CompactTopologyToken , "TP" ). +-define(CompactTransToken , "T" ). +-define(CompactResponseAckToken , "K" ). +-define(CompactV18Token , ?PrettyV18Token ). +-define(CompactV22Token , ?PrettyV22Token ). +-define(CompactV22bisToken , ?PrettyV22bisToken ). +-define(CompactV32Token , ?PrettyV32Token ). +-define(CompactV32bisToken , ?PrettyV32bisToken ). +-define(CompactV34Token , ?PrettyV34Token ). +-define(CompactV76Token , ?PrettyV76Token ). +-define(CompactV90Token , ?PrettyV90Token ). +-define(CompactV91Token , ?PrettyV91Token ). +-define(CompactVersionToken , "V" ). + +-define(white_space(Char), ((Char) =:= ?SpToken) orelse ((Char) =:= ?HtabToken)). +-define(end_of_line(Char), ((Char) =:= ?LfToken) orelse ((Char) =:= ?CrToken)). + +-define(classify_char(Char), + (case Char of + $+ -> safe_char; + $- -> safe_char; + $& -> safe_char; + $! -> safe_char; + $_ -> safe_char; + $/ -> safe_char; + $' -> safe_char; + $? -> safe_char; + $@ -> safe_char; + $^ -> safe_char; + $` -> safe_char; + $~ -> safe_char; + $* -> safe_char; + $$ -> safe_char; + ?BackslashToken -> safe_char; + ?LparToken -> safe_char; + ?RparToken -> safe_char; + $% -> safe_char; + ?VbarToken -> safe_char; + $. -> safe_char; + ?SemiColonToken -> rest_char; + ?LsbrktToken -> rest_char; + ?RsbrktToken -> rest_char; + ?LbrktToken -> rest_char; + ?RbrktToken -> rest_char; + ?ColonToken -> rest_char; + ?CommaToken -> rest_char; + ?NequalToken -> rest_char; + ?LesserToken -> rest_char; + ?GreaterToken -> rest_char; + ?EqualToken -> rest_char; + ?DoubleQuoteToken -> double_quote; + ?SpToken -> white_space; + ?HtabToken -> white_space; + ?LfToken -> end_of_line; + ?CrToken -> end_of_line; + _ when (Char >= $0) andalso (Char =< $9) -> safe_char; + _ when (Char >= $a) andalso (Char =< $z) -> safe_char; + _ when (Char >= $A) andalso (Char =< $Z) -> safe_char_upper; + _ -> bad_char + end)). + +-define(classify_char2(Char), + (case Char of + ?SemiColonToken -> rest_char; + ?LsbrktToken -> rest_char; + ?RsbrktToken -> rest_char; + ?LbrktToken -> rest_char; + ?RbrktToken -> rest_char; + ?ColonToken -> rest_char; + ?CommaToken -> rest_char; + ?NequalToken -> rest_char; + ?LesserToken -> rest_char; + ?GreaterToken -> rest_char; + ?EqualToken -> rest_char; + ?SpToken -> white_space; + ?HtabToken -> white_space; + ?LfToken -> end_of_line; + ?CrToken -> end_of_line; + _ -> no_skip_char + end)). + +-define(classify_char3(Char), + (case Char of + $+ -> safe_char; + $- -> safe_char; + $& -> safe_char; + $! -> safe_char; + $_ -> safe_char; + $/ -> safe_char; + $' -> safe_char; + $? -> safe_char; + $@ -> safe_char; + $^ -> safe_char; + $` -> safe_char; + $~ -> safe_char; + $* -> safe_char; + $$ -> safe_char; + ?BackslashToken -> safe_char; + ?LparToken -> safe_char; + ?RparToken -> safe_char; + $% -> safe_char; + ?VbarToken -> safe_char; + $. -> safe_char; + _ when (Char >= $0) andalso (Char =< $9) -> safe_char; + _ when (Char >= $a) andalso (Char =< $z) -> safe_char; + _ when (Char >= $A) andalso (Char =< $Z) -> safe_char_upper; + _ -> non_safe_char + end)). + +%% Only safe_char and safe_char_upper +-define(classify_char4(Char), + (case Char of + $+ -> safe_char; + $- -> safe_char; + $& -> safe_char; + $! -> safe_char; + $_ -> safe_char; + $/ -> safe_char; + $' -> safe_char; + $? -> safe_char; + $@ -> safe_char; + $^ -> safe_char; + $` -> safe_char; + $~ -> safe_char; + $* -> safe_char; + $$ -> safe_char; + ?BackslashToken -> safe_char; + ?LparToken -> safe_char; + ?RparToken -> safe_char; + $% -> safe_char; + ?VbarToken -> safe_char; + $. -> safe_char; + _ when (Char >= $0) andalso (Char =< $9) -> safe_char; + _ when (Char >= $a) andalso (Char =< $z) -> safe_char; + _ when (Char >= $A) andalso (Char =< $Z) -> safe_char_upper; + _ -> not_safe_char + end)). + diff --git a/lib/megaco/src/text/modules.mk b/lib/megaco/src/text/modules.mk new file mode 100644 index 0000000000..c493c978a8 --- /dev/null +++ b/lib/megaco/src/text/modules.mk @@ -0,0 +1,65 @@ +#-*-makefile-*- ; force emacs to enter makefile-mode + +# %CopyrightBegin% +# +# Copyright Ericsson AB 2001-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% + +MODULES = \ + megaco_compact_text_encoder \ + megaco_compact_text_encoder_v1 \ + megaco_compact_text_encoder_v2 \ + megaco_compact_text_encoder_v3 \ + megaco_compact_text_encoder_prev3a \ + megaco_compact_text_encoder_prev3b \ + megaco_compact_text_encoder_prev3c \ + megaco_pretty_text_encoder \ + megaco_pretty_text_encoder_v1 \ + megaco_pretty_text_encoder_v2 \ + megaco_pretty_text_encoder_v3 \ + megaco_pretty_text_encoder_prev3a \ + megaco_pretty_text_encoder_prev3b \ + megaco_pretty_text_encoder_prev3c \ + megaco_text_mini_decoder \ + megaco_text_scanner + + +INTERNAL_HRL_FILES = \ + megaco_text_gen_v1.hrl \ + megaco_text_gen_v2.hrl \ + megaco_text_gen_v3.hrl \ + megaco_text_gen_prev3a.hrl \ + megaco_text_gen_prev3b.hrl \ + megaco_text_gen_prev3c.hrl \ + megaco_text_parser_v1.hrl \ + megaco_text_parser_v2.hrl \ + megaco_text_parser_v3.hrl \ + megaco_text_parser_prev3a.hrl \ + megaco_text_parser_prev3b.hrl \ + megaco_text_parser_prev3c.hrl \ + megaco_text_mini_parser.hrl \ + megaco_text_tokens.hrl + + +INTERNAL_YRL_FILES = \ + megaco_text_parser_v1.yrl \ + megaco_text_parser_v2.yrl \ + megaco_text_parser_v3.yrl \ + megaco_text_parser_prev3a.yrl \ + megaco_text_parser_prev3b.yrl \ + megaco_text_parser_prev3c.yrl \ + megaco_text_mini_parser.yrl + + |