aboutsummaryrefslogtreecommitdiffstats
path: root/lib/megaco/src
diff options
context:
space:
mode:
authorErlang/OTP <[email protected]>2009-11-20 14:54:40 +0000
committerErlang/OTP <[email protected]>2009-11-20 14:54:40 +0000
commit84adefa331c4159d432d22840663c38f155cd4c1 (patch)
treebff9a9c66adda4df2106dfd0e5c053ab182a12bd /lib/megaco/src
downloadotp-84adefa331c4159d432d22840663c38f155cd4c1.tar.gz
otp-84adefa331c4159d432d22840663c38f155cd4c1.tar.bz2
otp-84adefa331c4159d432d22840663c38f155cd4c1.zip
The R13B03 release.OTP_R13B03
Diffstat (limited to 'lib/megaco/src')
-rw-r--r--lib/megaco/src/Makefile37
-rw-r--r--lib/megaco/src/app/Makefile129
-rw-r--r--lib/megaco/src/app/depend.mk22
-rw-r--r--lib/megaco/src/app/megaco.app.src143
-rw-r--r--lib/megaco/src/app/megaco.appup.src165
-rw-r--r--lib/megaco/src/app/megaco.erl1017
-rw-r--r--lib/megaco/src/app/megaco.mk56
-rw-r--r--lib/megaco/src/app/megaco_internal.hrl183
-rw-r--r--lib/megaco/src/app/modules.mk36
-rw-r--r--lib/megaco/src/binary/MEDIA-GATEWAY-CONTROL-prev3a.asn1001
-rw-r--r--lib/megaco/src/binary/MEDIA-GATEWAY-CONTROL-prev3b.asn1001
-rw-r--r--lib/megaco/src/binary/MEDIA-GATEWAY-CONTROL-prev3c.asn1073
-rw-r--r--lib/megaco/src/binary/MEDIA-GATEWAY-CONTROL-v1.asn982
-rw-r--r--lib/megaco/src/binary/MEDIA-GATEWAY-CONTROL-v2.asn966
-rw-r--r--lib/megaco/src/binary/MEDIA-GATEWAY-CONTROL-v3.asn1068
-rw-r--r--lib/megaco/src/binary/Makefile212
-rw-r--r--lib/megaco/src/binary/depend.mk557
-rw-r--r--lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3a.asn1config43
-rw-r--r--lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3a.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3b.asn1config43
-rw-r--r--lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3b.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3c.asn1config43
-rw-r--r--lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3c.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v1.asn1config44
-rw-r--r--lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v1.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v2.asn1config43
-rw-r--r--lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v2.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v3.asn1config43
-rw-r--r--lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v3.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_ber_bin_encoder.erl716
-rw-r--r--lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_prev3a.asn1config43
-rw-r--r--lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_prev3a.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_prev3b.asn1config43
-rw-r--r--lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_prev3b.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_prev3c.asn1config43
-rw-r--r--lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_prev3c.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_v1.asn1config44
-rw-r--r--lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_v1.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_v2.asn1config43
-rw-r--r--lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_v2.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_v3.asn1config43
-rw-r--r--lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_v3.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_ber_encoder.erl346
-rw-r--r--lib/megaco/src/binary/megaco_ber_media_gateway_control_prev3a.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_ber_media_gateway_control_prev3b.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_ber_media_gateway_control_prev3c.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_ber_media_gateway_control_v1.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_ber_media_gateway_control_v2.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_ber_media_gateway_control_v3.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_binary_encoder.erl588
-rw-r--r--lib/megaco/src/binary/megaco_binary_encoder_lib.erl317
-rw-r--r--lib/megaco/src/binary/megaco_binary_name_resolver_prev3a.erl2003
-rw-r--r--lib/megaco/src/binary/megaco_binary_name_resolver_prev3b.erl2003
-rw-r--r--lib/megaco/src/binary/megaco_binary_name_resolver_prev3c.erl2004
-rw-r--r--lib/megaco/src/binary/megaco_binary_name_resolver_v1.erl1613
-rw-r--r--lib/megaco/src/binary/megaco_binary_name_resolver_v2.erl1681
-rw-r--r--lib/megaco/src/binary/megaco_binary_name_resolver_v3.erl2016
-rw-r--r--lib/megaco/src/binary/megaco_binary_term_id.erl187
-rw-r--r--lib/megaco/src/binary/megaco_binary_term_id_gen.erl436
-rw-r--r--lib/megaco/src/binary/megaco_binary_transformer_prev3a.erl1629
-rw-r--r--lib/megaco/src/binary/megaco_binary_transformer_prev3b.erl1629
-rw-r--r--lib/megaco/src/binary/megaco_binary_transformer_prev3c.erl1756
-rw-r--r--lib/megaco/src/binary/megaco_binary_transformer_v1.erl1261
-rw-r--r--lib/megaco/src/binary/megaco_binary_transformer_v2.erl1544
-rw-r--r--lib/megaco/src/binary/megaco_binary_transformer_v3.erl1763
-rw-r--r--lib/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_prev3a.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_prev3b.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_prev3c.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_v1.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_v2.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_v3.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_per_bin_encoder.erl447
-rw-r--r--lib/megaco/src/binary/megaco_per_bin_media_gateway_control_prev3a.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_per_bin_media_gateway_control_prev3b.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_per_bin_media_gateway_control_prev3c.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_per_bin_media_gateway_control_v1.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_per_bin_media_gateway_control_v2.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_per_bin_media_gateway_control_v3.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_per_encoder.erl291
-rw-r--r--lib/megaco/src/binary/megaco_per_media_gateway_control_prev3a.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_per_media_gateway_control_prev3b.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_per_media_gateway_control_prev3c.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_per_media_gateway_control_v1.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_per_media_gateway_control_v2.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_per_media_gateway_control_v3.set.asn1
-rw-r--r--lib/megaco/src/binary/modules.mk128
-rw-r--r--lib/megaco/src/binary/old/megaco_ber_bin_drv_encoder.erl319
-rw-r--r--lib/megaco/src/binary/old/megaco_per_bin_drv_encoder.erl255
-rw-r--r--lib/megaco/src/engine/Makefile107
-rw-r--r--lib/megaco/src/engine/depend.mk81
-rw-r--r--lib/megaco/src/engine/megaco_config.erl2113
-rw-r--r--lib/megaco/src/engine/megaco_digit_map.erl856
-rw-r--r--lib/megaco/src/engine/megaco_edist_compress.erl33
-rw-r--r--lib/megaco/src/engine/megaco_encoder.erl37
-rw-r--r--lib/megaco/src/engine/megaco_erl_dist_encoder.erl275
-rw-r--r--lib/megaco/src/engine/megaco_erl_dist_encoder_mc.erl1894
-rw-r--r--lib/megaco/src/engine/megaco_filter.erl350
-rw-r--r--lib/megaco/src/engine/megaco_message_internal.hrl159
-rw-r--r--lib/megaco/src/engine/megaco_messenger.erl5158
-rw-r--r--lib/megaco/src/engine/megaco_messenger_misc.erl409
-rw-r--r--lib/megaco/src/engine/megaco_misc_sup.erl77
-rw-r--r--lib/megaco/src/engine/megaco_monitor.erl365
-rw-r--r--lib/megaco/src/engine/megaco_sdp.erl1645
-rw-r--r--lib/megaco/src/engine/megaco_stats.erl207
-rw-r--r--lib/megaco/src/engine/megaco_sup.erl116
-rw-r--r--lib/megaco/src/engine/megaco_timer.erl117
-rw-r--r--lib/megaco/src/engine/megaco_trans_sender.erl699
-rw-r--r--lib/megaco/src/engine/megaco_trans_sup.erl88
-rw-r--r--lib/megaco/src/engine/megaco_transport.erl32
-rw-r--r--lib/megaco/src/engine/megaco_user_default.erl185
-rw-r--r--lib/megaco/src/engine/modules.mk47
-rw-r--r--lib/megaco/src/flex/Makefile43
-rw-r--r--lib/megaco/src/flex/Makefile.in396
-rw-r--r--lib/megaco/src/flex/megaco_flex_scanner.erl230
-rw-r--r--lib/megaco/src/flex/megaco_flex_scanner_drv.flex.src1943
-rw-r--r--lib/megaco/src/flex/megaco_flex_scanner_handler.erl232
-rw-r--r--lib/megaco/src/flex/modules.mk27
-rw-r--r--lib/megaco/src/flex/prebuild.skip1
-rw-r--r--lib/megaco/src/rules.mk100
-rw-r--r--lib/megaco/src/subdirs.mk21
-rw-r--r--lib/megaco/src/tcp/Makefile107
-rw-r--r--lib/megaco/src/tcp/depend.mk42
-rw-r--r--lib/megaco/src/tcp/megaco_tcp.erl692
-rw-r--r--lib/megaco/src/tcp/megaco_tcp.hrl68
-rw-r--r--lib/megaco/src/tcp/megaco_tcp_accept.erl123
-rw-r--r--lib/megaco/src/tcp/megaco_tcp_accept_sup.erl95
-rw-r--r--lib/megaco/src/tcp/megaco_tcp_connection.erl275
-rw-r--r--lib/megaco/src/tcp/megaco_tcp_connection_sup.erl114
-rw-r--r--lib/megaco/src/tcp/megaco_tcp_sup.erl145
-rw-r--r--lib/megaco/src/tcp/modules.mk33
-rw-r--r--lib/megaco/src/text/Makefile148
-rw-r--r--lib/megaco/src/text/depend.mk187
-rw-r--r--lib/megaco/src/text/megaco_compact_text_encoder.erl560
-rw-r--r--lib/megaco/src/text/megaco_compact_text_encoder_prev3a.erl297
-rw-r--r--lib/megaco/src/text/megaco_compact_text_encoder_prev3b.erl432
-rw-r--r--lib/megaco/src/text/megaco_compact_text_encoder_prev3c.erl455
-rw-r--r--lib/megaco/src/text/megaco_compact_text_encoder_v1.erl407
-rw-r--r--lib/megaco/src/text/megaco_compact_text_encoder_v2.erl413
-rw-r--r--lib/megaco/src/text/megaco_compact_text_encoder_v3.erl455
-rw-r--r--lib/megaco/src/text/megaco_pretty_text_encoder.erl613
-rw-r--r--lib/megaco/src/text/megaco_pretty_text_encoder_prev3a.erl303
-rw-r--r--lib/megaco/src/text/megaco_pretty_text_encoder_prev3b.erl437
-rw-r--r--lib/megaco/src/text/megaco_pretty_text_encoder_prev3c.erl483
-rw-r--r--lib/megaco/src/text/megaco_pretty_text_encoder_v1.erl407
-rw-r--r--lib/megaco/src/text/megaco_pretty_text_encoder_v2.erl430
-rw-r--r--lib/megaco/src/text/megaco_pretty_text_encoder_v3.erl462
-rw-r--r--lib/megaco/src/text/megaco_text_gen_prev3a.hrl2945
-rw-r--r--lib/megaco/src/text/megaco_text_gen_prev3b.hrl2966
-rw-r--r--lib/megaco/src/text/megaco_text_gen_prev3c.hrl3443
-rw-r--r--lib/megaco/src/text/megaco_text_gen_v1.hrl2404
-rw-r--r--lib/megaco/src/text/megaco_text_gen_v2.hrl2794
-rw-r--r--lib/megaco/src/text/megaco_text_gen_v3.hrl3457
-rw-r--r--lib/megaco/src/text/megaco_text_mini_decoder.erl88
-rw-r--r--lib/megaco/src/text/megaco_text_mini_parser.hrl1246
-rw-r--r--lib/megaco/src/text/megaco_text_mini_parser.yrl398
-rw-r--r--lib/megaco/src/text/megaco_text_parser_prev3a.hrl1670
-rw-r--r--lib/megaco/src/text/megaco_text_parser_prev3a.yrl1591
-rw-r--r--lib/megaco/src/text/megaco_text_parser_prev3b.hrl1717
-rw-r--r--lib/megaco/src/text/megaco_text_parser_prev3b.yrl1601
-rw-r--r--lib/megaco/src/text/megaco_text_parser_prev3c.hrl1980
-rw-r--r--lib/megaco/src/text/megaco_text_parser_prev3c.yrl1673
-rw-r--r--lib/megaco/src/text/megaco_text_parser_v1.hrl1410
-rw-r--r--lib/megaco/src/text/megaco_text_parser_v1.yrl1364
-rw-r--r--lib/megaco/src/text/megaco_text_parser_v2.hrl1643
-rw-r--r--lib/megaco/src/text/megaco_text_parser_v2.yrl1538
-rw-r--r--lib/megaco/src/text/megaco_text_parser_v3.hrl2002
-rw-r--r--lib/megaco/src/text/megaco_text_parser_v3.yrl1680
-rw-r--r--lib/megaco/src/text/megaco_text_scanner.erl869
-rw-r--r--lib/megaco/src/text/megaco_text_tokens.hrl475
-rw-r--r--lib/megaco/src/text/modules.mk65
-rw-r--r--lib/megaco/src/udp/Makefile117
-rw-r--r--lib/megaco/src/udp/megaco_udp.erl324
-rw-r--r--lib/megaco/src/udp/megaco_udp.hrl64
-rw-r--r--lib/megaco/src/udp/megaco_udp_server.erl234
-rw-r--r--lib/megaco/src/udp/megaco_udp_sup.erl112
-rw-r--r--lib/megaco/src/udp/modules.mk30
176 files changed, 102260 insertions, 0 deletions
diff --git a/lib/megaco/src/Makefile b/lib/megaco/src/Makefile
new file mode 100644
index 0000000000..d2d66d2c89
--- /dev/null
+++ b/lib/megaco/src/Makefile
@@ -0,0 +1,37 @@
+#
+# %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
+include $(ERL_TOP)/make/$(TARGET)/otp.mk
+
+# ----------------------------------------------------
+# Common Macros
+# ----------------------------------------------------
+
+include subdirs.mk
+
+SPECIAL_TARGETS = setup
+
+# ----------------------------------------------------
+# Default Subdir Targets
+# ----------------------------------------------------
+include $(ERL_TOP)/make/otp_subdir.mk
+
+setup:
+ (cd flex && $(MAKE) $@)
+
diff --git a/lib/megaco/src/app/Makefile b/lib/megaco/src/app/Makefile
new file mode 100644
index 0000000000..01dfb9b860
--- /dev/null
+++ b/lib/megaco/src/app/Makefile
@@ -0,0 +1,129 @@
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2007-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)
+
+TARGET_FILES = \
+ $(MODULES:%=$(EBIN)/%.$(EMULATOR))
+
+APP_FILE = megaco.app
+APP_SRC = $(APP_FILE).src
+APP_TARGET = $(EBIN)/$(APP_FILE)
+
+APPUP_FILE = megaco.appup
+APPUP_SRC = $(APPUP_FILE).src
+APPUP_TARGET = $(EBIN)/$(APPUP_FILE)
+
+
+# ----------------------------------------------------
+# FLAGS
+# ----------------------------------------------------
+ifeq ($(TYPE),debug)
+ERL_COMPILE_FLAGS += -Ddebug
+endif
+
+include megaco.mk
+
+ERL_COMPILE_FLAGS += \
+ $(MEGACO_ERL_COMPILE_FLAGS) \
+ -I../../include
+
+
+# ----------------------------------------------------
+# Targets
+# ----------------------------------------------------
+debug:
+ @${MAKE} TYPE=debug opt
+
+opt: $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET)
+
+clean:
+ rm -f $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET)
+ rm -f errs core *~
+
+docs:
+
+info:
+ @echo "MODULES = $(MODULES)"
+ @echo ""
+
+
+# ----------------------------------------------------
+# Special Build Targets
+# ----------------------------------------------------
+
+$(APP_TARGET): $(APP_SRC) ../../vsn.mk
+ sed -e 's;%VSN%;$(VSN);' $< > $@
+
+$(APPUP_TARGET): $(APPUP_SRC) ../../vsn.mk
+ sed -e 's;%VSN%;$(VSN);' $< > $@
+
+
+
+# ----------------------------------------------------
+# Release Target
+# ----------------------------------------------------
+include $(ERL_TOP)/make/otp_release_targets.mk
+
+
+release_spec: opt
+ $(INSTALL_DIR) $(RELSYSDIR)/ebin
+ $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
+ $(INSTALL_DATA) $(APP_TARGET) $(APPUP_TARGET) $(RELSYSDIR)/ebin
+ $(INSTALL_DIR) $(RELSYSDIR)/src
+ $(INSTALL_DIR) $(RELSYSDIR)/src/app
+ $(INSTALL_DATA) $(ERL_FILES) $(INTERNAL_HRL_FILES) $(RELSYSDIR)/src/app
+ $(INSTALL_DIR) $(RELSYSDIR)/include
+ $(INSTALL_DATA) $(EXTERNAL_HRL_FILES) $(RELSYSDIR)/include
+
+
+release_docs_spec:
+
+
+# ----------------------------------------------------
+# Include dependencies
+# ----------------------------------------------------
+
+include depend.mk
+
diff --git a/lib/megaco/src/app/depend.mk b/lib/megaco/src/app/depend.mk
new file mode 100644
index 0000000000..27394d6f29
--- /dev/null
+++ b/lib/megaco/src/app/depend.mk
@@ -0,0 +1,22 @@
+#-*-makefile-*- ; force emacs to enter makefile-mode
+
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2007-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%
+
+$(EBIN)/megaco.$(EMULATOR): megaco.erl \
+ megaco_internal.hrl
+
diff --git a/lib/megaco/src/app/megaco.app.src b/lib/megaco/src/app/megaco.app.src
new file mode 100644
index 0000000000..503fcd7176
--- /dev/null
+++ b/lib/megaco/src/app/megaco.app.src
@@ -0,0 +1,143 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1999-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%
+%%
+
+{application, megaco,
+ [{description, "Megaco/H.248 protocol"},
+ {vsn, "%VSN%"},
+ {modules,
+ [
+ megaco,
+ megaco_ber_bin_encoder,
+ megaco_ber_bin_drv_media_gateway_control_v1,
+ megaco_ber_bin_drv_media_gateway_control_v2,
+ megaco_ber_bin_drv_media_gateway_control_prev3a,
+ megaco_ber_bin_drv_media_gateway_control_prev3b,
+ megaco_ber_bin_drv_media_gateway_control_prev3c,
+ megaco_ber_bin_drv_media_gateway_control_v3,
+ megaco_ber_bin_media_gateway_control_v1,
+ megaco_ber_bin_media_gateway_control_v2,
+ megaco_ber_bin_media_gateway_control_prev3a,
+ megaco_ber_bin_media_gateway_control_prev3b,
+ megaco_ber_bin_media_gateway_control_prev3c,
+ megaco_ber_bin_media_gateway_control_v3,
+ megaco_ber_encoder,
+ megaco_ber_media_gateway_control_v1,
+ megaco_ber_media_gateway_control_v2,
+ megaco_ber_media_gateway_control_prev3a,
+ megaco_ber_media_gateway_control_prev3b,
+ megaco_ber_media_gateway_control_prev3c,
+ megaco_ber_media_gateway_control_v3,
+ megaco_binary_encoder,
+ megaco_binary_encoder_lib,
+ megaco_binary_name_resolver_v1,
+ megaco_binary_name_resolver_v2,
+ megaco_binary_name_resolver_prev3a,
+ megaco_binary_name_resolver_prev3b,
+ megaco_binary_name_resolver_prev3c,
+ megaco_binary_name_resolver_v3,
+ megaco_binary_term_id,
+ megaco_binary_term_id_gen,
+ megaco_binary_transformer_v1,
+ megaco_binary_transformer_v2,
+ megaco_binary_transformer_prev3a,
+ megaco_binary_transformer_prev3b,
+ megaco_binary_transformer_prev3c,
+ megaco_binary_transformer_v3,
+ megaco_compact_text_encoder,
+ megaco_compact_text_encoder_v1,
+ megaco_compact_text_encoder_v2,
+ megaco_compact_text_encoder_prev3a,
+ megaco_compact_text_encoder_prev3b,
+ megaco_compact_text_encoder_prev3c,
+ megaco_compact_text_encoder_v3,
+ megaco_config,
+ megaco_digit_map,
+ megaco_encoder,
+ megaco_edist_compress,
+ megaco_erl_dist_encoder,
+ megaco_erl_dist_encoder_mc,
+ megaco_filter,
+ megaco_flex_scanner,
+ megaco_flex_scanner_handler,
+ megaco_messenger,
+ megaco_messenger_misc,
+ megaco_misc_sup,
+ megaco_monitor,
+ megaco_per_encoder,
+ megaco_per_media_gateway_control_v1,
+ megaco_per_media_gateway_control_v2,
+ megaco_per_media_gateway_control_prev3a,
+ megaco_per_media_gateway_control_prev3b,
+ megaco_per_media_gateway_control_prev3c,
+ megaco_per_media_gateway_control_v3,
+ megaco_per_bin_encoder,
+ megaco_per_bin_drv_media_gateway_control_v1,
+ megaco_per_bin_drv_media_gateway_control_v2,
+ megaco_per_bin_drv_media_gateway_control_prev3a,
+ megaco_per_bin_drv_media_gateway_control_prev3b,
+ megaco_per_bin_drv_media_gateway_control_prev3c,
+ megaco_per_bin_drv_media_gateway_control_v3,
+ megaco_per_bin_media_gateway_control_v1,
+ megaco_per_bin_media_gateway_control_v2,
+ megaco_per_bin_media_gateway_control_prev3a,
+ megaco_per_bin_media_gateway_control_prev3b,
+ megaco_per_bin_media_gateway_control_prev3c,
+ megaco_per_bin_media_gateway_control_v3,
+ megaco_pretty_text_encoder,
+ megaco_pretty_text_encoder_v1,
+ megaco_pretty_text_encoder_v2,
+ megaco_pretty_text_encoder_prev3a,
+ megaco_pretty_text_encoder_prev3b,
+ megaco_pretty_text_encoder_prev3c,
+ megaco_pretty_text_encoder_v3,
+ megaco_sdp,
+ megaco_stats,
+ megaco_sup,
+ megaco_tcp,
+ megaco_tcp_accept,
+ megaco_tcp_accept_sup,
+ megaco_tcp_connection,
+ megaco_tcp_connection_sup,
+ megaco_tcp_sup,
+ megaco_text_mini_decoder,
+ megaco_text_mini_parser,
+ megaco_text_parser_v1,
+ megaco_text_parser_v2,
+ megaco_text_parser_prev3a,
+ megaco_text_parser_prev3b,
+ megaco_text_parser_prev3c,
+ megaco_text_parser_v3,
+ megaco_text_scanner,
+ megaco_timer,
+ megaco_trans_sender,
+ megaco_trans_sup,
+ megaco_transport,
+ megaco_udp,
+ megaco_udp_server,
+ megaco_udp_sup,
+ megaco_user_default
+ ]},
+ {registered, [megaco_config, megaco_monitor,
+ megaco_trans_sup, megaco_misc_sup, megaco_sup]},
+ {applications, [stdlib, kernel]},
+ {env, []},
+ {mod, {megaco_sup, []}}
+ ]}.
+
+
diff --git a/lib/megaco/src/app/megaco.appup.src b/lib/megaco/src/app/megaco.appup.src
new file mode 100644
index 0000000000..163ff06651
--- /dev/null
+++ b/lib/megaco/src/app/megaco.appup.src
@@ -0,0 +1,165 @@
+%%
+%% %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%
+%%
+
+%%
+%% 3.4.3
+%% |
+%% v
+%% 3.4.4
+%% / \
+%% | |
+%% v v
+%% 3.5 3.4.5
+%% | |
+%% v v
+%% 3.5.1 <- 3.4.6
+%% |
+%% v
+%% 3.5.2
+%% |
+%% v
+%% 3.5.3
+%% |
+%% v
+%% 3.6
+%% |
+%% v
+%% 3.6.0.1
+%% |
+%% v
+%% 3.6.1
+%% |
+%% v
+%% 3.6.2
+%% / \
+%% | |
+%% v |
+%% 3.7 3.6.3
+%% | |
+%% v v
+%% 3.7.1 <- 3.6.4
+%% | |
+%% v v
+%% 3.7.2 <- 3.6.5
+%% | |
+%% v v
+%% 3.7.3 <- 3.6.6
+%% | |
+%% v v
+%% 3.7.4 <- 3.6.7
+%% | |
+%% v v
+%% 3.7.5 <- 3.6.9
+%% |
+%% v
+%% 3.8
+%% |
+%% v
+%% 3.8.1
+%% |
+%% v
+%% 3.8.2
+%% |
+%% v
+%% 3.9
+%% |
+%% v
+%% 3.9.1
+%% |
+%% v
+%% 3.9.1.1
+%% |
+%% v
+%% 3.9.2
+%% |
+%% v
+%% 3.9.3
+%% |
+%% v
+%% 3.9.4
+%% |
+%% v
+%% 3.10
+%% |
+%% v
+%% 3.10.0.1
+%% |
+%% v
+%% 3.10.1
+%% |
+%% v
+%% 3.11
+%% |
+%% v
+%% 3.11.1
+%% |
+%% v
+%% 3.11.2
+%% |
+%% v
+%% 3.11.3
+%% |
+%% v
+%% 3.12
+%% |
+%% v
+%% 3.13
+%%
+%%
+{"%VSN%",
+ [
+ {"3.12",
+ [
+ {load_module, megaco_udp, soft_purge, soft_purge, []},
+ {load_module, megaco_messenger, soft_purge, soft_purge, [megaco_monitor]},
+ {update, megaco_monitor, soft, soft_purge, soft_purge, []}
+ ]
+ },
+ {"3.11.3",
+ [
+ {load_module, megaco_udp, soft_purge, soft_purge, []},
+ {load_module, megaco_messenger, soft_purge, soft_purge,
+ [megaco_config, megaco_monitor]},
+ {update, megaco_monitor, soft, soft_purge, soft_purge, []},
+ {update, megaco_config, {advanced, upgrade_from_pre_3_12},
+ soft_purge, soft_purge, []}
+ ]
+ }
+ ],
+ [
+ {"3.12",
+ [
+ {load_module, megaco_udp, soft_purge, soft_purge, []},
+ {load_module, megaco_messenger, soft_purge, soft_purge, [megaco_monitor]},
+ {update, megaco_monitor, soft, soft_purge, soft_purge, []}
+ ]
+ },
+ {"3.11.3",
+ [
+ {load_module, megaco_udp, soft_purge, soft_purge, []},
+ {load_module, megaco_messenger, soft_purge, soft_purge,
+ [megaco_config, megaco_monitor]},
+ {update, megaco_monitor, soft, soft_purge, soft_purge, []},
+ {update, megaco_config, {advanced, downgrade_to_pre_3_12},
+ soft_purge, soft_purge, []}
+ ]
+ }
+ ]
+}.
+
diff --git a/lib/megaco/src/app/megaco.erl b/lib/megaco/src/app/megaco.erl
new file mode 100644
index 0000000000..215a516d77
--- /dev/null
+++ b/lib/megaco/src/app/megaco.erl
@@ -0,0 +1,1017 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1999-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 : Main API for Megaco/H.248 protocol stack
+%%----------------------------------------------------------------------
+
+-module(megaco).
+
+%%-----------------------------------------------------------------
+%% Public interface
+%%-----------------------------------------------------------------
+
+-export([
+ start/0,
+ stop/0,
+
+ start_user/2,
+ stop_user/1,
+
+ info/0,
+ user_info/1, user_info/2,
+ update_user_info/3,
+ conn_info/1, conn_info/2,
+ update_conn_info/3,
+ system_info/0, system_info/1,
+
+ connect/4, connect/5,
+ disconnect/2,
+
+ call/3,
+ cast/3,
+ cancel/2,
+ process_received_message/4, process_received_message/5,
+ receive_message/4, receive_message/5,
+
+ encode_actions/3,
+
+ token_tag2string/1, token_tag2string/2, token_tag2string/3,
+
+ parse_digit_map/1,
+ eval_digit_map/1,
+ eval_digit_map/2,
+ report_digit_event/2,
+ test_digit_event/2,
+
+ encode_binary_term_id/2,
+ decode_binary_term_id/2,
+
+ encode_sdp/1,
+ decode_sdp/1,
+
+ versions1/0, versions2/0,
+ print_version_info/0, print_version_info/1,
+ ms/0, nc/0, nc/1, ni/0, ni/1,
+
+ enable_trace/2, disable_trace/0, set_trace/1,
+
+ report_event/4, report_event/5,
+
+ test_request/5,
+ test_reply/5
+ ]).
+
+-export([
+ get_stats/0, get_stats/1, get_stats/2,
+ reset_stats/0, reset_stats/1
+ ]).
+
+%% Deprecated
+-export([format_versions/1]).
+
+%% Internal
+-export([format_timestamp/1]).
+
+%% This is for XREF
+-deprecated([{format_versions, 1, eventually}]).
+
+
+-include("megaco_internal.hrl").
+
+
+%%-----------------------------------------------------------------
+%% Starts the Megaco application
+%%-----------------------------------------------------------------
+
+start() ->
+ application:start(?APPLICATION).
+
+
+%%-----------------------------------------------------------------
+%% Stops the Megaco application
+%%-----------------------------------------------------------------
+
+stop() ->
+ application:stop(?APPLICATION).
+
+
+%%-----------------------------------------------------------------
+%% Initial configuration of a user
+%%-----------------------------------------------------------------
+
+start_user(UserMid, Config) ->
+ megaco_config:start_user(UserMid, Config).
+
+
+%%-----------------------------------------------------------------
+%% Delete the configuration of a user
+%%-----------------------------------------------------------------
+
+stop_user(UserMid) ->
+ megaco_config:stop_user(UserMid).
+
+
+%%-----------------------------------------------------------------
+%% Lookup user information
+%%-----------------------------------------------------------------
+
+user_info(UserMid) ->
+ [{requests, user_info(UserMid, requests)},
+ {replies, user_info(UserMid, replies)} | user_info(UserMid, all)].
+
+user_info(UserMid, requests) ->
+ megaco_messenger:which_requests(UserMid);
+user_info(UserMid, replies) ->
+ megaco_messenger:which_replies(UserMid);
+user_info(UserMid, Item) ->
+ megaco_config:user_info(UserMid, Item).
+
+
+%%-----------------------------------------------------------------
+%% Update information about a user
+%%-----------------------------------------------------------------
+
+update_user_info(UserMid, Item, Value) ->
+ megaco_config:update_user_info(UserMid, Item, Value).
+
+
+%%-----------------------------------------------------------------
+%% Lookup information about an active connection
+%%-----------------------------------------------------------------
+
+conn_info(ConnHandle) ->
+ [{requests, conn_info(ConnHandle, requests)},
+ {replies, conn_info(ConnHandle, replies)} | conn_info(ConnHandle, all)].
+
+conn_info(ConnHandle, requests) ->
+ megaco_messenger:which_requests(ConnHandle);
+conn_info(ConnHandle, replies) ->
+ megaco_messenger:which_replies(ConnHandle);
+conn_info(ConnHandle, Item) ->
+ megaco_config:conn_info(ConnHandle, Item).
+
+
+%%-----------------------------------------------------------------
+%% Update information about an active connection
+%%-----------------------------------------------------------------
+
+update_conn_info(ConnHandle, Item, Value) ->
+ megaco_config:update_conn_info(ConnHandle, Item, Value).
+
+
+%%-----------------------------------------------------------------
+%% All information for the application
+%%-----------------------------------------------------------------
+
+info() ->
+ Stats =
+ case get_stats() of
+ {ok, Statistics} ->
+ Statistics;
+ _ ->
+ []
+ end,
+ SysInfo = system_info(),
+ [{statistics, Stats} | info(SysInfo)].
+
+info(SysInfo) ->
+ info(SysInfo, []).
+
+info([], Acc) ->
+ lists:reverse(Acc);
+info([{connections, Conns} | SysInfo], Acc) ->
+ Conns2 = extend_conns_info(Conns),
+ info(SysInfo, [{connections, Conns2} | Acc]);
+info([{users, Users} | SysInfo], Acc) ->
+ Users2 = extend_users_info(Users),
+ info(SysInfo, [{users, Users2} | Acc]);
+info([Info | SysInfo], Acc) ->
+ info(SysInfo, [Info | Acc]).
+
+extend_conns_info(Conns) ->
+ extend_conns_info(Conns, []).
+
+extend_conns_info([], Acc) ->
+ lists:reverse(Acc);
+extend_conns_info([Conn | Conns], Acc) ->
+ ConnInfo = conn_info(Conn),
+ extend_conns_info(Conns, [{Conn, ConnInfo} | Acc]).
+
+extend_users_info(Users) ->
+ extend_users_info(Users, []).
+
+extend_users_info([], Acc) ->
+ lists:reverse(Acc);
+extend_users_info([User | Users], Acc) ->
+ UserInfo = user_info(User),
+ extend_users_info(Users, [{User, UserInfo} | Acc]).
+
+
+%%-----------------------------------------------------------------
+%% Lookup system information
+%%-----------------------------------------------------------------
+
+system_info_items() ->
+ [
+ text_config,
+ connections,
+ users,
+ n_active_requests,
+ n_active_replies,
+ n_active_connections,
+ pending_counters
+ ].
+
+system_info() ->
+ [{Item, system_info(Item)} || Item <- system_info_items()].
+
+system_info(Item) ->
+ megaco_config:system_info(Item).
+
+
+%%-----------------------------------------------------------------
+%% Establish a "virtual" connection
+%%-----------------------------------------------------------------
+
+connect(ReceiveHandle, RemoteMid, SendHandle, ControlPid) ->
+ megaco_messenger:connect(ReceiveHandle, RemoteMid, SendHandle, ControlPid).
+
+connect(ReceiveHandle, RemoteMid, SendHandle, ControlPid, Extra)
+ when (Extra =/= ?default_user_callback_extra) ->
+ megaco_messenger:connect(ReceiveHandle, RemoteMid, SendHandle,
+ ControlPid, Extra).
+
+
+%%-----------------------------------------------------------------
+%% Tear down a "virtual" connection
+%%-----------------------------------------------------------------
+
+disconnect(ConnHandle, Reason) ->
+ megaco_messenger:disconnect(ConnHandle, {user_disconnect, Reason}).
+
+
+%%-----------------------------------------------------------------
+%% Sends a transaction request and waits for a reply
+%%-----------------------------------------------------------------
+
+call(ConnHandle, ActionRequests, Options) ->
+ megaco_messenger:call(ConnHandle, ActionRequests, Options).
+
+
+%%-----------------------------------------------------------------
+%% Sends a transaction request but does NOT wait for a reply
+%%-----------------------------------------------------------------
+
+cast(ConnHandle, ActionRequests, Options) ->
+ megaco_messenger:cast(ConnHandle, ActionRequests, Options).
+
+
+%%-----------------------------------------------------------------
+%% Test the validity of the actions
+%%-----------------------------------------------------------------
+
+test_request(ConnHandle, Version, EncodingMod, EncodingConfig,
+ ActionRequests) ->
+ megaco_messenger:test_request(ConnHandle, ActionRequests,
+ Version, EncodingMod, EncodingConfig).
+
+%% This tests the actual_reply() type of return from the
+%% handle_trans_request function.
+%%
+test_reply(ConnHandle, Version, EncodingMod, EncodingConfig,
+ Reply) ->
+ megaco_messenger:test_reply(ConnHandle, Version,
+ EncodingMod, EncodingConfig, Reply).
+
+%%-----------------------------------------------------------------
+%% Func: get_stats/0, get_stats/1, get_stats/2
+%% Description: Retreive statistics (counters) for TCP
+%%-----------------------------------------------------------------
+get_stats() ->
+ megaco_messenger:get_stats().
+
+get_stats(SendHandle) ->
+ megaco_messenger:get_stats(SendHandle).
+
+get_stats(SendHandle, Counter) ->
+ megaco_messenger:get_stats(SendHandle, Counter).
+
+
+%%-----------------------------------------------------------------
+%% Func: reset_stats/0, reaet_stats/1
+%% Description: Reset statistics (counters) for TCP
+%%-----------------------------------------------------------------
+reset_stats() ->
+ megaco_messenger:reset_stats().
+
+reset_stats(SendHandle) ->
+ megaco_messenger:reset_stats(SendHandle).
+
+
+%%-----------------------------------------------------------------
+%% Cancel all outstanding messages for this connection
+%%-----------------------------------------------------------------
+
+cancel(ConnHandle, Reason) ->
+ megaco_messenger:cancel(ConnHandle, {user_cancel, Reason}).
+
+
+%%-----------------------------------------------------------------
+%% Process a received message
+%%-----------------------------------------------------------------
+
+process_received_message(ReceiveHandle, ControlPid, SendHandle, BinMsg) ->
+ megaco_messenger:process_received_message(ReceiveHandle, ControlPid,
+ SendHandle, BinMsg).
+
+process_received_message(ReceiveHandle, ControlPid, SendHandle, BinMsg, Extra) ->
+ megaco_messenger:process_received_message(ReceiveHandle, ControlPid,
+ SendHandle, BinMsg,
+ Extra).
+
+receive_message(ReceiveHandle, ControlPid, SendHandle, BinMsg) ->
+ megaco_messenger:receive_message(ReceiveHandle, ControlPid,
+ SendHandle, BinMsg).
+
+receive_message(ReceiveHandle, ControlPid, SendHandle, BinMsg, Extra) ->
+ megaco_messenger:receive_message(ReceiveHandle, ControlPid,
+ SendHandle, BinMsg,
+ Extra).
+
+
+%%-----------------------------------------------------------------
+%% Encode the actions list for one or more transactions.
+%%-----------------------------------------------------------------
+
+encode_actions(ConnHandle, ActionRequests, Options) ->
+ megaco_messenger:encode_actions(ConnHandle, ActionRequests, Options).
+
+
+%%-----------------------------------------------------------------
+%% Convert the (token) tags found in a decoded message into a
+%% printable string.
+%%-----------------------------------------------------------------
+
+token_tag2string(Tag) ->
+ token_tag2string(Tag, pretty).
+
+token_tag2string(Tag, pretty) ->
+ token_tag2string(Tag, megaco_pretty_text_encoder);
+token_tag2string(Tag, compact) ->
+ token_tag2string(Tag, megaco_compact_text_encoder);
+token_tag2string(Tag, Mod) when is_atom(Tag) and is_atom(Mod) ->
+ Mod:token_tag2string(Tag).
+
+token_tag2string(Tag, pretty, V) ->
+ token_tag2string(Tag, megaco_pretty_text_encoder, V);
+token_tag2string(Tag, compact, V) ->
+ token_tag2string(Tag, megaco_compact_text_encoder, V);
+token_tag2string(Tag, Mod, V) when is_atom(Tag) and is_atom(Mod) ->
+ Mod:token_tag2string(Tag, V).
+
+
+%%-----------------------------------------------------------------
+%% Parses a digit map body
+%%-----------------------------------------------------------------
+
+parse_digit_map(DigitMapBody) ->
+ megaco_digit_map:parse(DigitMapBody).
+
+
+%%-----------------------------------------------------------------
+%% Collect digit map letters according to the digit map
+%%-----------------------------------------------------------------
+
+eval_digit_map(DigitMap) ->
+ megaco_digit_map:eval(DigitMap).
+
+eval_digit_map(DigitMap, Timers) ->
+ megaco_digit_map:eval(DigitMap, Timers).
+
+
+%%-----------------------------------------------------------------
+%% Send one or more events to event collector process
+%%-----------------------------------------------------------------
+
+report_digit_event(DigitMapEvalPid, Event) ->
+ megaco_digit_map:report(DigitMapEvalPid, Event).
+
+
+%%-----------------------------------------------------------------
+%% Feed digit map collector with events and return the result
+%%-----------------------------------------------------------------
+
+test_digit_event(DigitMap, Events) ->
+ megaco_digit_map:test(DigitMap, Events).
+
+
+%%-----------------------------------------------------------------
+%% encode_binary_term_id(Config, MegacoTermId) ->
+%%
+%% {ok, TerminationId} | {error, Reason}
+%%
+%% Encode the Megaco internal form of a termination id (a
+%% megaco_term_id record) into ASN.1'1 internal form of a termination
+%% id (a 'TerminationId' record).
+%% %%-----------------------------------------------------------------
+
+encode_binary_term_id(Config, TermId) ->
+ megaco_binary_term_id:encode(Config, TermId).
+
+
+%%-----------------------------------------------------------------
+%% decode_binary_term_id(Config, TerminationId) ->
+%%
+%% {ok, MegacoTermId} | {error, Reason}
+%%
+%% Decode ASN.1's internal form of a termination id (a 'TerminationId'
+%% record) into the Megaco internal form of a termination id (a
+%% megaco_term_id record).
+%%-----------------------------------------------------------------
+
+decode_binary_term_id(Config, TermId) ->
+ megaco_binary_term_id:decode(Config, TermId).
+
+
+%%-----------------------------------------------------------------
+%% encode_sdp(SDP) ->
+%%
+%% {ok, PP} | {error, Reason}
+%%
+%% Encode a SDP construct into a property parm construct
+%%-----------------------------------------------------------------
+
+encode_sdp(SDP) ->
+ megaco_sdp:encode(SDP).
+
+
+%%-----------------------------------------------------------------
+%% decode_sdp(PP) ->
+%%
+%% {ok, SDP} | {error, Reason}
+%%
+%% Decode a property parm construct into a SDP construct
+%%-----------------------------------------------------------------
+
+decode_sdp(PP) ->
+ megaco_sdp:decode(PP).
+
+
+%%-----------------------------------------------------------------
+%% {ok, Vs} = megaco:versions1(), megaco:format_versions(Vs).
+
+print_version_info() ->
+ {ok, Versions} = megaco:versions1(),
+ print_version_info(Versions).
+
+print_version_info(Versions) when is_list(Versions) ->
+ print_sys_info(Versions),
+ print_os_info(Versions),
+ print_mods_info(Versions);
+print_version_info(BadVersions) ->
+ {error, {bad_versions, BadVersions}}.
+
+format_versions(Versions) ->
+ print_version_info(Versions).
+
+print_sys_info(Versions) ->
+ case key1search(sys_info, Versions) of
+ {value, SysInfo} when is_list(SysInfo) ->
+ {value, Arch} = key1search(arch, SysInfo, "Not found"),
+ {value, Ver} = key1search(ver, SysInfo, "Not found"),
+ io:format("System info: "
+ "~n Arch: ~s"
+ "~n Ver: ~s"
+ "~n", [Arch, Ver]),
+ ok;
+ _ ->
+ io:format("System info: Not found~n", []),
+ not_found
+ end.
+
+print_os_info(Versions) ->
+ case key1search(os_info, Versions) of
+ {value, OsInfo} when is_list(OsInfo) ->
+ Fam =
+ case key1search(fam, OsInfo, "Not found") of
+ {value, F} when is_atom(F) ->
+ atom_to_list(F);
+ {value, LF} when is_list(LF) ->
+ LF;
+ {value, XF} ->
+ lists:flatten(io_lib:format("~p", [XF]))
+ end,
+ Name =
+ case key1search(name, OsInfo) of
+ {value, N} when is_atom(N) ->
+ "[" ++ atom_to_list(N) ++ "]";
+ {value, LN} when is_list(LN) ->
+ "[" ++ LN ++ "]";
+ not_found ->
+ ""
+ end,
+ Ver =
+ case key1search(ver, OsInfo, "Not found") of
+ {value, T} when is_tuple(T) ->
+ tversion(T);
+ {value, LV} when is_list(LV) ->
+ LV;
+ {value, XV} ->
+ lists:flatten(io_lib:format("~p", [XV]))
+ end,
+ io:format("OS info: "
+ "~n Family: ~s ~s"
+ "~n Ver: ~s"
+ "~n", [Fam, Name, Ver]),
+ ok;
+ _ ->
+ io:format("OS info: Not found~n", []),
+ not_found
+ end.
+
+%% tversion({A, B, C}) ->
+%% lists:flatten(io_lib:format("~w.~w.~w", [A, B, C]));
+tversion(T) ->
+ L = tuple_to_list(T),
+ lversion(L).
+
+lversion([]) ->
+ "";
+lversion([A]) ->
+ integer_to_list(A);
+lversion([A|R]) ->
+ integer_to_list(A) ++ "." ++ lversion(R).
+
+print_mods_info(Versions) ->
+ case key1search(mod_info, Versions) of
+ {value, ModsInfo} when is_list(ModsInfo) ->
+ io:format("Module info: ~n", []),
+ lists:foreach(fun print_mod_info/1, ModsInfo);
+ _ ->
+ io:format("Module info: Not found~n", []),
+ not_found
+ end.
+
+print_mod_info({Module, Info}) ->
+ % Maybe a asn1 generated module
+ Asn1Vsn =
+ case (catch Module:info()) of
+ AI when is_list(AI) ->
+ case (catch key1search(vsn, AI)) of
+ {value, V} when is_atom(V) ->
+ atom_to_list(V);
+ _ ->
+ "-"
+ end;
+ _ ->
+ "-"
+ end,
+ Vsn =
+ case key1search(vsn, Info) of
+ {value, I} when is_integer(I) ->
+ integer_to_list(I);
+ _ ->
+ "Not found"
+ end,
+ AppVsn =
+ case key1search(app_vsn, Info) of
+ {value, S1} when is_list(S1) ->
+ S1;
+ _ ->
+ "Not found"
+ end,
+ CompVer =
+ case key1search(compiler_version, Info) of
+ {value, S2} when is_list(S2) ->
+ S2;
+ _ ->
+ "Not found"
+ end,
+ CompDate =
+ case key1search(compile_time, Info) of
+ {value, {Year, Month, Day, Hour, Min, Sec}} ->
+ lists:flatten(
+ io_lib:format("~w-~2..0w-~2..0w ~2..0w:~2..0w:~2..0w",
+ [Year, Month, Day, Hour, Min, Sec]));
+ _ ->
+ "Not found"
+ end,
+ io:format(" ~w:~n"
+ " Vsn: ~s~n"
+ " App vsn: ~s~n"
+ " ASN.1 vsn: ~s~n"
+ " Compiler ver: ~s~n"
+ " Compile time: ~s~n",
+ [Module, Vsn, AppVsn, Asn1Vsn, CompVer, CompDate]),
+ ok.
+
+
+
+key1search(Key, Vals) ->
+ case lists:keysearch(Key, 1, Vals) of
+ {value, {Key, Val}} ->
+ {value, Val};
+ false ->
+ not_found
+ end.
+
+key1search(Key, Vals, Def) ->
+ case key1search(Key, Vals) of
+ not_found ->
+ {value, Def};
+ Value ->
+ Value
+ end.
+
+
+%%-----------------------------------------------------------------
+
+versions1() ->
+ case ms1() of
+ {ok, Mods} ->
+ {ok, version_info(Mods)};
+ Error ->
+ Error
+ end.
+
+versions2() ->
+ case ms2() of
+ {ok, Mods} ->
+ {ok, version_info(Mods)};
+ Error ->
+ Error
+ end.
+
+version_info(Mods) ->
+ SysInfo = sys_info(),
+ OsInfo = os_info(),
+ ModInfo = [mod_version_info(Mod) || Mod <- Mods],
+ [{sys_info, SysInfo}, {os_info, OsInfo}, {mod_info, ModInfo}].
+
+mod_version_info(Mod) ->
+ Info = Mod:module_info(),
+ {value, {attributes, Attr}} = lists:keysearch(attributes, 1, Info),
+ {value, {vsn, [Vsn]}} = lists:keysearch(vsn, 1, Attr),
+ {value, {app_vsn, AppVsn}} = lists:keysearch(app_vsn, 1, Attr),
+ {value, {compile, Comp}} = lists:keysearch(compile, 1, Info),
+ {value, {version, Ver}} = lists:keysearch(version, 1, Comp),
+ {value, {time, Time}} = lists:keysearch(time, 1, Comp),
+ {Mod, [{vsn, Vsn},
+ {app_vsn, AppVsn},
+ {compiler_version, Ver},
+ {compile_time, Time}]}.
+
+sys_info() ->
+ SysArch = string:strip(erlang:system_info(system_architecture),right,$\n),
+ SysVer = string:strip(erlang:system_info(system_version),right,$\n),
+ [{arch, SysArch}, {ver, SysVer}].
+
+os_info() ->
+ V = os:version(),
+ case os:type() of
+ {OsFam, OsName} ->
+ [{fam, OsFam}, {name, OsName}, {ver, V}];
+ OsFam ->
+ [{fam, OsFam}, {ver, V}]
+ end.
+
+ms() ->
+ ms1().
+
+ms1() ->
+ App = ?APPLICATION,
+ LibDir = code:lib_dir(App),
+ File = filename:join([LibDir, "ebin", atom_to_list(App) ++ ".app"]),
+ case file:consult(File) of
+ {ok, [{application, App, AppFile}]} ->
+ case lists:keysearch(modules, 1, AppFile) of
+ {value, {modules, Mods}} ->
+ {ok, Mods};
+ _ ->
+ {error, {invalid_format, modules}}
+ end;
+ Error ->
+ {error, {invalid_format, Error}}
+ end.
+
+ms2() ->
+ application:get_key(?APPLICATION, modules).
+
+nc() ->
+ {ok, Mods} = ms(),
+ nc(Mods).
+
+nc(all) ->
+ application:load(?APPLICATION),
+ case application:get_key(?APPLICATION, modules) of
+ {ok, Mods} ->
+ application:unload(?APPLICATION),
+ nc(Mods);
+ _ ->
+ {error, not_found}
+ end;
+nc(Mods) when is_list(Mods) ->
+ [Mod || Mod <- Mods, ok /= load(Mod, compile)].
+
+ni() ->
+ case ms() of
+ {ok, Mods} ->
+ ni(Mods);
+ Error ->
+ Error
+ end.
+
+ni(all) ->
+ application:load(?APPLICATION),
+ case application:get_key(?APPLICATION, modules) of
+ {ok, Mods} ->
+ application:unload(?APPLICATION),
+ ni(Mods);
+ _ ->
+ {error, not_found}
+ end;
+ni(Mods) when is_list(Mods) ->
+ [Mod || Mod <- Mods, ok /= load(Mod, interpret)].
+
+load(Mod, How) when is_atom(Mod) ->
+ case try_load(Mod, How) of
+ ok ->
+ ok;
+ _ ->
+ io:format( "~n RETRY ~p FROM: ", [Mod]),
+ ModString = atom_to_list(Mod) ++ ".erl",
+ LibDir = code:lib_dir(?APPLICATION),
+ case find_file([LibDir], ModString) of
+ {ok, Abs} ->
+ load(Abs, How);
+ {error, Reason} ->
+ io:format( " *** ERROR *** ~p~n", [Reason]),
+ {error, Reason}
+ end
+ end;
+load(Abs, How) ->
+ case try_load(Abs, How) of
+ ok ->
+ ok;
+ {error, Reason} ->
+ io:format( " *** ERROR *** ~p~n", [Reason]),
+ {error, Reason}
+ end.
+
+try_load(Mod, How) ->
+ io:format( " ~p ", [Mod]),
+ Flags = [{d, debug}],
+ case How of
+ compile ->
+ case catch c:nc(Mod, Flags) of
+ {ok, _} -> ok;
+ Other -> {error, Other}
+ end;
+ interpret ->
+ case catch int:ni(Mod, Flags) of
+ {module, _} -> ok;
+ Other -> {error, Other}
+ end
+ end.
+
+find_file([Dir | Dirs], File) ->
+ case file:list_dir(Dir) of
+ {ok, List} ->
+ case lists:member(File, List) of
+ true ->
+ {ok, filename:join([Dir, File])};
+ false ->
+ SubDirs = [filename:join([Dir, Sub]) || Sub <- List],
+ case find_file(SubDirs, File) of
+ {ok, Abs} ->
+ {ok, Abs};
+ {error, _Reason} ->
+ find_file(Dirs, File)
+ end
+ end;
+ {error, _Reason} ->
+ find_file(Dirs, File)
+ end;
+find_file([], File) ->
+ {error, {no_such_file, File}}.
+
+
+%%-----------------------------------------------------------------
+
+%% -----------------------------
+%% These functions can be used instead of the et tool for
+%% managing trace of the megaco application.
+
+%%-----------------------------------------------------------------
+%% enable_trace(Level, Destination) -> void()
+%%
+%% Parameters:
+%% Level -> max | min | integer()
+%% Destination -> File | Port | io | {io, Verbosity} | HandlerSpec
+%% File -> string()
+%% Port -> integer()
+%% Verbosity -> true | false
+%% HandlerSpec = {function(), Data}
+%% Data = term()
+%%
+%% Description:
+%% This function is used to start tracing at level Level and send
+%% the result either to the file File or the port Port. Note that
+%% it starts a tracer server.
+%% When Destination is the atom io (or the tuple {io, Verbosity}),
+%% all (printable) megaco trace events (trace_ts events which has
+%% Severity withing Limit) will be written to stdout using io:format.
+%%
+%%-----------------------------------------------------------------
+enable_trace(Level, File) when is_list(File) ->
+ case file:open(File, [write]) of
+ {ok, Fd} ->
+ HandleSpec = {fun handle_trace/2, Fd},
+ dbg:tracer(process, HandleSpec),
+ set_trace(Level);
+ Err ->
+ Err
+ end;
+enable_trace(Level, Port) when is_integer(Port) ->
+ dbg:tracer(port, dbg:trace_port(ip, Port)),
+ set_trace(Level);
+enable_trace(Level, io) ->
+ HandleSpec = {fun handle_trace/2, standard_io},
+ dbg:tracer(process, HandleSpec),
+ set_trace(Level);
+enable_trace(Level, {Fun, _Data} = HandleSpec) when is_function(Fun) ->
+ dbg:tracer(process, HandleSpec),
+ set_trace(Level).
+
+
+%%-----------------------------------------------------------------
+%% disable_trace() -> void()
+%%
+%% Description:
+%% This function is used to stop tracing.
+%%-----------------------------------------------------------------
+disable_trace() ->
+ %% This is to make handle_trace/2 close the output file (if the
+ %% event gets there before dbg closes)
+ report_event(stop_trace, stop_trace, stop_trace, stop_trace, stop_trace),
+ dbg:stop().
+
+
+%%-----------------------------------------------------------------
+%% set_trace(Level) -> void()
+%%
+%% Parameters:
+%% Level -> max | min | integer()
+%%
+%% Description:
+%% This function is used to change the trace level when tracing has
+%% already been started.
+%%-----------------------------------------------------------------
+set_trace(Level) ->
+ Pat = et_selector:make_pattern({?MODULE, Level}),
+ et_selector:change_pattern(Pat).
+
+report_event(DetailLevel, FromTo, Label, Contents) ->
+ %% N.B External call
+ ?MODULE:report_event(DetailLevel, FromTo, FromTo, Label, Contents).
+
+report_event(_DetailLevel, _From, _To, _Label, _Contents) ->
+ hopefully_traced.
+
+
+%% ----------------------------------------------------------------------
+%% handle_trace(Event, Verbosity) -> Verbosity
+%%
+%% Parameters:
+%% Event -> The trace event (only megaco 'trace_ts' events are printed)
+%% Verbosity -> max | min | integer() (see Level above)
+%%
+%% Description:
+%% This function is "receive" and print the trace events.
+%% Events are printed if:
+%% - Verbosity is max
+%% - Severity is =< Verbosity (e.g. Severity = 30, and Verbosity = 40)
+%% Events are not printed if:
+%% - Verbosity is min
+%% - Severity is > Verbosity
+%%-----------------------------------------------------------------
+
+handle_trace(_, closed_file = Fd) ->
+ Fd;
+handle_trace({trace_ts, _Who, call,
+ {?MODULE, report_event,
+ [stop_trace, stop_trace, stop_trace, stop_trace, stop_trace]},
+ _Timestamp},
+ standard_io = Fd) ->
+ Fd;
+handle_trace({trace_ts, _Who, call,
+ {?MODULE, report_event,
+ [stop_trace, stop_trace, stop_trace, stop_trace, stop_trace]},
+ Timestamp},
+ Fd) ->
+ (catch io:format(Fd, "stop trace at ~s~n", [format_timestamp(Timestamp)])),
+ (catch file:close(Fd)),
+ closed_file;
+handle_trace({trace_ts, Who, call,
+ {?MODULE, report_event,
+ [Sev, From, To, Label, Content]}, Timestamp},
+ Fd) ->
+ (catch print_megaco_trace(Fd, Sev, Who, Timestamp, Label, From, To, Content)),
+ Fd;
+handle_trace(Event, Fd) ->
+ (catch print_trace(Fd, Event)),
+ Fd.
+
+
+print_megaco_trace(Fd, Sev, Who, Timestamp, Label, From, To, Content) ->
+ Ts = format_timestamp(Timestamp),
+ io:format(Fd, "[megaco trace ~w ~w ~s] ~s "
+ "~n From: ~p"
+ "~n To: ~p"
+ "~n Content: ~p"
+ "~n",
+ [Sev, Who, Ts, Label, From, To, Content]).
+
+print_trace(Fd, {trace, Who, What, Where}) ->
+ io:format(Fd, "[trace]"
+ "~n Who: ~p"
+ "~n What: ~p"
+ "~n Where: ~p"
+ "~n", [Who, What, Where]);
+
+print_trace(Fd, {trace, Who, What, Where, Extra}) ->
+ io:format(Fd, "[trace]"
+ "~n Who: ~p"
+ "~n What: ~p"
+ "~n Where: ~p"
+ "~n Extra: ~p"
+ "~n", [Who, What, Where, Extra]);
+
+print_trace(Fd, {trace_ts, Who, What, Where, When}) ->
+ Ts = format_timestamp(When),
+ io:format(Fd, "[trace ~s]"
+ "~n Who: ~p"
+ "~n What: ~p"
+ "~n Where: ~p"
+ "~n", [Ts, Who, What, Where]);
+
+print_trace(Fd, {trace_ts, Who, What, Where, Extra, When}) ->
+ Ts = format_timestamp(When),
+ io:format(Fd, "[trace ~s]"
+ "~n Who: ~p"
+ "~n What: ~p"
+ "~n Where: ~p"
+ "~n Extra: ~p"
+ "~n", [Ts, Who, What, Where, Extra]);
+
+print_trace(Fd, {seq_trace, What, Where}) ->
+ io:format(Fd, "[seq trace]"
+ "~n What: ~p"
+ "~n Where: ~p"
+ "~n", [What, Where]);
+
+print_trace(Fd, {seq_trace, What, Where, When}) ->
+ Ts = format_timestamp(When),
+ io:format(Fd, "[seq trace ~s]"
+ "~n What: ~p"
+ "~n Where: ~p"
+ "~n", [Ts, What, Where]);
+
+print_trace(Fd, {drop, Num}) ->
+ io:format(Fd, "[drop trace] ~p~n", [Num]);
+
+print_trace(Fd, Trace) ->
+ io:format(Fd, "[trace] "
+ "~n ~p"
+ "~n", [Trace]).
+
+
+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/app/megaco.mk b/lib/megaco/src/app/megaco.mk
new file mode 100644
index 0000000000..7bc276d26d
--- /dev/null
+++ b/lib/megaco/src/app/megaco.mk
@@ -0,0 +1,56 @@
+#-*-makefile-*- ; force emacs to enter makefile-mode
+
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2007-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%
+
+ifeq ($(MEGACO_TRACE), io)
+ERL_COMPILE_FLAGS += -Dmegaco_trace_io
+endif
+
+ifeq ($(MEGACO_EXTENDED_TRACE), true)
+ERL_COMPILE_FLAGS += -Dmegaco_extended_trace
+endif
+
+ifeq ($(USE_MEGACO_TEST_CODE), true)
+ERL_COMPILE_FLAGS += -DMEGACO_TEST_CODE=mona_lisa_spelar_doom
+endif
+
+ifeq ($(MEGACO_DEBUG), true)
+ERL_COMPILE_FLAGS += -Dmegaco_debug
+endif
+
+ifneq ($(MEGACO_PARSER_INLINE), false)
+ERL_COMPILE_FLAGS += -Dmegaco_parser_inline
+endif
+
+ifeq ($(USE_MEGACO_HIPE), true)
+ERL_COMPILE_FLAGS += +native
+endif
+
+ifeq ($(WARN_UNUSED_WARS), true)
+ERL_COMPILE_FLAGS += +warn_unused_vars
+endif
+
+MEGACO_APP_VSN_COMPILE_FLAGS = \
+ +'{parse_transform,sys_pre_attributes}' \
+ +'{attribute,insert,app_vsn,$(APP_VSN)}'
+
+MEGACO_ERL_COMPILE_FLAGS += \
+ -pa $(ERL_TOP)/lib/et/ebin \
+ -pa $(ERL_TOP)/lib/megaco/ebin \
+ $(MEGACO_APP_VSN_COMPILE_FLAGS)
+
diff --git a/lib/megaco/src/app/megaco_internal.hrl b/lib/megaco/src/app/megaco_internal.hrl
new file mode 100644
index 0000000000..adbaacacef
--- /dev/null
+++ b/lib/megaco/src/app/megaco_internal.hrl
@@ -0,0 +1,183 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1999-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 internal data structures and error codes
+%%----------------------------------------------------------------------
+
+-define(APPLICATION, megaco).
+
+%% -define(debug, true).
+
+%% N.B. Update megaco_config when a new field is added
+-record(conn_data,
+ {
+ conn_handle,
+ serial,
+ max_serial,
+ request_timer,
+ long_request_timer,
+
+ %% Auto send of ack: false | true
+ %% (if true, and if trans_ack is false or trans_timer
+ %% is zero (0), then acks will be sent immediatly)
+ auto_ack,
+
+ %% ------
+ %% Accumulate trans acks/requests and send them "all" later
+ %% in one bigger message.
+ %% For this to take effekt, trans_timer has to be > 0
+ %% trans_ack and/or trans_req has to be true.
+ %% Accumulate transactions, and send them later, either
+ %% when the timer expires, when maxcount number of
+ %% transactions has been accumulated or in the case
+ %% requests, when the maxsize number of bytes has been
+ %% accumulated (whichever happens first).
+ %% (Note that, for acks, this is only valid if auto_ack
+ %% is true)
+
+ trans_ack, % false
+ trans_ack_maxcount, % 10
+
+ trans_req, % false
+ trans_req_maxcount, % 10
+ trans_req_maxsize, % 2048
+
+ trans_timer, % 0 (don't accumulate transactions)
+ trans_sender, % The trans sender process ref, or undefined
+
+ pending_timer,
+
+ %% ------
+ %% These counter's are used for the MGCOriginatedPendingLimit
+ %% and MGOriginatedPendingLimit counters (of the root package).
+ %% If the user is an MGC, then
+ %% sent_pending_limit - represent MGCOriginatedPendingLimit
+ %% recv_pending_limit - represent MGOriginatedPendingLimit
+ %% If the user is an MG, then
+ %% sent_pending_limit - represent MGOriginatedPendingLimit
+ %% recv_pending_limit - represent MGCOriginatedPendingLimit
+ sent_pending_limit, % infinity | integer() > 0
+ recv_pending_limit, % infinity | integer() > 0
+
+ reply_timer,
+ control_pid,
+ monitor_ref,
+ send_mod,
+ send_handle,
+ encoding_mod,
+ encoding_config,
+ protocol_version,
+ auth_data,
+ user_mod,
+ user_args,
+ reply_action, % call | cast
+ reply_data, % term()
+ threaded, % boolean(), false
+ strict_version, % boolean(), true
+ long_request_resend, % boolean(), false
+ call_proxy_gc_timeout, % integer() > 0
+
+ %% This flag is used when a connection is being cancelled.
+ %% The purpuse is to avoid raise conditions with replies
+ %% during the cancellation.
+ cancel, % boolean(), false
+ resend_indication, % boolean(), false
+
+ %% -------
+ %% Defined in the Segmentation Package (extends the root package)
+ %%
+ segment_reply_ind, % boolean(), false
+ segment_recv_acc, % bool()
+ segment_recv_timer, % megaco_timer() | integer() > 0 | infinity
+ segment_send, % none | infinity | integer() > 0
+ segment_send_timer, % megaco_timer() | integer() > 0 | infinity
+ max_pdu_size, % infinity | integer() > 0
+
+ request_keep_alive_timeout % plain | integer() >= 0
+ }).
+
+
+%% N.B. Update megaco_config when a new field is added
+-record(remote_conn_data,
+ {conn_handle,
+ user_node,
+ monitor_ref}).
+
+
+%%%----------------------------------------------------------------------
+%%% Error/warning/info message macro(s)
+%%%----------------------------------------------------------------------
+
+-define(megaco_info(F, A),
+ (catch error_logger:info_msg("[ ~w : ~w : ~p ] ~n" ++ F ++ "~n",
+ [?APPLICATION, ?MODULE, self()|A]))).
+
+-define(megaco_warning(F, A),
+ (catch error_logger:warning_msg("[ ~w : ~w : ~p ] ~n" ++ F ++ "~n",
+ [?APPLICATION, ?MODULE, self()|A]))).
+
+-define(megaco_error(F, A),
+ (catch error_logger:error_msg("[ ~w : ~w : ~p ] ~n" ++ F ++ "~n",
+ [?APPLICATION, ?MODULE, self()|A]))).
+
+
+%%%----------------------------------------------------------------------
+%%% Default (ignore) value of the Extra argument to the
+%%% megaco:receive_message/5 and process_received_message functions/5.
+%%%----------------------------------------------------------------------
+
+-define(default_user_callback_extra, ignore_extra).
+
+
+%%%----------------------------------------------------------------------
+%%% Event Trace
+%%%----------------------------------------------------------------------
+
+-ifdef(megaco_trace_io).
+-define(report(Level, C, Label, Contents),
+ io:format("*** [~s] ~p ~p *** "
+ "~n ~p[~p] " ++ Label ++
+ "~n ~p"
+ "~n ~p"
+ "~n",
+ [megaco:format_timestamp(now()),
+ self(), Level, ?MODULE, ?LINE, C, Contents])).
+-else.
+-define(report(Level, C, Label, Contents),
+ megaco:report_event(Level, ?APPLICATION, Label,
+ [{line, ?MODULE, ?LINE}, C | Contents])).
+-endif.
+
+-define(report_important(C, Label, Contents), ?report(20, C, Label, Contents)).
+-define(report_verbose( C, Label, Contents), ?report(40, C, Label, Contents)).
+-define(report_debug( C, Label, Contents), ?report(60, C, Label, Contents)).
+-define(report_trace( C, Label, Contents), ?report(80, C, Label, Contents)).
+
+
+%%%----------------------------------------------------------------------
+%%% Debug
+%%%----------------------------------------------------------------------
+
+-ifdef(megaco_debug).
+-define(d(F,A), io:format("~w: " ++ F ++ "~n",[?MODULE|A])).
+-else.
+-define(d(F,A), ok).
+-endif.
diff --git a/lib/megaco/src/app/modules.mk b/lib/megaco/src/app/modules.mk
new file mode 100644
index 0000000000..42a2e94752
--- /dev/null
+++ b/lib/megaco/src/app/modules.mk
@@ -0,0 +1,36 @@
+#-*-makefile-*- ; force emacs to enter makefile-mode
+
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2007-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
+
+EXTERNAL_HRL_FILES = \
+ ../../include/megaco.hrl \
+ ../../include/megaco_message_v1.hrl \
+ ../../include/megaco_message_v2.hrl \
+ ../../include/megaco_message_prev3a.hrl \
+ ../../include/megaco_message_prev3b.hrl \
+ ../../include/megaco_message_prev3c.hrl \
+ ../../include/megaco_message_v3.hrl \
+ ../../include/megaco_sdp.hrl
+
+INTERNAL_HRL_FILES = \
+ megaco_internal.hrl
+
+
diff --git a/lib/megaco/src/binary/MEDIA-GATEWAY-CONTROL-prev3a.asn b/lib/megaco/src/binary/MEDIA-GATEWAY-CONTROL-prev3a.asn
new file mode 100644
index 0000000000..083f7e8271
--- /dev/null
+++ b/lib/megaco/src/binary/MEDIA-GATEWAY-CONTROL-prev3a.asn
@@ -0,0 +1,1001 @@
+MEDIA-GATEWAY-CONTROL-prev3a
+{itu-t(0) recommendation(0) h(8) h248(248)
+ modules(0) media-gateway-control(0) version3(3)}
+DEFINITIONS AUTOMATIC TAGS ::=
+BEGIN
+
+
+MegacoMessage ::= SEQUENCE
+ {
+ authHeader AuthenticationHeader OPTIONAL,
+ mess Message
+ }
+
+AuthenticationHeader ::= SEQUENCE
+ {
+ secParmIndex SecurityParmIndex,
+ seqNum SequenceNum,
+ ad AuthData
+ }
+
+SecurityParmIndex ::= OCTET STRING(SIZE(4))
+
+SequenceNum ::= OCTET STRING(SIZE(4))
+
+AuthData ::= OCTET STRING (SIZE (12..32))
+
+Message ::= SEQUENCE
+ {
+ version INTEGER(0..99),
+ -- The version of the protocol defined here is equal to 3.
+ mId MId, -- Name/address of message originator
+ messageBody CHOICE
+ {
+ messageError ErrorDescriptor,
+ transactions SEQUENCE OF Transaction
+ },
+ ...
+ }
+
+MId ::= CHOICE
+ {
+ ip4Address IP4Address,
+ ip6Address IP6Address,
+ domainName DomainName,
+ deviceName PathName,
+ mtpAddress OCTET STRING(SIZE(2..4)),
+ -- Addressing structure of mtpAddress:
+ -- 25 - 15 0
+ -- | PC | NI |
+ -- 24 - 14 bits 2 bits
+ -- Note: 14 bits are defined for international use.
+ -- Two national options exist where the point code is 16 or 24
+ -- bits.
+ -- To octet align the mtpAddress, the MSBs shall be encoded as 0s.
+ ...
+ }
+
+DomainName ::= SEQUENCE
+ {
+ name IA5String,
+ -- The name starts with an alphanumeric digit followed by a
+ -- sequence of alphanumeric digits, hyphens and dots. No two
+ -- dots shall occur consecutively.
+ portNumber INTEGER(0..65535) OPTIONAL
+ }
+
+IP4Address ::= SEQUENCE
+ {
+ address OCTET STRING (SIZE(4)),
+ portNumber INTEGER(0..65535) OPTIONAL
+ }
+
+IP6Address ::= SEQUENCE
+ {
+ address OCTET STRING (SIZE(16)),
+ portNumber INTEGER(0..65535) OPTIONAL
+ }
+
+PathName ::= IA5String(SIZE (1..64))
+-- See A.3
+
+Transaction ::= CHOICE
+ {
+ transactionRequest TransactionRequest,
+ transactionPending TransactionPending,
+ transactionReply TransactionReply,
+ transactionResponseAck TransactionResponseAck,
+ -- use of response acks is dependent on underlying transport
+ ...
+ }
+
+TransactionId ::= INTEGER(0..4294967295) -- 32-bit unsigned integer
+
+TransactionRequest ::= SEQUENCE
+ {
+ transactionId TransactionId,
+ actions SEQUENCE OF ActionRequest,
+ ...
+ }
+
+TransactionPending ::= SEQUENCE
+ {
+ transactionId TransactionId,
+ ...
+ }
+
+TransactionReply ::= SEQUENCE
+ {
+ transactionId TransactionId,
+ immAckRequired NULL OPTIONAL,
+ transactionResult CHOICE
+ {
+ transactionError ErrorDescriptor,
+ actionReplies SEQUENCE OF ActionReply
+ },
+ ...,
+ -- Erlang Note: NOT REALLY PART OF THIS IMPLEMENTATION
+ -- Erlang Note: The only reason why we need to include
+ -- Erlang Note: these definitions in this version is
+ -- Erlang Note: that we cannot distinguish between v3
+ -- Erlang Note: versions in the megaco_messenger module
+ segmentNumber SegmentNumber OPTIONAL,
+ segmentationComplete NULL OPTIONAL
+ }
+
+-- SegmentReply ::= SEQUENCE
+-- {
+-- transactionId TransactionId,
+-- segmentNumber SegmentNumber,
+-- segmentationComplete NULL OPTIONAL,
+-- ...
+-- }
+--
+SegmentNumber ::= INTEGER(0..65535)
+
+TransactionResponseAck ::= SEQUENCE OF TransactionAck
+TransactionAck ::= SEQUENCE
+ {
+ firstAck TransactionId,
+ lastAck TransactionId OPTIONAL
+ }
+
+ErrorDescriptor ::= SEQUENCE
+ {
+ errorCode ErrorCode,
+ errorText ErrorText OPTIONAL
+ }
+
+ErrorCode ::= INTEGER(0..65535)
+-- See clause 14 for IANA considerations with respect to error codes
+ErrorText ::= IA5String
+
+ContextID ::= INTEGER(0..4294967295)
+
+-- Context NULL Value: 0
+-- Context CHOOSE Value: 4294967294 (0xFFFFFFFE)
+-- Context ALL Value: 4294967295 (0xFFFFFFFF)
+
+
+ActionRequest ::= SEQUENCE
+ {
+ contextId ContextID,
+ contextRequest ContextRequest OPTIONAL,
+ contextAttrAuditReq ContextAttrAuditRequest OPTIONAL,
+ commandRequests SEQUENCE OF CommandRequest
+ }
+
+ActionReply ::= SEQUENCE
+ {
+ contextId ContextID,
+ errorDescriptor ErrorDescriptor OPTIONAL,
+ contextReply ContextRequest OPTIONAL,
+ commandReply SEQUENCE OF CommandReply
+ }
+
+ContextRequest ::= SEQUENCE
+ {
+ priority INTEGER(0..15) OPTIONAL,
+ emergency BOOLEAN OPTIONAL,
+ topologyReq SEQUENCE OF TopologyRequest OPTIONAL,
+ ...,
+ iepsCallind BOOLEAN OPTIONAL, -- Fixed
+ contextProp SEQUENCE OF PropertyParm OPTIONAL
+ }
+
+ContextAttrAuditRequest ::= SEQUENCE
+ {
+ topology NULL OPTIONAL,
+ emergency NULL OPTIONAL,
+ priority NULL OPTIONAL,
+ ...,
+ iepsCallind NULL OPTIONAL, -- Fixed
+ contextPropAud SEQUENCE OF IndAudPropertyParm OPTIONAL
+ }
+
+CommandRequest ::= SEQUENCE
+ {
+ command Command,
+ optional NULL OPTIONAL,
+ wildcardReturn NULL OPTIONAL,
+ ...
+ }
+
+Command ::= CHOICE
+ {
+ addReq AmmRequest,
+ moveReq AmmRequest,
+ modReq AmmRequest,
+ -- Add, Move, Modify requests have the same parameters
+ subtractReq SubtractRequest,
+ auditCapRequest AuditRequest,
+ auditValueRequest AuditRequest,
+ notifyReq NotifyRequest,
+ serviceChangeReq ServiceChangeRequest,
+ ...
+ }
+
+CommandReply ::= CHOICE
+ {
+ addReply AmmsReply,
+ moveReply AmmsReply,
+ modReply AmmsReply,
+ subtractReply AmmsReply,
+ -- Add, Move, Modify, Subtract replies have the same parameters
+ auditCapReply AuditReply,
+ auditValueReply AuditReply,
+ notifyReply NotifyReply,
+ serviceChangeReply ServiceChangeReply,
+ ...
+ }
+
+TopologyRequest ::= SEQUENCE
+ {
+ terminationFrom TerminationID,
+ terminationTo TerminationID,
+ topologyDirection ENUMERATED
+ {
+ bothway(0),
+ isolate(1),
+ oneway(2)
+ },
+ ...,
+ streamID StreamID OPTIONAL
+ }
+
+AmmRequest ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ descriptors SEQUENCE OF AmmDescriptor,
+ -- At most one descriptor of each type (see AmmDescriptor)
+ -- allowed in the sequence.
+ ...
+ }
+
+AmmDescriptor ::= CHOICE
+ {
+ mediaDescriptor MediaDescriptor,
+ modemDescriptor ModemDescriptor,
+ muxDescriptor MuxDescriptor,
+ eventsDescriptor EventsDescriptor,
+ eventBufferDescriptor EventBufferDescriptor,
+ signalsDescriptor SignalsDescriptor,
+ digitMapDescriptor DigitMapDescriptor,
+ auditDescriptor AuditDescriptor,
+ ...,
+ statisticsDescriptor StatisticsDescriptor
+ }
+
+
+AmmsReply ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ terminationAudit TerminationAudit OPTIONAL,
+ ...
+ }
+
+SubtractRequest ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ auditDescriptor AuditDescriptor OPTIONAL,
+ ...
+ }
+
+AuditRequest ::= SEQUENCE
+ {
+ terminationID TerminationID,
+ auditDescriptor AuditDescriptor,
+ ...
+ }
+
+AuditReply ::= CHOICE
+ {
+ contextAuditResult TerminationIDList,
+ error ErrorDescriptor,
+ auditResult AuditResult,
+ ...
+ }
+
+AuditResult ::= SEQUENCE
+ {
+
+ terminationID TerminationID,
+ terminationAuditResult TerminationAudit
+ }
+
+
+
+TerminationAudit ::= SEQUENCE OF AuditReturnParameter
+
+AuditReturnParameter ::= CHOICE
+ {
+ errorDescriptor ErrorDescriptor,
+ mediaDescriptor MediaDescriptor,
+ modemDescriptor ModemDescriptor,
+ muxDescriptor MuxDescriptor,
+ eventsDescriptor EventsDescriptor,
+ eventBufferDescriptor EventBufferDescriptor,
+ signalsDescriptor SignalsDescriptor,
+ digitMapDescriptor DigitMapDescriptor,
+ observedEventsDescriptor ObservedEventsDescriptor,
+ statisticsDescriptor StatisticsDescriptor,
+ packagesDescriptor PackagesDescriptor,
+ emptyDescriptors AuditDescriptor,
+ ...
+ }
+
+AuditDescriptor ::= SEQUENCE
+ {
+ auditToken BIT STRING
+ {
+ muxToken(0), modemToken(1), mediaToken(2),
+ eventsToken(3), signalsToken(4),
+ digitMapToken(5), statsToken(6),
+ observedEventsToken(7),
+ packagesToken(8), eventBufferToken(9)
+ } OPTIONAL,
+ ...,
+ auditPropertyToken SEQUENCE OF IndAuditParameter OPTIONAL
+ }
+
+
+IndAuditParameter ::= CHOICE
+ {
+ -- Note that the lower/upper case letters of the tags have
+ -- been changed. The same changes has been made in text...
+ indAudMediaDescriptor IndAudMediaDescriptor,
+ indAudEventsDescriptor IndAudEventsDescriptor,
+ indAudEventBufferDescriptor IndAudEventBufferDescriptor,
+ indAudSignalsDescriptor IndAudSignalsDescriptor,
+ indAudDigitMapDescriptor IndAudDigitMapDescriptor,
+ indAudStatisticsDescriptor IndAudStatisticsDescriptor,
+ indAudPackagesDescriptor IndAudPackagesDescriptor,
+ ...
+ }
+
+IndAudMediaDescriptor ::= SEQUENCE
+ {
+
+ termStateDescr IndAudTerminationStateDescriptor OPTIONAL,
+ streams CHOICE
+ {
+ oneStream IndAudStreamParms,
+ multiStream SEQUENCE OF IndAudStreamDescriptor
+ } OPTIONAL,
+ ...
+ }
+
+IndAudStreamDescriptor ::= SEQUENCE
+ {
+ streamID StreamID,
+ streamParms IndAudStreamParms
+ }
+
+IndAudStreamParms ::= SEQUENCE
+ {
+ localControlDescriptor IndAudLocalControlDescriptor OPTIONAL,
+ localDescriptor IndAudLocalRemoteDescriptor OPTIONAL,
+ remoteDescriptor IndAudLocalRemoteDescriptor OPTIONAL,
+ ...,
+ statisticsDescriptor IndAudStatisticsDescriptor OPTIONAL
+ }
+
+IndAudLocalControlDescriptor ::= SEQUENCE
+ {
+ streamMode NULL OPTIONAL,
+ reserveValue NULL OPTIONAL,
+ reserveGroup NULL OPTIONAL,
+ propertyParms SEQUENCE OF IndAudPropertyParm OPTIONAL,
+ ...
+ }
+
+IndAudPropertyParm ::= SEQUENCE
+ {
+ name PkgdName,
+ ...
+ }
+
+IndAudLocalRemoteDescriptor ::= SEQUENCE
+ {
+ propGroupID INTEGER(0..65535) OPTIONAL,
+ propGrps IndAudPropertyGroup,
+ ...
+ }
+
+IndAudPropertyGroup ::= SEQUENCE OF IndAudPropertyParm
+
+IndAudTerminationStateDescriptor ::= SEQUENCE
+ {
+ propertyParms SEQUENCE OF IndAudPropertyParm,
+ eventBufferControl NULL OPTIONAL,
+ serviceState NULL OPTIONAL,
+ ...
+ }
+
+IndAudEventsDescriptor ::= SEQUENCE
+ {
+ requestID RequestID OPTIONAL,
+ pkgdName PkgdName,
+ streamID StreamID OPTIONAL,
+ ...
+ }
+
+IndAudEventBufferDescriptor ::= SEQUENCE
+ {
+ eventName PkgdName,
+ streamID StreamID OPTIONAL,
+ ...
+ }
+
+IndAudSignalsDescriptor ::=CHOICE
+ {
+ signal IndAudSignal,
+ seqSigList IndAudSeqSigList,
+ ...
+ }
+
+IndAudSeqSigList ::= SEQUENCE
+ {
+ id INTEGER(0..65535),
+ signalList IndAudSignal OPTIONAL
+ }
+
+IndAudSignal ::= SEQUENCE
+ {
+ signalName PkgdName,
+ streamID StreamID OPTIONAL,
+ ...
+ }
+
+IndAudDigitMapDescriptor ::= SEQUENCE
+ {
+ digitMapName DigitMapName OPTIONAL
+ }
+
+IndAudStatisticsDescriptor ::= SEQUENCE
+ {
+ statName PkgdName
+ }
+
+IndAudPackagesDescriptor ::= SEQUENCE
+ {
+ packageName Name,
+ packageVersion INTEGER(0..99),
+ ...
+ }
+
+NotifyRequest ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ observedEventsDescriptor ObservedEventsDescriptor,
+ errorDescriptor ErrorDescriptor OPTIONAL,
+ ...
+ }
+
+NotifyReply ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ errorDescriptor ErrorDescriptor OPTIONAL,
+ ...
+ }
+
+ObservedEventsDescriptor ::= SEQUENCE
+ {
+ requestId RequestID,
+ observedEventLst SEQUENCE OF ObservedEvent
+ }
+
+ObservedEvent ::= SEQUENCE
+ {
+ eventName EventName,
+ streamID StreamID OPTIONAL,
+ eventParList SEQUENCE OF EventParameter,
+ timeNotation TimeNotation OPTIONAL,
+ ...
+ }
+
+EventName ::= PkgdName
+
+EventParameter ::= SEQUENCE
+ {
+ eventParameterName Name,
+ value Value,
+ -- For use of extraInfo see the comment related to PropertyParm
+ extraInfo CHOICE
+ {
+ relation Relation,
+ range BOOLEAN,
+ sublist BOOLEAN
+ } OPTIONAL,
+ ...
+
+ }
+
+ServiceChangeRequest ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ serviceChangeParms ServiceChangeParm,
+ ...
+ }
+
+ServiceChangeReply ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ serviceChangeResult ServiceChangeResult,
+ ...
+ }
+
+-- For ServiceChangeResult, no parameters are mandatory. Hence the
+-- distinction between ServiceChangeParm and ServiceChangeResParm.
+
+ServiceChangeResult ::= CHOICE
+ {
+ errorDescriptor ErrorDescriptor,
+ serviceChangeResParms ServiceChangeResParm
+ }
+
+WildcardField ::= OCTET STRING(SIZE(1))
+
+TerminationID ::= SEQUENCE
+ {
+ wildcard SEQUENCE OF WildcardField,
+ id OCTET STRING(SIZE(1..8)),
+ ...
+ }
+-- See A.1 for explanation of wildcarding mechanism.
+-- Termination ID 0xFFFFFFFFFFFFFFFF indicates the ROOT Termination.
+
+TerminationIDList ::= SEQUENCE OF TerminationID
+
+MediaDescriptor ::= SEQUENCE
+ {
+ termStateDescr TerminationStateDescriptor OPTIONAL,
+ streams CHOICE
+ {
+ oneStream StreamParms,
+ multiStream SEQUENCE OF StreamDescriptor
+ } OPTIONAL,
+ ...
+ }
+
+StreamDescriptor ::= SEQUENCE
+ {
+ streamID StreamID,
+ streamParms StreamParms
+ }
+
+StreamParms ::= SEQUENCE
+ {
+ localControlDescriptor LocalControlDescriptor OPTIONAL,
+ localDescriptor LocalRemoteDescriptor OPTIONAL,
+ remoteDescriptor LocalRemoteDescriptor OPTIONAL,
+ ...,
+ statisticsDescriptor StatisticsDescriptor OPTIONAL
+ }
+
+LocalControlDescriptor ::= SEQUENCE
+ {
+ streamMode StreamMode OPTIONAL,
+ reserveValue BOOLEAN OPTIONAL,
+ reserveGroup BOOLEAN OPTIONAL,
+ propertyParms SEQUENCE OF PropertyParm,
+ ...
+ }
+
+StreamMode ::= ENUMERATED
+ {
+ sendOnly(0),
+ recvOnly(1),
+ sendRecv(2),
+ inactive(3),
+ loopBack(4),
+ ...
+ }
+
+-- In PropertyParm, value is a SEQUENCE OF octet string. When sent
+-- by an MGC the interpretation is as follows:
+-- empty sequence means CHOOSE
+-- one element sequence specifies value
+-- If the sublist field is not selected, a longer sequence means
+-- "choose one of the values" (i.e. value1 OR value2 OR ...)
+-- If the sublist field is selected,
+-- a sequence with more than one element encodes the value of a
+-- list-valued property (i.e. value1 AND value2 AND ...).
+-- The relation field may only be selected if the value sequence
+-- has length 1. It indicates that the MG has to choose a value
+-- for the property. E.g. x > 3 (using the greaterThan
+-- value for relation) instructs the MG to choose any value larger
+-- than 3 for property x.
+-- The range field may only be selected if the value sequence
+-- has length 2. It indicates that the MG has to choose a value
+-- in the range between the first octet in the value sequence and
+-- the trailing octet in the value sequence, including the
+-- boundary values.
+-- When sent by the MG, only responses to an AuditCapability request
+-- may contain multiple values, a range, or a relation field.
+
+PropertyParm ::= SEQUENCE
+ {
+ name PkgdName,
+ value SEQUENCE OF OCTET STRING,
+ extraInfo CHOICE
+ {
+ relation Relation,
+ range BOOLEAN,
+ sublist BOOLEAN
+ } OPTIONAL,
+ ...
+ }
+
+Name ::= OCTET STRING(SIZE(2))
+
+PkgdName ::= OCTET STRING(SIZE(4))
+-- represents Package Name (2 octets) plus Property, Event,
+-- Signal Names or Statistics ID. (2 octets)
+-- To wildcard a package use 0xFFFF for first two octets, choose
+-- is not allowed. To reference native property tag specified in
+-- Annex C, use 0x0000 as first two octets.
+-- To wildcard a Property, Event, Signal, or Statistics ID, use
+-- 0xFFFF for last two octets, choose is not allowed.
+-- Wildcarding of Package Name is permitted only if Property,
+-- Event, Signal, or Statistics ID are
+-- also wildcarded.
+
+Relation ::= ENUMERATED
+ {
+ greaterThan(0),
+ smallerThan(1),
+ unequalTo(2),
+ ...
+ }
+
+LocalRemoteDescriptor ::= SEQUENCE
+ {
+ propGrps SEQUENCE OF PropertyGroup,
+ ...
+ }
+
+PropertyGroup ::= SEQUENCE OF PropertyParm
+
+TerminationStateDescriptor ::= SEQUENCE
+ {
+ propertyParms SEQUENCE OF PropertyParm,
+ eventBufferControl EventBufferControl OPTIONAL,
+ serviceState ServiceState OPTIONAL,
+ ...
+ }
+
+EventBufferControl ::= ENUMERATED
+ {
+ off(0),
+ lockStep(1),
+ ...
+ }
+
+ServiceState ::= ENUMERATED
+ {
+ test(0),
+ outOfSvc(1),
+ inSvc(2),
+ ...
+ }
+
+MuxDescriptor ::= SEQUENCE
+ {
+ muxType MuxType,
+ termList SEQUENCE OF TerminationID,
+ nonStandardData NonStandardData OPTIONAL,
+ ...
+ }
+
+MuxType ::= ENUMERATED
+ {
+ h221(0),
+ h223(1),
+ h226(2),
+ v76(3),
+ ...,
+ nx64k(4)
+ }
+
+StreamID ::= INTEGER(0..65535) -- 16-bit unsigned integer
+
+EventsDescriptor ::= SEQUENCE
+ {
+ requestID RequestID OPTIONAL,
+ -- RequestID must be present if eventList
+ -- is non empty
+ eventList SEQUENCE OF RequestedEvent,
+ ...
+ }
+
+RequestedEvent ::= SEQUENCE
+ {
+ pkgdName PkgdName,
+ streamID StreamID OPTIONAL,
+ eventAction RequestedActions OPTIONAL,
+ evParList SEQUENCE OF EventParameter,
+ ...
+ }
+
+RequestedActions ::= SEQUENCE
+ {
+ keepActive BOOLEAN OPTIONAL,
+ eventDM EventDM OPTIONAL,
+ secondEvent SecondEventsDescriptor OPTIONAL,
+ signalsDescriptor SignalsDescriptor OPTIONAL,
+ ...
+ }
+
+EventDM ::= CHOICE
+ {
+ digitMapName DigitMapName,
+ digitMapValue DigitMapValue
+ }
+
+SecondEventsDescriptor ::= SEQUENCE
+ {
+ requestID RequestID OPTIONAL,
+ eventList SEQUENCE OF SecondRequestedEvent,
+ ...
+ }
+
+SecondRequestedEvent ::= SEQUENCE
+ {
+ pkgdName PkgdName,
+ streamID StreamID OPTIONAL,
+ eventAction SecondRequestedActions OPTIONAL,
+ evParList SEQUENCE OF EventParameter,
+ ...
+ }
+
+SecondRequestedActions ::= SEQUENCE
+ {
+ keepActive BOOLEAN OPTIONAL,
+ eventDM EventDM OPTIONAL,
+ signalsDescriptor SignalsDescriptor OPTIONAL,
+ ...
+ }
+
+EventBufferDescriptor ::= SEQUENCE OF EventSpec
+
+EventSpec ::= SEQUENCE
+ {
+ eventName EventName,
+ streamID StreamID OPTIONAL,
+ eventParList SEQUENCE OF EventParameter,
+ ...
+ }
+
+
+SignalsDescriptor ::= SEQUENCE OF SignalRequest
+
+SignalRequest ::= CHOICE
+ {
+ signal Signal,
+ seqSigList SeqSigList,
+ ...
+ }
+
+SeqSigList ::= SEQUENCE
+ {
+ id INTEGER(0..65535),
+ signalList SEQUENCE OF Signal
+ }
+
+Signal ::= SEQUENCE
+ {
+ signalName SignalName,
+ streamID StreamID OPTIONAL,
+ sigType SignalType OPTIONAL,
+ duration INTEGER (0..65535) OPTIONAL,
+ notifyCompletion NotifyCompletion OPTIONAL,
+ keepActive BOOLEAN OPTIONAL,
+ sigParList SEQUENCE OF SigParameter,
+ ...,
+ direction SignalDirection OPTIONAL,
+ requestID RequestID OPTIONAL
+ }
+
+SignalType ::= ENUMERATED
+ {
+ brief(0),
+ onOff(1),
+ timeOut(2),
+ ...
+ }
+
+SignalDirection ::= ENUMERATED
+ {
+ internal(0),
+ external(1),
+ both(3),
+ ...
+ }
+
+SignalName ::= PkgdName
+
+NotifyCompletion ::= BIT STRING
+ {
+ onTimeOut(0), onInterruptByEvent(1),
+ onInterruptByNewSignalDescr(2), otherReason(3)
+ }
+
+SigParameter ::= SEQUENCE
+ {
+ sigParameterName Name,
+ value Value,
+ -- For use of extraInfo see the comment related to PropertyParm
+ extraInfo CHOICE
+ {
+ relation Relation,
+ range BOOLEAN,
+ sublist BOOLEAN
+ } OPTIONAL,
+ ...
+ }
+
+-- For an AuditCapReply with all events, the RequestID SHALL be ALL.
+-- ALL is represented by 0xffffffff.
+
+RequestID ::= INTEGER(0..4294967295) -- 32-bit unsigned integer
+
+ModemDescriptor ::= SEQUENCE
+ {
+ mtl SEQUENCE OF ModemType,
+ mpl SEQUENCE OF PropertyParm,
+ nonStandardData NonStandardData OPTIONAL
+ }
+
+ModemType ::= ENUMERATED
+ {
+ v18(0),
+ v22(1),
+ v22bis(2),
+ v32(3),
+ v32bis(4),
+ v34(5),
+ v90(6),
+ v91(7),
+ synchISDN(8),
+ ...
+ }
+
+DigitMapDescriptor ::= SEQUENCE
+ {
+ digitMapName DigitMapName OPTIONAL,
+ digitMapValue DigitMapValue OPTIONAL
+ }
+
+DigitMapName ::= Name
+
+DigitMapValue ::= SEQUENCE
+ {
+ startTimer INTEGER(0..99) OPTIONAL,
+ shortTimer INTEGER(0..99) OPTIONAL,
+ longTimer INTEGER(0..99) OPTIONAL,
+ digitMapBody IA5String,
+ -- Units are seconds for start, short and long timers, and
+ -- hundreds of milliseconds for duration timer. Thus start,
+ -- short, and long range from 1 to 99 seconds and duration
+ -- from 100 ms to 9.9 s
+ -- See A.3 for explanation of digit map syntax
+ ...,
+ durationTimer INTEGER (0..99) OPTIONAL
+ }
+
+ServiceChangeParm ::= SEQUENCE
+ {
+ serviceChangeMethod ServiceChangeMethod,
+ serviceChangeAddress ServiceChangeAddress OPTIONAL,
+ serviceChangeVersion INTEGER(0..99) OPTIONAL,
+ serviceChangeProfile ServiceChangeProfile OPTIONAL,
+ serviceChangeReason Value,
+ -- A serviceChangeReason consists of a numeric reason code
+ -- and an optional text description.
+ -- The serviceChangeReason SHALL be a string consisting of
+ -- a decimal reason code, optionally followed by a single
+ -- space character and a textual description string.
+ -- This string is first BER-encoded as an IA5String.
+ -- The result of this BER-encoding is then encoded as
+ -- an ASN.1 OCTET STRING type, "double wrapping" the
+ -- value
+ -- as was done for package elements.
+ serviceChangeDelay INTEGER(0..4294967295) OPTIONAL,
+ -- 32-bit unsigned integer
+ serviceChangeMgcId MId OPTIONAL,
+ timeStamp TimeNotation OPTIONAL,
+ nonStandardData NonStandardData OPTIONAL,
+ ...,
+ serviceChangeInfo AuditDescriptor OPTIONAL,
+ serviceChangeIncompleteFlag NULL OPTIONAL
+ }
+
+ServiceChangeAddress ::= CHOICE
+ {
+ portNumber INTEGER(0..65535), -- TCP/UDP port number
+ ip4Address IP4Address,
+ ip6Address IP6Address,
+ domainName DomainName,
+ deviceName PathName,
+ mtpAddress OCTET STRING(SIZE(2..4)),
+ ...
+ }
+
+ServiceChangeResParm ::= SEQUENCE
+ {
+ serviceChangeMgcId MId OPTIONAL,
+ serviceChangeAddress ServiceChangeAddress OPTIONAL,
+ serviceChangeVersion INTEGER(0..99) OPTIONAL,
+ serviceChangeProfile ServiceChangeProfile OPTIONAL,
+ timestamp TimeNotation OPTIONAL,
+ ...
+ }
+
+ServiceChangeMethod ::= ENUMERATED
+ {
+ failover(0),
+ forced(1),
+ graceful(2),
+ restart(3),
+ disconnected(4),
+ handOff(5),
+ ...
+ }
+
+ServiceChangeProfile ::= SEQUENCE
+ {
+ profileName IA5String(SIZE (1..67))
+
+ -- 64 characters for name, 1 for "/", 2 for version to match ABNF
+ }
+
+PackagesDescriptor ::= SEQUENCE OF PackagesItem
+PackagesItem ::= SEQUENCE
+ {
+ packageName Name,
+ packageVersion INTEGER(0..99),
+ ...
+ }
+
+StatisticsDescriptor ::= SEQUENCE OF StatisticsParameter
+
+StatisticsParameter ::= SEQUENCE
+ {
+ statName PkgdName,
+ statValue Value OPTIONAL
+ }
+
+NonStandardData ::= SEQUENCE
+ {
+ nonStandardIdentifier NonStandardIdentifier,
+ data OCTET STRING
+ }
+
+NonStandardIdentifier ::= CHOICE
+ {
+ object OBJECT IDENTIFIER,
+ h221NonStandard H221NonStandard,
+ experimental IA5String(SIZE(8)),
+ -- first two characters SHOULD be "X-" or "X+"
+ ...
+ }
+
+H221NonStandard ::= SEQUENCE
+ { t35CountryCode1 INTEGER(0..255),
+ t35CountryCode2 INTEGER(0..255), -- country, as per T.35
+ t35Extension INTEGER(0..255), -- assigned nationally
+ manufacturerCode INTEGER(0..65535), -- assigned nationally
+ ...
+ }
+
+TimeNotation ::= SEQUENCE
+ {
+ date IA5String(SIZE(8)), -- yyyymmdd format
+ time IA5String(SIZE(8)) -- hhmmssss format
+ -- per ISO 8601:1988
+ }
+
+Value ::= SEQUENCE OF OCTET STRING
+
+END
diff --git a/lib/megaco/src/binary/MEDIA-GATEWAY-CONTROL-prev3b.asn b/lib/megaco/src/binary/MEDIA-GATEWAY-CONTROL-prev3b.asn
new file mode 100644
index 0000000000..1fb4d8fff2
--- /dev/null
+++ b/lib/megaco/src/binary/MEDIA-GATEWAY-CONTROL-prev3b.asn
@@ -0,0 +1,1001 @@
+MEDIA-GATEWAY-CONTROL-prev3b
+{itu-t(0) recommendation(0) h(8) h248(248)
+ modules(0) media-gateway-control(0) version3(3)}
+DEFINITIONS AUTOMATIC TAGS ::=
+BEGIN
+
+
+MegacoMessage ::= SEQUENCE
+ {
+ authHeader AuthenticationHeader OPTIONAL,
+ mess Message
+ }
+
+AuthenticationHeader ::= SEQUENCE
+ {
+ secParmIndex SecurityParmIndex,
+ seqNum SequenceNum,
+ ad AuthData
+ }
+
+SecurityParmIndex ::= OCTET STRING(SIZE(4))
+
+SequenceNum ::= OCTET STRING(SIZE(4))
+
+AuthData ::= OCTET STRING (SIZE (12..32))
+
+Message ::= SEQUENCE
+ {
+ version INTEGER(0..99),
+ -- The version of the protocol defined here is equal to 3.
+ mId MId, -- Name/address of message originator
+ messageBody CHOICE
+ {
+ messageError ErrorDescriptor,
+ transactions SEQUENCE OF Transaction
+ },
+ ...
+ }
+
+MId ::= CHOICE
+ {
+ ip4Address IP4Address,
+ ip6Address IP6Address,
+ domainName DomainName,
+ deviceName PathName,
+ mtpAddress OCTET STRING(SIZE(2..4)),
+ -- Addressing structure of mtpAddress:
+ -- 25 - 15 0
+ -- | PC | NI |
+ -- 24 - 14 bits 2 bits
+ -- Note: 14 bits are defined for international use.
+ -- Two national options exist where the point code is 16 or 24
+ -- bits.
+ -- To octet align the mtpAddress, the MSBs shall be encoded as 0s.
+ ...
+ }
+
+DomainName ::= SEQUENCE
+ {
+ name IA5String,
+ -- The name starts with an alphanumeric digit followed by a
+ -- sequence of alphanumeric digits, hyphens and dots. No two
+ -- dots shall occur consecutively.
+ portNumber INTEGER(0..65535) OPTIONAL
+ }
+
+IP4Address ::= SEQUENCE
+ {
+ address OCTET STRING (SIZE(4)),
+ portNumber INTEGER(0..65535) OPTIONAL
+ }
+
+IP6Address ::= SEQUENCE
+ {
+ address OCTET STRING (SIZE(16)),
+ portNumber INTEGER(0..65535) OPTIONAL
+ }
+
+PathName ::= IA5String(SIZE (1..64))
+-- See A.3
+
+Transaction ::= CHOICE
+ {
+ transactionRequest TransactionRequest,
+ transactionPending TransactionPending,
+ transactionReply TransactionReply,
+ transactionResponseAck TransactionResponseAck,
+ -- use of response acks is dependent on underlying transport
+ ...
+ }
+
+TransactionId ::= INTEGER(0..4294967295) -- 32-bit unsigned integer
+
+TransactionRequest ::= SEQUENCE
+ {
+ transactionId TransactionId,
+ actions SEQUENCE OF ActionRequest,
+ ...
+ }
+
+TransactionPending ::= SEQUENCE
+ {
+ transactionId TransactionId,
+ ...
+ }
+
+TransactionReply ::= SEQUENCE
+ {
+ transactionId TransactionId,
+ immAckRequired NULL OPTIONAL,
+ transactionResult CHOICE
+ {
+ transactionError ErrorDescriptor,
+ actionReplies SEQUENCE OF ActionReply
+ },
+ ...,
+ -- Erlang Note: NOT REALLY PART OF THIS IMPLEMENTATION
+ -- Erlang Note: The only reason why we need to include
+ -- Erlang Note: these definitions in this version is
+ -- Erlang Note: that we cannot distinguish between v3
+ -- Erlang Note: versions in the megaco_messenger module
+ segmentNumber SegmentNumber OPTIONAL,
+ segmentationComplete NULL OPTIONAL
+ }
+
+-- SegmentReply ::= SEQUENCE
+-- {
+-- transactionId TransactionId,
+-- segmentNumber SegmentNumber,
+-- segmentationComplete NULL OPTIONAL,
+-- ...
+-- }
+--
+SegmentNumber ::= INTEGER(0..65535)
+
+TransactionResponseAck ::= SEQUENCE OF TransactionAck
+TransactionAck ::= SEQUENCE
+ {
+ firstAck TransactionId,
+ lastAck TransactionId OPTIONAL
+ }
+
+ErrorDescriptor ::= SEQUENCE
+ {
+ errorCode ErrorCode,
+ errorText ErrorText OPTIONAL
+ }
+
+ErrorCode ::= INTEGER(0..65535)
+-- See clause 14 for IANA considerations with respect to error codes
+ErrorText ::= IA5String
+
+ContextID ::= INTEGER(0..4294967295)
+
+-- Context NULL Value: 0
+-- Context CHOOSE Value: 4294967294 (0xFFFFFFFE)
+-- Context ALL Value: 4294967295 (0xFFFFFFFF)
+
+
+ActionRequest ::= SEQUENCE
+ {
+ contextId ContextID,
+ contextRequest ContextRequest OPTIONAL,
+ contextAttrAuditReq ContextAttrAuditRequest OPTIONAL,
+ commandRequests SEQUENCE OF CommandRequest
+ }
+
+ActionReply ::= SEQUENCE
+ {
+ contextId ContextID,
+ errorDescriptor ErrorDescriptor OPTIONAL,
+ contextReply ContextRequest OPTIONAL,
+ commandReply SEQUENCE OF CommandReply
+ }
+
+ContextRequest ::= SEQUENCE
+ {
+ priority INTEGER(0..15) OPTIONAL,
+ emergency BOOLEAN OPTIONAL,
+ topologyReq SEQUENCE OF TopologyRequest OPTIONAL,
+ ...,
+ iepscallind BOOLEAN OPTIONAL,
+ contextProp SEQUENCE OF PropertyParm OPTIONAL
+ }
+
+ContextAttrAuditRequest ::= SEQUENCE
+ {
+ topology NULL OPTIONAL,
+ emergency NULL OPTIONAL,
+ priority NULL OPTIONAL,
+ ...,
+ iepscallind NULL OPTIONAL,
+ contextPropAud SEQUENCE OF IndAudPropertyParm OPTIONAL
+ }
+
+CommandRequest ::= SEQUENCE
+ {
+ command Command,
+ optional NULL OPTIONAL,
+ wildcardReturn NULL OPTIONAL,
+ ...
+ }
+
+Command ::= CHOICE
+ {
+ addReq AmmRequest,
+ moveReq AmmRequest,
+ modReq AmmRequest,
+ -- Add, Move, Modify requests have the same parameters
+ subtractReq SubtractRequest,
+ auditCapRequest AuditRequest,
+ auditValueRequest AuditRequest,
+ notifyReq NotifyRequest,
+ serviceChangeReq ServiceChangeRequest,
+ ...
+ }
+
+CommandReply ::= CHOICE
+ {
+ addReply AmmsReply,
+ moveReply AmmsReply,
+ modReply AmmsReply,
+ subtractReply AmmsReply,
+ -- Add, Move, Modify, Subtract replies have the same parameters
+ auditCapReply AuditReply,
+ auditValueReply AuditReply,
+ notifyReply NotifyReply,
+ serviceChangeReply ServiceChangeReply,
+ ...
+ }
+
+TopologyRequest ::= SEQUENCE
+ {
+ terminationFrom TerminationID,
+ terminationTo TerminationID,
+ topologyDirection ENUMERATED
+ {
+ bothway(0),
+ isolate(1),
+ oneway(2)
+ },
+ ...,
+ streamID StreamID OPTIONAL
+ }
+
+AmmRequest ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ descriptors SEQUENCE OF AmmDescriptor,
+ -- At most one descriptor of each type (see AmmDescriptor)
+ -- allowed in the sequence.
+ ...
+ }
+
+AmmDescriptor ::= CHOICE
+ {
+ mediaDescriptor MediaDescriptor,
+ modemDescriptor ModemDescriptor,
+ muxDescriptor MuxDescriptor,
+ eventsDescriptor EventsDescriptor,
+ eventBufferDescriptor EventBufferDescriptor,
+ signalsDescriptor SignalsDescriptor,
+ digitMapDescriptor DigitMapDescriptor,
+ auditDescriptor AuditDescriptor,
+ ...,
+ statisticsDescriptor StatisticsDescriptor
+ }
+
+
+AmmsReply ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ terminationAudit TerminationAudit OPTIONAL,
+ ...
+ }
+
+SubtractRequest ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ auditDescriptor AuditDescriptor OPTIONAL,
+ ...
+ }
+
+AuditRequest ::= SEQUENCE
+ {
+ terminationID TerminationID,
+ auditDescriptor AuditDescriptor,
+ ...
+ }
+
+AuditReply ::= CHOICE
+ {
+ contextAuditResult TerminationIDList,
+ error ErrorDescriptor,
+ auditResult AuditResult,
+ ...
+ }
+
+AuditResult ::= SEQUENCE
+ {
+
+ terminationID TerminationID,
+ terminationAuditResult TerminationAudit
+ }
+
+
+
+TerminationAudit ::= SEQUENCE OF AuditReturnParameter
+
+AuditReturnParameter ::= CHOICE
+ {
+ errorDescriptor ErrorDescriptor,
+ mediaDescriptor MediaDescriptor,
+ modemDescriptor ModemDescriptor,
+ muxDescriptor MuxDescriptor,
+ eventsDescriptor EventsDescriptor,
+ eventBufferDescriptor EventBufferDescriptor,
+ signalsDescriptor SignalsDescriptor,
+ digitMapDescriptor DigitMapDescriptor,
+ observedEventsDescriptor ObservedEventsDescriptor,
+ statisticsDescriptor StatisticsDescriptor,
+ packagesDescriptor PackagesDescriptor,
+ emptyDescriptors AuditDescriptor,
+ ...
+ }
+
+AuditDescriptor ::= SEQUENCE
+ {
+ auditToken BIT STRING
+ {
+ muxToken(0), modemToken(1), mediaToken(2),
+ eventsToken(3), signalsToken(4),
+ digitMapToken(5), statsToken(6),
+ observedEventsToken(7),
+ packagesToken(8), eventBufferToken(9)
+ } OPTIONAL,
+ ...,
+ auditPropertyToken SEQUENCE OF IndAuditParameter OPTIONAL
+ }
+
+
+IndAuditParameter ::= CHOICE
+ {
+ -- Note that the lower/upper case letters of the tags have
+ -- been changed. The same changes has been made in text...
+ indAudMediaDescriptor IndAudMediaDescriptor,
+ indAudEventsDescriptor IndAudEventsDescriptor,
+ indAudEventBufferDescriptor IndAudEventBufferDescriptor,
+ indAudSignalsDescriptor IndAudSignalsDescriptor,
+ indAudDigitMapDescriptor IndAudDigitMapDescriptor,
+ indAudStatisticsDescriptor IndAudStatisticsDescriptor,
+ indAudPackagesDescriptor IndAudPackagesDescriptor,
+ ...
+ }
+
+IndAudMediaDescriptor ::= SEQUENCE
+ {
+
+ termStateDescr IndAudTerminationStateDescriptor OPTIONAL,
+ streams CHOICE
+ {
+ oneStream IndAudStreamParms,
+ multiStream SEQUENCE OF IndAudStreamDescriptor
+ } OPTIONAL,
+ ...
+ }
+
+IndAudStreamDescriptor ::= SEQUENCE
+ {
+ streamID StreamID,
+ streamParms IndAudStreamParms
+ }
+
+IndAudStreamParms ::= SEQUENCE
+ {
+ localControlDescriptor IndAudLocalControlDescriptor OPTIONAL,
+ localDescriptor IndAudLocalRemoteDescriptor OPTIONAL,
+ remoteDescriptor IndAudLocalRemoteDescriptor OPTIONAL,
+ ...,
+ statisticsDescriptor IndAudStatisticsDescriptor OPTIONAL
+ }
+
+IndAudLocalControlDescriptor ::= SEQUENCE
+ {
+ streamMode NULL OPTIONAL,
+ reserveValue NULL OPTIONAL,
+ reserveGroup NULL OPTIONAL,
+ propertyParms SEQUENCE OF IndAudPropertyParm OPTIONAL,
+ ...
+ }
+
+IndAudPropertyParm ::= SEQUENCE
+ {
+ name PkgdName,
+ ...
+ }
+
+IndAudLocalRemoteDescriptor ::= SEQUENCE
+ {
+ propGroupID INTEGER(0..65535) OPTIONAL,
+ propGrps IndAudPropertyGroup,
+ ...
+ }
+
+IndAudPropertyGroup ::= SEQUENCE OF IndAudPropertyParm
+
+IndAudTerminationStateDescriptor ::= SEQUENCE
+ {
+ propertyParms SEQUENCE OF IndAudPropertyParm,
+ eventBufferControl NULL OPTIONAL,
+ serviceState NULL OPTIONAL,
+ ...
+ }
+
+IndAudEventsDescriptor ::= SEQUENCE
+ {
+ requestID RequestID OPTIONAL,
+ pkgdName PkgdName,
+ streamID StreamID OPTIONAL,
+ ...
+ }
+
+IndAudEventBufferDescriptor ::= SEQUENCE
+ {
+ eventName PkgdName,
+ streamID StreamID OPTIONAL,
+ ...
+ }
+
+IndAudSignalsDescriptor ::=CHOICE
+ {
+ signal IndAudSignal,
+ seqSigList IndAudSeqSigList,
+ ...
+ }
+
+IndAudSeqSigList ::= SEQUENCE
+ {
+ id INTEGER(0..65535),
+ signalList IndAudSignal OPTIONAL
+ }
+
+IndAudSignal ::= SEQUENCE
+ {
+ signalName PkgdName,
+ streamID StreamID OPTIONAL,
+ ...
+ }
+
+IndAudDigitMapDescriptor ::= SEQUENCE
+ {
+ digitMapName DigitMapName OPTIONAL
+ }
+
+IndAudStatisticsDescriptor ::= SEQUENCE
+ {
+ statName PkgdName
+ }
+
+IndAudPackagesDescriptor ::= SEQUENCE
+ {
+ packageName Name,
+ packageVersion INTEGER(0..99),
+ ...
+ }
+
+NotifyRequest ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ observedEventsDescriptor ObservedEventsDescriptor,
+ errorDescriptor ErrorDescriptor OPTIONAL,
+ ...
+ }
+
+NotifyReply ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ errorDescriptor ErrorDescriptor OPTIONAL,
+ ...
+ }
+
+ObservedEventsDescriptor ::= SEQUENCE
+ {
+ requestId RequestID,
+ observedEventLst SEQUENCE OF ObservedEvent
+ }
+
+ObservedEvent ::= SEQUENCE
+ {
+ eventName EventName,
+ streamID StreamID OPTIONAL,
+ eventParList SEQUENCE OF EventParameter,
+ timeNotation TimeNotation OPTIONAL,
+ ...
+ }
+
+EventName ::= PkgdName
+
+EventParameter ::= SEQUENCE
+ {
+ eventParameterName Name,
+ value Value,
+ -- For use of extraInfo see the comment related to PropertyParm
+ extraInfo CHOICE
+ {
+ relation Relation,
+ range BOOLEAN,
+ sublist BOOLEAN
+ } OPTIONAL,
+ ...
+
+ }
+
+ServiceChangeRequest ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ serviceChangeParms ServiceChangeParm,
+ ...
+ }
+
+ServiceChangeReply ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ serviceChangeResult ServiceChangeResult,
+ ...
+ }
+
+-- For ServiceChangeResult, no parameters are mandatory. Hence the
+-- distinction between ServiceChangeParm and ServiceChangeResParm.
+
+ServiceChangeResult ::= CHOICE
+ {
+ errorDescriptor ErrorDescriptor,
+ serviceChangeResParms ServiceChangeResParm
+ }
+
+WildcardField ::= OCTET STRING(SIZE(1))
+
+TerminationID ::= SEQUENCE
+ {
+ wildcard SEQUENCE OF WildcardField,
+ id OCTET STRING(SIZE(1..8)),
+ ...
+ }
+-- See A.1 for explanation of wildcarding mechanism.
+-- Termination ID 0xFFFFFFFFFFFFFFFF indicates the ROOT Termination.
+
+TerminationIDList ::= SEQUENCE OF TerminationID
+
+MediaDescriptor ::= SEQUENCE
+ {
+ termStateDescr TerminationStateDescriptor OPTIONAL,
+ streams CHOICE
+ {
+ oneStream StreamParms,
+ multiStream SEQUENCE OF StreamDescriptor
+ } OPTIONAL,
+ ...
+ }
+
+StreamDescriptor ::= SEQUENCE
+ {
+ streamID StreamID,
+ streamParms StreamParms
+ }
+
+StreamParms ::= SEQUENCE
+ {
+ localControlDescriptor LocalControlDescriptor OPTIONAL,
+ localDescriptor LocalRemoteDescriptor OPTIONAL,
+ remoteDescriptor LocalRemoteDescriptor OPTIONAL,
+ ...,
+ statisticsDescriptor StatisticsDescriptor OPTIONAL
+ }
+
+LocalControlDescriptor ::= SEQUENCE
+ {
+ streamMode StreamMode OPTIONAL,
+ reserveValue BOOLEAN OPTIONAL,
+ reserveGroup BOOLEAN OPTIONAL,
+ propertyParms SEQUENCE OF PropertyParm,
+ ...
+ }
+
+StreamMode ::= ENUMERATED
+ {
+ sendOnly(0),
+ recvOnly(1),
+ sendRecv(2),
+ inactive(3),
+ loopBack(4),
+ ...
+ }
+
+-- In PropertyParm, value is a SEQUENCE OF octet string. When sent
+-- by an MGC the interpretation is as follows:
+-- empty sequence means CHOOSE
+-- one element sequence specifies value
+-- If the sublist field is not selected, a longer sequence means
+-- "choose one of the values" (i.e. value1 OR value2 OR ...)
+-- If the sublist field is selected,
+-- a sequence with more than one element encodes the value of a
+-- list-valued property (i.e. value1 AND value2 AND ...).
+-- The relation field may only be selected if the value sequence
+-- has length 1. It indicates that the MG has to choose a value
+-- for the property. E.g. x > 3 (using the greaterThan
+-- value for relation) instructs the MG to choose any value larger
+-- than 3 for property x.
+-- The range field may only be selected if the value sequence
+-- has length 2. It indicates that the MG has to choose a value
+-- in the range between the first octet in the value sequence and
+-- the trailing octet in the value sequence, including the
+-- boundary values.
+-- When sent by the MG, only responses to an AuditCapability request
+-- may contain multiple values, a range, or a relation field.
+
+PropertyParm ::= SEQUENCE
+ {
+ name PkgdName,
+ value SEQUENCE OF OCTET STRING,
+ extraInfo CHOICE
+ {
+ relation Relation,
+ range BOOLEAN,
+ sublist BOOLEAN
+ } OPTIONAL,
+ ...
+ }
+
+Name ::= OCTET STRING(SIZE(2))
+
+PkgdName ::= OCTET STRING(SIZE(4))
+-- represents Package Name (2 octets) plus Property, Event,
+-- Signal Names or Statistics ID. (2 octets)
+-- To wildcard a package use 0xFFFF for first two octets, choose
+-- is not allowed. To reference native property tag specified in
+-- Annex C, use 0x0000 as first two octets.
+-- To wildcard a Property, Event, Signal, or Statistics ID, use
+-- 0xFFFF for last two octets, choose is not allowed.
+-- Wildcarding of Package Name is permitted only if Property,
+-- Event, Signal, or Statistics ID are
+-- also wildcarded.
+
+Relation ::= ENUMERATED
+ {
+ greaterThan(0),
+ smallerThan(1),
+ unequalTo(2),
+ ...
+ }
+
+LocalRemoteDescriptor ::= SEQUENCE
+ {
+ propGrps SEQUENCE OF PropertyGroup,
+ ...
+ }
+
+PropertyGroup ::= SEQUENCE OF PropertyParm
+
+TerminationStateDescriptor ::= SEQUENCE
+ {
+ propertyParms SEQUENCE OF PropertyParm,
+ eventBufferControl EventBufferControl OPTIONAL,
+ serviceState ServiceState OPTIONAL,
+ ...
+ }
+
+EventBufferControl ::= ENUMERATED
+ {
+ off(0),
+ lockStep(1),
+ ...
+ }
+
+ServiceState ::= ENUMERATED
+ {
+ test(0),
+ outOfSvc(1),
+ inSvc(2),
+ ...
+ }
+
+MuxDescriptor ::= SEQUENCE
+ {
+ muxType MuxType,
+ termList SEQUENCE OF TerminationID,
+ nonStandardData NonStandardData OPTIONAL,
+ ...
+ }
+
+MuxType ::= ENUMERATED
+ {
+ h221(0),
+ h223(1),
+ h226(2),
+ v76(3),
+ ...,
+ nx64k(4)
+ }
+
+StreamID ::= INTEGER(0..65535) -- 16-bit unsigned integer
+
+EventsDescriptor ::= SEQUENCE
+ {
+ requestID RequestID OPTIONAL,
+ -- RequestID must be present if eventList
+ -- is non empty
+ eventList SEQUENCE OF RequestedEvent,
+ ...
+ }
+
+RequestedEvent ::= SEQUENCE
+ {
+ pkgdName PkgdName,
+ streamID StreamID OPTIONAL,
+ eventAction RequestedActions OPTIONAL,
+ evParList SEQUENCE OF EventParameter,
+ ...
+ }
+
+RequestedActions ::= SEQUENCE
+ {
+ keepActive BOOLEAN OPTIONAL,
+ eventDM EventDM OPTIONAL,
+ secondEvent SecondEventsDescriptor OPTIONAL,
+ signalsDescriptor SignalsDescriptor OPTIONAL,
+ ...
+ }
+
+EventDM ::= CHOICE
+ {
+ digitMapName DigitMapName,
+ digitMapValue DigitMapValue
+ }
+
+SecondEventsDescriptor ::= SEQUENCE
+ {
+ requestID RequestID OPTIONAL,
+ eventList SEQUENCE OF SecondRequestedEvent,
+ ...
+ }
+
+SecondRequestedEvent ::= SEQUENCE
+ {
+ pkgdName PkgdName,
+ streamID StreamID OPTIONAL,
+ eventAction SecondRequestedActions OPTIONAL,
+ evParList SEQUENCE OF EventParameter,
+ ...
+ }
+
+SecondRequestedActions ::= SEQUENCE
+ {
+ keepActive BOOLEAN OPTIONAL,
+ eventDM EventDM OPTIONAL,
+ signalsDescriptor SignalsDescriptor OPTIONAL,
+ ...
+ }
+
+EventBufferDescriptor ::= SEQUENCE OF EventSpec
+
+EventSpec ::= SEQUENCE
+ {
+ eventName EventName,
+ streamID StreamID OPTIONAL,
+ eventParList SEQUENCE OF EventParameter,
+ ...
+ }
+
+
+SignalsDescriptor ::= SEQUENCE OF SignalRequest
+
+SignalRequest ::= CHOICE
+ {
+ signal Signal,
+ seqSigList SeqSigList,
+ ...
+ }
+
+SeqSigList ::= SEQUENCE
+ {
+ id INTEGER(0..65535),
+ signalList SEQUENCE OF Signal
+ }
+
+Signal ::= SEQUENCE
+ {
+ signalName SignalName,
+ streamID StreamID OPTIONAL,
+ sigType SignalType OPTIONAL,
+ duration INTEGER (0..65535) OPTIONAL,
+ notifyCompletion NotifyCompletion OPTIONAL,
+ keepActive BOOLEAN OPTIONAL,
+ sigParList SEQUENCE OF SigParameter,
+ ...,
+ direction SignalDirection OPTIONAL,
+ requestID RequestID OPTIONAL
+ }
+
+SignalType ::= ENUMERATED
+ {
+ brief(0),
+ onOff(1),
+ timeOut(2),
+ ...
+ }
+
+SignalDirection ::= ENUMERATED
+ {
+ internal(0),
+ external(1),
+ both(3),
+ ...
+ }
+
+SignalName ::= PkgdName
+
+NotifyCompletion ::= BIT STRING
+ {
+ onTimeOut(0), onInterruptByEvent(1),
+ onInterruptByNewSignalDescr(2), otherReason(3)
+ }
+
+SigParameter ::= SEQUENCE
+ {
+ sigParameterName Name,
+ value Value,
+ -- For use of extraInfo see the comment related to PropertyParm
+ extraInfo CHOICE
+ {
+ relation Relation,
+ range BOOLEAN,
+ sublist BOOLEAN
+ } OPTIONAL,
+ ...
+ }
+
+-- For an AuditCapReply with all events, the RequestID SHALL be ALL.
+-- ALL is represented by 0xffffffff.
+
+RequestID ::= INTEGER(0..4294967295) -- 32-bit unsigned integer
+
+ModemDescriptor ::= SEQUENCE
+ {
+ mtl SEQUENCE OF ModemType,
+ mpl SEQUENCE OF PropertyParm,
+ nonStandardData NonStandardData OPTIONAL
+ }
+
+ModemType ::= ENUMERATED
+ {
+ v18(0),
+ v22(1),
+ v22bis(2),
+ v32(3),
+ v32bis(4),
+ v34(5),
+ v90(6),
+ v91(7),
+ synchISDN(8),
+ ...
+ }
+
+DigitMapDescriptor ::= SEQUENCE
+ {
+ digitMapName DigitMapName OPTIONAL,
+ digitMapValue DigitMapValue OPTIONAL
+ }
+
+DigitMapName ::= Name
+
+DigitMapValue ::= SEQUENCE
+ {
+ startTimer INTEGER(0..99) OPTIONAL,
+ shortTimer INTEGER(0..99) OPTIONAL,
+ longTimer INTEGER(0..99) OPTIONAL,
+ digitMapBody IA5String,
+ -- Units are seconds for start, short and long timers, and
+ -- hundreds of milliseconds for duration timer. Thus start,
+ -- short, and long range from 1 to 99 seconds and duration
+ -- from 100 ms to 9.9 s
+ -- See A.3 for explanation of digit map syntax
+ ...,
+ durationTimer INTEGER (0..99) OPTIONAL
+ }
+
+ServiceChangeParm ::= SEQUENCE
+ {
+ serviceChangeMethod ServiceChangeMethod,
+ serviceChangeAddress ServiceChangeAddress OPTIONAL,
+ serviceChangeVersion INTEGER(0..99) OPTIONAL,
+ serviceChangeProfile ServiceChangeProfile OPTIONAL,
+ serviceChangeReason Value,
+ -- A serviceChangeReason consists of a numeric reason code
+ -- and an optional text description.
+ -- The serviceChangeReason SHALL be a string consisting of
+ -- a decimal reason code, optionally followed by a single
+ -- space character and a textual description string.
+ -- This string is first BER-encoded as an IA5String.
+ -- The result of this BER-encoding is then encoded as
+ -- an ASN.1 OCTET STRING type, "double wrapping" the
+ -- value
+ -- as was done for package elements.
+ serviceChangeDelay INTEGER(0..4294967295) OPTIONAL,
+ -- 32-bit unsigned integer
+ serviceChangeMgcId MId OPTIONAL,
+ timeStamp TimeNotation OPTIONAL,
+ nonStandardData NonStandardData OPTIONAL,
+ ...,
+ serviceChangeInfo AuditDescriptor OPTIONAL,
+ serviceChangeIncompleteFlag NULL OPTIONAL
+ }
+
+ServiceChangeAddress ::= CHOICE
+ {
+ portNumber INTEGER(0..65535), -- TCP/UDP port number
+ ip4Address IP4Address,
+ ip6Address IP6Address,
+ domainName DomainName,
+ deviceName PathName,
+ mtpAddress OCTET STRING(SIZE(2..4)),
+ ...
+ }
+
+ServiceChangeResParm ::= SEQUENCE
+ {
+ serviceChangeMgcId MId OPTIONAL,
+ serviceChangeAddress ServiceChangeAddress OPTIONAL,
+ serviceChangeVersion INTEGER(0..99) OPTIONAL,
+ serviceChangeProfile ServiceChangeProfile OPTIONAL,
+ timestamp TimeNotation OPTIONAL,
+ ...
+ }
+
+ServiceChangeMethod ::= ENUMERATED
+ {
+ failover(0),
+ forced(1),
+ graceful(2),
+ restart(3),
+ disconnected(4),
+ handOff(5),
+ ...
+ }
+
+ServiceChangeProfile ::= SEQUENCE
+ {
+ profileName IA5String(SIZE (1..67))
+
+ -- 64 characters for name, 1 for "/", 2 for version to match ABNF
+ }
+
+PackagesDescriptor ::= SEQUENCE OF PackagesItem
+PackagesItem ::= SEQUENCE
+ {
+ packageName Name,
+ packageVersion INTEGER(0..99),
+ ...
+ }
+
+StatisticsDescriptor ::= SEQUENCE OF StatisticsParameter
+
+StatisticsParameter ::= SEQUENCE
+ {
+ statName PkgdName,
+ statValue Value OPTIONAL
+ }
+
+NonStandardData ::= SEQUENCE
+ {
+ nonStandardIdentifier NonStandardIdentifier,
+ data OCTET STRING
+ }
+
+NonStandardIdentifier ::= CHOICE
+ {
+ object OBJECT IDENTIFIER,
+ h221NonStandard H221NonStandard,
+ experimental IA5String(SIZE(8)),
+ -- first two characters SHOULD be "X-" or "X+"
+ ...
+ }
+
+H221NonStandard ::= SEQUENCE
+ { t35CountryCode1 INTEGER(0..255),
+ t35CountryCode2 INTEGER(0..255), -- country, as per T.35
+ t35Extension INTEGER(0..255), -- assigned nationally
+ manufacturerCode INTEGER(0..65535), -- assigned nationally
+ ...
+ }
+
+TimeNotation ::= SEQUENCE
+ {
+ date IA5String(SIZE(8)), -- yyyymmdd format
+ time IA5String(SIZE(8)) -- hhmmssss format
+ -- per ISO 8601:1988
+ }
+
+Value ::= SEQUENCE OF OCTET STRING
+
+END
diff --git a/lib/megaco/src/binary/MEDIA-GATEWAY-CONTROL-prev3c.asn b/lib/megaco/src/binary/MEDIA-GATEWAY-CONTROL-prev3c.asn
new file mode 100644
index 0000000000..cb6940e8b0
--- /dev/null
+++ b/lib/megaco/src/binary/MEDIA-GATEWAY-CONTROL-prev3c.asn
@@ -0,0 +1,1073 @@
+MEDIA-GATEWAY-CONTROL-prev3c
+{itu-t(0) recommendation(0) h(8) h248(248)
+ modules(0) media-gateway-control(0) version3(3)}
+DEFINITIONS AUTOMATIC TAGS ::=
+BEGIN
+
+
+MegacoMessage ::= SEQUENCE
+ {
+ authHeader AuthenticationHeader OPTIONAL,
+ mess Message
+ }
+
+AuthenticationHeader ::= SEQUENCE
+ {
+ secParmIndex SecurityParmIndex,
+ seqNum SequenceNum,
+ ad AuthData
+ }
+
+SecurityParmIndex ::= OCTET STRING(SIZE(4))
+
+SequenceNum ::= OCTET STRING(SIZE(4))
+
+AuthData ::= OCTET STRING (SIZE (12..32))
+
+Message ::= SEQUENCE
+ {
+ version INTEGER(0..99),
+ -- The version of the protocol defined here is equal to 3.
+ mId MId, -- Name/address of message originator
+ messageBody CHOICE
+ {
+ messageError ErrorDescriptor,
+ transactions SEQUENCE OF Transaction
+ },
+ ...
+ }
+
+MId ::= CHOICE
+ {
+ ip4Address IP4Address,
+ ip6Address IP6Address,
+ domainName DomainName,
+ deviceName PathName,
+ mtpAddress OCTET STRING(SIZE(2..4)),
+ -- Addressing structure of mtpAddress:
+ -- 25 - 15 0
+ -- | PC | NI |
+ -- 24 - 14 bits 2 bits
+ -- Note: 14 bits are defined for international use.
+ -- Two national options exist where the point code is 16 or 24
+ -- bits.
+ -- To octet align the mtpAddress, the MSBs shall be encoded as 0s.
+ ...
+ }
+
+DomainName ::= SEQUENCE
+ {
+ name IA5String,
+ -- The name starts with an alphanumeric digit followed by a
+ -- sequence of alphanumeric digits, hyphens and dots. No two
+ -- dots shall occur consecutively.
+ portNumber INTEGER(0..65535) OPTIONAL
+ }
+
+IP4Address ::= SEQUENCE
+ {
+ address OCTET STRING (SIZE(4)),
+ portNumber INTEGER(0..65535) OPTIONAL
+ }
+
+IP6Address ::= SEQUENCE
+ {
+ address OCTET STRING (SIZE(16)),
+ portNumber INTEGER(0..65535) OPTIONAL
+ }
+
+PathName ::= IA5String(SIZE (1..64))
+-- See A.3
+
+Transaction ::= CHOICE
+ {
+ transactionRequest TransactionRequest,
+ transactionPending TransactionPending,
+ transactionReply TransactionReply,
+ transactionResponseAck TransactionResponseAck,
+ -- use of response acks is dependent on underlying transport
+ ...
+ -- segmentReply SegmentReply
+ }
+
+TransactionId ::= INTEGER(0..4294967295) -- 32-bit unsigned integer
+
+TransactionRequest ::= SEQUENCE
+ {
+ transactionId TransactionId,
+ actions SEQUENCE OF ActionRequest,
+ ...
+ }
+
+TransactionPending ::= SEQUENCE
+ {
+ transactionId TransactionId,
+ ...
+ }
+
+TransactionReply ::= SEQUENCE
+ {
+ transactionId TransactionId,
+ immAckRequired NULL OPTIONAL,
+ transactionResult CHOICE
+ {
+ transactionError ErrorDescriptor,
+ actionReplies SEQUENCE OF ActionReply
+ },
+ ...,
+ -- Erlang Note: NOT REALLY PART OF THIS IMPLEMENTATION
+ -- Erlang Note: The only reason why we need to include
+ -- Erlang Note: these definitions in this version is
+ -- Erlang Note: that we cannot distinguish between v3
+ -- Erlang Note: versions in the megaco_messenger module
+ segmentNumber SegmentNumber OPTIONAL,
+ segmentationComplete NULL OPTIONAL
+ }
+
+-- SegmentReply ::= SEQUENCE
+-- {
+-- transactionId TransactionId,
+-- segmentNumber SegmentNumber,
+-- segmentationComplete NULL OPTIONAL,
+-- ...
+-- }
+--
+SegmentNumber ::= INTEGER(0..65535)
+
+TransactionResponseAck ::= SEQUENCE OF TransactionAck
+TransactionAck ::= SEQUENCE
+ {
+ firstAck TransactionId,
+ lastAck TransactionId OPTIONAL
+ }
+
+ErrorDescriptor ::= SEQUENCE
+ {
+ errorCode ErrorCode,
+ errorText ErrorText OPTIONAL
+ }
+
+ErrorCode ::= INTEGER(0..65535)
+-- See clause 14 for IANA considerations with respect to error codes
+ErrorText ::= IA5String
+
+ContextID ::= INTEGER(0..4294967295)
+-- Context NULL Value: 0
+-- Context CHOOSE Value: 4294967294 (0xFFFFFFFE)
+-- Context ALL Value: 4294967295 (0xFFFFFFFF)
+
+
+ActionRequest ::= SEQUENCE
+ {
+ contextId ContextID,
+ contextRequest ContextRequest OPTIONAL,
+ contextAttrAuditReq ContextAttrAuditRequest OPTIONAL,
+ commandRequests SEQUENCE OF CommandRequest
+ }
+
+ActionReply ::= SEQUENCE
+ {
+ contextId ContextID,
+ errorDescriptor ErrorDescriptor OPTIONAL,
+ contextReply ContextRequest OPTIONAL,
+ commandReply SEQUENCE OF CommandReply
+ }
+
+ContextRequest ::= SEQUENCE
+ {
+ priority INTEGER(0..15) OPTIONAL,
+ emergency BOOLEAN OPTIONAL,
+ topologyReq SEQUENCE OF TopologyRequest OPTIONAL,
+ ...,
+ iepscallind BOOLEAN OPTIONAL,
+ contextProp SEQUENCE OF PropertyParm OPTIONAL,
+ contextList SEQUENCE OF ContextID OPTIONAL
+ }
+-- When returning a contextList, the contextId in the ActionReply
+-- construct will return the contextId from the associated ActionRequest.
+
+ContextAttrAuditRequest ::= SEQUENCE
+ {
+ topology NULL OPTIONAL,
+ emergency NULL OPTIONAL,
+ priority NULL OPTIONAL,
+ ...,
+ iepscallind NULL OPTIONAL,
+ contextPropAud SEQUENCE OF IndAudPropertyParm OPTIONAL,
+
+ selectpriority INTEGER(0..15) OPTIONAL,
+ -- to select given priority
+
+ selectemergency BOOLEAN OPTIONAL,
+ -- to select if emergency set/not set (T/F)
+
+ selectiepscallind BOOLEAN OPTIONAL,
+ -- to select if IEPS set/not set (T/F)
+
+ selectLogic SelectLogic OPTIONAL -- default is AND
+ }
+
+SelectLogic ::= CHOICE
+ {
+ andAUDITSelect NULL, -- all selection conditions satisfied
+ orAUDITSelect NULL, -- at least one selection condition satisfied
+ ...
+ }
+
+
+CommandRequest ::= SEQUENCE
+ {
+ command Command,
+ optional NULL OPTIONAL,
+ wildcardReturn NULL OPTIONAL,
+ ...
+ }
+
+Command ::= CHOICE
+ {
+ addReq AmmRequest,
+ moveReq AmmRequest,
+ modReq AmmRequest,
+ -- Add, Move, Modify requests have the same parameters
+ subtractReq SubtractRequest,
+ auditCapRequest AuditRequest,
+ auditValueRequest AuditRequest,
+ notifyReq NotifyRequest,
+ serviceChangeReq ServiceChangeRequest,
+ ...
+ }
+
+CommandReply ::= CHOICE
+ {
+ addReply AmmsReply,
+ moveReply AmmsReply,
+ modReply AmmsReply,
+ subtractReply AmmsReply,
+ -- Add, Move, Modify, Subtract replies have the same parameters
+ auditCapReply AuditReply,
+ auditValueReply AuditReply,
+ notifyReply NotifyReply,
+ serviceChangeReply ServiceChangeReply,
+ ...
+ }
+
+TopologyRequest ::= SEQUENCE
+ {
+ terminationFrom TerminationID,
+ terminationTo TerminationID,
+ topologyDirection ENUMERATED
+ {
+ bothway(0),
+ isolate(1),
+ oneway(2)
+ },
+ ...,
+ streamID StreamID OPTIONAL,
+ topologyDirectionExtension ENUMERATED
+ {
+ onewayexternal(0),
+ onewayboth(1),
+ ...
+ } OPTIONAL
+ -- This is not according to the standard, but without it
+ -- the TopologyRequest will be useless since topologyDirection
+ -- and topologyDirectionExtension are contradictory.
+ }
+
+AmmRequest ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ descriptors SEQUENCE OF AmmDescriptor,
+ -- At most one descriptor of each type (see AmmDescriptor)
+ -- allowed in the sequence.
+ ...
+ }
+
+AmmDescriptor ::= CHOICE
+ {
+ mediaDescriptor MediaDescriptor,
+ modemDescriptor ModemDescriptor,
+ muxDescriptor MuxDescriptor,
+ eventsDescriptor EventsDescriptor,
+ eventBufferDescriptor EventBufferDescriptor,
+ signalsDescriptor SignalsDescriptor,
+ digitMapDescriptor DigitMapDescriptor,
+ auditDescriptor AuditDescriptor,
+ ...,
+ statisticsDescriptor StatisticsDescriptor
+ }
+
+
+AmmsReply ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ terminationAudit TerminationAudit OPTIONAL,
+ ...
+ }
+
+SubtractRequest ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ auditDescriptor AuditDescriptor OPTIONAL,
+ ...
+ }
+
+AuditRequest ::= SEQUENCE
+ {
+ terminationID TerminationID,
+ auditDescriptor AuditDescriptor,
+ ...,
+ terminationIDList TerminationIDList OPTIONAL
+ }
+-- terminationID shall contain the first termination in the
+-- list when using the terminationIDList construct in AuditRequest
+
+AuditReply ::= CHOICE
+ {
+ contextAuditResult TerminationIDList,
+ error ErrorDescriptor,
+ auditResult AuditResult,
+ ...,
+ auditResultTermList TermListAuditResult
+ }
+
+AuditResult ::= SEQUENCE
+ {
+
+ terminationID TerminationID,
+ terminationAuditResult TerminationAudit
+ }
+
+TermListAuditResult ::= SEQUENCE
+ {
+ terminationIDList TerminationIDList,
+ terminationAuditResult TerminationAudit,
+ ...
+ }
+
+TerminationAudit ::= SEQUENCE OF AuditReturnParameter
+
+AuditReturnParameter ::= CHOICE
+ {
+ errorDescriptor ErrorDescriptor,
+ mediaDescriptor MediaDescriptor,
+ modemDescriptor ModemDescriptor,
+ muxDescriptor MuxDescriptor,
+ eventsDescriptor EventsDescriptor,
+ eventBufferDescriptor EventBufferDescriptor,
+ signalsDescriptor SignalsDescriptor,
+ digitMapDescriptor DigitMapDescriptor,
+ observedEventsDescriptor ObservedEventsDescriptor,
+ statisticsDescriptor StatisticsDescriptor,
+ packagesDescriptor PackagesDescriptor,
+ emptyDescriptors AuditDescriptor,
+ ...
+ }
+
+AuditDescriptor ::= SEQUENCE
+ {
+ auditToken BIT STRING
+ {
+ muxToken(0), modemToken(1), mediaToken(2),
+ eventsToken(3), signalsToken(4),
+ digitMapToken(5), statsToken(6),
+ observedEventsToken(7),
+ packagesToken(8), eventBufferToken(9)
+ } OPTIONAL,
+ ...,
+ auditPropertyToken SEQUENCE OF IndAuditParameter OPTIONAL
+ }
+
+
+IndAuditParameter ::= CHOICE
+ {
+ -- Note that the lower/upper case letters of the tags have
+ -- been changed. The same changes has been made in text...
+ indAudMediaDescriptor IndAudMediaDescriptor,
+ indAudEventsDescriptor IndAudEventsDescriptor,
+ indAudEventBufferDescriptor IndAudEventBufferDescriptor,
+ indAudSignalsDescriptor IndAudSignalsDescriptor,
+ indAudDigitMapDescriptor IndAudDigitMapDescriptor,
+ indAudStatisticsDescriptor IndAudStatisticsDescriptor,
+ indAudPackagesDescriptor IndAudPackagesDescriptor,
+ ...
+ }
+
+IndAudMediaDescriptor ::= SEQUENCE
+ {
+
+ termStateDescr IndAudTerminationStateDescriptor OPTIONAL,
+ streams CHOICE
+ {
+ oneStream IndAudStreamParms,
+ multiStream SEQUENCE OF IndAudStreamDescriptor
+ } OPTIONAL,
+ ...
+ }
+
+IndAudStreamDescriptor ::= SEQUENCE
+ {
+ streamID StreamID,
+ streamParms IndAudStreamParms
+ }
+
+IndAudStreamParms ::= SEQUENCE
+ {
+ localControlDescriptor IndAudLocalControlDescriptor OPTIONAL,
+ localDescriptor IndAudLocalRemoteDescriptor OPTIONAL,
+ remoteDescriptor IndAudLocalRemoteDescriptor OPTIONAL,
+ ...,
+ statisticsDescriptor IndAudStatisticsDescriptor OPTIONAL
+ }
+
+IndAudLocalControlDescriptor ::= SEQUENCE
+ {
+ streamMode NULL OPTIONAL,
+ reserveValue NULL OPTIONAL,
+ reserveGroup NULL OPTIONAL,
+ propertyParms SEQUENCE OF IndAudPropertyParm OPTIONAL,
+ ...,
+ streamModeSel StreamMode OPTIONAL
+ -- must not have both streamMode and streamModeSel
+ -- if both are present only streamModeSel shall be honoured
+ }
+
+IndAudPropertyParm ::= SEQUENCE
+ {
+ name PkgdName,
+ ...,
+ propertyParms PropertyParm OPTIONAL
+ }
+-- to select based on property values
+-- AND/OR selection logic is specified at context level
+
+IndAudLocalRemoteDescriptor ::= SEQUENCE
+ {
+ propGroupID INTEGER(0..65535) OPTIONAL,
+ propGrps IndAudPropertyGroup,
+ ...
+ }
+
+IndAudPropertyGroup ::= SEQUENCE OF IndAudPropertyParm
+
+IndAudTerminationStateDescriptor ::= SEQUENCE
+ {
+ propertyParms SEQUENCE OF IndAudPropertyParm,
+ eventBufferControl NULL OPTIONAL,
+ serviceState NULL OPTIONAL,
+ ...,
+ serviceStateSel ServiceState OPTIONAL
+ -- must not have both serviceState and serviceStateSel
+ -- if both are present only serviceStateSel shall be honoured
+ }
+
+IndAudEventsDescriptor ::= SEQUENCE
+ {
+ requestID RequestID OPTIONAL,
+ pkgdName PkgdName,
+ streamID StreamID OPTIONAL,
+ ...
+ }
+
+IndAudEventBufferDescriptor ::= SEQUENCE
+ {
+ eventName PkgdName,
+ streamID StreamID OPTIONAL,
+ ...
+ }
+
+IndAudSignalsDescriptor ::=CHOICE
+ {
+ signal IndAudSignal,
+ seqSigList IndAudSeqSigList,
+ ...
+ }
+
+IndAudSeqSigList ::= SEQUENCE
+ {
+ id INTEGER(0..65535),
+ signalList IndAudSignal OPTIONAL
+ }
+
+IndAudSignal ::= SEQUENCE
+ {
+ signalName PkgdName,
+ streamID StreamID OPTIONAL,
+ ...,
+ signalRequestID RequestID OPTIONAL
+ }
+
+IndAudDigitMapDescriptor ::= SEQUENCE
+ {
+ digitMapName DigitMapName OPTIONAL
+ }
+
+IndAudStatisticsDescriptor ::= SEQUENCE
+ {
+ statName PkgdName
+ }
+
+IndAudPackagesDescriptor ::= SEQUENCE
+ {
+ packageName Name,
+ packageVersion INTEGER(0..99),
+ ...
+ }
+
+NotifyRequest ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ observedEventsDescriptor ObservedEventsDescriptor,
+ errorDescriptor ErrorDescriptor OPTIONAL,
+ ...
+ }
+
+NotifyReply ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ errorDescriptor ErrorDescriptor OPTIONAL,
+ ...
+ }
+
+ObservedEventsDescriptor ::= SEQUENCE
+ {
+ requestId RequestID,
+ observedEventLst SEQUENCE OF ObservedEvent
+ }
+
+ObservedEvent ::= SEQUENCE
+ {
+ eventName EventName,
+ streamID StreamID OPTIONAL,
+ eventParList SEQUENCE OF EventParameter,
+ timeNotation TimeNotation OPTIONAL,
+ ...
+ }
+
+EventName ::= PkgdName
+
+EventParameter ::= SEQUENCE
+ {
+ eventParameterName Name,
+ value Value,
+ -- For use of extraInfo see the comment related to PropertyParm
+ extraInfo CHOICE
+ {
+ relation Relation,
+ range BOOLEAN,
+ sublist BOOLEAN
+ } OPTIONAL,
+ ...
+
+ }
+
+ServiceChangeRequest ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ serviceChangeParms ServiceChangeParm,
+ ...
+ }
+
+ServiceChangeReply ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ serviceChangeResult ServiceChangeResult,
+ ...
+ }
+
+-- For ServiceChangeResult, no parameters are mandatory. Hence the
+-- distinction between ServiceChangeParm and ServiceChangeResParm.
+ServiceChangeResult ::= CHOICE
+ {
+ errorDescriptor ErrorDescriptor,
+ serviceChangeResParms ServiceChangeResParm
+ }
+
+WildcardField ::= OCTET STRING(SIZE(1))
+
+TerminationID ::= SEQUENCE
+ {
+ wildcard SEQUENCE OF WildcardField,
+ id OCTET STRING(SIZE(1..8)),
+ ...
+ }
+-- See A.1 for explanation of wildcarding mechanism.
+-- Termination ID 0xFFFFFFFFFFFFFFFF indicates the ROOT Termination.
+
+TerminationIDList ::= SEQUENCE OF TerminationID
+
+MediaDescriptor ::= SEQUENCE
+ {
+ termStateDescr TerminationStateDescriptor OPTIONAL,
+ streams CHOICE
+ {
+ oneStream StreamParms,
+ multiStream SEQUENCE OF StreamDescriptor
+ } OPTIONAL,
+ ...
+ }
+
+StreamDescriptor ::= SEQUENCE
+ {
+ streamID StreamID,
+ streamParms StreamParms
+ }
+
+StreamParms ::= SEQUENCE
+ {
+ localControlDescriptor LocalControlDescriptor OPTIONAL,
+ localDescriptor LocalRemoteDescriptor OPTIONAL,
+ remoteDescriptor LocalRemoteDescriptor OPTIONAL,
+ ...,
+ statisticsDescriptor StatisticsDescriptor OPTIONAL
+ }
+
+LocalControlDescriptor ::= SEQUENCE
+ {
+ streamMode StreamMode OPTIONAL,
+ reserveValue BOOLEAN OPTIONAL,
+ reserveGroup BOOLEAN OPTIONAL,
+ propertyParms SEQUENCE OF PropertyParm,
+ ...
+ }
+
+StreamMode ::= ENUMERATED
+ {
+ sendOnly(0),
+ recvOnly(1),
+ sendRecv(2),
+ inactive(3),
+ loopBack(4),
+ ...
+ }
+
+-- In PropertyParm, value is a SEQUENCE OF octet string. When sent
+-- by an MGC the interpretation is as follows:
+-- empty sequence means CHOOSE
+-- one element sequence specifies value
+-- If the sublist field is not selected, a longer sequence means
+-- "choose one of the values" (i.e. value1 OR value2 OR ...)
+-- If the sublist field is selected,
+-- a sequence with more than one element encodes the value of a
+-- list-valued property (i.e. value1 AND value2 AND ...).
+-- The relation field may only be selected if the value sequence
+-- has length 1. It indicates that the MG has to choose a value
+-- for the property. E.g. x > 3 (using the greaterThan
+-- value for relation) instructs the MG to choose any value larger
+-- than 3 for property x.
+-- The range field may only be selected if the value sequence
+-- has length 2. It indicates that the MG has to choose a value
+-- in the range between the first octet in the value sequence and
+-- the trailing octet in the value sequence, including the
+-- boundary values.
+-- When sent by the MG, only responses to an AuditCapability request
+-- may contain multiple values, a range, or a relation field.
+
+PropertyParm ::= SEQUENCE
+ {
+ name PkgdName,
+ value SEQUENCE OF OCTET STRING,
+ extraInfo CHOICE
+ {
+ relation Relation,
+ range BOOLEAN,
+ sublist BOOLEAN
+ } OPTIONAL,
+ ...
+ }
+
+Name ::= OCTET STRING(SIZE(2))
+
+PkgdName ::= OCTET STRING(SIZE(4))
+-- represents Package Name (2 octets) plus Property, Event,
+-- Signal Names or Statistics ID. (2 octets)
+-- To wildcard a package use 0xFFFF for first two octets, choose
+-- is not allowed. To reference native property tag specified in
+-- Annex C, use 0x0000 as first two octets.
+-- To wildcard a Property, Event, Signal, or Statistics ID, use
+-- 0xFFFF for last two octets, choose is not allowed.
+-- Wildcarding of Package Name is permitted only if Property,
+-- Event, Signal, or Statistics ID are
+-- also wildcarded.
+
+Relation ::= ENUMERATED
+ {
+ greaterThan(0),
+ smallerThan(1),
+ unequalTo(2),
+ ...
+ }
+
+LocalRemoteDescriptor ::= SEQUENCE
+ {
+ propGrps SEQUENCE OF PropertyGroup,
+ ...
+ }
+
+PropertyGroup ::= SEQUENCE OF PropertyParm
+
+TerminationStateDescriptor ::= SEQUENCE
+ {
+ propertyParms SEQUENCE OF PropertyParm,
+ eventBufferControl EventBufferControl OPTIONAL,
+ serviceState ServiceState OPTIONAL,
+ ...
+ }
+
+EventBufferControl ::= ENUMERATED
+ {
+ off(0),
+ lockStep(1),
+ ...
+ }
+
+ServiceState ::= ENUMERATED
+ {
+ test(0),
+ outOfSvc(1),
+ inSvc(2),
+ ...
+ }
+
+MuxDescriptor ::= SEQUENCE
+ {
+ muxType MuxType,
+ termList SEQUENCE OF TerminationID,
+ nonStandardData NonStandardData OPTIONAL,
+ ...
+ }
+
+MuxType ::= ENUMERATED
+ {
+ h221(0),
+ h223(1),
+ h226(2),
+ v76(3),
+ ...,
+ nx64k(4)
+ }
+
+StreamID ::= INTEGER(0..65535) -- 16-bit unsigned integer
+
+EventsDescriptor ::= SEQUENCE
+ {
+ requestID RequestID OPTIONAL,
+ -- RequestID must be present if eventList
+ -- is non empty
+ eventList SEQUENCE OF RequestedEvent,
+ ...
+ }
+
+RequestedEvent ::= SEQUENCE
+ {
+ pkgdName PkgdName,
+ streamID StreamID OPTIONAL,
+ eventAction RequestedActions OPTIONAL,
+ evParList SEQUENCE OF EventParameter,
+ ...
+ }
+
+RegulatedEmbeddedDescriptor ::= SEQUENCE
+ {
+ secondEvent SecondEventsDescriptor OPTIONAL,
+ signalsDescriptor SignalsDescriptor OPTIONAL,
+ ...
+ }
+
+NotifyBehaviour ::= CHOICE
+ {
+ notifyImmediate NULL,
+ notifyRegulated RegulatedEmbeddedDescriptor,
+ neverNotify NULL,
+ ...
+ }
+
+RequestedActions ::= SEQUENCE
+ {
+ keepActive BOOLEAN OPTIONAL,
+ eventDM EventDM OPTIONAL,
+ secondEvent SecondEventsDescriptor OPTIONAL,
+ signalsDescriptor SignalsDescriptor OPTIONAL,
+ ...,
+ notifyBehaviour NotifyBehaviour OPTIONAL,
+ resetEventsDescriptor NULL OPTIONAL
+ }
+
+EventDM ::= CHOICE
+ {
+ digitMapName DigitMapName,
+ digitMapValue DigitMapValue
+ }
+
+SecondEventsDescriptor ::= SEQUENCE
+ {
+ requestID RequestID OPTIONAL,
+ eventList SEQUENCE OF SecondRequestedEvent,
+ ...
+ }
+
+SecondRequestedEvent ::= SEQUENCE
+ {
+ pkgdName PkgdName,
+ streamID StreamID OPTIONAL,
+ eventAction SecondRequestedActions OPTIONAL,
+ evParList SEQUENCE OF EventParameter,
+ ...
+ }
+
+SecondRequestedActions ::= SEQUENCE
+ {
+ keepActive BOOLEAN OPTIONAL,
+ eventDM EventDM OPTIONAL,
+ signalsDescriptor SignalsDescriptor OPTIONAL,
+ ...,
+ notifyBehaviour NotifyBehaviour OPTIONAL,
+ resetEventsDescriptor NULL OPTIONAL
+ }
+
+EventBufferDescriptor ::= SEQUENCE OF EventSpec
+
+EventSpec ::= SEQUENCE
+ {
+ eventName EventName,
+ streamID StreamID OPTIONAL,
+ eventParList SEQUENCE OF EventParameter,
+ ...
+ }
+
+
+SignalsDescriptor ::= SEQUENCE OF SignalRequest
+
+SignalRequest ::= CHOICE
+ {
+ signal Signal,
+ seqSigList SeqSigList,
+ ...
+ }
+
+SeqSigList ::= SEQUENCE
+ {
+ id INTEGER(0..65535),
+ signalList SEQUENCE OF Signal
+ }
+
+Signal ::= SEQUENCE
+ {
+ signalName SignalName,
+ streamID StreamID OPTIONAL,
+ sigType SignalType OPTIONAL,
+ duration INTEGER (0..65535) OPTIONAL,
+ notifyCompletion NotifyCompletion OPTIONAL,
+ keepActive BOOLEAN OPTIONAL,
+ sigParList SEQUENCE OF SigParameter,
+ ...,
+ direction SignalDirection OPTIONAL,
+ requestID RequestID OPTIONAL,
+ intersigDelay INTEGER (0..65535) OPTIONAL
+ }
+
+SignalType ::= ENUMERATED
+ {
+ brief(0),
+ onOff(1),
+ timeOut(2),
+ ...
+ }
+
+SignalDirection ::= ENUMERATED
+ {
+ internal(0),
+ external(1),
+ both(3),
+ ...
+ }
+
+SignalName ::= PkgdName
+
+NotifyCompletion ::= BIT STRING
+ {
+ onTimeOut(0), onInterruptByEvent(1),
+ onInterruptByNewSignalDescr(2), otherReason(3), onIteration(4)
+ }
+
+SigParameter ::= SEQUENCE
+ {
+ sigParameterName Name,
+ value Value,
+ -- For use of extraInfo see the comment related to PropertyParm
+ extraInfo CHOICE
+ {
+ relation Relation,
+ range BOOLEAN,
+ sublist BOOLEAN
+ } OPTIONAL,
+ ...
+ }
+
+-- For an AuditCapReply with all events, the RequestID SHALL be ALL.
+-- ALL is represented by 0xffffffff.
+RequestID ::= INTEGER(0..4294967295) -- 32-bit unsigned integer
+
+ModemDescriptor ::= SEQUENCE
+ {
+ mtl SEQUENCE OF ModemType,
+ mpl SEQUENCE OF PropertyParm,
+ nonStandardData NonStandardData OPTIONAL
+ }
+
+ModemType ::= ENUMERATED
+ {
+ v18(0),
+ v22(1),
+ v22bis(2),
+ v32(3),
+ v32bis(4),
+ v34(5),
+ v90(6),
+ v91(7),
+ synchISDN(8),
+ ...
+ }
+
+DigitMapDescriptor ::= SEQUENCE
+ {
+ digitMapName DigitMapName OPTIONAL,
+ digitMapValue DigitMapValue OPTIONAL
+ }
+
+DigitMapName ::= Name
+
+DigitMapValue ::= SEQUENCE
+ {
+ startTimer INTEGER(0..99) OPTIONAL,
+ shortTimer INTEGER(0..99) OPTIONAL,
+ longTimer INTEGER(0..99) OPTIONAL,
+ digitMapBody IA5String,
+ -- Units are seconds for start, short and long timers, and
+ -- hundreds of milliseconds for duration timer. Thus start,
+ -- short, and long range from 1 to 99 seconds and duration
+ -- from 100 ms to 9.9 s
+ -- See A.3 for explanation of digit map syntax
+ ...,
+ durationTimer INTEGER (0..99) OPTIONAL
+ }
+
+ServiceChangeParm ::= SEQUENCE
+ {
+ serviceChangeMethod ServiceChangeMethod,
+ serviceChangeAddress ServiceChangeAddress OPTIONAL,
+ serviceChangeVersion INTEGER(0..99) OPTIONAL,
+ serviceChangeProfile ServiceChangeProfile OPTIONAL,
+ serviceChangeReason Value,
+ -- A serviceChangeReason consists of a numeric reason code
+ -- and an optional text description.
+ -- The serviceChangeReason SHALL be a string consisting of
+ -- a decimal reason code, optionally followed by a single
+ -- space character and a textual description string.
+ -- This string is first BER-encoded as an IA5String.
+ -- The result of this BER-encoding is then encoded as
+ -- an ASN.1 OCTET STRING type, "double wrapping" the
+ -- value
+ -- as was done for package elements.
+ serviceChangeDelay INTEGER(0..4294967295) OPTIONAL,
+ -- 32-bit unsigned integer
+ serviceChangeMgcId MId OPTIONAL,
+ timeStamp TimeNotation OPTIONAL,
+ nonStandardData NonStandardData OPTIONAL,
+ ...,
+ serviceChangeInfo AuditDescriptor OPTIONAL,
+ serviceChangeIncompleteFlag NULL OPTIONAL
+ }
+
+ServiceChangeAddress ::= CHOICE
+ {
+ portNumber INTEGER(0..65535), -- TCP/UDP port number
+ ip4Address IP4Address,
+ ip6Address IP6Address,
+ domainName DomainName,
+ deviceName PathName,
+ mtpAddress OCTET STRING(SIZE(2..4)),
+ ...
+ }
+
+ServiceChangeResParm ::= SEQUENCE
+ {
+ serviceChangeMgcId MId OPTIONAL,
+ serviceChangeAddress ServiceChangeAddress OPTIONAL,
+ serviceChangeVersion INTEGER(0..99) OPTIONAL,
+ serviceChangeProfile ServiceChangeProfile OPTIONAL,
+ timestamp TimeNotation OPTIONAL,
+ ...
+ }
+
+ServiceChangeMethod ::= ENUMERATED
+ {
+ failover(0),
+ forced(1),
+ graceful(2),
+ restart(3),
+ disconnected(4),
+ handOff(5),
+ ...
+ }
+
+ServiceChangeProfile ::= SEQUENCE
+ {
+ profileName IA5String(SIZE (1..67))
+
+ -- 64 characters for name, 1 for "/", 2 for version to match ABNF
+ }
+
+PackagesDescriptor ::= SEQUENCE OF PackagesItem
+
+PackagesItem ::= SEQUENCE
+ {
+ packageName Name,
+ packageVersion INTEGER(0..99),
+ ...
+ }
+
+StatisticsDescriptor ::= SEQUENCE OF StatisticsParameter
+
+StatisticsParameter ::= SEQUENCE
+ {
+ statName PkgdName,
+ statValue Value OPTIONAL
+ }
+
+-- If statistic consists of a sub-list there will be more than one
+-- octetstring in statValue.
+
+NonStandardData ::= SEQUENCE
+ {
+ nonStandardIdentifier NonStandardIdentifier,
+ data OCTET STRING
+ }
+
+NonStandardIdentifier ::= CHOICE
+ {
+ object OBJECT IDENTIFIER,
+ h221NonStandard H221NonStandard,
+ experimental IA5String(SIZE(8)),
+ -- first two characters SHOULD be "X-" or "X+"
+ ...
+ }
+
+H221NonStandard ::= SEQUENCE
+ { t35CountryCode1 INTEGER(0..255),
+ t35CountryCode2 INTEGER(0..255), -- country, as per T.35
+ t35Extension INTEGER(0..255), -- assigned nationally
+ manufacturerCode INTEGER(0..65535), -- assigned nationally
+ ...
+ }
+
+TimeNotation ::= SEQUENCE
+ {
+ date IA5String(SIZE(8)), -- yyyymmdd format
+ time IA5String(SIZE(8)) -- hhmmssss format
+ -- per ISO 8601:1988
+ }
+
+Value ::= SEQUENCE OF OCTET STRING
+
+END
diff --git a/lib/megaco/src/binary/MEDIA-GATEWAY-CONTROL-v1.asn b/lib/megaco/src/binary/MEDIA-GATEWAY-CONTROL-v1.asn
new file mode 100644
index 0000000000..717517938f
--- /dev/null
+++ b/lib/megaco/src/binary/MEDIA-GATEWAY-CONTROL-v1.asn
@@ -0,0 +1,982 @@
+-- This ASN.1 spec has been extracted from the Megaco/H.248 spec
+-- http://www.ietf.org/internet-drafts/draft-ietf-megaco-merged-01.txt
+--
+-- o Removed stuff named nonStandard
+-- o Major enhancements of the indentation has been performed.
+--
+-- Hakan Mattsson <[email protected]>
+--
+-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
+-- ANNEX A: BINARY ENCODING OF THE PROTOCOL (NORMATIVE)
+-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
+--
+-- This Annex specifies the syntax of messages using the notation
+-- defined in ASN.1 [ITU-T Recommendation X.680 (1997): Information
+-- Technology - Abstract Syntax Notation One (ASN.1) - Specification of
+-- basic notation.]. Messages shall be encoded for transmission by
+-- applying the basic encoding rules specified in [ITU-T Recommendation
+-- X.690(1994) Information Technology - ASN.1 Encoding Rules:
+-- Specification of Basic Encoding Rules (BER)].
+--
+-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
+-- A.1 Coding of wildcards
+-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
+--
+-- The use of wildcards ALL and CHOOSE is allowed in the protocol.
+-- This allows a MGC to partially specify Termination IDs and let the
+-- MG choose from the values that conform to the partial specification.
+-- Termination IDs may encode a hierarchy of names. This hierarchy is
+-- provisioned. For instance, a TerminationID may consist of a trunk
+-- group, a trunk within the group and a circuit. Wildcarding must be
+-- possible at all levels. The following paragraphs explain how this
+-- is achieved.
+--
+-- The ASN.1 description uses octet strings of up to 8 octets in length
+-- for Termination IDs. This means that Termination IDs consist of at
+-- most 64 bits. A fully specified Termination ID may be preceded by a
+-- sequence of wildcarding fields. A wildcarding field is one octet in
+-- length. Bit 7 (the most significant bit) of this octet specifies
+-- what type of wildcarding is invoked: if the bit value equals 1,
+-- then the ALL wildcard is used; if the bit value if 0, then the
+-- CHOOSE wildcard is used. Bit 6 of the wildcarding field specifies
+-- whether the wildcarding pertains to one level in the hierarchical
+-- naming scheme (bit value 0) or to the level of the hierarchy
+-- specified in the wildcarding field plus all lower levels (bit value
+-- 1). Bits 0 through 5 of the wildcarding field specify the bit
+-- position in the Termination ID at which the starts.
+--
+-- We illustrate this scheme with some examples. In these examples,
+-- the most significant bit in a string of bits appears on the left
+-- hand side.
+--
+-- Assume that Termination IDs are three octets long and that each
+-- octet represents a level in a hierarchical naming scheme. A valid
+-- Termination ID is
+-- 00000001 00011110 01010101.
+--
+-- Addressing ALL names with prefix 00000001 00011110 is done as
+-- follows:
+-- wildcarding field: 10000111
+-- Termination ID: 00000001 00011110 xxxxxxxx.
+--
+-- The values of the bits labeled "x" is irrelevant and shall be
+-- ignored by the receiver.
+--
+-- Indicating to the receiver that is must choose a name with 00011110
+-- as the second octet is done as follows:
+-- wildcarding fields: 00010111 followed by 00000111
+-- Termination ID: xxxxxxxx 00011110 xxxxxxxx.
+--
+-- The first wildcard field indicates a CHOOSE wildcard for the level
+-- in the naming hierarchy starting at bit 23, the highest level in our
+-- assumed naming scheme. The second wildcard field indicates a CHOOSE
+-- wildcard for the level in the naming hierarchy starting at bit 7,
+-- the lowest level in our assumed naming scheme.
+--
+-- Finally, a CHOOSE-wildcarded name with the highest level of the name
+-- equal to 00000001 is specified as follows:
+-- wildcard field: 01001111
+-- Termination ID: 0000001 xxxxxxxx xxxxxxxx .
+--
+-- Bit value 1 at bit position 6 of the first octet of the wildcard
+-- field indicates that the wildcarding pertains to the specified level
+-- in the naming hierarchy and all lower levels.
+--
+-- Context IDs may also be wildcarded. In the case of Context IDs,
+-- however, specifying partial names is not allowed. Context ID 0x0
+-- SHALL be used to indicate the NULL Context, Context ID 0xFFFFFFFE
+-- SHALL be used to indicate a CHOOSE wildcard, and Context ID
+-- 0xFFFFFFFF SHALL be used to indicate an ALL wildcard.
+--
+-- TerminationID 0xFFFFFFFFFFFFFFFF SHALL be used to indicate the ROOT
+-- Termination.
+--
+-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
+-- Digit maps and path names
+-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
+--
+-- From a syntactic viewpoint, digit maps are strings with syntactic
+-- restrictions imposed upon them. The syntax of valid digit maps is
+-- specified in ABNF [RFC 2234]. The syntax for digit maps presented
+-- in this section is for illustrative purposes only. The definition of
+-- digitMap in Annex B takes precedence in the case of differences
+-- between the two.
+--
+-- digitMap = (digitString / LWSP "(" LWSP digitStringList LWSP ")"
+-- LWSP)
+-- digitStringList = digitString *( LWSP "/" LWSP digitString )
+-- digitString = 1*(digitStringElement)
+-- digitStringElement = digitPosition [DOT]
+-- digitPosition = digitMapLetter / digitMapRange
+-- digitMapRange = ("x" / LWSP "[" LWSP digitLetter LWSP "]" LWSP)
+-- digitLetter = *((DIGIT "-" DIGIT) /digitMapLetter)
+-- digitMapLetter = DIGIT ;digits 0-9
+-- / %x41-4B / %x61-6B ;a-k and A-K
+-- / "L" / "S" ;Inter-event timers
+-- ;(long, short)
+-- / "Z" ;Long duration event
+-- DOT = %x2E ; "."
+-- LWSP = *(WSP / COMMENT / EOL)
+-- WSP = SP / HTAB
+-- COMMENT = ";" *(SafeChar / RestChar / WSP) EOL
+-- EOL = (CR [LF]) / LF
+-- SP = %x20
+-- HTAB = %x09
+-- CR = %x0D
+-- LF = %x0A
+-- SafeChar = DIGIT / ALPHA / "+" / "-" / "&" / "!" / "_" / "/" /
+-- "'" / "?" / "@" / "^" / "`" / "~" / "*" / "$" / "\" /
+-- "(" / ")" / "%" / "."
+-- RestChar = ";" / "[" / "]" / "{" / "}" / ":" / "," / "#" /
+-- "<" / ">" / "=" / %x22
+-- DIGIT = %x30-39 ; digits 0 through 9
+-- ALPHA = %x41-5A / %x61-7A ; A-Z, a-z
+-- A path name is also a string with syntactic restrictions imposed
+-- upon it. The ABNF production defining it is copied from Annex B.
+--
+-- PathName = NAME *(["/"] ["*"] ["@"] (ALPHA / DIGIT)) ["*"]
+-- NAME = ALPHA *63(ALPHA / DIGIT / "_" )
+--
+-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
+-- A.2 ASN.1 syntax specification
+-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
+--
+-- This section contains the ASN.1 specification of the H.248 protocol
+-- syntax.
+--
+-- NOTE - In case a transport mechanism is used that employs
+-- application level framing, the definition of Transaction below
+-- changes. Refer to the annex defining the transport mechanism for
+-- the definition that applies in that case.
+--
+-- NOTE - The ASN.1 specification below contains a clause defining
+-- TerminationIDList as a sequence of TerminationIDs. The length of
+-- this sequence SHALL be one, except possibly when used in
+-- contextAuditResult.
+-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
+
+MEDIA-GATEWAY-CONTROL-v1
+DEFINITIONS AUTOMATIC TAGS ::=
+BEGIN
+
+MegacoMessage ::= SEQUENCE
+{
+ authHeader AuthenticationHeader OPTIONAL,
+ mess Message
+}
+
+AuthenticationHeader ::= SEQUENCE
+{
+ secParmIndex SecurityParmIndex,
+ seqNum SequenceNum,
+ ad AuthData
+}
+
+SecurityParmIndex ::= OCTET STRING(SIZE(4))
+
+SequenceNum ::= OCTET STRING(SIZE(4))
+
+AuthData ::= OCTET STRING (SIZE (12..32))
+
+Message ::= SEQUENCE
+{
+ version INTEGER(0..99),
+ -- The version of the protocol defined here is equal to 1.
+ mId MId, -- Name/address of message originator
+ messageBody CHOICE
+ {
+ messageError ErrorDescriptor,
+ transactions SEQUENCE OF Transaction
+ },
+ ...
+}
+
+MId ::= CHOICE
+{
+ ip4Address IP4Address,
+ ip6Address IP6Address,
+ domainName DomainName,
+ deviceName PathName,
+ mtpAddress OCTET STRING(SIZE(2..4)),
+ -- Addressing structure of mtpAddress:
+ -- 15 0
+ -- | PC | NI |
+ -- 14 bits 2 bits
+ ...
+}
+
+DomainName ::= SEQUENCE
+{
+ name IA5String,
+ -- The name starts with an alphanumeric digit followed by a
+ -- sequence of alphanumeric digits, hyphens and dots. No two
+ -- dots shall occur consecutively.
+ portNumber INTEGER(0..65535) OPTIONAL
+}
+
+IP4Address ::= SEQUENCE
+{
+ address OCTET STRING (SIZE(4)),
+ portNumber INTEGER(0..65535) OPTIONAL
+}
+
+IP6Address ::= SEQUENCE
+{
+ address OCTET STRING (SIZE(16)),
+ portNumber INTEGER(0..65535) OPTIONAL
+}
+
+PathName ::= IA5String(SIZE (1..64))
+-- See section A.3
+
+Transaction ::= CHOICE
+{
+ transactionRequest TransactionRequest,
+ transactionPending TransactionPending,
+ transactionReply TransactionReply,
+ transactionResponseAck TransactionResponseAck,
+ -- use of response acks is dependent on underlying transport
+ ...
+}
+
+TransactionId ::= INTEGER(0..4294967295) -- 32 bit unsigned integer
+
+TransactionRequest ::= SEQUENCE
+{
+ transactionId TransactionId,
+ actions SEQUENCE OF ActionRequest,
+ ...
+}
+
+TransactionPending ::= SEQUENCE
+{
+ transactionId TransactionId,
+ ...
+}
+
+TransactionReply ::= SEQUENCE
+{
+ transactionId TransactionId,
+ immAckRequired NULL OPTIONAL,
+ transactionResult CHOICE
+ {
+ transactionError ErrorDescriptor,
+ actionReplies SEQUENCE OF ActionReply
+ },
+ ...
+}
+
+TransactionResponseAck ::= SEQUENCE OF TransactionAck
+
+TransactionAck ::= SEQUENCE
+{
+ firstAck TransactionId,
+ lastAck TransactionId OPTIONAL
+}
+
+ErrorDescriptor ::= SEQUENCE
+{
+ errorCode ErrorCode,
+ errorText ErrorText OPTIONAL
+}
+
+ErrorCode ::= INTEGER(0..65535)
+-- See section 13 for IANA considerations w.r.t. error codes
+
+ErrorText ::= IA5String
+
+ContextID ::= INTEGER(0..4294967295)
+
+-- Context NULL Value: 0
+-- Context CHOOSE Value: 4294967294 (0xFFFFFFFE)
+-- Context ALL Value: 4294967295 (0xFFFFFFFF)
+
+
+ActionRequest ::= SEQUENCE
+{
+ contextId ContextID,
+ contextRequest ContextRequest OPTIONAL,
+ contextAttrAuditReq ContextAttrAuditRequest OPTIONAL,
+ commandRequests SEQUENCE OF CommandRequest
+}
+
+ActionReply ::= SEQUENCE
+{
+ contextId ContextID,
+ errorDescriptor ErrorDescriptor OPTIONAL,
+ contextReply ContextRequest OPTIONAL,
+ commandReply SEQUENCE OF CommandReply
+}
+
+ContextRequest ::= SEQUENCE
+{
+ priority INTEGER(0..15) OPTIONAL,
+ emergency BOOLEAN OPTIONAL,
+ topologyReq SEQUENCE OF TopologyRequest OPTIONAL,
+ ...
+}
+
+ContextAttrAuditRequest ::= SEQUENCE
+{
+ topology NULL OPTIONAL,
+ emergency NULL OPTIONAL,
+ priority NULL OPTIONAL,
+ ...
+}
+
+CommandRequest ::= SEQUENCE
+{
+ command Command,
+ optional NULL OPTIONAL,
+ wildcardReturn NULL OPTIONAL,
+ ...
+}
+
+Command ::= CHOICE
+{
+ addReq AmmRequest,
+ moveReq AmmRequest,
+ modReq AmmRequest,
+ -- Add, Move, Modify requests have the same parameters
+ subtractReq SubtractRequest,
+ auditCapRequest AuditRequest,
+ auditValueRequest AuditRequest,
+ notifyReq NotifyRequest,
+ serviceChangeReq ServiceChangeRequest,
+ ...
+}
+
+CommandReply ::= CHOICE
+{
+ addReply AmmsReply,
+ moveReply AmmsReply,
+ modReply AmmsReply,
+ subtractReply AmmsReply,
+ -- Add, Move, Modify, Subtract replies have the same parameters
+ auditCapReply AuditReply,
+ auditValueReply AuditReply,
+ notifyReply NotifyReply,
+ serviceChangeReply ServiceChangeReply,
+ ...
+}
+
+TopologyRequest ::= SEQUENCE
+{
+ terminationFrom TerminationID,
+ terminationTo TerminationID,
+ topologyDirection ENUMERATED
+ {
+ bothway(0),
+ isolate(1),
+ oneway(2)
+ }
+}
+
+AmmRequest ::= SEQUENCE
+{
+ terminationID TerminationIDList,
+ descriptors SEQUENCE OF AmmDescriptor,
+ -- At most one descriptor of each type (see AmmDescriptor)
+ -- allowed in the sequence.
+ ...
+}
+
+AmmDescriptor ::= CHOICE
+{
+ mediaDescriptor MediaDescriptor,
+ modemDescriptor ModemDescriptor,
+ muxDescriptor MuxDescriptor,
+ eventsDescriptor EventsDescriptor,
+ eventBufferDescriptor EventBufferDescriptor,
+ signalsDescriptor SignalsDescriptor,
+ digitMapDescriptor DigitMapDescriptor,
+ auditDescriptor AuditDescriptor,
+...
+}
+
+AmmsReply ::= SEQUENCE
+{
+ terminationID TerminationIDList,
+ terminationAudit TerminationAudit OPTIONAL,
+ ...
+}
+
+SubtractRequest ::= SEQUENCE
+{
+ terminationID TerminationIDList,
+ auditDescriptor AuditDescriptor OPTIONAL,
+ ...
+}
+
+AuditRequest ::= SEQUENCE
+{
+ terminationID TerminationID,
+ auditDescriptor AuditDescriptor,
+ ...
+}
+
+AuditReply ::= CHOICE
+{
+ contextAuditResult TerminationIDList,
+ error ErrorDescriptor,
+ auditResult AuditResult,
+ ...
+}
+
+AuditResult ::= SEQUENCE
+{
+ terminationID TerminationID,
+ terminationAuditResult TerminationAudit
+}
+
+TerminationAudit ::= SEQUENCE OF AuditReturnParameter
+
+AuditReturnParameter ::= CHOICE
+{
+ errorDescriptor ErrorDescriptor,
+ mediaDescriptor MediaDescriptor,
+ modemDescriptor ModemDescriptor,
+ muxDescriptor MuxDescriptor,
+ eventsDescriptor EventsDescriptor,
+ eventBufferDescriptor EventBufferDescriptor,
+ signalsDescriptor SignalsDescriptor,
+ digitMapDescriptor DigitMapDescriptor,
+ observedEventsDescriptor ObservedEventsDescriptor,
+ statisticsDescriptor StatisticsDescriptor,
+ packagesDescriptor PackagesDescriptor,
+ emptyDescriptors AuditDescriptor,
+ ...
+}
+
+AuditDescriptor ::= SEQUENCE
+{
+ auditToken BIT STRING
+ {
+ muxToken(0),
+ modemToken(1),
+ mediaToken(2),
+ eventsToken(3),
+ signalsToken(4),
+ digitMapToken(5),
+ statsToken(6),
+ observedEventsToken(7),
+ packagesToken(8),
+ eventBufferToken(9)
+ } OPTIONAL,
+ ...
+}
+
+NotifyRequest ::= SEQUENCE
+{
+ terminationID TerminationIDList,
+ observedEventsDescriptor ObservedEventsDescriptor,
+ errorDescriptor ErrorDescriptor OPTIONAL,
+ ...
+}
+
+NotifyReply ::= SEQUENCE
+{
+ terminationID TerminationIDList,
+ errorDescriptor ErrorDescriptor OPTIONAL,
+ ...
+}
+
+ObservedEventsDescriptor ::= SEQUENCE
+{
+ requestId RequestID,
+ observedEventLst SEQUENCE OF ObservedEvent
+}
+
+ObservedEvent ::= SEQUENCE
+{
+ eventName EventName,
+ streamID StreamID OPTIONAL,
+ eventParList SEQUENCE OF EventParameter,
+ timeNotation TimeNotation OPTIONAL,
+ ...
+}
+
+EventName ::= PkgdName
+
+EventParameter ::= SEQUENCE
+{
+ eventParameterName Name,
+ value Value,
+ -- For use of extraInfo see the comment related to propertyParm
+ extraInfo CHOICE
+ {
+ relation Relation,
+ range BOOLEAN,
+ sublist BOOLEAN
+ } OPTIONAL,
+ ...
+}
+
+ServiceChangeRequest ::= SEQUENCE
+{
+ terminationID TerminationIDList,
+ serviceChangeParms ServiceChangeParm,
+ ...
+}
+
+ServiceChangeReply ::= SEQUENCE
+{
+ terminationID TerminationIDList,
+ serviceChangeResult ServiceChangeResult,
+ ...
+}
+
+-- For ServiceChangeResult, no parameters are mandatory. Hence the
+-- distinction between ServiceChangeParm and ServiceChangeResParm.
+
+ServiceChangeResult ::= CHOICE
+{
+ errorDescriptor ErrorDescriptor,
+ serviceChangeResParms ServiceChangeResParm
+}
+
+WildcardField ::= OCTET STRING(SIZE(1))
+
+TerminationID ::= SEQUENCE
+{
+ wildcard SEQUENCE OF WildcardField,
+ id OCTET STRING(SIZE(1..8)),
+ ...
+}
+-- See Section A.1 for explanation of wildcarding mechanism.
+-- Termination ID 0xFFFFFFFFFFFFFFFF indicates the ROOT Termination.
+
+TerminationIDList ::= SEQUENCE OF TerminationID
+
+MediaDescriptor ::= SEQUENCE
+{
+
+ termStateDescr TerminationStateDescriptor OPTIONAL,
+ streams CHOICE
+ {
+ oneStream StreamParms,
+ multiStream SEQUENCE OF StreamDescriptor
+ } OPTIONAL,
+ ...
+}
+
+StreamDescriptor ::= SEQUENCE
+{
+ streamID StreamID,
+ streamParms StreamParms
+}
+
+StreamParms ::= SEQUENCE
+{
+ localControlDescriptor LocalControlDescriptor OPTIONAL,
+ localDescriptor LocalRemoteDescriptor OPTIONAL,
+ remoteDescriptor LocalRemoteDescriptor OPTIONAL,
+ ...
+}
+
+LocalControlDescriptor ::= SEQUENCE
+{
+ streamMode StreamMode OPTIONAL,
+ reserveValue BOOLEAN OPTIONAL,
+ reserveGroup BOOLEAN OPTIONAL,
+ propertyParms SEQUENCE OF PropertyParm,
+ ...
+}
+
+StreamMode ::= ENUMERATED
+{
+ sendOnly(0),
+ recvOnly(1),
+ sendRecv(2),
+ inactive(3),
+ loopBack(4),
+ ...
+}
+
+-- In PropertyParm, value is a SEQUENCE OF octet string. When sent
+-- by an MGC the interpretation is as follows:
+-- empty sequence means CHOOSE
+-- one element sequence specifies value
+-- If the sublist field is not selected, a longer sequence means
+-- "choose one of the values" (i.e. value1 OR value2 OR ...)
+-- If the sublist field is selected,
+-- a sequence with more than one element encodes the value of a
+-- list-valued property (i.e. value1 AND value2 AND ...).
+-- The relation field may only be selected if the value sequence
+-- has length 1. It indicates that the MG has to choose a value
+-- for the property. E.g., x > 3 (using the greaterThan
+-- value for relation) instructs the MG to choose any value larger
+-- than 3 for property x.
+-- The range field may only be selected if the value sequence
+-- has length 2. It indicates that the MG has to choose a value
+-- in the range between the first octet in the value sequence and
+-- the trailing octet in the value sequence, including the
+-- boundary values.
+-- When sent by the MG, only responses to an AuditCapability request
+-- may contain multiple values, a range, or a relation field.
+
+PropertyParm ::= SEQUENCE
+{
+ name PkgdName,
+ value SEQUENCE OF OCTET STRING,
+ extraInfo CHOICE
+ {
+ relation Relation,
+ range BOOLEAN,
+ sublist BOOLEAN
+ } OPTIONAL,
+ ...
+}
+
+Name ::= OCTET STRING(SIZE(2))
+
+PkgdName ::= OCTET STRING(SIZE(4))
+-- represents Package Name (2 octets) plus Property Name (2 octets)
+-- To wildcard a package use 0xFFFF for first two octets, choose
+-- is not allowed. To reference native property tag specified in
+-- Annex C, use 0x0000 as first two octets.
+-- Wildcarding of Package Name is permitted only if Property Name is
+-- also wildcarded.
+
+Relation ::= ENUMERATED
+{
+ greaterThan(0),
+ smallerThan(1),
+ unequalTo(2),
+ ...
+}
+
+LocalRemoteDescriptor ::= SEQUENCE
+{
+ propGrps SEQUENCE OF PropertyGroup,
+ ...
+}
+
+PropertyGroup ::= SEQUENCE OF PropertyParm
+
+TerminationStateDescriptor ::= SEQUENCE
+{
+ propertyParms SEQUENCE OF PropertyParm,
+ eventBufferControl EventBufferControl OPTIONAL,
+ serviceState ServiceState OPTIONAL,
+ ...
+}
+
+EventBufferControl ::= ENUMERATED
+{
+ off(0),
+ lockStep(1),
+ ...
+}
+
+ServiceState ::= ENUMERATED
+{
+ test(0),
+ outOfSvc(1),
+ inSvc(2),
+ ...
+}
+
+MuxDescriptor ::= SEQUENCE
+{
+ muxType MuxType,
+ termList SEQUENCE OF TerminationID,
+ nonStandardData NonStandardData OPTIONAL,
+ ...
+}
+
+MuxType ::= ENUMERATED
+{
+ h221(0),
+ h223(1),
+ h226(2),
+ v76(3),
+ ...
+}
+
+StreamID ::= INTEGER(0..65535) -- 16 bit unsigned integer
+
+EventsDescriptor ::= SEQUENCE
+{
+ requestID RequestID,
+ -- IG 6.82 was withdrawn
+ -- requestID RequestID OPTIONAL,
+ -- RequestID must be present if eventList is non empty
+ eventList SEQUENCE OF RequestedEvent,
+ ...
+}
+
+RequestedEvent ::= SEQUENCE
+{
+ pkgdName PkgdName,
+ streamID StreamID OPTIONAL,
+ eventAction RequestedActions OPTIONAL,
+ evParList SEQUENCE OF EventParameter,
+ ...
+}
+
+RequestedActions ::= SEQUENCE
+{
+ keepActive BOOLEAN OPTIONAL,
+ eventDM EventDM OPTIONAL,
+ secondEvent SecondEventsDescriptor OPTIONAL,
+ signalsDescriptor SignalsDescriptor OPTIONAL,
+ ...
+}
+
+
+EventDM ::= CHOICE
+{
+ digitMapName DigitMapName,
+ digitMapValue DigitMapValue
+}
+
+SecondEventsDescriptor ::= SEQUENCE
+{
+ requestID RequestID,
+ -- IG 6.82 was withdrawn
+ -- requestID RequestID OPTIONAL,
+ -- RequestID must be present if eventList is non empty
+ eventList SEQUENCE OF SecondRequestedEvent,
+ ...
+}
+
+SecondRequestedEvent ::= SEQUENCE
+{
+ pkgdName PkgdName,
+ streamID StreamID OPTIONAL,
+ eventAction SecondRequestedActions OPTIONAL,
+ evParList SEQUENCE OF EventParameter,
+ ...
+}
+
+SecondRequestedActions ::= SEQUENCE
+{
+ keepActive BOOLEAN OPTIONAL,
+ eventDM EventDM OPTIONAL,
+ signalsDescriptor SignalsDescriptor OPTIONAL,
+ ...
+}
+
+EventBufferDescriptor ::= SEQUENCE OF EventSpec
+
+EventSpec ::= SEQUENCE
+{
+ eventName EventName,
+ streamID StreamID OPTIONAL,
+ eventParList SEQUENCE OF EventParameter,
+ ...
+}
+
+SignalsDescriptor ::= SEQUENCE OF SignalRequest
+
+SignalRequest ::= CHOICE
+{
+ signal Signal,
+ seqSigList SeqSigList,
+ ...
+}
+
+SeqSigList ::= SEQUENCE
+{
+ id INTEGER(0..65535),
+ signalList SEQUENCE OF Signal
+}
+
+Signal ::= SEQUENCE
+{
+ signalName SignalName,
+ streamID StreamID OPTIONAL,
+ sigType SignalType OPTIONAL,
+ duration INTEGER (0..65535) OPTIONAL,
+ notifyCompletion NotifyCompletion OPTIONAL,
+ keepActive BOOLEAN OPTIONAL,
+ sigParList SEQUENCE OF SigParameter,
+ ...
+}
+
+SignalType ::= ENUMERATED
+{
+ brief(0),
+ onOff(1),
+ timeOut(2),
+ ...
+}
+
+SignalName ::= PkgdName
+
+NotifyCompletion ::= BIT STRING
+{
+ onTimeOut(0),
+ onInterruptByEvent(1),
+ onInterruptByNewSignalDescr(2),
+ otherReason(3)
+}
+
+SigParameter ::= SEQUENCE
+{
+ sigParameterName Name,
+ value Value,
+ -- For use of extraInfo see the comment related to propertyParm
+ extraInfo CHOICE
+ {
+ relation Relation,
+ range BOOLEAN,
+ sublist BOOLEAN
+ } OPTIONAL,
+ ...
+}
+
+RequestID ::= INTEGER(0..4294967295) -- 32 bit unsigned integer
+-- Request ALL Value: 4294967295 (0xFFFFFFFF)
+
+ModemDescriptor ::= SEQUENCE
+{
+ mtl SEQUENCE OF ModemType,
+ mpl SEQUENCE OF PropertyParm,
+ nonStandardData NonStandardData OPTIONAL
+}
+
+ModemType ::= ENUMERATED
+{
+ v18(0),
+ v22(1),
+ v22bis(2),
+ v32(3),
+ v32bis(4),
+ v34(5),
+ v90(6),
+ v91(7),
+ synchISDN(8),
+ ...
+}
+
+DigitMapDescriptor ::= SEQUENCE
+{
+ digitMapName DigitMapName OPTIONAL,
+ digitMapValue DigitMapValue OPTIONAL
+}
+
+DigitMapName ::= Name
+
+DigitMapValue ::= SEQUENCE
+{
+ startTimer INTEGER(0..99) OPTIONAL,
+ shortTimer INTEGER(0..99) OPTIONAL,
+ longTimer INTEGER(0..99) OPTIONAL,
+ digitMapBody IA5String,
+ -- See Section A.3 for explanation of digit map syntax
+ ...
+}
+
+ServiceChangeParm ::= SEQUENCE
+{
+ serviceChangeMethod ServiceChangeMethod,
+ serviceChangeAddress ServiceChangeAddress OPTIONAL,
+ serviceChangeVersion INTEGER(0..99) OPTIONAL,
+ serviceChangeProfile ServiceChangeProfile OPTIONAL,
+ serviceChangeReason Value,
+ serviceChangeDelay INTEGER(0..4294967295) OPTIONAL,
+ -- 32 bit unsigned integer
+ serviceChangeMgcId MId OPTIONAL,
+ timeStamp TimeNotation OPTIONAL,
+ nonStandardData NonStandardData OPTIONAL,
+ ...
+}
+
+ServiceChangeAddress ::= CHOICE
+{
+ portNumber INTEGER(0..65535), -- TCP/UDP port number
+ ip4Address IP4Address,
+ ip6Address IP6Address,
+ domainName DomainName,
+ deviceName PathName,
+ mtpAddress OCTET STRING(SIZE(2..4)),
+ ...
+}
+
+ServiceChangeResParm ::= SEQUENCE
+{
+ serviceChangeMgcId MId OPTIONAL,
+ serviceChangeAddress ServiceChangeAddress OPTIONAL,
+ serviceChangeVersion INTEGER(0..99) OPTIONAL,
+ serviceChangeProfile ServiceChangeProfile OPTIONAL,
+ timeStamp TimeNotation OPTIONAL,
+ ...
+}
+
+ServiceChangeMethod ::= ENUMERATED
+{
+ failover(0),
+ forced(1),
+ graceful(2),
+ restart(3),
+ disconnected(4),
+ handOff(5),
+ ...
+}
+
+ServiceChangeProfile ::= SEQUENCE
+{
+ profileName IA5String(SIZE (1..67))
+ -- 64 characters for name, 1 for "/", 2 for version to match ABNF
+}
+
+-- ServiceChangeProfile ::= SEQUENCE
+-- {
+-- profileName Name,
+-- version INTEGER(0..99)
+-- }
+
+PackagesDescriptor ::= SEQUENCE OF PackagesItem
+
+PackagesItem ::= SEQUENCE
+{
+ packageName Name,
+ packageVersion INTEGER(0..99),
+ ...
+}
+
+StatisticsDescriptor ::= SEQUENCE OF StatisticsParameter
+
+StatisticsParameter ::= SEQUENCE
+{
+ statName PkgdName,
+ statValue Value OPTIONAL
+}
+
+NonStandardData ::= SEQUENCE
+{
+ nonStandardIdentifier NonStandardIdentifier,
+ data OCTET STRING
+}
+
+NonStandardIdentifier ::= CHOICE
+{
+ object OBJECT IDENTIFIER,
+ h221NonStandard H221NonStandard,
+ experimental IA5String(SIZE(8)),
+ -- first two characters should be "X-" or "X+"
+ ...
+}
+
+H221NonStandard ::= SEQUENCE
+{
+ t35CountryCode1 INTEGER(0..255),
+ t35CountryCode2 INTEGER(0..255), -- country, as per T.35
+ t35Extension INTEGER(0..255), -- assigned nationally
+ manufacturerCode INTEGER(0..65535), -- assigned nationally
+ ...
+}
+
+TimeNotation ::= SEQUENCE
+{
+ date IA5String(SIZE(8)), -- yyyymmdd format
+ time IA5String(SIZE(8)) -- hhmmssss format
+}
+
+Value ::= SEQUENCE OF OCTET STRING
+
+
+END
+
diff --git a/lib/megaco/src/binary/MEDIA-GATEWAY-CONTROL-v2.asn b/lib/megaco/src/binary/MEDIA-GATEWAY-CONTROL-v2.asn
new file mode 100644
index 0000000000..b75925b30e
--- /dev/null
+++ b/lib/megaco/src/binary/MEDIA-GATEWAY-CONTROL-v2.asn
@@ -0,0 +1,966 @@
+MEDIA-GATEWAY-CONTROL-v2
+{itu-t(0) recommendation(0) h(8) h248(248)
+ modules(0) media-gateway-control(0) version2(2)}
+DEFINITIONS AUTOMATIC TAGS ::=
+BEGIN
+
+
+MegacoMessage ::= SEQUENCE
+ {
+ authHeader AuthenticationHeader OPTIONAL,
+ mess Message
+ }
+
+AuthenticationHeader ::= SEQUENCE
+ {
+ secParmIndex SecurityParmIndex,
+ seqNum SequenceNum,
+ ad AuthData
+ }
+
+SecurityParmIndex ::= OCTET STRING(SIZE(4))
+
+SequenceNum ::= OCTET STRING(SIZE(4))
+
+AuthData ::= OCTET STRING (SIZE (12..32))
+
+Message ::= SEQUENCE
+ {
+ version INTEGER(0..99),
+ -- The version of the protocol defined here is equal to 2.
+ mId MId, -- Name/address of message originator
+ messageBody CHOICE
+ {
+ messageError ErrorDescriptor,
+ transactions SEQUENCE OF Transaction
+ },
+ ...
+ }
+
+MId ::= CHOICE
+ {
+ ip4Address IP4Address,
+ ip6Address IP6Address,
+ domainName DomainName,
+ deviceName PathName,
+ mtpAddress OCTET STRING(SIZE(2..4)),
+ -- Addressing structure of mtpAddress:
+ -- 25 - 15 0
+ -- | PC | NI |
+ -- 24 - 14 bits 2 bits
+ -- Note: 14 bits are defined for international use.
+ -- Two national options exist where the point code is 16 or 24
+ -- bits.
+ -- To octet align the mtpAddress, the MSBs shall be encoded as 0s.
+ ...
+ }
+
+DomainName ::= SEQUENCE
+ {
+ name IA5String,
+ -- The name starts with an alphanumeric digit followed by a
+ -- sequence of alphanumeric digits, hyphens and dots. No two
+ -- dots shall occur consecutively.
+ portNumber INTEGER(0..65535) OPTIONAL
+ }
+
+IP4Address ::= SEQUENCE
+ {
+ address OCTET STRING (SIZE(4)),
+ portNumber INTEGER(0..65535) OPTIONAL
+ }
+
+IP6Address ::= SEQUENCE
+ {
+ address OCTET STRING (SIZE(16)),
+ portNumber INTEGER(0..65535) OPTIONAL
+ }
+
+PathName ::= IA5String(SIZE (1..64))
+-- See A.3
+
+Transaction ::= CHOICE
+ {
+ transactionRequest TransactionRequest,
+ transactionPending TransactionPending,
+ transactionReply TransactionReply,
+ transactionResponseAck TransactionResponseAck,
+ -- use of response acks is dependent on underlying transport
+ ...
+ }
+
+TransactionId ::= INTEGER(0..4294967295) -- 32-bit unsigned integer
+
+TransactionRequest ::= SEQUENCE
+ {
+ transactionId TransactionId,
+ actions SEQUENCE OF ActionRequest,
+ ...
+ }
+
+TransactionPending ::= SEQUENCE
+ {
+ transactionId TransactionId,
+ ...
+ }
+
+TransactionReply ::= SEQUENCE
+ {
+ transactionId TransactionId,
+ immAckRequired NULL OPTIONAL,
+ transactionResult CHOICE
+ {
+ transactionError ErrorDescriptor,
+ actionReplies SEQUENCE OF ActionReply
+ },
+ ...
+ }
+
+TransactionResponseAck ::= SEQUENCE OF TransactionAck
+TransactionAck ::= SEQUENCE
+ {
+ firstAck TransactionId,
+ lastAck TransactionId OPTIONAL
+ }
+
+ErrorDescriptor ::= SEQUENCE
+ {
+ errorCode ErrorCode,
+ errorText ErrorText OPTIONAL
+ }
+
+ErrorCode ::= INTEGER(0..65535)
+-- See clause 14 for IANA considerations with respect to error codes
+ErrorText ::= IA5String
+
+ContextID ::= INTEGER(0..4294967295)
+
+-- Context NULL Value: 0
+-- Context CHOOSE Value: 4294967294 (0xFFFFFFFE)
+-- Context ALL Value: 4294967295 (0xFFFFFFFF)
+
+
+ActionRequest ::= SEQUENCE
+ {
+ contextId ContextID,
+ contextRequest ContextRequest OPTIONAL,
+ contextAttrAuditReq ContextAttrAuditRequest OPTIONAL,
+ commandRequests SEQUENCE OF CommandRequest
+ }
+
+ActionReply ::= SEQUENCE
+ {
+ contextId ContextID,
+ errorDescriptor ErrorDescriptor OPTIONAL,
+ contextReply ContextRequest OPTIONAL,
+ commandReply SEQUENCE OF CommandReply
+ }
+
+ContextRequest ::= SEQUENCE
+ {
+ priority INTEGER(0..15) OPTIONAL,
+ emergency BOOLEAN OPTIONAL,
+ topologyReq SEQUENCE OF TopologyRequest OPTIONAL,
+ ...
+ }
+
+ContextAttrAuditRequest ::= SEQUENCE
+ {
+ topology NULL OPTIONAL,
+ emergency NULL OPTIONAL,
+ priority NULL OPTIONAL,
+ ...
+ }
+
+CommandRequest ::= SEQUENCE
+ {
+ command Command,
+ optional NULL OPTIONAL,
+ wildcardReturn NULL OPTIONAL,
+ ...
+ }
+
+Command ::= CHOICE
+ {
+ addReq AmmRequest,
+ moveReq AmmRequest,
+ modReq AmmRequest,
+ -- Add, Move, Modify requests have the same parameters
+ subtractReq SubtractRequest,
+ auditCapRequest AuditRequest,
+ auditValueRequest AuditRequest,
+ notifyReq NotifyRequest,
+ serviceChangeReq ServiceChangeRequest,
+ ...
+ }
+
+CommandReply ::= CHOICE
+ {
+ addReply AmmsReply,
+ moveReply AmmsReply,
+ modReply AmmsReply,
+ subtractReply AmmsReply,
+ -- Add, Move, Modify, Subtract replies have the same parameters
+ auditCapReply AuditReply,
+ auditValueReply AuditReply,
+ notifyReply NotifyReply,
+ serviceChangeReply ServiceChangeReply,
+ ...
+ }
+
+TopologyRequest ::= SEQUENCE
+ {
+ terminationFrom TerminationID,
+ terminationTo TerminationID,
+ topologyDirection ENUMERATED
+ {
+ bothway(0),
+ isolate(1),
+ oneway(2)
+ },
+ ...,
+ streamID StreamID OPTIONAL
+ }
+
+AmmRequest ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ descriptors SEQUENCE OF AmmDescriptor,
+ -- At most one descriptor of each type (see AmmDescriptor)
+ -- allowed in the sequence.
+ ...
+ }
+
+AmmDescriptor ::= CHOICE
+ {
+ mediaDescriptor MediaDescriptor,
+ modemDescriptor ModemDescriptor,
+ muxDescriptor MuxDescriptor,
+ eventsDescriptor EventsDescriptor,
+ eventBufferDescriptor EventBufferDescriptor,
+ signalsDescriptor SignalsDescriptor,
+ digitMapDescriptor DigitMapDescriptor,
+ auditDescriptor AuditDescriptor,
+ ...
+ }
+
+
+AmmsReply ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ terminationAudit TerminationAudit OPTIONAL,
+ ...
+ }
+
+SubtractRequest ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ auditDescriptor AuditDescriptor OPTIONAL,
+ ...
+ }
+
+AuditRequest ::= SEQUENCE
+ {
+ terminationID TerminationID,
+ auditDescriptor AuditDescriptor,
+ ...
+ }
+
+AuditReply ::= CHOICE
+ {
+ contextAuditResult TerminationIDList,
+ error ErrorDescriptor,
+ auditResult AuditResult,
+ ...
+ }
+
+AuditResult ::= SEQUENCE
+ {
+
+ terminationID TerminationID,
+ terminationAuditResult TerminationAudit
+ }
+
+
+
+TerminationAudit ::= SEQUENCE OF AuditReturnParameter
+
+AuditReturnParameter ::= CHOICE
+ {
+ errorDescriptor ErrorDescriptor,
+ mediaDescriptor MediaDescriptor,
+ modemDescriptor ModemDescriptor,
+ muxDescriptor MuxDescriptor,
+ eventsDescriptor EventsDescriptor,
+ eventBufferDescriptor EventBufferDescriptor,
+ signalsDescriptor SignalsDescriptor,
+ digitMapDescriptor DigitMapDescriptor,
+ observedEventsDescriptor ObservedEventsDescriptor,
+ statisticsDescriptor StatisticsDescriptor,
+ packagesDescriptor PackagesDescriptor,
+ emptyDescriptors AuditDescriptor,
+ ...
+ }
+
+AuditDescriptor ::= SEQUENCE
+ {
+ auditToken BIT STRING
+ {
+ muxToken(0), modemToken(1), mediaToken(2),
+ eventsToken(3), signalsToken(4),
+ digitMapToken(5), statsToken(6),
+ observedEventsToken(7),
+ packagesToken(8), eventBufferToken(9)
+ } OPTIONAL,
+ ...,
+ auditPropertyToken SEQUENCE OF IndAuditParameter OPTIONAL
+ }
+
+
+IndAuditParameter ::= CHOICE
+ {
+ -- Note that the lower/upper case letters of the tags have
+ -- been changed. The same changes has been made in text...
+ indAudMediaDescriptor IndAudMediaDescriptor,
+ indAudEventsDescriptor IndAudEventsDescriptor,
+ indAudEventBufferDescriptor IndAudEventBufferDescriptor,
+ indAudSignalsDescriptor IndAudSignalsDescriptor,
+ indAudDigitMapDescriptor IndAudDigitMapDescriptor,
+ indAudStatisticsDescriptor IndAudStatisticsDescriptor,
+ indAudPackagesDescriptor IndAudPackagesDescriptor,
+ ...
+ }
+
+IndAudMediaDescriptor ::= SEQUENCE
+ {
+
+ termStateDescr IndAudTerminationStateDescriptor OPTIONAL,
+ streams CHOICE
+ {
+ oneStream IndAudStreamParms,
+ multiStream SEQUENCE OF IndAudStreamDescriptor
+ } OPTIONAL,
+ ...
+ }
+
+IndAudStreamDescriptor ::= SEQUENCE
+ {
+ streamID StreamID,
+ streamParms IndAudStreamParms
+ }
+
+IndAudStreamParms ::= SEQUENCE
+ {
+ localControlDescriptor IndAudLocalControlDescriptor OPTIONAL,
+ localDescriptor IndAudLocalRemoteDescriptor OPTIONAL,
+ remoteDescriptor IndAudLocalRemoteDescriptor OPTIONAL,
+ ...
+ }
+
+IndAudLocalControlDescriptor ::= SEQUENCE
+ {
+ streamMode NULL OPTIONAL,
+ reserveValue NULL OPTIONAL,
+ reserveGroup NULL OPTIONAL,
+ propertyParms SEQUENCE OF IndAudPropertyParm OPTIONAL,
+ ...
+ }
+
+IndAudPropertyParm ::= SEQUENCE
+ {
+ name PkgdName,
+ ...
+ }
+
+IndAudLocalRemoteDescriptor ::= SEQUENCE
+ {
+ propGroupID INTEGER(0..65535) OPTIONAL,
+ propGrps IndAudPropertyGroup,
+ ...
+ }
+
+IndAudPropertyGroup ::= SEQUENCE OF IndAudPropertyParm
+
+IndAudTerminationStateDescriptor ::= SEQUENCE
+ {
+ propertyParms SEQUENCE OF IndAudPropertyParm,
+ eventBufferControl NULL OPTIONAL,
+ serviceState NULL OPTIONAL,
+ ...
+ }
+
+IndAudEventsDescriptor ::= SEQUENCE
+ {
+ requestID RequestID OPTIONAL,
+ pkgdName PkgdName,
+ streamID StreamID OPTIONAL,
+ ...
+ }
+
+IndAudEventBufferDescriptor ::= SEQUENCE
+ {
+ eventName PkgdName,
+ streamID StreamID OPTIONAL,
+ ...
+ }
+
+IndAudSignalsDescriptor ::=CHOICE
+ {
+ signal IndAudSignal,
+ seqSigList IndAudSeqSigList,
+ ...
+ }
+
+IndAudSeqSigList ::= SEQUENCE
+ {
+ id INTEGER(0..65535),
+ signalList IndAudSignal OPTIONAL
+ }
+
+IndAudSignal ::= SEQUENCE
+ {
+ signalName PkgdName,
+ streamID StreamID OPTIONAL,
+ ...
+ }
+
+IndAudDigitMapDescriptor ::= SEQUENCE
+ {
+ digitMapName DigitMapName OPTIONAL
+ }
+
+IndAudStatisticsDescriptor ::= SEQUENCE
+ {
+ statName PkgdName
+ }
+
+IndAudPackagesDescriptor ::= SEQUENCE
+ {
+ packageName Name,
+ packageVersion INTEGER(0..99),
+ ...
+ }
+
+NotifyRequest ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ observedEventsDescriptor ObservedEventsDescriptor,
+ errorDescriptor ErrorDescriptor OPTIONAL,
+ ...
+ }
+
+NotifyReply ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ errorDescriptor ErrorDescriptor OPTIONAL,
+ ...
+ }
+
+ObservedEventsDescriptor ::= SEQUENCE
+ {
+ requestId RequestID,
+ observedEventLst SEQUENCE OF ObservedEvent
+ }
+
+ObservedEvent ::= SEQUENCE
+ {
+ eventName EventName,
+ streamID StreamID OPTIONAL,
+ eventParList SEQUENCE OF EventParameter,
+ timeNotation TimeNotation OPTIONAL,
+ ...
+ }
+
+EventName ::= PkgdName
+
+EventParameter ::= SEQUENCE
+ {
+ eventParameterName Name,
+ value Value,
+ -- For use of extraInfo see the comment related to PropertyParm
+ extraInfo CHOICE
+ {
+ relation Relation,
+ range BOOLEAN,
+ sublist BOOLEAN
+ } OPTIONAL,
+ ...
+
+ }
+
+ServiceChangeRequest ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ serviceChangeParms ServiceChangeParm,
+ ...
+ }
+
+ServiceChangeReply ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ serviceChangeResult ServiceChangeResult,
+ ...
+ }
+
+-- For ServiceChangeResult, no parameters are mandatory. Hence the
+-- distinction between ServiceChangeParm and ServiceChangeResParm.
+
+ServiceChangeResult ::= CHOICE
+ {
+ errorDescriptor ErrorDescriptor,
+ serviceChangeResParms ServiceChangeResParm
+ }
+
+WildcardField ::= OCTET STRING(SIZE(1))
+
+TerminationID ::= SEQUENCE
+ {
+ wildcard SEQUENCE OF WildcardField,
+ id OCTET STRING(SIZE(1..8)),
+ ...
+ }
+-- See A.1 for explanation of wildcarding mechanism.
+-- Termination ID 0xFFFFFFFFFFFFFFFF indicates the ROOT Termination.
+
+TerminationIDList ::= SEQUENCE OF TerminationID
+
+MediaDescriptor ::= SEQUENCE
+ {
+ termStateDescr TerminationStateDescriptor OPTIONAL,
+ streams CHOICE
+ {
+ oneStream StreamParms,
+ multiStream SEQUENCE OF StreamDescriptor
+ } OPTIONAL,
+ ...
+ }
+
+StreamDescriptor ::= SEQUENCE
+ {
+ streamID StreamID,
+ streamParms StreamParms
+ }
+
+StreamParms ::= SEQUENCE
+ {
+ localControlDescriptor LocalControlDescriptor OPTIONAL,
+ localDescriptor LocalRemoteDescriptor OPTIONAL,
+ remoteDescriptor LocalRemoteDescriptor OPTIONAL,
+ ...
+ }
+
+LocalControlDescriptor ::= SEQUENCE
+ {
+ streamMode StreamMode OPTIONAL,
+ reserveValue BOOLEAN OPTIONAL,
+ reserveGroup BOOLEAN OPTIONAL,
+ propertyParms SEQUENCE OF PropertyParm,
+ ...
+ }
+
+StreamMode ::= ENUMERATED
+ {
+ sendOnly(0),
+ recvOnly(1),
+ sendRecv(2),
+ inactive(3),
+ loopBack(4),
+ ...
+ }
+
+-- In PropertyParm, value is a SEQUENCE OF octet string. When sent
+-- by an MGC the interpretation is as follows:
+-- empty sequence means CHOOSE
+-- one element sequence specifies value
+-- If the sublist field is not selected, a longer sequence means
+-- "choose one of the values" (i.e. value1 OR value2 OR ...)
+-- If the sublist field is selected,
+-- a sequence with more than one element encodes the value of a
+-- list-valued property (i.e. value1 AND value2 AND ...).
+-- The relation field may only be selected if the value sequence
+-- has length 1. It indicates that the MG has to choose a value
+-- for the property. E.g. x > 3 (using the greaterThan
+-- value for relation) instructs the MG to choose any value larger
+-- than 3 for property x.
+-- The range field may only be selected if the value sequence
+-- has length 2. It indicates that the MG has to choose a value
+-- in the range between the first octet in the value sequence and
+-- the trailing octet in the value sequence, including the
+-- boundary values.
+-- When sent by the MG, only responses to an AuditCapability request
+-- may contain multiple values, a range, or a relation field.
+
+PropertyParm ::= SEQUENCE
+ {
+ name PkgdName,
+ value SEQUENCE OF OCTET STRING,
+ extraInfo CHOICE
+ {
+ relation Relation,
+ range BOOLEAN,
+ sublist BOOLEAN
+ } OPTIONAL,
+ ...
+ }
+
+Name ::= OCTET STRING(SIZE(2))
+
+PkgdName ::= OCTET STRING(SIZE(4))
+-- represents Package Name (2 octets) plus Property, Event,
+-- Signal Names or Statistics ID. (2 octets)
+-- To wildcard a package use 0xFFFF for first two octets, choose
+-- is not allowed. To reference native property tag specified in
+-- Annex C, use 0x0000 as first two octets.
+-- To wildcard a Property, Event, Signal, or Statistics ID, use
+-- 0xFFFF for last two octets, choose is not allowed.
+-- Wildcarding of Package Name is permitted only if Property,
+-- Event, Signal, or Statistics ID are
+-- also wildcarded.
+
+Relation ::= ENUMERATED
+ {
+ greaterThan(0),
+ smallerThan(1),
+ unequalTo(2),
+ ...
+ }
+
+LocalRemoteDescriptor ::= SEQUENCE
+ {
+ propGrps SEQUENCE OF PropertyGroup,
+ ...
+ }
+
+PropertyGroup ::= SEQUENCE OF PropertyParm
+
+TerminationStateDescriptor ::= SEQUENCE
+ {
+ propertyParms SEQUENCE OF PropertyParm,
+ eventBufferControl EventBufferControl OPTIONAL,
+ serviceState ServiceState OPTIONAL,
+ ...
+ }
+
+EventBufferControl ::= ENUMERATED
+ {
+ off(0),
+ lockStep(1),
+ ...
+ }
+
+ServiceState ::= ENUMERATED
+ {
+ test(0),
+ outOfSvc(1),
+ inSvc(2),
+ ...
+ }
+
+MuxDescriptor ::= SEQUENCE
+ {
+ muxType MuxType,
+ termList SEQUENCE OF TerminationID,
+ nonStandardData NonStandardData OPTIONAL,
+ ...
+ }
+
+MuxType ::= ENUMERATED
+ {
+ h221(0),
+ h223(1),
+ h226(2),
+ v76(3),
+ ...,
+ nx64k(4)
+ }
+
+StreamID ::= INTEGER(0..65535) -- 16-bit unsigned integer
+
+EventsDescriptor ::= SEQUENCE
+ {
+ requestID RequestID OPTIONAL,
+ -- RequestID must be present if eventList
+ -- is non empty
+ eventList SEQUENCE OF RequestedEvent,
+ ...
+ }
+
+RequestedEvent ::= SEQUENCE
+ {
+ pkgdName PkgdName,
+ streamID StreamID OPTIONAL,
+ eventAction RequestedActions OPTIONAL,
+ evParList SEQUENCE OF EventParameter,
+ ...
+ }
+
+RequestedActions ::= SEQUENCE
+ {
+ keepActive BOOLEAN OPTIONAL,
+ eventDM EventDM OPTIONAL,
+ secondEvent SecondEventsDescriptor OPTIONAL,
+ signalsDescriptor SignalsDescriptor OPTIONAL,
+ ...
+ }
+
+EventDM ::= CHOICE
+ {
+ digitMapName DigitMapName,
+ digitMapValue DigitMapValue
+ }
+
+SecondEventsDescriptor ::= SEQUENCE
+ {
+ requestID RequestID OPTIONAL,
+ eventList SEQUENCE OF SecondRequestedEvent,
+ ...
+ }
+
+SecondRequestedEvent ::= SEQUENCE
+ {
+ pkgdName PkgdName,
+ streamID StreamID OPTIONAL,
+ eventAction SecondRequestedActions OPTIONAL,
+ evParList SEQUENCE OF EventParameter,
+ ...
+ }
+
+SecondRequestedActions ::= SEQUENCE
+ {
+ keepActive BOOLEAN OPTIONAL,
+ eventDM EventDM OPTIONAL,
+ signalsDescriptor SignalsDescriptor OPTIONAL,
+ ...
+ }
+
+EventBufferDescriptor ::= SEQUENCE OF EventSpec
+
+EventSpec ::= SEQUENCE
+ {
+ eventName EventName,
+ streamID StreamID OPTIONAL,
+ eventParList SEQUENCE OF EventParameter,
+ ...
+ }
+
+
+SignalsDescriptor ::= SEQUENCE OF SignalRequest
+
+SignalRequest ::= CHOICE
+ {
+ signal Signal,
+ seqSigList SeqSigList,
+ ...
+ }
+
+SeqSigList ::= SEQUENCE
+ {
+ id INTEGER(0..65535),
+ signalList SEQUENCE OF Signal
+ }
+
+Signal ::= SEQUENCE
+ {
+ signalName SignalName,
+ streamID StreamID OPTIONAL,
+ sigType SignalType OPTIONAL,
+ duration INTEGER (0..65535) OPTIONAL,
+ notifyCompletion NotifyCompletion OPTIONAL,
+ keepActive BOOLEAN OPTIONAL,
+ sigParList SEQUENCE OF SigParameter,
+ ...
+ }
+
+SignalType ::= ENUMERATED
+ {
+ brief(0),
+ onOff(1),
+ timeOut(2),
+ ...
+ }
+
+SignalName ::= PkgdName
+
+NotifyCompletion ::= BIT STRING
+ {
+ onTimeOut(0), onInterruptByEvent(1),
+ onInterruptByNewSignalDescr(2), otherReason(3)
+ }
+
+SigParameter ::= SEQUENCE
+ {
+ sigParameterName Name,
+ value Value,
+ -- For use of extraInfo see the comment related to PropertyParm
+ extraInfo CHOICE
+ {
+ relation Relation,
+ range BOOLEAN,
+ sublist BOOLEAN
+ } OPTIONAL,
+ ...
+ }
+
+-- For an AuditCapReply with all events, the RequestID SHALL be ALL.
+-- ALL is represented by 0xffffffff.
+
+RequestID ::= INTEGER(0..4294967295) -- 32-bit unsigned integer
+
+ModemDescriptor ::= SEQUENCE
+ {
+ mtl SEQUENCE OF ModemType,
+ mpl SEQUENCE OF PropertyParm,
+ nonStandardData NonStandardData OPTIONAL
+ }
+
+ModemType ::= ENUMERATED
+ {
+ v18(0),
+ v22(1),
+ v22bis(2),
+ v32(3),
+ v32bis(4),
+ v34(5),
+ v90(6),
+ v91(7),
+ synchISDN(8),
+ ...
+ }
+
+DigitMapDescriptor ::= SEQUENCE
+ {
+ digitMapName DigitMapName OPTIONAL,
+ digitMapValue DigitMapValue OPTIONAL
+ }
+
+DigitMapName ::= Name
+
+DigitMapValue ::= SEQUENCE
+ {
+ startTimer INTEGER(0..99) OPTIONAL,
+ shortTimer INTEGER(0..99) OPTIONAL,
+ longTimer INTEGER(0..99) OPTIONAL,
+ digitMapBody IA5String,
+ -- Units are seconds for start, short and long timers, and
+ -- hundreds of milliseconds for duration timer. Thus start,
+ -- short, and long range from 1 to 99 seconds and duration
+ -- from 100 ms to 9.9 s
+ -- See A.3 for explanation of digit map syntax
+ ...,
+ durationTimer INTEGER (0..99) OPTIONAL
+ }
+
+ServiceChangeParm ::= SEQUENCE
+ {
+ serviceChangeMethod ServiceChangeMethod,
+ serviceChangeAddress ServiceChangeAddress OPTIONAL,
+ serviceChangeVersion INTEGER(0..99) OPTIONAL,
+ serviceChangeProfile ServiceChangeProfile OPTIONAL,
+ serviceChangeReason Value,
+ -- A serviceChangeReason consists of a numeric reason code
+ -- and an optional text description.
+ -- The serviceChangeReason SHALL be a string consisting of
+ -- a decimal reason code, optionally followed by a single
+ -- space character and a textual description string.
+ -- This string is first BER-encoded as an IA5String.
+ -- The result of this BER-encoding is then encoded as
+ -- an ASN.1 OCTET STRING type, "double wrapping" the
+ -- value
+ -- as was done for package elements.
+ serviceChangeDelay INTEGER(0..4294967295) OPTIONAL,
+ -- 32-bit unsigned integer
+ serviceChangeMgcId MId OPTIONAL,
+ timeStamp TimeNotation OPTIONAL,
+ nonStandardData NonStandardData OPTIONAL,
+ ...,
+ serviceChangeInfo AuditDescriptor OPTIONAL
+ }
+
+ServiceChangeAddress ::= CHOICE
+ {
+ portNumber INTEGER(0..65535), -- TCP/UDP port number
+ ip4Address IP4Address,
+ ip6Address IP6Address,
+ domainName DomainName,
+ deviceName PathName,
+ mtpAddress OCTET STRING(SIZE(2..4)),
+ ...
+ }
+
+ServiceChangeResParm ::= SEQUENCE
+ {
+ serviceChangeMgcId MId OPTIONAL,
+ serviceChangeAddress ServiceChangeAddress OPTIONAL,
+ serviceChangeVersion INTEGER(0..99) OPTIONAL,
+ serviceChangeProfile ServiceChangeProfile OPTIONAL,
+ timestamp TimeNotation OPTIONAL,
+ ...
+ }
+
+ServiceChangeMethod ::= ENUMERATED
+ {
+ failover(0),
+ forced(1),
+ graceful(2),
+ restart(3),
+ disconnected(4),
+ handOff(5),
+ ...
+ }
+
+ServiceChangeProfile ::= SEQUENCE
+ {
+ profileName IA5String(SIZE (1..67))
+
+ -- 64 characters for name, 1 for "/", 2 for version to match ABNF
+ }
+
+PackagesDescriptor ::= SEQUENCE OF PackagesItem
+PackagesItem ::= SEQUENCE
+ {
+ packageName Name,
+ packageVersion INTEGER(0..99),
+ ...
+ }
+
+StatisticsDescriptor ::= SEQUENCE OF StatisticsParameter
+
+StatisticsParameter ::= SEQUENCE
+ {
+ statName PkgdName,
+ statValue Value OPTIONAL
+ }
+
+NonStandardData ::= SEQUENCE
+ {
+ nonStandardIdentifier NonStandardIdentifier,
+ data OCTET STRING
+ }
+
+NonStandardIdentifier ::= CHOICE
+ {
+ object OBJECT IDENTIFIER,
+ h221NonStandard H221NonStandard,
+ experimental IA5String(SIZE(8)),
+ -- first two characters SHOULD be "X-" or "X+"
+ ...
+ }
+
+H221NonStandard ::= SEQUENCE
+ { t35CountryCode1 INTEGER(0..255),
+ t35CountryCode2 INTEGER(0..255), -- country, as per T.35
+ t35Extension INTEGER(0..255), -- assigned nationally
+ manufacturerCode INTEGER(0..65535), -- assigned nationally
+ ...
+ }
+
+TimeNotation ::= SEQUENCE
+ {
+ date IA5String(SIZE(8)), -- yyyymmdd format
+ time IA5String(SIZE(8)) -- hhmmssss format
+ -- per ISO 8601:1988
+ }
+
+Value ::= SEQUENCE OF OCTET STRING
+
+END
diff --git a/lib/megaco/src/binary/MEDIA-GATEWAY-CONTROL-v3.asn b/lib/megaco/src/binary/MEDIA-GATEWAY-CONTROL-v3.asn
new file mode 100644
index 0000000000..644a35ffee
--- /dev/null
+++ b/lib/megaco/src/binary/MEDIA-GATEWAY-CONTROL-v3.asn
@@ -0,0 +1,1068 @@
+MEDIA-GATEWAY-CONTROL-v3
+{itu-t(0) recommendation(0) h(8) h248(248)
+ modules(0) media-gateway-control(0) version3(3)}
+DEFINITIONS AUTOMATIC TAGS ::=
+BEGIN
+
+
+MegacoMessage ::= SEQUENCE
+ {
+ authHeader AuthenticationHeader OPTIONAL,
+ mess Message
+ }
+
+AuthenticationHeader ::= SEQUENCE
+ {
+ secParmIndex SecurityParmIndex,
+ seqNum SequenceNum,
+ ad AuthData
+ }
+
+SecurityParmIndex ::= OCTET STRING(SIZE(4))
+
+SequenceNum ::= OCTET STRING(SIZE(4))
+
+AuthData ::= OCTET STRING (SIZE (12..32))
+
+Message ::= SEQUENCE
+ {
+ version INTEGER(0..99),
+ -- The version of the protocol defined here is equal to 3.
+ mId MId, -- Name/address of message originator
+ messageBody CHOICE
+ {
+ messageError ErrorDescriptor,
+ transactions SEQUENCE OF Transaction
+ },
+ ...
+ }
+
+MId ::= CHOICE
+ {
+ ip4Address IP4Address,
+ ip6Address IP6Address,
+ domainName DomainName,
+ deviceName PathName,
+ mtpAddress OCTET STRING(SIZE(2..4)),
+ -- Addressing structure of mtpAddress:
+ -- 25 - 15 0
+ -- | PC | NI |
+ -- 24 - 14 bits 2 bits
+ -- Note: 14 bits are defined for international use.
+ -- Two national options exist where the point code is 16 or 24
+ -- bits.
+ -- To octet align the mtpAddress, the MSBs shall be encoded as 0s.
+ ...
+ }
+
+DomainName ::= SEQUENCE
+ {
+ name IA5String,
+ -- The name starts with an alphanumeric digit followed by a
+ -- sequence of alphanumeric digits, hyphens and dots. No two
+ -- dots shall occur consecutively.
+ portNumber INTEGER(0..65535) OPTIONAL
+ }
+
+IP4Address ::= SEQUENCE
+ {
+ address OCTET STRING (SIZE(4)),
+ portNumber INTEGER(0..65535) OPTIONAL
+ }
+
+IP6Address ::= SEQUENCE
+ {
+ address OCTET STRING (SIZE(16)),
+ portNumber INTEGER(0..65535) OPTIONAL
+ }
+
+PathName ::= IA5String(SIZE (1..64))
+-- See A.3
+
+Transaction ::= CHOICE
+ {
+ transactionRequest TransactionRequest,
+ transactionPending TransactionPending,
+ transactionReply TransactionReply,
+ transactionResponseAck TransactionResponseAck,
+ -- use of response acks is dependent on underlying transport
+ ...,
+ segmentReply SegmentReply
+ }
+
+TransactionId ::= INTEGER(0..4294967295) -- 32-bit unsigned integer
+
+TransactionRequest ::= SEQUENCE
+ {
+ transactionId TransactionId,
+ actions SEQUENCE OF ActionRequest,
+ ...
+ }
+
+TransactionPending ::= SEQUENCE
+ {
+ transactionId TransactionId,
+ ...
+ }
+
+TransactionReply ::= SEQUENCE
+ {
+ transactionId TransactionId,
+ immAckRequired NULL OPTIONAL,
+ transactionResult CHOICE
+ {
+ transactionError ErrorDescriptor,
+ actionReplies SEQUENCE OF ActionReply
+ },
+ ...,
+ segmentNumber SegmentNumber OPTIONAL,
+ segmentationComplete NULL OPTIONAL
+ }
+
+SegmentReply ::= SEQUENCE
+ {
+ transactionId TransactionId,
+ segmentNumber SegmentNumber,
+ segmentationComplete NULL OPTIONAL,
+ ...
+ }
+
+SegmentNumber ::= INTEGER(0..65535)
+
+TransactionResponseAck ::= SEQUENCE OF TransactionAck
+TransactionAck ::= SEQUENCE
+ {
+ firstAck TransactionId,
+ lastAck TransactionId OPTIONAL
+ }
+
+ErrorDescriptor ::= SEQUENCE
+ {
+ errorCode ErrorCode,
+ errorText ErrorText OPTIONAL
+ }
+
+ErrorCode ::= INTEGER(0..65535)
+-- See clause 14 for IANA considerations with respect to error codes
+ErrorText ::= IA5String
+
+ContextID ::= INTEGER(0..4294967295)
+-- Context NULL Value: 0
+-- Context CHOOSE Value: 4294967294 (0xFFFFFFFE)
+-- Context ALL Value: 4294967295 (0xFFFFFFFF)
+
+
+ActionRequest ::= SEQUENCE
+ {
+ contextId ContextID,
+ contextRequest ContextRequest OPTIONAL,
+ contextAttrAuditReq ContextAttrAuditRequest OPTIONAL,
+ commandRequests SEQUENCE OF CommandRequest
+ }
+
+ActionReply ::= SEQUENCE
+ {
+ contextId ContextID,
+ errorDescriptor ErrorDescriptor OPTIONAL,
+ contextReply ContextRequest OPTIONAL,
+ commandReply SEQUENCE OF CommandReply
+ }
+
+ContextRequest ::= SEQUENCE
+ {
+ priority INTEGER(0..15) OPTIONAL,
+ emergency BOOLEAN OPTIONAL,
+ topologyReq SEQUENCE OF TopologyRequest OPTIONAL,
+ ...,
+ iepscallind BOOLEAN OPTIONAL,
+ contextProp SEQUENCE OF PropertyParm OPTIONAL,
+ contextList SEQUENCE OF ContextID OPTIONAL
+ }
+-- When returning a contextList, the contextId in the ActionReply
+-- construct will return the contextId from the associated ActionRequest.
+
+ContextAttrAuditRequest ::= SEQUENCE
+ {
+ topology NULL OPTIONAL,
+ emergency NULL OPTIONAL,
+ priority NULL OPTIONAL,
+ ...,
+ iepscallind NULL OPTIONAL,
+ contextPropAud SEQUENCE OF IndAudPropertyParm OPTIONAL,
+
+ selectpriority INTEGER(0..15) OPTIONAL,
+ -- to select given priority
+
+ selectemergency BOOLEAN OPTIONAL,
+ -- to select if emergency set/not set (T/F)
+
+ selectiepscallind BOOLEAN OPTIONAL,
+ -- to select if IEPS set/not set (T/F)
+
+ selectLogic SelectLogic OPTIONAL -- default is AND
+ }
+
+SelectLogic ::= CHOICE
+ {
+ andAUDITSelect NULL, -- all selection conditions satisfied
+ orAUDITSelect NULL, -- at least one selection condition satisfied
+ ...
+ }
+
+
+CommandRequest ::= SEQUENCE
+ {
+ command Command,
+ optional NULL OPTIONAL,
+ wildcardReturn NULL OPTIONAL,
+ ...
+ }
+
+Command ::= CHOICE
+ {
+ addReq AmmRequest,
+ moveReq AmmRequest,
+ modReq AmmRequest,
+ -- Add, Move, Modify requests have the same parameters
+ subtractReq SubtractRequest,
+ auditCapRequest AuditRequest,
+ auditValueRequest AuditRequest,
+ notifyReq NotifyRequest,
+ serviceChangeReq ServiceChangeRequest,
+ ...
+ }
+
+CommandReply ::= CHOICE
+ {
+ addReply AmmsReply,
+ moveReply AmmsReply,
+ modReply AmmsReply,
+ subtractReply AmmsReply,
+ -- Add, Move, Modify, Subtract replies have the same parameters
+ auditCapReply AuditReply,
+ auditValueReply AuditReply,
+ notifyReply NotifyReply,
+ serviceChangeReply ServiceChangeReply,
+ ...
+ }
+
+TopologyRequest ::= SEQUENCE
+ {
+ terminationFrom TerminationID,
+ terminationTo TerminationID,
+ topologyDirection ENUMERATED
+ {
+ bothway(0),
+ isolate(1),
+ oneway(2)
+ },
+ ...,
+ streamID StreamID OPTIONAL,
+ topologyDirectionExtension ENUMERATED
+ {
+ onewayexternal(0),
+ onewayboth(1),
+ ...
+ } OPTIONAL
+ -- This is not according to the standard, but without it
+ -- the TopologyRequest will be useless since topologyDirection
+ -- and topologyDirectionExtension are contradictory.
+ }
+
+AmmRequest ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ descriptors SEQUENCE OF AmmDescriptor,
+ -- At most one descriptor of each type (see AmmDescriptor)
+ -- allowed in the sequence.
+ ...
+ }
+
+AmmDescriptor ::= CHOICE
+ {
+ mediaDescriptor MediaDescriptor,
+ modemDescriptor ModemDescriptor,
+ muxDescriptor MuxDescriptor,
+ eventsDescriptor EventsDescriptor,
+ eventBufferDescriptor EventBufferDescriptor,
+ signalsDescriptor SignalsDescriptor,
+ digitMapDescriptor DigitMapDescriptor,
+ auditDescriptor AuditDescriptor,
+ ...,
+ statisticsDescriptor StatisticsDescriptor
+ }
+
+
+AmmsReply ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ terminationAudit TerminationAudit OPTIONAL,
+ ...
+ }
+
+SubtractRequest ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ auditDescriptor AuditDescriptor OPTIONAL,
+ ...
+ }
+
+AuditRequest ::= SEQUENCE
+ {
+ terminationID TerminationID,
+ auditDescriptor AuditDescriptor,
+ ...,
+ terminationIDList TerminationIDList OPTIONAL
+ }
+-- terminationID shall contain the first termination in the
+-- list when using the terminationIDList construct in AuditRequest
+
+AuditReply ::= CHOICE
+ {
+ contextAuditResult TerminationIDList,
+ error ErrorDescriptor,
+ auditResult AuditResult,
+ ...,
+ auditResultTermList TermListAuditResult
+ }
+
+AuditResult ::= SEQUENCE
+ {
+
+ terminationID TerminationID,
+ terminationAuditResult TerminationAudit
+ }
+
+TermListAuditResult ::= SEQUENCE
+ {
+ terminationIDList TerminationIDList,
+ terminationAuditResult TerminationAudit,
+ ...
+ }
+
+TerminationAudit ::= SEQUENCE OF AuditReturnParameter
+
+AuditReturnParameter ::= CHOICE
+ {
+ errorDescriptor ErrorDescriptor,
+ mediaDescriptor MediaDescriptor,
+ modemDescriptor ModemDescriptor,
+ muxDescriptor MuxDescriptor,
+ eventsDescriptor EventsDescriptor,
+ eventBufferDescriptor EventBufferDescriptor,
+ signalsDescriptor SignalsDescriptor,
+ digitMapDescriptor DigitMapDescriptor,
+ observedEventsDescriptor ObservedEventsDescriptor,
+ statisticsDescriptor StatisticsDescriptor,
+ packagesDescriptor PackagesDescriptor,
+ emptyDescriptors AuditDescriptor,
+ ...
+ }
+
+AuditDescriptor ::= SEQUENCE
+ {
+ auditToken BIT STRING
+ {
+ muxToken(0), modemToken(1), mediaToken(2),
+ eventsToken(3), signalsToken(4),
+ digitMapToken(5), statsToken(6),
+ observedEventsToken(7),
+ packagesToken(8), eventBufferToken(9)
+ } OPTIONAL,
+ ...,
+ auditPropertyToken SEQUENCE OF IndAuditParameter OPTIONAL
+ }
+
+
+IndAuditParameter ::= CHOICE
+ {
+ -- Note that the lower/upper case letters of the tags have
+ -- been changed. The same changes has been made in text...
+ indAudMediaDescriptor IndAudMediaDescriptor,
+ indAudEventsDescriptor IndAudEventsDescriptor,
+ indAudEventBufferDescriptor IndAudEventBufferDescriptor,
+ indAudSignalsDescriptor IndAudSignalsDescriptor,
+ indAudDigitMapDescriptor IndAudDigitMapDescriptor,
+ indAudStatisticsDescriptor IndAudStatisticsDescriptor,
+ indAudPackagesDescriptor IndAudPackagesDescriptor,
+ ...
+ }
+
+IndAudMediaDescriptor ::= SEQUENCE
+ {
+
+ termStateDescr IndAudTerminationStateDescriptor OPTIONAL,
+ streams CHOICE
+ {
+ oneStream IndAudStreamParms,
+ multiStream SEQUENCE OF IndAudStreamDescriptor
+ } OPTIONAL,
+ ...
+ }
+
+IndAudStreamDescriptor ::= SEQUENCE
+ {
+ streamID StreamID,
+ streamParms IndAudStreamParms
+ }
+
+IndAudStreamParms ::= SEQUENCE
+ {
+ localControlDescriptor IndAudLocalControlDescriptor OPTIONAL,
+ localDescriptor IndAudLocalRemoteDescriptor OPTIONAL,
+ remoteDescriptor IndAudLocalRemoteDescriptor OPTIONAL,
+ ...,
+ statisticsDescriptor IndAudStatisticsDescriptor OPTIONAL
+ }
+
+IndAudLocalControlDescriptor ::= SEQUENCE
+ {
+ streamMode NULL OPTIONAL,
+ reserveValue NULL OPTIONAL,
+ reserveGroup NULL OPTIONAL,
+ propertyParms SEQUENCE OF IndAudPropertyParm OPTIONAL,
+ ...,
+ streamModeSel StreamMode OPTIONAL
+ -- must not have both streamMode and streamModeSel
+ -- if both are present only streamModeSel shall be honoured
+ }
+
+IndAudPropertyParm ::= SEQUENCE
+ {
+ name PkgdName,
+ ...,
+ propertyParms PropertyParm OPTIONAL
+ }
+-- to select based on property values
+-- AND/OR selection logic is specified at context level
+
+IndAudLocalRemoteDescriptor ::= SEQUENCE
+ {
+ propGroupID INTEGER(0..65535) OPTIONAL,
+ propGrps IndAudPropertyGroup,
+ ...
+ }
+
+IndAudPropertyGroup ::= SEQUENCE OF IndAudPropertyParm
+
+IndAudTerminationStateDescriptor ::= SEQUENCE
+ {
+ propertyParms SEQUENCE OF IndAudPropertyParm,
+ eventBufferControl NULL OPTIONAL,
+ serviceState NULL OPTIONAL,
+ ...,
+ serviceStateSel ServiceState OPTIONAL
+ -- must not have both serviceState and serviceStateSel
+ -- if both are present only serviceStateSel shall be honoured
+ }
+
+IndAudEventsDescriptor ::= SEQUENCE
+ {
+ requestID RequestID OPTIONAL,
+ pkgdName PkgdName,
+ streamID StreamID OPTIONAL,
+ ...
+ }
+
+IndAudEventBufferDescriptor ::= SEQUENCE
+ {
+ eventName PkgdName,
+ streamID StreamID OPTIONAL,
+ ...
+ }
+
+IndAudSignalsDescriptor ::=CHOICE
+ {
+ signal IndAudSignal,
+ seqSigList IndAudSeqSigList,
+ ...
+ }
+
+IndAudSeqSigList ::= SEQUENCE
+ {
+ id INTEGER(0..65535),
+ signalList IndAudSignal OPTIONAL
+ }
+
+IndAudSignal ::= SEQUENCE
+ {
+ signalName PkgdName,
+ streamID StreamID OPTIONAL,
+ ...,
+ signalRequestID RequestID OPTIONAL
+ }
+
+IndAudDigitMapDescriptor ::= SEQUENCE
+ {
+ digitMapName DigitMapName OPTIONAL
+ }
+
+IndAudStatisticsDescriptor ::= SEQUENCE
+ {
+ statName PkgdName
+ }
+
+IndAudPackagesDescriptor ::= SEQUENCE
+ {
+ packageName Name,
+ packageVersion INTEGER(0..99),
+ ...
+ }
+
+NotifyRequest ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ observedEventsDescriptor ObservedEventsDescriptor,
+ errorDescriptor ErrorDescriptor OPTIONAL,
+ ...
+ }
+
+NotifyReply ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ errorDescriptor ErrorDescriptor OPTIONAL,
+ ...
+ }
+
+ObservedEventsDescriptor ::= SEQUENCE
+ {
+ requestId RequestID,
+ observedEventLst SEQUENCE OF ObservedEvent
+ }
+
+ObservedEvent ::= SEQUENCE
+ {
+ eventName EventName,
+ streamID StreamID OPTIONAL,
+ eventParList SEQUENCE OF EventParameter,
+ timeNotation TimeNotation OPTIONAL,
+ ...
+ }
+
+EventName ::= PkgdName
+
+EventParameter ::= SEQUENCE
+ {
+ eventParameterName Name,
+ value Value,
+ -- For use of extraInfo see the comment related to PropertyParm
+ extraInfo CHOICE
+ {
+ relation Relation,
+ range BOOLEAN,
+ sublist BOOLEAN
+ } OPTIONAL,
+ ...
+
+ }
+
+ServiceChangeRequest ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ serviceChangeParms ServiceChangeParm,
+ ...
+ }
+
+ServiceChangeReply ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ serviceChangeResult ServiceChangeResult,
+ ...
+ }
+
+-- For ServiceChangeResult, no parameters are mandatory. Hence the
+-- distinction between ServiceChangeParm and ServiceChangeResParm.
+ServiceChangeResult ::= CHOICE
+ {
+ errorDescriptor ErrorDescriptor,
+ serviceChangeResParms ServiceChangeResParm
+ }
+
+WildcardField ::= OCTET STRING(SIZE(1))
+
+TerminationID ::= SEQUENCE
+ {
+ wildcard SEQUENCE OF WildcardField,
+ id OCTET STRING(SIZE(1..8)),
+ ...
+ }
+-- See A.1 for explanation of wildcarding mechanism.
+-- Termination ID 0xFFFFFFFFFFFFFFFF indicates the ROOT Termination.
+
+TerminationIDList ::= SEQUENCE OF TerminationID
+
+MediaDescriptor ::= SEQUENCE
+ {
+ termStateDescr TerminationStateDescriptor OPTIONAL,
+ streams CHOICE
+ {
+ oneStream StreamParms,
+ multiStream SEQUENCE OF StreamDescriptor
+ } OPTIONAL,
+ ...
+ }
+
+StreamDescriptor ::= SEQUENCE
+ {
+ streamID StreamID,
+ streamParms StreamParms
+ }
+
+StreamParms ::= SEQUENCE
+ {
+ localControlDescriptor LocalControlDescriptor OPTIONAL,
+ localDescriptor LocalRemoteDescriptor OPTIONAL,
+ remoteDescriptor LocalRemoteDescriptor OPTIONAL,
+ ...,
+ statisticsDescriptor StatisticsDescriptor OPTIONAL
+ }
+
+LocalControlDescriptor ::= SEQUENCE
+ {
+ streamMode StreamMode OPTIONAL,
+ reserveValue BOOLEAN OPTIONAL,
+ reserveGroup BOOLEAN OPTIONAL,
+ propertyParms SEQUENCE OF PropertyParm,
+ ...
+ }
+
+StreamMode ::= ENUMERATED
+ {
+ sendOnly(0),
+ recvOnly(1),
+ sendRecv(2),
+ inactive(3),
+ loopBack(4),
+ ...
+ }
+
+-- In PropertyParm, value is a SEQUENCE OF octet string. When sent
+-- by an MGC the interpretation is as follows:
+-- empty sequence means CHOOSE
+-- one element sequence specifies value
+-- If the sublist field is not selected, a longer sequence means
+-- "choose one of the values" (i.e. value1 OR value2 OR ...)
+-- If the sublist field is selected,
+-- a sequence with more than one element encodes the value of a
+-- list-valued property (i.e. value1 AND value2 AND ...).
+-- The relation field may only be selected if the value sequence
+-- has length 1. It indicates that the MG has to choose a value
+-- for the property. E.g. x > 3 (using the greaterThan
+-- value for relation) instructs the MG to choose any value larger
+-- than 3 for property x.
+-- The range field may only be selected if the value sequence
+-- has length 2. It indicates that the MG has to choose a value
+-- in the range between the first octet in the value sequence and
+-- the trailing octet in the value sequence, including the
+-- boundary values.
+-- When sent by the MG, only responses to an AuditCapability request
+-- may contain multiple values, a range, or a relation field.
+
+PropertyParm ::= SEQUENCE
+ {
+ name PkgdName,
+ value SEQUENCE OF OCTET STRING,
+ extraInfo CHOICE
+ {
+ relation Relation,
+ range BOOLEAN,
+ sublist BOOLEAN
+ } OPTIONAL,
+ ...
+ }
+
+Name ::= OCTET STRING(SIZE(2))
+
+PkgdName ::= OCTET STRING(SIZE(4))
+-- represents Package Name (2 octets) plus Property, Event,
+-- Signal Names or Statistics ID. (2 octets)
+-- To wildcard a package use 0xFFFF for first two octets, choose
+-- is not allowed. To reference native property tag specified in
+-- Annex C, use 0x0000 as first two octets.
+-- To wildcard a Property, Event, Signal, or Statistics ID, use
+-- 0xFFFF for last two octets, choose is not allowed.
+-- Wildcarding of Package Name is permitted only if Property,
+-- Event, Signal, or Statistics ID are
+-- also wildcarded.
+
+Relation ::= ENUMERATED
+ {
+ greaterThan(0),
+ smallerThan(1),
+ unequalTo(2),
+ ...
+ }
+
+LocalRemoteDescriptor ::= SEQUENCE
+ {
+ propGrps SEQUENCE OF PropertyGroup,
+ ...
+ }
+
+PropertyGroup ::= SEQUENCE OF PropertyParm
+
+TerminationStateDescriptor ::= SEQUENCE
+ {
+ propertyParms SEQUENCE OF PropertyParm,
+ eventBufferControl EventBufferControl OPTIONAL,
+ serviceState ServiceState OPTIONAL,
+ ...
+ }
+
+EventBufferControl ::= ENUMERATED
+ {
+ off(0),
+ lockStep(1),
+ ...
+ }
+
+ServiceState ::= ENUMERATED
+ {
+ test(0),
+ outOfSvc(1),
+ inSvc(2),
+ ...
+ }
+
+MuxDescriptor ::= SEQUENCE
+ {
+ muxType MuxType,
+ termList SEQUENCE OF TerminationID,
+ nonStandardData NonStandardData OPTIONAL,
+ ...
+ }
+
+MuxType ::= ENUMERATED
+ {
+ h221(0),
+ h223(1),
+ h226(2),
+ v76(3),
+ ...,
+ nx64k(4)
+ }
+
+StreamID ::= INTEGER(0..65535) -- 16-bit unsigned integer
+
+EventsDescriptor ::= SEQUENCE
+ {
+ requestID RequestID OPTIONAL,
+ -- RequestID must be present if eventList
+ -- is non empty
+ eventList SEQUENCE OF RequestedEvent,
+ ...
+ }
+
+RequestedEvent ::= SEQUENCE
+ {
+ pkgdName PkgdName,
+ streamID StreamID OPTIONAL,
+ eventAction RequestedActions OPTIONAL,
+ evParList SEQUENCE OF EventParameter,
+ ...
+ }
+
+RegulatedEmbeddedDescriptor ::= SEQUENCE
+ {
+ secondEvent SecondEventsDescriptor OPTIONAL,
+ signalsDescriptor SignalsDescriptor OPTIONAL,
+ ...
+ }
+
+NotifyBehaviour ::= CHOICE
+ {
+ notifyImmediate NULL,
+ notifyRegulated RegulatedEmbeddedDescriptor,
+ neverNotify NULL,
+ ...
+ }
+
+RequestedActions ::= SEQUENCE
+ {
+ keepActive BOOLEAN OPTIONAL,
+ eventDM EventDM OPTIONAL,
+ secondEvent SecondEventsDescriptor OPTIONAL,
+ signalsDescriptor SignalsDescriptor OPTIONAL,
+ ...,
+ notifyBehaviour NotifyBehaviour OPTIONAL,
+ resetEventsDescriptor NULL OPTIONAL
+ }
+
+EventDM ::= CHOICE
+ {
+ digitMapName DigitMapName,
+ digitMapValue DigitMapValue
+ }
+
+SecondEventsDescriptor ::= SEQUENCE
+ {
+ requestID RequestID OPTIONAL,
+ eventList SEQUENCE OF SecondRequestedEvent,
+ ...
+ }
+
+SecondRequestedEvent ::= SEQUENCE
+ {
+ pkgdName PkgdName,
+ streamID StreamID OPTIONAL,
+ eventAction SecondRequestedActions OPTIONAL,
+ evParList SEQUENCE OF EventParameter,
+ ...
+ }
+
+SecondRequestedActions ::= SEQUENCE
+ {
+ keepActive BOOLEAN OPTIONAL,
+ eventDM EventDM OPTIONAL,
+ signalsDescriptor SignalsDescriptor OPTIONAL,
+ ...,
+ notifyBehaviour NotifyBehaviour OPTIONAL,
+ resetEventsDescriptor NULL OPTIONAL
+ }
+
+EventBufferDescriptor ::= SEQUENCE OF EventSpec
+
+EventSpec ::= SEQUENCE
+ {
+ eventName EventName,
+ streamID StreamID OPTIONAL,
+ eventParList SEQUENCE OF EventParameter,
+ ...
+ }
+
+
+SignalsDescriptor ::= SEQUENCE OF SignalRequest
+
+SignalRequest ::= CHOICE
+ {
+ signal Signal,
+ seqSigList SeqSigList,
+ ...
+ }
+
+SeqSigList ::= SEQUENCE
+ {
+ id INTEGER(0..65535),
+ signalList SEQUENCE OF Signal
+ }
+
+Signal ::= SEQUENCE
+ {
+ signalName SignalName,
+ streamID StreamID OPTIONAL,
+ sigType SignalType OPTIONAL,
+ duration INTEGER (0..65535) OPTIONAL,
+ notifyCompletion NotifyCompletion OPTIONAL,
+ keepActive BOOLEAN OPTIONAL,
+ sigParList SEQUENCE OF SigParameter,
+ ...,
+ direction SignalDirection OPTIONAL,
+ requestID RequestID OPTIONAL,
+ intersigDelay INTEGER (0..65535) OPTIONAL
+ }
+
+SignalType ::= ENUMERATED
+ {
+ brief(0),
+ onOff(1),
+ timeOut(2),
+ ...
+ }
+
+SignalDirection ::= ENUMERATED
+ {
+ internal(0),
+ external(1),
+ both(3),
+ ...
+ }
+
+SignalName ::= PkgdName
+
+NotifyCompletion ::= BIT STRING
+ {
+ onTimeOut(0), onInterruptByEvent(1),
+ onInterruptByNewSignalDescr(2), otherReason(3), onIteration(4)
+ }
+
+SigParameter ::= SEQUENCE
+ {
+ sigParameterName Name,
+ value Value,
+ -- For use of extraInfo see the comment related to PropertyParm
+ extraInfo CHOICE
+ {
+ relation Relation,
+ range BOOLEAN,
+ sublist BOOLEAN
+ } OPTIONAL,
+ ...
+ }
+
+-- For an AuditCapReply with all events, the RequestID SHALL be ALL.
+-- ALL is represented by 0xffffffff.
+RequestID ::= INTEGER(0..4294967295) -- 32-bit unsigned integer
+
+ModemDescriptor ::= SEQUENCE
+ {
+ mtl SEQUENCE OF ModemType,
+ mpl SEQUENCE OF PropertyParm,
+ nonStandardData NonStandardData OPTIONAL
+ }
+
+ModemType ::= ENUMERATED
+ {
+ v18(0),
+ v22(1),
+ v22bis(2),
+ v32(3),
+ v32bis(4),
+ v34(5),
+ v90(6),
+ v91(7),
+ synchISDN(8),
+ ...
+ }
+
+DigitMapDescriptor ::= SEQUENCE
+ {
+ digitMapName DigitMapName OPTIONAL,
+ digitMapValue DigitMapValue OPTIONAL
+ }
+
+DigitMapName ::= Name
+
+DigitMapValue ::= SEQUENCE
+ {
+ startTimer INTEGER(0..99) OPTIONAL,
+ shortTimer INTEGER(0..99) OPTIONAL,
+ longTimer INTEGER(0..99) OPTIONAL,
+ digitMapBody IA5String,
+ -- Units are seconds for start, short and long timers, and
+ -- hundreds of milliseconds for duration timer. Thus start,
+ -- short, and long range from 1 to 99 seconds and duration
+ -- from 100 ms to 9.9 s
+ -- See A.3 for explanation of digit map syntax
+ ...,
+ durationTimer INTEGER (0..99) OPTIONAL
+ }
+
+ServiceChangeParm ::= SEQUENCE
+ {
+ serviceChangeMethod ServiceChangeMethod,
+ serviceChangeAddress ServiceChangeAddress OPTIONAL,
+ serviceChangeVersion INTEGER(0..99) OPTIONAL,
+ serviceChangeProfile ServiceChangeProfile OPTIONAL,
+ serviceChangeReason Value,
+ -- A serviceChangeReason consists of a numeric reason code
+ -- and an optional text description.
+ -- The serviceChangeReason SHALL be a string consisting of
+ -- a decimal reason code, optionally followed by a single
+ -- space character and a textual description string.
+ -- This string is first BER-encoded as an IA5String.
+ -- The result of this BER-encoding is then encoded as
+ -- an ASN.1 OCTET STRING type, "double wrapping" the
+ -- value
+ -- as was done for package elements.
+ serviceChangeDelay INTEGER(0..4294967295) OPTIONAL,
+ -- 32-bit unsigned integer
+ serviceChangeMgcId MId OPTIONAL,
+ timeStamp TimeNotation OPTIONAL,
+ nonStandardData NonStandardData OPTIONAL,
+ ...,
+ serviceChangeInfo AuditDescriptor OPTIONAL,
+ serviceChangeIncompleteFlag NULL OPTIONAL
+ }
+
+ServiceChangeAddress ::= CHOICE
+ {
+ portNumber INTEGER(0..65535), -- TCP/UDP port number
+ ip4Address IP4Address,
+ ip6Address IP6Address,
+ domainName DomainName,
+ deviceName PathName,
+ mtpAddress OCTET STRING(SIZE(2..4)),
+ ...
+ }
+
+ServiceChangeResParm ::= SEQUENCE
+ {
+ serviceChangeMgcId MId OPTIONAL,
+ serviceChangeAddress ServiceChangeAddress OPTIONAL,
+ serviceChangeVersion INTEGER(0..99) OPTIONAL,
+ serviceChangeProfile ServiceChangeProfile OPTIONAL,
+ timestamp TimeNotation OPTIONAL,
+ ...
+ }
+
+ServiceChangeMethod ::= ENUMERATED
+ {
+ failover(0),
+ forced(1),
+ graceful(2),
+ restart(3),
+ disconnected(4),
+ handOff(5),
+ ...
+ }
+
+ServiceChangeProfile ::= SEQUENCE
+ {
+ profileName IA5String(SIZE (1..67))
+
+ -- 64 characters for name, 1 for "/", 2 for version to match ABNF
+ }
+
+PackagesDescriptor ::= SEQUENCE OF PackagesItem
+
+PackagesItem ::= SEQUENCE
+ {
+ packageName Name,
+ packageVersion INTEGER(0..99),
+ ...
+ }
+
+StatisticsDescriptor ::= SEQUENCE OF StatisticsParameter
+
+StatisticsParameter ::= SEQUENCE
+ {
+ statName PkgdName,
+ statValue Value OPTIONAL
+ }
+
+-- If statistic consists of a sub-list there will be more than one
+-- octetstring in statValue.
+
+NonStandardData ::= SEQUENCE
+ {
+ nonStandardIdentifier NonStandardIdentifier,
+ data OCTET STRING
+ }
+
+NonStandardIdentifier ::= CHOICE
+ {
+ object OBJECT IDENTIFIER,
+ h221NonStandard H221NonStandard,
+ experimental IA5String(SIZE(8)),
+ -- first two characters SHOULD be "X-" or "X+"
+ ...
+ }
+
+H221NonStandard ::= SEQUENCE
+ { t35CountryCode1 INTEGER(0..255),
+ t35CountryCode2 INTEGER(0..255), -- country, as per T.35
+ t35Extension INTEGER(0..255), -- assigned nationally
+ manufacturerCode INTEGER(0..65535), -- assigned nationally
+ ...
+ }
+
+TimeNotation ::= SEQUENCE
+ {
+ date IA5String(SIZE(8)), -- yyyymmdd format
+ time IA5String(SIZE(8)) -- hhmmssss format
+ -- per ISO 8601:1988
+ }
+
+Value ::= SEQUENCE OF OCTET STRING
+
+END
diff --git a/lib/megaco/src/binary/Makefile b/lib/megaco/src/binary/Makefile
new file mode 100644
index 0000000000..d594f34f43
--- /dev/null
+++ b/lib/megaco/src/binary/Makefile
@@ -0,0 +1,212 @@
+#
+# %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
+MEGACO_ENGINEDIR = ../engine
+
+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
+
+ASN1_SPECS = $(ASN1_V1_SPEC) \
+ $(ASN1_V2_SPEC) \
+ $(ASN1_PREV3A_SPEC)
+ASN1_FILES = $(ASN1_SPECS:%=%.asn)
+
+V1_SPECS = $(BER_ASN1_V1_SPEC) \
+ $(BER_BIN_ASN1_V1_SPEC) \
+ $(BER_BIN_DRV_ASN1_V1_SPEC) \
+ $(PER_ASN1_V1_SPEC) \
+ $(PER_BIN_ASN1_V1_SPEC) \
+ $(PER_BIN_DRV_ASN1_V1_SPEC)
+
+V2_SPECS = $(BER_ASN1_V2_SPEC) \
+ $(BER_BIN_ASN1_V2_SPEC) \
+ $(BER_BIN_DRV_ASN1_V2_SPEC) \
+ $(PER_ASN1_V2_SPEC) \
+ $(PER_BIN_ASN1_V2_SPEC) \
+ $(PER_BIN_DRV_ASN1_V2_SPEC)
+
+PREV3A_SPECS = $(BER_ASN1_PREV3A_SPEC) \
+ $(BER_BIN_ASN1_PREV3A_SPEC) \
+ $(BER_BIN_DRV_ASN1_PREV3A_SPEC) \
+ $(PER_ASN1_PREV3A_SPEC) \
+ $(PER_BIN_ASN1_PREV3A_SPEC) \
+ $(PER_BIN_DRV_ASN1_PREV3A_SPEC)
+
+PREV3B_SPECS = $(BER_ASN1_PREV3B_SPEC) \
+ $(BER_BIN_ASN1_PREV3B_SPEC) \
+ $(BER_BIN_DRV_ASN1_PREV3B_SPEC) \
+ $(PER_ASN1_PREV3B_SPEC) \
+ $(PER_BIN_ASN1_PREV3B_SPEC) \
+ $(PER_BIN_DRV_ASN1_PREV3B_SPEC)
+
+PREV3C_SPECS = $(BER_ASN1_PREV3C_SPEC) \
+ $(BER_BIN_ASN1_PREV3C_SPEC) \
+ $(BER_BIN_DRV_ASN1_PREV3C_SPEC) \
+ $(PER_ASN1_PREV3C_SPEC) \
+ $(PER_BIN_ASN1_PREV3C_SPEC) \
+ $(PER_BIN_DRV_ASN1_PREV3C_SPEC)
+
+V3_SPECS = $(BER_ASN1_V3_SPEC) \
+ $(BER_BIN_ASN1_V3_SPEC) \
+ $(BER_BIN_DRV_ASN1_V3_SPEC) \
+ $(PER_ASN1_V3_SPEC) \
+ $(PER_BIN_ASN1_V3_SPEC) \
+ $(PER_BIN_DRV_ASN1_V3_SPEC) \
+ $(PREV3A_SPECS) $(PREV3B_SPECS) $(PREV3C_SPECS)
+
+SPECS = $(V1_SPECS) $(V2_SPECS) $(V3_SPECS)
+
+V1_SPEC_ASN1DB = $(V1_SPECS:%=%.asn1db)
+V2_SPEC_ASN1DB = $(V2_SPECS:%=%.asn1db)
+PREV3A_SPEC_ASN1DB = $(PREV3A_SPECS:%=%.asn1db)
+PREV3B_SPEC_ASN1DB = $(PREV3B_SPECS:%=%.asn1db)
+PREV3C_SPEC_ASN1DB = $(PREV3C_SPECS:%=%.asn1db)
+V3_SPEC_ASN1DB = $(V3_SPECS:%=%.asn1db) \
+ $(PREV3A_SPEC_ASN1DB) \
+ $(PREV3B_SPEC_ASN1DB) \
+ $(PREV3C_SPEC_ASN1DB)
+SPEC_ASN1DB = $(V1_SPEC_ASN1DB) \
+ $(V2_SPEC_ASN1DB)\
+ $(V3_SPEC_ASN1DB)
+
+V1_SPEC_BINS = $(V1_SPECS:%=%.erl) $(V1_SPECS:%=%.hrl)
+V2_SPEC_BINS = $(V2_SPECS:%=%.erl) $(V2_SPECS:%=%.hrl)
+PREV3A_SPEC_BINS = $(PREV3A_SPECS:%=%.erl) $(PREV3A_SPECS:%=%.hrl)
+PREV3B_SPEC_BINS = $(PREV3B_SPECS:%=%.erl) $(PREV3B_SPECS:%=%.hrl)
+PREV3C_SPEC_BINS = $(PREV3C_SPECS:%=%.erl) $(PREV3C_SPECS:%=%.hrl)
+V3_SPEC_BINS = $(V3_SPECS:%=%.erl) $(V3_SPECS:%=%.hrl) \
+ $(PREV3A_SPEC_BINS) \
+ $(PREV3B_SPEC_BINS) \
+ $(PREV3C_SPEC_BINS)
+SPEC_BINS = $(V1_SPEC_BINS) $(V2_SPEC_BINS) $(V3_SPEC_BINS)
+
+ERL_FILES = $(MODULES:%=%.erl)
+HRL_FILES = $(INTERNAL_HRL_FILES) \
+ $(V1_SPECS:%=%.hrl) \
+ $(V2_SPECS:%=%.hrl) \
+ $(V3_SPECS:%=%.hrl)
+
+TARGET_FILES = \
+ $(MODULES:%=$(EBIN)/%.$(EMULATOR))
+
+
+# ----------------------------------------------------
+# FLAGS
+# ----------------------------------------------------
+ifeq ($(TYPE),debug)
+ERL_COMPILE_FLAGS += -Ddebug
+endif
+
+include ../app/megaco.mk
+
+ERL_COMPILE_FLAGS += \
+ $(MEGACO_ERL_COMPILE_FLAGS) \
+ -I../../include
+
+
+# ----------------------------------------------------
+# Targets
+# ----------------------------------------------------
+debug:
+ @${MAKE} TYPE=debug opt
+
+opt: prebuild $(TARGET_FILES)
+
+prebuild: prebuild.skip
+
+prebuild.skip:
+ @echo "Building prebuild.skip\c"
+ @touch prebuild.skip
+ @for a in $(SPEC_ASN1DB); do \
+ echo $$a >> prebuild.skip; \
+ done
+ @echo ""
+
+v1: $(V2_SPEC_BINS)
+
+v2: $(V2_SPEC_BINS)
+
+v3: $(V3_SPEC_BINS)
+
+specs: v1 v2 v3
+
+clean:
+ rm -f $(TARGET_FILES)
+ rm -f $(SPEC_BINS)
+ rm -f $(SPEC_ASN1DB)
+ rm -f prebuild.skip
+ rm -f core *~
+
+docs:
+
+info:
+ @echo "MODULES: $(MODULES)"
+ @echo "ERL_FILES: $(ERL_FILES)"
+ @echo "HRL_FILES: $(HRL_FILES)"
+ @echo "TARGET_FILES: $(TARGET_FILES)"
+ @echo "ASN1_SPECS: $(ASN1_SPECS)"
+ @echo "SPECS: $(SPECS)"
+ @echo "SPEC_BINS: $(SPEC_BINS)"
+
+
+# ----------------------------------------------------
+# Release Target
+# ----------------------------------------------------
+include $(ERL_TOP)/make/otp_release_targets.mk
+
+
+release_spec: opt
+ $(INSTALL_DIR) $(RELSYSDIR)/ebin
+ $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
+ $(INSTALL_DIR) $(RELSYSDIR)/src
+ $(INSTALL_DIR) $(RELSYSDIR)/src/binary
+ $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(ASN1_FILES) $(RELSYSDIR)/src/binary
+
+
+release_docs_spec:
+
+
+# ----------------------------------------------------
+# Include dependencies
+# ----------------------------------------------------
+
+include depend.mk
+
diff --git a/lib/megaco/src/binary/depend.mk b/lib/megaco/src/binary/depend.mk
new file mode 100644
index 0000000000..5ec4977175
--- /dev/null
+++ b/lib/megaco/src/binary/depend.mk
@@ -0,0 +1,557 @@
+#-*-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%
+
+# Flag description:
+#
+# +optimize
+# For ber_bin this means "optimize" (whatever that is),
+# but for per_bin it means that a stage in the encode
+# is done in the asn1 driver.
+#
+# +driver
+# For ber_bin this means that part of the decode is done
+# in the asn1 driver.
+#
+# +asn1config
+# This is only used by the ber_bin, and means that
+# some partial decode functions will be created
+# (as described by the asn1config file).
+#
+# +inline
+# This means that the ASN.1 runtime library will be inlined.
+#
+
+ASN1_CT_OPTS += +noobj
+ifeq ($(MEGACO_INLINE_ASN1_RT),true)
+# We need atleast version 1.4.6 of the ANS.1 application
+ASN1_CT_OPTS += +inline
+endif
+
+BER_V1_FLAGS = $(ASN1_CT_OPTS)
+BER_BIN_V1_FLAGS = $(ASN1_CT_OPTS) +asn1config +optimize
+BER_BIN_DRV_V1_FLAGS = $(ASN1_CT_OPTS) +asn1config +optimize +driver
+BER_V2_FLAGS = $(ASN1_CT_OPTS)
+BER_BIN_V2_FLAGS = $(ASN1_CT_OPTS) +asn1config +optimize
+BER_BIN_DRV_V2_FLAGS = $(ASN1_CT_OPTS) +asn1config +optimize +driver
+BER_PREV3A_FLAGS = $(ASN1_CT_OPTS)
+BER_BIN_PREV3A_FLAGS = $(ASN1_CT_OPTS) +asn1config +optimize
+BER_BIN_DRV_PREV3A_FLAGS = $(ASN1_CT_OPTS) +asn1config +optimize +driver
+BER_PREV3B_FLAGS = $(ASN1_CT_OPTS)
+BER_BIN_PREV3B_FLAGS = $(ASN1_CT_OPTS) +asn1config +optimize
+BER_BIN_DRV_PREV3B_FLAGS = $(ASN1_CT_OPTS) +asn1config +optimize +driver
+BER_PREV3C_FLAGS = $(ASN1_CT_OPTS)
+BER_BIN_PREV3C_FLAGS = $(ASN1_CT_OPTS) +asn1config +optimize
+BER_BIN_DRV_PREV3C_FLAGS = $(ASN1_CT_OPTS) +asn1config +optimize +driver
+BER_V3_FLAGS = $(ASN1_CT_OPTS)
+BER_BIN_V3_FLAGS = $(ASN1_CT_OPTS) +asn1config +optimize
+BER_BIN_DRV_V3_FLAGS = $(ASN1_CT_OPTS) +asn1config +optimize +driver
+PER_V1_FLAGS = $(ASN1_CT_OPTS)
+PER_BIN_V1_FLAGS = $(ASN1_CT_OPTS)
+PER_BIN_DRV_V1_FLAGS = $(ASN1_CT_OPTS) +optimize
+PER_V2_FLAGS = $(ASN1_CT_OPTS)
+PER_BIN_V2_FLAGS = $(ASN1_CT_OPTS)
+PER_BIN_DRV_V2_FLAGS = $(ASN1_CT_OPTS) +optimize
+PER_PREV3A_FLAGS = $(ASN1_CT_OPTS)
+PER_BIN_PREV3A_FLAGS = $(ASN1_CT_OPTS)
+PER_BIN_DRV_PREV3A_FLAGS = $(ASN1_CT_OPTS) +optimize
+PER_PREV3B_FLAGS = $(ASN1_CT_OPTS)
+PER_BIN_PREV3B_FLAGS = $(ASN1_CT_OPTS)
+PER_BIN_DRV_PREV3B_FLAGS = $(ASN1_CT_OPTS) +optimize
+PER_PREV3C_FLAGS = $(ASN1_CT_OPTS)
+PER_BIN_PREV3C_FLAGS = $(ASN1_CT_OPTS)
+PER_BIN_DRV_PREV3C_FLAGS = $(ASN1_CT_OPTS) +optimize
+PER_V3_FLAGS = $(ASN1_CT_OPTS)
+PER_BIN_V3_FLAGS = $(ASN1_CT_OPTS)
+PER_BIN_DRV_V3_FLAGS = $(ASN1_CT_OPTS) +optimize
+
+
+# --- Version 1 ---
+
+$(BER_ASN1_V1_SPEC).erl $(BER_ASN1_V1_SPEC).hrl: \
+ $(BER_ASN1_V1_SPEC).set.asn \
+ $(ASN1_V1_SPEC).asn
+ @echo "$(BER_ASN1_V1_SPEC):"
+ $(ERLC) -bber $(BER_V1_FLAGS) $(BER_ASN1_V1_SPEC).set.asn
+
+$(EBIN)/$(BER_ASN1_V1_SPEC).$(EMULATOR): \
+ $(BER_ASN1_V1_SPEC).erl \
+ $(BER_ASN1_V1_SPEC).hrl
+
+$(BER_BIN_ASN1_V1_SPEC).erl $(BER_BIN_ASN1_V1_SPEC).hrl: \
+ $(BER_BIN_ASN1_V1_SPEC).set.asn \
+ $(BER_BIN_ASN1_V1_SPEC).asn1config \
+ $(ASN1_V1_SPEC).asn
+ @echo "$(BER_BIN_ASN1_V1_SPEC):"
+ $(ERLC) -bber_bin $(BER_BIN_V1_FLAGS) $(BER_BIN_ASN1_V1_SPEC).set.asn
+
+$(EBIN)/$(BER_BIN_ASN1_V1_SPEC).$(EMULATOR): \
+ $(BER_BIN_ASN1_V1_SPEC).erl \
+ $(BER_BIN_ASN1_V1_SPEC).hrl
+
+$(BER_BIN_DRV_ASN1_V1_SPEC).erl $(BER_BIN_DRV_ASN1_V1_SPEC).hrl: \
+ $(BER_BIN_DRV_ASN1_V1_SPEC).set.asn \
+ $(BER_BIN_DRV_ASN1_V1_SPEC).asn1config \
+ $(ASN1_V1_SPEC).asn
+ @echo "$(BER_BIN_DRV_ASN1_V1_SPEC):"
+ $(ERLC) -bber_bin $(BER_BIN_DRV_V1_FLAGS) $(BER_BIN_DRV_ASN1_V1_SPEC).set.asn
+
+$(EBIN)/$(BER_BIN_DRV_ASN1_V1_SPEC).$(EMULATOR): \
+ $(BER_BIN_DRV_ASN1_V1_SPEC).erl \
+ $(BER_BIN_DRV_ASN1_V1_SPEC).hrl
+
+$(PER_ASN1_V1_SPEC).erl $(PER_ASN1_V1_SPEC).hrl: \
+ $(PER_ASN1_V1_SPEC).set.asn \
+ $(ASN1_V1_SPEC).asn
+ @echo "$(PER_ASN1_V1_SPEC):"
+ $(ERLC) -bper $(PER_V1_FLAGS) $(PER_ASN1_V1_SPEC).set.asn
+
+$(EBIN)/$(PER_ASN1_V1_SPEC).$(EMULATOR): \
+ $(PER_ASN1_V1_SPEC).erl \
+ $(PER_ASN1_V1_SPEC).hrl
+
+$(PER_BIN_ASN1_V1_SPEC).erl $(PER_BIN_ASN1_V1_SPEC).hrl: \
+ $(PER_BIN_ASN1_V1_SPEC).set.asn \
+ $(ASN1_V1_SPEC).asn
+ @echo "$(PER_BIN_ASN1_V1_SPEC):"
+ $(ERLC) -bper_bin $(PER_BIN_V1_FLAGS) $(PER_BIN_ASN1_V1_SPEC).set.asn
+
+$(EBIN)/$(PER_BIN_ASN1_V1_SPEC).$(EMULATOR): \
+ $(PER_BIN_ASN1_V1_SPEC).erl \
+ $(PER_BIN_ASN1_V1_SPEC).hrl
+
+$(PER_BIN_DRV_ASN1_V1_SPEC).erl $(PER_BIN_DRV_ASN1_V1_SPEC).hrl: \
+ $(PER_BIN_DRV_ASN1_V1_SPEC).set.asn \
+ $(ASN1_V1_SPEC).asn
+ @echo "$(PER_BIN_DRV_ASN1_V1_SPEC):"
+ $(ERLC) -bper_bin $(PER_BIN_DRV_V1_FLAGS) $(PER_BIN_DRV_ASN1_V1_SPEC).set.asn
+
+$(EBIN)/$(PER_BIN_DRV_ASN1_V1_SPEC).$(EMULATOR): \
+ $(PER_BIN_DRV_ASN1_V1_SPEC).erl \
+ $(PER_BIN_DRV_ASN1_V1_SPEC).hrl
+
+
+# --- Version 2 ---
+
+$(BER_ASN1_V2_SPEC).erl $(BER_ASN1_V2_SPEC).hrl: \
+ $(BER_ASN1_V2_SPEC).set.asn \
+ $(ASN1_V2_SPEC).asn
+ @echo "$(BER_ASN1_V2_SPEC):"
+ $(ERLC) -bber $(BER_V2_FLAGS) $(BER_ASN1_V2_SPEC).set.asn
+
+$(EBIN)/$(BER_ASN1_V2_SPEC).$(EMULATOR): \
+ $(BER_ASN1_V2_SPEC).erl \
+ $(BER_ASN1_V2_SPEC).hrl
+
+$(BER_BIN_ASN1_V2_SPEC).erl $(BER_BIN_ASN1_V2_SPEC).hrl: \
+ $(BER_BIN_ASN1_V2_SPEC).set.asn \
+ $(BER_BIN_ASN1_V2_SPEC).asn1config \
+ $(ASN1_V2_SPEC).asn
+ @echo "$(BER_BIN_ASN1_V2_SPEC):"
+ $(ERLC) -bber_bin $(BER_BIN_V2_FLAGS) $(BER_BIN_ASN1_V2_SPEC).set.asn
+
+$(EBIN)/$(BER_BIN_ASN1_V2_SPEC).$(EMULATOR): \
+ $(BER_BIN_ASN1_V2_SPEC).erl \
+ $(BER_BIN_ASN1_V2_SPEC).hrl
+
+$(BER_BIN_DRV_ASN1_V2_SPEC).erl $(BER_BIN_DRV_ASN1_V2_SPEC).hrl: \
+ $(BER_BIN_DRV_ASN1_V2_SPEC).set.asn \
+ $(BER_BIN_DRV_ASN1_V2_SPEC).asn1config \
+ $(ASN1_V2_SPEC).asn
+ @echo "$(BER_BIN_DRV_ASN1_V2_SPEC):"
+ $(ERLC) -bber_bin $(BER_BIN_DRV_V2_FLAGS) $(BER_BIN_DRV_ASN1_V2_SPEC).set.asn
+
+$(EBIN)/$(BER_BIN_DRV_ASN1_V2_SPEC).$(EMULATOR): \
+ $(BER_BIN_DRV_ASN1_V2_SPEC).erl \
+ $(BER_BIN_DRV_ASN1_V2_SPEC).hrl
+
+$(PER_ASN1_V2_SPEC).erl $(PER_ASN1_V2_SPEC).hrl: \
+ $(PER_ASN1_V2_SPEC).set.asn \
+ $(ASN1_V2_SPEC).asn
+ @echo "$(PER_ASN1_V2_SPEC):"
+ $(ERLC) -bper $(PER_V2_FLAGS) $(PER_ASN1_V2_SPEC).set.asn
+
+$(EBIN)/$(PER_ASN1_V2_SPEC).$(EMULATOR): \
+ $(PER_ASN1_V2_SPEC).erl \
+ $(PER_ASN1_V2_SPEC).hrl
+
+$(PER_BIN_ASN1_V2_SPEC).erl $(PER_BIN_ASN1_V2_SPEC).hrl: \
+ $(PER_BIN_ASN1_V2_SPEC).set.asn \
+ $(ASN1_V2_SPEC).asn
+ @echo "$(PER_BIN_ASN1_V2_SPEC):"
+ $(ERLC) -bper_bin $(PER_BIN_V2_FLAGS) $(PER_BIN_ASN1_V2_SPEC).set.asn
+
+$(EBIN)/$(PER_BIN_ASN1_V2_SPEC).$(EMULATOR): \
+ $(PER_BIN_ASN1_V2_SPEC).erl \
+ $(PER_BIN_ASN1_V2_SPEC).hrl
+
+$(PER_BIN_DRV_ASN1_V2_SPEC).erl $(PER_BIN_DRV_ASN1_V2_SPEC).hrl: \
+ $(PER_BIN_DRV_ASN1_V2_SPEC).set.asn \
+ $(ASN1_V2_SPEC).asn
+ @echo "$(PER_BIN_DRV_ASN1_V2_SPEC):"
+ $(ERLC) -bper_bin $(PER_BIN_DRV_V2_FLAGS) $(PER_BIN_DRV_ASN1_V2_SPEC).set.asn
+
+$(EBIN)/$(PER_BIN_DRV_ASN1_V2_SPEC).$(EMULATOR): \
+ $(PER_BIN_DRV_ASN1_V2_SPEC).erl \
+ $(PER_BIN_DRV_ASN1_V2_SPEC).hrl
+
+
+# --- Version 3 ---
+
+# -- (prev3a) --
+
+$(BER_ASN1_PREV3A_SPEC).erl $(BER_ASN1_PREV3A_SPEC).hrl: \
+ $(BER_ASN1_PREV3A_SPEC).set.asn \
+ $(ASN1_PREV3A_SPEC).asn
+ @echo "$(BER_ASN1_PREV3A_SPEC):"
+ $(ERLC) -bber $(BER_PREV3A_FLAGS) $(BER_ASN1_PREV3A_SPEC).set.asn
+
+$(EBIN)/$(BER_ASN1_PREV3A_SPEC).$(EMULATOR): \
+ $(BER_ASN1_PREV3A_SPEC).erl \
+ $(BER_ASN1_PREV3A_SPEC).hrl
+
+$(BER_BIN_ASN1_PREV3A_SPEC).erl $(BER_BIN_ASN1_PREV3A_SPEC).hrl: \
+ $(BER_BIN_ASN1_PREV3A_SPEC).set.asn \
+ $(BER_BIN_ASN1_PREV3A_SPEC).asn1config \
+ $(ASN1_PREV3A_SPEC).asn
+ @echo "$(BER_BIN_ASN1_PREV3A_SPEC):"
+ $(ERLC) -bber_bin $(BER_BIN_PREV3A_FLAGS) $(BER_BIN_ASN1_PREV3A_SPEC).set.asn
+
+$(EBIN)/$(BER_BIN_ASN1_PREV3A_SPEC).$(EMULATOR): \
+ $(BER_BIN_ASN1_PREV3A_SPEC).erl \
+ $(BER_BIN_ASN1_PREV3A_SPEC).hrl
+
+$(BER_BIN_DRV_ASN1_PREV3A_SPEC).erl $(BER_BIN_DRV_ASN1_PREV3A_SPEC).hrl: \
+ $(BER_BIN_DRV_ASN1_PREV3A_SPEC).set.asn \
+ $(BER_BIN_DRV_ASN1_PREV3A_SPEC).asn1config \
+ $(ASN1_PREV3A_SPEC).asn
+ @echo "$(BER_BIN_DRV_ASN1_PREV3A_SPEC):"
+ $(ERLC) -bber_bin $(BER_BIN_DRV_PREV3A_FLAGS) $(BER_BIN_DRV_ASN1_PREV3A_SPEC).set.asn
+
+$(EBIN)/$(BER_BIN_DRV_ASN1_PREV3A_SPEC).$(EMULATOR): \
+ $(BER_BIN_DRV_ASN1_PREV3A_SPEC).erl \
+ $(BER_BIN_DRV_ASN1_PREV3A_SPEC).hrl
+
+$(PER_ASN1_PREV3A_SPEC).erl $(PER_ASN1_PREV3A_SPEC).hrl: \
+ $(PER_ASN1_PREV3A_SPEC).set.asn \
+ $(ASN1_PREV3A_SPEC).asn
+ @echo "$(PER_ASN1_PREV3A_SPEC):"
+ $(ERLC) -bper $(PER_PREV3A_FLAGS) $(PER_ASN1_PREV3A_SPEC).set.asn
+
+$(EBIN)/$(PER_ASN1_PREV3A_SPEC).$(EMULATOR): \
+ $(PER_ASN1_PREV3A_SPEC).erl \
+ $(PER_ASN1_PREV3A_SPEC).hrl
+
+$(PER_BIN_ASN1_PREV3A_SPEC).erl $(PER_BIN_ASN1_PREV3A_SPEC).hrl: \
+ $(PER_BIN_ASN1_PREV3A_SPEC).set.asn \
+ $(ASN1_PREV3A_SPEC).asn
+ @echo "$(PER_BIN_ASN1_PREV3A_SPEC):"
+ $(ERLC) -bper_bin $(PER_BIN_PREV3A_FLAGS) $(PER_BIN_ASN1_PREV3A_SPEC).set.asn
+
+$(EBIN)/$(PER_BIN_ASN1_PREV3A_SPEC).$(EMULATOR): \
+ $(PER_BIN_ASN1_PREV3A_SPEC).erl \
+ $(PER_BIN_ASN1_PREV3A_SPEC).hrl
+
+$(PER_BIN_DRV_ASN1_PREV3A_SPEC).erl $(PER_BIN_DRV_ASN1_PREV3A_SPEC).hrl: \
+ $(PER_BIN_DRV_ASN1_PREV3A_SPEC).set.asn \
+ $(ASN1_PREV3A_SPEC).asn
+ @echo "$(PER_BIN_DRV_ASN1_PREV3A_SPEC):"
+ $(ERLC) -bper_bin $(PER_BIN_DRV_PREV3A_FLAGS) $(PER_BIN_DRV_ASN1_PREV3A_SPEC).set.asn
+
+$(EBIN)/$(PER_BIN_DRV_ASN1_PREV3A_SPEC).$(EMULATOR): \
+ $(PER_BIN_DRV_ASN1_PREV3A_SPEC).erl \
+ $(PER_BIN_DRV_ASN1_PREV3A_SPEC).hrl
+
+# -- (prev3b) --
+
+$(BER_ASN1_PREV3B_SPEC).erl $(BER_ASN1_PREV3B_SPEC).hrl: \
+ $(BER_ASN1_PREV3B_SPEC).set.asn \
+ $(ASN1_PREV3B_SPEC).asn
+ @echo "$(BER_ASN1_PREV3B_SPEC):"
+ $(ERLC) -bber $(BER_PREV3B_FLAGS) $(BER_ASN1_PREV3B_SPEC).set.asn
+
+$(EBIN)/$(BER_ASN1_PREV3B_SPEC).$(EMULATOR): \
+ $(BER_ASN1_PREV3B_SPEC).erl \
+ $(BER_ASN1_PREV3B_SPEC).hrl
+
+$(BER_BIN_ASN1_PREV3B_SPEC).erl $(BER_BIN_ASN1_PREV3B_SPEC).hrl: \
+ $(BER_BIN_ASN1_PREV3B_SPEC).set.asn \
+ $(BER_BIN_ASN1_PREV3B_SPEC).asn1config \
+ $(ASN1_PREV3B_SPEC).asn
+ @echo "$(BER_BIN_ASN1_PREV3B_SPEC):"
+ $(ERLC) -bber_bin $(BER_BIN_PREV3B_FLAGS) $(BER_BIN_ASN1_PREV3B_SPEC).set.asn
+
+$(EBIN)/$(BER_BIN_ASN1_PREV3B_SPEC).$(EMULATOR): \
+ $(BER_BIN_ASN1_PREV3B_SPEC).erl \
+ $(BER_BIN_ASN1_PREV3B_SPEC).hrl
+
+$(BER_BIN_DRV_ASN1_PREV3B_SPEC).erl $(BER_BIN_DRV_ASN1_PREV3B_SPEC).hrl: \
+ $(BER_BIN_DRV_ASN1_PREV3B_SPEC).set.asn \
+ $(BER_BIN_DRV_ASN1_PREV3B_SPEC).asn1config \
+ $(ASN1_PREV3B_SPEC).asn
+ @echo "$(BER_BIN_DRV_ASN1_PREV3B_SPEC):"
+ $(ERLC) -bber_bin $(BER_BIN_DRV_PREV3B_FLAGS) $(BER_BIN_DRV_ASN1_PREV3B_SPEC).set.asn
+
+$(EBIN)/$(BER_BIN_DRV_ASN1_PREV3B_SPEC).$(EMULATOR): \
+ $(BER_BIN_DRV_ASN1_PREV3B_SPEC).erl \
+ $(BER_BIN_DRV_ASN1_PREV3B_SPEC).hrl
+
+$(PER_ASN1_PREV3B_SPEC).erl $(PER_ASN1_PREV3B_SPEC).hrl: \
+ $(PER_ASN1_PREV3B_SPEC).set.asn \
+ $(ASN1_PREV3B_SPEC).asn
+ @echo "$(PER_ASN1_PREV3B_SPEC):"
+ $(ERLC) -bper $(PER_PREV3B_FLAGS) $(PER_ASN1_PREV3B_SPEC).set.asn
+
+$(EBIN)/$(PER_ASN1_PREV3B_SPEC).$(EMULATOR): \
+ $(PER_ASN1_PREV3B_SPEC).erl \
+ $(PER_ASN1_PREV3B_SPEC).hrl
+
+$(PER_BIN_ASN1_PREV3B_SPEC).erl $(PER_BIN_ASN1_PREV3B_SPEC).hrl: \
+ $(PER_BIN_ASN1_PREV3B_SPEC).set.asn \
+ $(ASN1_PREV3B_SPEC).asn
+ @echo "$(PER_BIN_ASN1_PREV3B_SPEC):"
+ $(ERLC) -bper_bin $(PER_BIN_PREV3B_FLAGS) $(PER_BIN_ASN1_PREV3B_SPEC).set.asn
+
+$(EBIN)/$(PER_BIN_ASN1_PREV3B_SPEC).$(EMULATOR): \
+ $(PER_BIN_ASN1_PREV3B_SPEC).erl \
+ $(PER_BIN_ASN1_PREV3B_SPEC).hrl
+
+$(PER_BIN_DRV_ASN1_PREV3B_SPEC).erl $(PER_BIN_DRV_ASN1_PREV3B_SPEC).hrl: \
+ $(PER_BIN_DRV_ASN1_PREV3B_SPEC).set.asn \
+ $(ASN1_PREV3B_SPEC).asn
+ @echo "$(PER_BIN_DRV_ASN1_PREV3B_SPEC):"
+ $(ERLC) -bper_bin $(PER_BIN_DRV_PREV3B_FLAGS) $(PER_BIN_DRV_ASN1_PREV3B_SPEC).set.asn
+
+$(EBIN)/$(PER_BIN_DRV_ASN1_PREV3B_SPEC).$(EMULATOR): \
+ $(PER_BIN_DRV_ASN1_PREV3B_SPEC).erl \
+ $(PER_BIN_DRV_ASN1_PREV3B_SPEC).hrl
+
+
+# -- (prev3c) --
+
+$(BER_ASN1_PREV3C_SPEC).erl $(BER_ASN1_PREV3C_SPEC).hrl: \
+ $(BER_ASN1_PREV3C_SPEC).set.asn \
+ $(ASN1_PREV3C_SPEC).asn
+ @echo "$(BER_ASN1_PREV3C_SPEC):"
+ $(ERLC) -bber $(BER_PREV3C_FLAGS) $(BER_ASN1_PREV3C_SPEC).set.asn
+
+$(EBIN)/$(BER_ASN1_PREV3C_SPEC).$(EMULATOR): \
+ $(BER_ASN1_PREV3C_SPEC).erl \
+ $(BER_ASN1_PREV3C_SPEC).hrl
+
+$(BER_BIN_ASN1_PREV3C_SPEC).erl $(BER_BIN_ASN1_PREV3C_SPEC).hrl: \
+ $(BER_BIN_ASN1_PREV3C_SPEC).set.asn \
+ $(BER_BIN_ASN1_PREV3C_SPEC).asn1config \
+ $(ASN1_PREV3C_SPEC).asn
+ @echo "$(BER_BIN_ASN1_PREV3C_SPEC):"
+ $(ERLC) -bber_bin $(BER_BIN_PREV3C_FLAGS) $(BER_BIN_ASN1_PREV3C_SPEC).set.asn
+
+$(EBIN)/$(BER_BIN_ASN1_PREV3C_SPEC).$(EMULATOR): \
+ $(BER_BIN_ASN1_PREV3C_SPEC).erl \
+ $(BER_BIN_ASN1_PREV3C_SPEC).hrl
+
+$(BER_BIN_DRV_ASN1_PREV3C_SPEC).erl $(BER_BIN_DRV_ASN1_PREV3C_SPEC).hrl: \
+ $(BER_BIN_DRV_ASN1_PREV3C_SPEC).set.asn \
+ $(BER_BIN_DRV_ASN1_PREV3C_SPEC).asn1config \
+ $(ASN1_PREV3C_SPEC).asn
+ @echo "$(BER_BIN_DRV_ASN1_PREV3C_SPEC):"
+ $(ERLC) -bber_bin $(BER_BIN_DRV_PREV3C_FLAGS) $(BER_BIN_DRV_ASN1_PREV3C_SPEC).set.asn
+
+$(EBIN)/$(BER_BIN_DRV_ASN1_PREV3C_SPEC).$(EMULATOR): \
+ $(BER_BIN_DRV_ASN1_PREV3C_SPEC).erl \
+ $(BER_BIN_DRV_ASN1_PREV3C_SPEC).hrl
+
+$(PER_ASN1_PREV3C_SPEC).erl $(PER_ASN1_PREV3C_SPEC).hrl: \
+ $(PER_ASN1_PREV3C_SPEC).set.asn \
+ $(ASN1_PREV3C_SPEC).asn
+ @echo "$(PER_ASN1_PREV3C_SPEC):"
+ $(ERLC) -bper $(PER_PREV3C_FLAGS) $(PER_ASN1_PREV3C_SPEC).set.asn
+
+$(EBIN)/$(PER_ASN1_PREV3C_SPEC).$(EMULATOR): \
+ $(PER_ASN1_PREV3C_SPEC).erl \
+ $(PER_ASN1_PREV3C_SPEC).hrl
+
+$(PER_BIN_ASN1_PREV3C_SPEC).erl $(PER_BIN_ASN1_PREV3C_SPEC).hrl: \
+ $(PER_BIN_ASN1_PREV3C_SPEC).set.asn \
+ $(ASN1_PREV3C_SPEC).asn
+ @echo "$(PER_BIN_ASN1_PREV3C_SPEC):"
+ $(ERLC) -bper_bin $(PER_BIN_PREV3C_FLAGS) $(PER_BIN_ASN1_PREV3C_SPEC).set.asn
+
+$(EBIN)/$(PER_BIN_ASN1_PREV3C_SPEC).$(EMULATOR): \
+ $(PER_BIN_ASN1_PREV3C_SPEC).erl \
+ $(PER_BIN_ASN1_PREV3C_SPEC).hrl
+
+$(PER_BIN_DRV_ASN1_PREV3C_SPEC).erl $(PER_BIN_DRV_ASN1_PREV3C_SPEC).hrl: \
+ $(PER_BIN_DRV_ASN1_PREV3C_SPEC).set.asn \
+ $(ASN1_PREV3C_SPEC).asn
+ @echo "$(PER_BIN_DRV_ASN1_PREV3C_SPEC):"
+ $(ERLC) -bper_bin $(PER_BIN_DRV_PREV3C_FLAGS) $(PER_BIN_DRV_ASN1_PREV3C_SPEC).set.asn
+
+$(EBIN)/$(PER_BIN_DRV_ASN1_PREV3C_SPEC).$(EMULATOR): \
+ $(PER_BIN_DRV_ASN1_PREV3C_SPEC).erl \
+ $(PER_BIN_DRV_ASN1_PREV3C_SPEC).hrl
+
+
+# -- (v3) --
+
+$(BER_ASN1_V3_SPEC).erl $(BER_ASN1_V3_SPEC).hrl: \
+ $(BER_ASN1_V3_SPEC).set.asn \
+ $(ASN1_V3_SPEC).asn
+ @echo "$(BER_ASN1_V3_SPEC):"
+ $(ERLC) -bber $(BER_V3_FLAGS) $(BER_ASN1_V3_SPEC).set.asn
+
+$(EBIN)/$(BER_ASN1_V3_SPEC).$(EMULATOR): \
+ $(BER_ASN1_V3_SPEC).erl \
+ $(BER_ASN1_V3_SPEC).hrl
+
+$(BER_BIN_ASN1_V3_SPEC).erl $(BER_BIN_ASN1_V3_SPEC).hrl: \
+ $(BER_BIN_ASN1_V3_SPEC).set.asn \
+ $(BER_BIN_ASN1_V3_SPEC).asn1config \
+ $(ASN1_V3_SPEC).asn
+ @echo "$(BER_BIN_ASN1_V3_SPEC):"
+ $(ERLC) -bber_bin $(BER_BIN_V3_FLAGS) $(BER_BIN_ASN1_V3_SPEC).set.asn
+
+$(EBIN)/$(BER_BIN_ASN1_V3_SPEC).$(EMULATOR): \
+ $(BER_BIN_ASN1_V3_SPEC).erl \
+ $(BER_BIN_ASN1_V3_SPEC).hrl
+
+$(BER_BIN_DRV_ASN1_V3_SPEC).erl $(BER_BIN_DRV_ASN1_V3_SPEC).hrl: \
+ $(BER_BIN_DRV_ASN1_V3_SPEC).set.asn \
+ $(BER_BIN_DRV_ASN1_V3_SPEC).asn1config \
+ $(ASN1_V3_SPEC).asn
+ @echo "$(BER_BIN_DRV_ASN1_V3_SPEC):"
+ $(ERLC) -bber_bin $(BER_BIN_DRV_V3_FLAGS) $(BER_BIN_DRV_ASN1_V3_SPEC).set.asn
+
+$(EBIN)/$(BER_BIN_DRV_ASN1_V3_SPEC).$(EMULATOR): \
+ $(BER_BIN_DRV_ASN1_V3_SPEC).erl \
+ $(BER_BIN_DRV_ASN1_V3_SPEC).hrl
+
+$(PER_ASN1_V3_SPEC).erl $(PER_ASN1_V3_SPEC).hrl: \
+ $(PER_ASN1_V3_SPEC).set.asn \
+ $(ASN1_V3_SPEC).asn
+ @echo "$(PER_ASN1_V3_SPEC):"
+ $(ERLC) -bper $(PER_V3_FLAGS) $(PER_ASN1_V3_SPEC).set.asn
+
+$(EBIN)/$(PER_ASN1_V3_SPEC).$(EMULATOR): \
+ $(PER_ASN1_V3_SPEC).erl \
+ $(PER_ASN1_V3_SPEC).hrl
+
+$(PER_BIN_ASN1_V3_SPEC).erl $(PER_BIN_ASN1_V3_SPEC).hrl: \
+ $(PER_BIN_ASN1_V3_SPEC).set.asn \
+ $(ASN1_V3_SPEC).asn
+ @echo "$(PER_BIN_ASN1_V3_SPEC):"
+ $(ERLC) -bper_bin $(PER_BIN_V3_FLAGS) $(PER_BIN_ASN1_V3_SPEC).set.asn
+
+$(EBIN)/$(PER_BIN_ASN1_V3_SPEC).$(EMULATOR): \
+ $(PER_BIN_ASN1_V3_SPEC).erl \
+ $(PER_BIN_ASN1_V3_SPEC).hrl
+
+$(PER_BIN_DRV_ASN1_V3_SPEC).erl $(PER_BIN_DRV_ASN1_V3_SPEC).hrl: \
+ $(PER_BIN_DRV_ASN1_V3_SPEC).set.asn \
+ $(ASN1_V3_SPEC).asn
+ @echo "$(PER_BIN_DRV_ASN1_V3_SPEC):"
+ $(ERLC) -bper_bin $(PER_BIN_DRV_V3_FLAGS) $(PER_BIN_DRV_ASN1_V3_SPEC).set.asn
+
+$(EBIN)/$(PER_BIN_DRV_ASN1_V3_SPEC).$(EMULATOR): \
+ $(PER_BIN_DRV_ASN1_V3_SPEC).erl \
+ $(PER_BIN_DRV_ASN1_V3_SPEC).hrl
+
+
+# -------------
+
+$(EBIN)/megaco_ber_encoder.$(EMULATOR): megaco_ber_encoder.erl \
+ $(MEGACO_ENGINEDIR)/megaco_message_internal.hrl
+
+$(EBIN)/megaco_ber_bin_encoder.$(EMULATOR): megaco_ber_bin_encoder.erl \
+ $(MEGACO_ENGINEDIR)/megaco_message_internal.hrl
+
+$(EBIN)/megaco_per_encoder.$(EMULATOR): megaco_per_encoder.erl \
+ $(MEGACO_ENGINEDIR)/megaco_message_internal.hrl
+
+$(EBIN)/megaco_per_bin_encoder.$(EMULATOR): megaco_per_bin_encoder.erl \
+ $(MEGACO_ENGINEDIR)/megaco_message_internal.hrl
+
+$(EBIN)/megaco_binary_encoder_lib.$(EMULATOR): megaco_binary_encoder_lib.erl \
+ $(MEGACO_ENGINEDIR)/megaco_message_internal.hrl
+
+$(EBIN)/megaco_binary_encoder.$(EMULATOR): megaco_binary_encoder.erl \
+ $(MEGACO_ENGINEDIR)/megaco_message_internal.hrl
+
+$(EBIN)/megaco_binary_name_resolver_v1.$(EMULATOR): \
+ megaco_binary_name_resolver_v1.erl \
+ ../app/megaco_internal.hrl
+
+$(EBIN)/megaco_binary_name_resolver_v2.$(EMULATOR): \
+ megaco_binary_name_resolver_v2.erl \
+ ../app/megaco_internal.hrl
+
+$(EBIN)/megaco_binary_name_resolver_prev3a.$(EMULATOR): \
+ megaco_binary_name_resolver_prev3a.erl \
+ ../app/megaco_internal.hrl
+
+$(EBIN)/megaco_binary_name_resolver_prev3b.$(EMULATOR): \
+ megaco_binary_name_resolver_prev3b.erl \
+ ../app/megaco_internal.hrl
+
+$(EBIN)/megaco_binary_name_resolver_prev3c.$(EMULATOR): \
+ megaco_binary_name_resolver_prev3c.erl \
+ ../app/megaco_internal.hrl
+
+$(EBIN)/megaco_binary_name_resolver_v3.$(EMULATOR): \
+ megaco_binary_name_resolver_v3.erl
+
+$(EBIN)/megaco_binary_term_id.$(EMULATOR): megaco_binary_term_id.erl
+
+$(EBIN)/megaco_binary_term_id_gen.$(EMULATOR): megaco_binary_term_id_gen.erl
+
+$(EBIN)/megaco_binary_transformer_v1.$(EMULATOR): \
+ megaco_binary_transformer_v1.erl \
+ ../app/megaco_internal.hrl \
+ $(MEGACO_INCLUDEDIR)/megaco.hrl \
+ $(MEGACO_INCLUDEDIR)/megaco_message_v1.hrl
+
+$(EBIN)/megaco_binary_transformer_v2.$(EMULATOR): \
+ megaco_binary_transformer_v2.erl \
+ ../app/megaco_internal.hrl \
+ $(MEGACO_INCLUDEDIR)/megaco.hrl \
+ $(MEGACO_INCLUDEDIR)/megaco_message_v2.hrl
+
+$(EBIN)/megaco_binary_transformer_prev3a.$(EMULATOR): \
+ megaco_binary_transformer_prev3a.erl \
+ ../app/megaco_internal.hrl \
+ $(MEGACO_INCLUDEDIR)/megaco.hrl \
+ $(MEGACO_INCLUDEDIR)/megaco_message_prev3a.hrl
+
+$(EBIN)/megaco_binary_transformer_prev3b.$(EMULATOR): \
+ megaco_binary_transformer_prev3b.erl \
+ ../app/megaco_internal.hrl \
+ $(MEGACO_INCLUDEDIR)/megaco.hrl \
+ $(MEGACO_INCLUDEDIR)/megaco_message_prev3b.hrl
+
+$(EBIN)/megaco_binary_transformer_prev3c.$(EMULATOR): \
+ megaco_binary_transformer_prev3c.erl \
+ ../app/megaco_internal.hrl \
+ $(MEGACO_INCLUDEDIR)/megaco.hrl \
+ $(MEGACO_INCLUDEDIR)/megaco_message_prev3c.hrl
+
+$(EBIN)/megaco_binary_transformer_v3.$(EMULATOR): \
+ megaco_binary_transformer_v3.erl \
+ ../app/megaco_internal.hrl \
+ $(MEGACO_INCLUDEDIR)/megaco.hrl \
+ $(MEGACO_INCLUDEDIR)/megaco_message_v3.hrl
+
diff --git a/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3a.asn1config b/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3a.asn1config
new file mode 100644
index 0000000000..179473717d
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3a.asn1config
@@ -0,0 +1,43 @@
+{exclusive_decode,
+ {'megaco_ber_bin_drv_media_gateway_control_prev3a',
+ [
+ {decode_message_trans_partial,
+ [
+ 'MegacoMessage',[{mess,[{messageBody,[{transactions,parts}]}]}]
+ ]
+ },
+ {decode_message_acts_partial,
+ ['Transaction',
+ [
+ {transactionRequest,
+ [
+ {actions,parts}
+ ]
+ },
+ {transactionReply,
+ [
+ {transactionResult, [{actionReplies,parts}]}
+ ]
+ }
+ ]
+ ]
+ },
+ {decode_message_version,
+ ['MegacoMessage',
+ [
+ {authHeader,undecoded},
+ {mess,[{mId,undecoded},{messageBody,undecoded}]}
+ ]
+ ]
+ },
+ {decode_message_mId,
+ ['MegacoMessage',
+ [
+ {authHeader,undecoded},
+ {mess,[{messageBody,undecoded}]}
+ ]
+ ]
+ }
+ ]
+ }
+}.
diff --git a/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3a.set.asn b/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3a.set.asn
new file mode 100644
index 0000000000..b9ba7ffdb4
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3a.set.asn
@@ -0,0 +1 @@
+MEDIA-GATEWAY-CONTROL-prev3a.asn
diff --git a/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3b.asn1config b/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3b.asn1config
new file mode 100644
index 0000000000..ceda97fbd1
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3b.asn1config
@@ -0,0 +1,43 @@
+{exclusive_decode,
+ {'megaco_ber_bin_drv_media_gateway_control_prev3b',
+ [
+ {decode_message_trans_partial,
+ [
+ 'MegacoMessage',[{mess,[{messageBody,[{transactions,parts}]}]}]
+ ]
+ },
+ {decode_message_acts_partial,
+ ['Transaction',
+ [
+ {transactionRequest,
+ [
+ {actions,parts}
+ ]
+ },
+ {transactionReply,
+ [
+ {transactionResult, [{actionReplies,parts}]}
+ ]
+ }
+ ]
+ ]
+ },
+ {decode_message_version,
+ ['MegacoMessage',
+ [
+ {authHeader,undecoded},
+ {mess,[{mId,undecoded},{messageBody,undecoded}]}
+ ]
+ ]
+ },
+ {decode_message_mId,
+ ['MegacoMessage',
+ [
+ {authHeader,undecoded},
+ {mess,[{messageBody,undecoded}]}
+ ]
+ ]
+ }
+ ]
+ }
+}.
diff --git a/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3b.set.asn b/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3b.set.asn
new file mode 100644
index 0000000000..0437bde310
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3b.set.asn
@@ -0,0 +1 @@
+MEDIA-GATEWAY-CONTROL-prev3b.asn
diff --git a/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3c.asn1config b/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3c.asn1config
new file mode 100644
index 0000000000..d181ef44bd
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3c.asn1config
@@ -0,0 +1,43 @@
+{exclusive_decode,
+ {'megaco_ber_bin_drv_media_gateway_control_prev3c',
+ [
+ {decode_message_trans_partial,
+ [
+ 'MegacoMessage',[{mess,[{messageBody,[{transactions,parts}]}]}]
+ ]
+ },
+ {decode_message_acts_partial,
+ ['Transaction',
+ [
+ {transactionRequest,
+ [
+ {actions,parts}
+ ]
+ },
+ {transactionReply,
+ [
+ {transactionResult, [{actionReplies,parts}]}
+ ]
+ }
+ ]
+ ]
+ },
+ {decode_message_version,
+ ['MegacoMessage',
+ [
+ {authHeader,undecoded},
+ {mess,[{mId,undecoded},{messageBody,undecoded}]}
+ ]
+ ]
+ },
+ {decode_message_mId,
+ ['MegacoMessage',
+ [
+ {authHeader,undecoded},
+ {mess,[{messageBody,undecoded}]}
+ ]
+ ]
+ }
+ ]
+ }
+}.
diff --git a/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3c.set.asn b/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3c.set.asn
new file mode 100644
index 0000000000..e78055fbad
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3c.set.asn
@@ -0,0 +1 @@
+MEDIA-GATEWAY-CONTROL-prev3c.asn
diff --git a/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v1.asn1config b/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v1.asn1config
new file mode 100644
index 0000000000..ea10a7d527
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v1.asn1config
@@ -0,0 +1,44 @@
+{exclusive_decode,
+ {'megaco_ber_bin_drv_media_gateway_control_v1',
+ [
+ {decode_message_trans_partial,
+ [
+ 'MegacoMessage',[{mess,[{messageBody,[{transactions,parts}]}]}]
+ ]
+ },
+ {decode_message_acts_partial,
+ ['Transaction',
+ [
+ {transactionRequest,
+ [
+ {actions,parts}
+ ]
+ },
+ {transactionReply,
+ [
+ {transactionResult, [{actionReplies,parts}]}
+ ]
+ }
+ ]
+ ]
+ },
+ {decode_message_version,
+ ['MegacoMessage',
+ [
+ {authHeader,undecoded},
+ {mess,[{mId,undecoded},{messageBody,undecoded}]}
+ ]
+ ]
+ },
+ {decode_message_mId,
+ ['MegacoMessage',
+ [
+ {authHeader,undecoded},
+ {mess,[{messageBody,undecoded}]}
+ ]
+ ]
+ }
+ ]
+ }
+}.
+
diff --git a/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v1.set.asn b/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v1.set.asn
new file mode 100644
index 0000000000..0f5a92dba1
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v1.set.asn
@@ -0,0 +1 @@
+MEDIA-GATEWAY-CONTROL-v1.asn
diff --git a/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v2.asn1config b/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v2.asn1config
new file mode 100644
index 0000000000..3d0cb9a019
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v2.asn1config
@@ -0,0 +1,43 @@
+{exclusive_decode,
+ {'megaco_ber_bin_drv_media_gateway_control_v2',
+ [
+ {decode_message_trans_partial,
+ [
+ 'MegacoMessage',[{mess,[{messageBody,[{transactions,parts}]}]}]
+ ]
+ },
+ {decode_message_acts_partial,
+ ['Transaction',
+ [
+ {transactionRequest,
+ [
+ {actions,parts}
+ ]
+ },
+ {transactionReply,
+ [
+ {transactionResult, [{actionReplies,parts}]}
+ ]
+ }
+ ]
+ ]
+ },
+ {decode_message_version,
+ ['MegacoMessage',
+ [
+ {authHeader,undecoded},
+ {mess,[{mId,undecoded},{messageBody,undecoded}]}
+ ]
+ ]
+ },
+ {decode_message_mId,
+ ['MegacoMessage',
+ [
+ {authHeader,undecoded},
+ {mess,[{messageBody,undecoded}]}
+ ]
+ ]
+ }
+ ]
+ }
+}.
diff --git a/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v2.set.asn b/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v2.set.asn
new file mode 100644
index 0000000000..7fc82b127f
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v2.set.asn
@@ -0,0 +1 @@
+MEDIA-GATEWAY-CONTROL-v2.asn
diff --git a/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v3.asn1config b/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v3.asn1config
new file mode 100644
index 0000000000..cc662c0145
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v3.asn1config
@@ -0,0 +1,43 @@
+{exclusive_decode,
+ {'megaco_ber_bin_drv_media_gateway_control_v3',
+ [
+ {decode_message_trans_partial,
+ [
+ 'MegacoMessage',[{mess,[{messageBody,[{transactions,parts}]}]}]
+ ]
+ },
+ {decode_message_acts_partial,
+ ['Transaction',
+ [
+ {transactionRequest,
+ [
+ {actions,parts}
+ ]
+ },
+ {transactionReply,
+ [
+ {transactionResult, [{actionReplies,parts}]}
+ ]
+ }
+ ]
+ ]
+ },
+ {decode_message_version,
+ ['MegacoMessage',
+ [
+ {authHeader,undecoded},
+ {mess,[{mId,undecoded},{messageBody,undecoded}]}
+ ]
+ ]
+ },
+ {decode_message_mId,
+ ['MegacoMessage',
+ [
+ {authHeader,undecoded},
+ {mess,[{messageBody,undecoded}]}
+ ]
+ ]
+ }
+ ]
+ }
+}.
diff --git a/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v3.set.asn b/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v3.set.asn
new file mode 100644
index 0000000000..1d7950a283
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v3.set.asn
@@ -0,0 +1 @@
+MEDIA-GATEWAY-CONTROL-v3.asn
diff --git a/lib/megaco/src/binary/megaco_ber_bin_encoder.erl b/lib/megaco/src/binary/megaco_ber_bin_encoder.erl
new file mode 100644
index 0000000000..bf9926c7e5
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_ber_bin_encoder.erl
@@ -0,0 +1,716 @@
+%%
+%% %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 : Handle ASN.1 BER encoding of Megaco/H.248
+%%----------------------------------------------------------------------
+
+-module(megaco_ber_bin_encoder).
+
+-behaviour(megaco_encoder).
+
+-export([encode_message/3, decode_message/3,
+ decode_mini_message/3,
+
+ encode_transaction/3,
+ encode_action_requests/3,
+ encode_action_request/3,
+ encode_action_reply/3,
+
+ version_of/2]).
+
+%% Backward compatible functions:
+-export([encode_message/2, decode_message/2]).
+
+-include_lib("megaco/src/engine/megaco_message_internal.hrl").
+
+-define(V1_ASN1_MOD, megaco_ber_bin_media_gateway_control_v1).
+-define(V2_ASN1_MOD, megaco_ber_bin_media_gateway_control_v2).
+-define(V3_ASN1_MOD, megaco_ber_bin_media_gateway_control_v3).
+-define(PREV3A_ASN1_MOD, megaco_ber_bin_media_gateway_control_prev3a).
+-define(PREV3B_ASN1_MOD, megaco_ber_bin_media_gateway_control_prev3b).
+-define(PREV3C_ASN1_MOD, megaco_ber_bin_media_gateway_control_prev3c).
+-define(V1_ASN1_MOD_DRV, megaco_ber_bin_drv_media_gateway_control_v1).
+-define(V2_ASN1_MOD_DRV, megaco_ber_bin_drv_media_gateway_control_v2).
+-define(V3_ASN1_MOD_DRV, megaco_ber_bin_drv_media_gateway_control_v3).
+-define(PREV3A_ASN1_MOD_DRV, megaco_ber_bin_drv_media_gateway_control_prev3a).
+-define(PREV3B_ASN1_MOD_DRV, megaco_ber_bin_drv_media_gateway_control_prev3b).
+-define(PREV3C_ASN1_MOD_DRV, megaco_ber_bin_drv_media_gateway_control_prev3c).
+
+-define(V1_TRANS_MOD, megaco_binary_transformer_v1).
+-define(V2_TRANS_MOD, megaco_binary_transformer_v2).
+-define(V3_TRANS_MOD, megaco_binary_transformer_v3).
+-define(PREV3A_TRANS_MOD, megaco_binary_transformer_prev3a).
+-define(PREV3B_TRANS_MOD, megaco_binary_transformer_prev3b).
+-define(PREV3C_TRANS_MOD, megaco_binary_transformer_prev3c).
+
+-define(BIN_LIB, megaco_binary_encoder_lib).
+
+
+%%----------------------------------------------------------------------
+%% Detect (check/get) message version
+%% Return {ok, Version} | {error, Reason}
+%%----------------------------------------------------------------------
+
+version_of([{version3,v3},driver|EC], Binary) ->
+ Decoders = [?V1_ASN1_MOD_DRV, ?V2_ASN1_MOD_DRV, ?V3_ASN1_MOD_DRV],
+ ?BIN_LIB:version_of(EC, Binary, dynamic, Decoders);
+version_of([{version3,prev3c},driver|EC], Binary) ->
+ Decoders = [?V1_ASN1_MOD_DRV, ?V2_ASN1_MOD_DRV, ?PREV3C_ASN1_MOD_DRV],
+ ?BIN_LIB:version_of(EC, Binary, dynamic, Decoders);
+version_of([{version3,prev3b},driver|EC], Binary) ->
+ Decoders = [?V1_ASN1_MOD_DRV, ?V2_ASN1_MOD_DRV, ?PREV3B_ASN1_MOD_DRV],
+ ?BIN_LIB:version_of(EC, Binary, dynamic, Decoders);
+version_of([{version3,prev3a},driver|EC], Binary) ->
+ Decoders = [?V1_ASN1_MOD_DRV, ?V2_ASN1_MOD_DRV, ?PREV3A_ASN1_MOD_DRV],
+ ?BIN_LIB:version_of(EC, Binary, dynamic, Decoders);
+version_of([{version3,v3}|EC], Binary) ->
+ Decoders = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?V3_ASN1_MOD],
+ ?BIN_LIB:version_of(EC, Binary, dynamic, Decoders);
+version_of([{version3,prev3c}|EC], Binary) ->
+ Decoders = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?PREV3C_ASN1_MOD],
+ ?BIN_LIB:version_of(EC, Binary, dynamic, Decoders);
+version_of([{version3,prev3b}|EC], Binary) ->
+ Decoders = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?PREV3B_ASN1_MOD],
+ ?BIN_LIB:version_of(EC, Binary, dynamic, Decoders);
+version_of([{version3,prev3a}|EC], Binary) ->
+ Decoders = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?PREV3A_ASN1_MOD],
+ ?BIN_LIB:version_of(EC, Binary, dynamic, Decoders);
+version_of([driver|EC], Binary) ->
+ Decoders = [?V1_ASN1_MOD_DRV, ?V2_ASN1_MOD_DRV, ?V3_ASN1_MOD_DRV],
+ ?BIN_LIB:version_of(EC, Binary, dynamic, Decoders);
+
+%% All values we need to take (special) care of has been delt with,
+%% so just pass the rest on
+version_of(EC, Binary) ->
+ Decoders = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?V3_ASN1_MOD],
+ ?BIN_LIB:version_of(EC, Binary, dynamic, Decoders).
+
+
+%%----------------------------------------------------------------------
+%% Convert a 'MegacoMessage' record into a binary
+%% Return {ok, Binary} | {error, Reason}
+%%----------------------------------------------------------------------
+
+
+encode_message(EC,
+ #'MegacoMessage'{mess = #'Message'{version = V}} = MegaMsg) ->
+ encode_message(EC, V, MegaMsg).
+
+
+%% -- Version 1 --
+
+encode_message([{version3, _},driver|EC], 1, MegaMsg) ->
+ AsnMod = ?V1_ASN1_MOD_DRV,
+ TransMod = ?V1_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message([driver|EC], 1, MegaMsg) ->
+ AsnMod = ?V1_ASN1_MOD_DRV,
+ TransMod = ?V1_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message([{version3,_}|EC], 1, MegaMsg) ->
+ AsnMod = ?V1_ASN1_MOD,
+ TransMod = ?V1_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+
+%% All values we need to take (special) care of has been delt with,
+%% so just pass the rest on
+encode_message(EC, 1, MegaMsg) ->
+ AsnMod = ?V1_ASN1_MOD,
+ TransMod = ?V1_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+
+
+%% -- Version 2 --
+
+encode_message([{version3,_},driver|EC], 2, MegaMsg) ->
+ AsnMod = ?V2_ASN1_MOD_DRV,
+ TransMod = ?V2_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message([driver|EC], 2, MegaMsg) ->
+ AsnMod = ?V2_ASN1_MOD_DRV,
+ TransMod = ?V2_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message([{version3,_}|EC], 2, MegaMsg) ->
+ AsnMod = ?V2_ASN1_MOD,
+ TransMod = ?V2_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+
+%% All values we need to take (special) care of has been delt with,
+%% so just pass the rest on
+encode_message(EC, 2, MegaMsg) ->
+ AsnMod = ?V2_ASN1_MOD,
+ TransMod = ?V2_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+
+
+%% -- Version 3 --
+
+encode_message([{version3,v3},driver|EC], 3, MegaMsg) ->
+ AsnMod = ?V3_ASN1_MOD_DRV,
+ TransMod = ?V3_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message([{version3,prev3c},driver|EC], 3, MegaMsg) ->
+ AsnMod = ?PREV3C_ASN1_MOD_DRV,
+ TransMod = ?PREV3C_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message([{version3,prev3b},driver|EC], 3, MegaMsg) ->
+ AsnMod = ?PREV3B_ASN1_MOD_DRV,
+ TransMod = ?PREV3B_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message([{version3,prev3a},driver|EC], 3, MegaMsg) ->
+ AsnMod = ?PREV3A_ASN1_MOD_DRV,
+ TransMod = ?PREV3A_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message([{version3,v3}|EC], 3, MegaMsg) ->
+ AsnMod = ?V3_ASN1_MOD,
+ TransMod = ?V3_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message([{version3,prev3c}|EC], 3, MegaMsg) ->
+ AsnMod = ?PREV3C_ASN1_MOD,
+ TransMod = ?PREV3C_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message([{version3,prev3b}|EC], 3, MegaMsg) ->
+ AsnMod = ?PREV3B_ASN1_MOD,
+ TransMod = ?PREV3B_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message([{version3,prev3a}|EC], 3, MegaMsg) ->
+ AsnMod = ?PREV3A_ASN1_MOD,
+ TransMod = ?PREV3A_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message([driver|EC], 3, MegaMsg) ->
+ AsnMod = ?V3_ASN1_MOD_DRV,
+ TransMod = ?V3_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+
+%% All values we need to take (special) care of has been delt with,
+%% so just pass the rest on
+encode_message(EC, 3, MegaMsg) ->
+ AsnMod = ?V3_ASN1_MOD,
+ TransMod = ?V3_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list).
+
+
+%%----------------------------------------------------------------------
+%% Convert a transaction (or transactions in the case of ack) record(s)
+%% into a binary
+%% Return {ok, Binary} | {error, Reason}
+%%----------------------------------------------------------------------
+
+%% encode_transaction([] = EC, 1, Trans) ->
+%% AsnMod = ?V1_ASN1_MOD,
+%% TransMod = ?V1_TRANS_MOD,
+%% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
+%% io_list);
+%% encode_transaction([native] = EC, 1, Trans) ->
+%% AsnMod = ?V1_ASN1_MOD,
+%% TransMod = ?V1_TRANS_MOD,
+%% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
+%% io_list);
+%% encode_transaction([driver|EC], 1, Trans) ->
+%% AsnMod = ?V1_ASN1_MOD_DRV,
+%% TransMod = ?V1_TRANS_MOD,
+%% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
+%% io_list);
+%% encode_transaction(_EC, 1, _Trans) ->
+%% AsnMod = ?V1_ASN1_MOD,
+%% TransMod = ?V1_TRANS_MOD,
+%% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
+%% io_list);
+%% encode_transaction([] = EC, 2, Trans) ->
+%% AsnMod = ?V2_ASN1_MOD,
+%% TransMod = ?V2_TRANS_MOD,
+%% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
+%% io_list);
+%% encode_transaction([native] = EC, 2, Trans) ->
+%% AsnMod = ?V2_ASN1_MOD,
+%% TransMod = ?V2_TRANS_MOD,
+%% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
+%% io_list);
+%% encode_transaction([driver|EC], 2, Trans) ->
+%% AsnMod = ?V2_ASN1_MOD_DRV,
+%% TransMod = ?V2_TRANS_MOD,
+%% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
+%% io_list);
+%%encode_transaction(_EC, 2, _Trans) ->
+%% AsnMod = ?V2_ASN1_MOD,
+%% TransMod = ?V2_TRANS_MOD,
+%% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
+%% io_list).
+%% encode_transaction([] = EC, 3, Trans) ->
+%% AsnMod = ?V3_ASN1_MOD,
+%% TransMod = ?V3_TRANS_MOD,
+%% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
+%% io_list);
+%% encode_transaction([native] = EC, 3, Trans) ->
+%% AsnMod = ?V3_ASN1_MOD,
+%% TransMod = ?V3_TRANS_MOD,
+%% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
+%% io_list);
+%% encode_transaction([driver|EC], 3, Trans) ->
+%% AsnMod = ?V3_ASN1_MOD_DRV,
+%% TransMod = ?V3_TRANS_MOD,
+%% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
+%% io_list);
+%%encode_transaction(_EC, 3, _Trans) ->
+%% AsnMod = ?V3_ASN1_MOD,
+%% TransMod = ?V3_TRANS_MOD,
+%% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
+%% io_list).
+encode_transaction(_EC, _V, _Trans) ->
+ {error, not_implemented}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a list of ActionRequest record's into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+%% encode_action_requests([] = EC, 1, ActReqs) when is_list(ActReqs) ->
+%% AsnMod = ?V1_ASN1_MOD,
+%% TransMod = ?V1_TRANS_MOD,
+%% ?BIN_LIB:encode_action_requests(EC, ActReqs,
+%% AsnMod, TransMod,
+%% io_list);
+%% encode_action_requests([native] = EC, 1, ActReqs) when is_list(ActReqs) ->
+%% AsnMod = ?V1_ASN1_MOD,
+%% TransMod = ?V1_TRANS_MOD,
+%% ?BIN_LIB:encode_action_requests(EC, ActReqs,
+%% AsnMod, TransMod,
+%% io_list);
+%% encode_action_requests([driver|EC], 1, ActReqs) when is_list(ActReqs) ->
+%% AsnMod = ?V1_ASN1_MOD_DRV,
+%% TransMod = ?V1_TRANS_MOD,
+%% ?BIN_LIB:encode_action_requests(EC, ActReqs,
+%% AsnMod, TransMod,
+%% io_list);
+%% encode_action_requests(_EC, 1, ActReqs) when is_list(ActReqs) ->
+%% AsnMod = ?V1_ASN1_MOD,
+%% TransMod = ?V1_TRANS_MOD,
+%% ?BIN_LIB:encode_action_requests(EC, ActReqs,
+%% AsnMod, TransMod,
+%% io_list);
+%% encode_action_requests([] = EC, 2, ActReqs) when is_list(ActReqs) ->
+%% AsnMod = ?V2_ASN1_MOD,
+%% TransMod = ?V2_TRANS_MOD,
+%% ?BIN_LIB:encode_action_requests(EC, ActReqs,
+%% AsnMod, TransMod,
+%% io_list);
+%% encode_action_requests([native] = EC, 2, ActReqs) when is_list(ActReqs) ->
+%% AsnMod = ?V2_ASN1_MOD,
+%% TransMod = ?V2_TRANS_MOD,
+%% ?BIN_LIB:encode_action_requests(EC, ActReqs,
+%% AsnMod, TransMod,
+%% io_list);
+%% encode_action_requests([driver|EC], 2, ActReqs) when is_list(ActReqs) ->
+%% AsnMod = ?V2_ASN1_MOD_DRV,
+%% TransMod = ?V2_TRANS_MOD,
+%% ?BIN_LIB:encode_action_requests(EC, ActReqs,
+%% AsnMod, TransMod,
+%% io_list);
+%% encode_action_requests(_EC, 2, ActReqs) when is_list(ActReqs) ->
+%% AsnMod = ?V2_ASN1_MOD,
+%% TransMod = ?V2_TRANS_MOD,
+%% ?BIN_LIB:encode_action_requests(EC, ActReqs,
+%% AsnMod, TransMod,
+%% io_list);
+%% encode_action_requests([] = EC, 3, ActReqs) when is_list(ActReqs) ->
+%% AsnMod = ?V3_ASN1_MOD,
+%% TransMod = ?V3_TRANS_MOD,
+%% ?BIN_LIB:encode_action_requests(EC, ActReqs,
+%% AsnMod, TransMod,
+%% io_list);
+%% encode_action_requests([native] = EC, 3, ActReqs) when is_list(ActReqs) ->
+%% AsnMod = ?V3_ASN1_MOD,
+%% TransMod = ?V3_TRANS_MOD,
+%% ?BIN_LIB:encode_action_requests(EC, ActReqs,
+%% AsnMod, TransMod,
+%% io_list);
+%% encode_action_requests([driver|EC], 3, ActReqs) when is_list(ActReqs) ->
+%% AsnMod = ?V3_ASN1_MOD_DRV,
+%% TransMod = ?V3_TRANS_MOD,
+%% ?BIN_LIB:encode_action_requests(EC, ActReqs,
+%% AsnMod, TransMod,
+%% io_list);
+%%encode_action_requests(_EC, 3, ActReqs) when is_list(ActReqs) ->
+%% AsnMod = ?V3_ASN1_MOD,
+%% TransMod = ?V3_TRANS_MOD,
+%% ?BIN_LIB:encode_action_requests(EC, ActReqs,
+%% AsnMod, TransMod,
+%% io_list);
+%% encode_action_requests(_EC, V, _ActReqs) ->
+%% {error, {bad_version, V}}.
+encode_action_requests(_EC, _V, _ActReqs) ->
+ {error, not_implemented}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a ActionRequest record into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+%% encode_action_request([] = EC, 1, ActReq) ->
+%% AsnMod = ?V1_ASN1_MOD,
+%% TransMod = ?V1_TRANS_MOD,
+%% ?BIN_LIB:encode_action_request(EC, ActReq,
+%% AsnMod, TransMod,
+%% io_list);
+%% encode_action_request([native] = EC, 1, ActReq) ->
+%% AsnMod = ?V1_ASN1_MOD,
+%% TransMod = ?V1_TRANS_MOD,
+%% ?BIN_LIB:encode_action_request(EC, ActReq,
+%% AsnMod, TransMod,
+%% io_list);
+%% encode_action_request([driver|EC], 1, ActReq) ->
+%% AsnMod = ?V1_ASN1_MOD_DRV,
+%% TransMod = ?V1_TRANS_MOD,
+%% ?BIN_LIB:encode_action_request(EC, ActReq,
+%% AsnMod, TransMod,
+%% io_list);
+%% encode_action_request(_EC, 1, ActReq) ->
+%% AsnMod = ?V1_ASN1_MOD,
+%% TransMod = ?V1_TRANS_MOD,
+%% ?BIN_LIB:encode_action_request(EC, ActReq,
+%% AsnMod, TransMod,
+%% io_list);
+%% encode_action_request([] = EC, 2, ActReq) ->
+%% AsnMod = ?V2_ASN1_MOD,
+%% TransMod = ?V2_TRANS_MOD,
+%% ?BIN_LIB:encode_action_request(EC, ActReq,
+%% AsnMod, TransMod,
+%% io_list);
+%% encode_action_request([native] = EC, 2, ActReq) ->
+%% AsnMod = ?V2_ASN1_MOD,
+%% TransMod = ?V2_TRANS_MOD,
+%% ?BIN_LIB:encode_action_request(EC, ActReq,
+%% AsnMod, TransMod,
+%% io_list);
+%% encode_action_request([driver|EC], 2, ActReq) ->
+%% AsnMod = ?V2_ASN1_MOD_DRV,
+%% TransMod = ?V2_TRANS_MOD,
+%% ?BIN_LIB:encode_action_request(EC, ActReq,
+%% AsnMod, TransMod,
+%% io_list);
+%% encode_action_request(_EC, 2, ActReq) ->
+%% AsnMod = ?V2_ASN1_MOD,
+%% TransMod = ?V2_TRANS_MOD,
+%% ?BIN_LIB:encode_action_request(EC, ActReq,
+%% AsnMod, TransMod,
+%% io_list);
+%% encode_action_request([] = EC, 3, ActReq) ->
+%% AsnMod = ?V3_ASN1_MOD,
+%% TransMod = ?V3_TRANS_MOD,
+%% ?BIN_LIB:encode_action_request(EC, ActReq,
+%% AsnMod, TransMod,
+%% io_list);
+%% encode_action_request([native] = EC, 3, ActReq) ->
+%% AsnMod = ?V3_ASN1_MOD,
+%% TransMod = ?V3_TRANS_MOD,
+%% ?BIN_LIB:encode_action_request(EC, ActReq,
+%% AsnMod, TransMod,
+%% io_list);
+%% encode_action_request([driver|EC], 3, ActReq) ->
+%% AsnMod = ?V3_ASN1_MOD_DRV,
+%% TransMod = ?V3_TRANS_MOD,
+%% ?BIN_LIB:encode_action_request(EC, ActReq,
+%% AsnMod, TransMod,
+%% io_list);
+%% encode_action_request(_EC, 3, ActReq) ->
+%% AsnMod = ?V3_ASN1_MOD,
+%% TransMod = ?V3_TRANS_MOD,
+%% ?BIN_LIB:encode_action_request(EC, ActReq,
+%% AsnMod, TransMod,
+%% io_list);
+encode_action_request(_EC, _V, _ActReq) ->
+ {error, not_implemented}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a action reply into a deep io list
+%% Not yest supported by this binary codec!
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+
+encode_action_reply(_EC, _V, _AcionReply) ->
+ {error, not_implemented}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a binary into a 'MegacoMessage' record
+%% Return {ok, MegacoMessageRecord} | {error, Reason}
+%%----------------------------------------------------------------------
+
+%% Old decode function
+decode_message(EC, Binary) ->
+ decode_message(EC, 1, Binary).
+
+%% -- Dynamic version detection --
+
+%% Select from message
+decode_message([{version3,v3},driver|EC], dynamic, Binary) ->
+ Mods = [{?V1_ASN1_MOD_DRV, ?V1_TRANS_MOD},
+ {?V2_ASN1_MOD_DRV, ?V2_TRANS_MOD},
+ {?V3_ASN1_MOD_DRV, ?V3_TRANS_MOD}],
+ ?BIN_LIB:decode_message_dynamic(EC, Binary, Mods, binary);
+decode_message([{version3,prev3c},driver|EC], dynamic, Binary) ->
+ Mods = [{?V1_ASN1_MOD_DRV, ?V1_TRANS_MOD},
+ {?V2_ASN1_MOD_DRV, ?V2_TRANS_MOD},
+ {?PREV3C_ASN1_MOD_DRV, ?PREV3C_TRANS_MOD}],
+ ?BIN_LIB:decode_message_dynamic(EC, Binary, Mods, binary);
+decode_message([{version3,prev3b},driver|EC], dynamic, Binary) ->
+ Mods = [{?V1_ASN1_MOD_DRV, ?V1_TRANS_MOD},
+ {?V2_ASN1_MOD_DRV, ?V2_TRANS_MOD},
+ {?PREV3B_ASN1_MOD_DRV, ?PREV3B_TRANS_MOD}],
+ ?BIN_LIB:decode_message_dynamic(EC, Binary, Mods, binary);
+decode_message([{version3,prev3a},driver|EC], dynamic, Binary) ->
+ Mods = [{?V1_ASN1_MOD_DRV, ?V1_TRANS_MOD},
+ {?V2_ASN1_MOD_DRV, ?V2_TRANS_MOD},
+ {?PREV3A_ASN1_MOD_DRV, ?PREV3A_TRANS_MOD}],
+ ?BIN_LIB:decode_message_dynamic(EC, Binary, Mods, binary);
+decode_message([{version3,v3}|EC], dynamic, Binary) ->
+ Mods = [{?V1_ASN1_MOD, ?V1_TRANS_MOD},
+ {?V2_ASN1_MOD, ?V2_TRANS_MOD},
+ {?V3_ASN1_MOD, ?V3_TRANS_MOD}],
+ ?BIN_LIB:decode_message_dynamic(EC, Binary, Mods, binary);
+decode_message([{version3,prev3c}|EC], dynamic, Binary) ->
+ Mods = [{?V1_ASN1_MOD, ?V1_TRANS_MOD},
+ {?V2_ASN1_MOD, ?V2_TRANS_MOD},
+ {?PREV3C_ASN1_MOD, ?PREV3C_TRANS_MOD}],
+ ?BIN_LIB:decode_message_dynamic(EC, Binary, Mods, binary);
+decode_message([{version3,prev3b}|EC], dynamic, Binary) ->
+ Mods = [{?V1_ASN1_MOD, ?V1_TRANS_MOD},
+ {?V2_ASN1_MOD, ?V2_TRANS_MOD},
+ {?PREV3B_ASN1_MOD, ?PREV3B_TRANS_MOD}],
+ ?BIN_LIB:decode_message_dynamic(EC, Binary, Mods, binary);
+decode_message([{version3,prev3a}|EC], dynamic, Binary) ->
+ Mods = [{?V1_ASN1_MOD, ?V1_TRANS_MOD},
+ {?V2_ASN1_MOD, ?V2_TRANS_MOD},
+ {?PREV3A_ASN1_MOD, ?PREV3A_TRANS_MOD}],
+ ?BIN_LIB:decode_message_dynamic(EC, Binary, Mods, binary);
+decode_message([driver|EC], dynamic, Binary) ->
+ Mods = [{?V1_ASN1_MOD_DRV, ?V1_TRANS_MOD},
+ {?V2_ASN1_MOD_DRV, ?V2_TRANS_MOD},
+ {?V3_ASN1_MOD_DRV, ?V3_TRANS_MOD}],
+ ?BIN_LIB:decode_message_dynamic(EC, Binary, Mods, binary);
+
+%% All values we need to take (special) care of has been delt with,
+%% so just pass the rest on
+decode_message(EC, dynamic, Binary) ->
+ Mods = [{?V1_ASN1_MOD, ?V1_TRANS_MOD},
+ {?V2_ASN1_MOD, ?V2_TRANS_MOD},
+ {?V3_ASN1_MOD, ?V3_TRANS_MOD}],
+ ?BIN_LIB:decode_message_dynamic(EC, Binary, Mods, binary);
+
+
+%% -- Version 1 --
+
+decode_message([{version3,_},driver|EC], 1, Binary) ->
+ AsnMod = ?V1_ASN1_MOD_DRV,
+ TransMod = ?V1_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([driver|EC], 1, Binary) ->
+ AsnMod = ?V1_ASN1_MOD_DRV,
+ TransMod = ?V1_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([{version3,_}|EC], 1, Binary) ->
+ AsnMod = ?V1_ASN1_MOD,
+ TransMod = ?V1_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+
+%% All values we need to take (special) care of has been delt with,
+%% so just pass the rest on
+decode_message(EC, 1, Binary) ->
+ AsnMod = ?V1_ASN1_MOD,
+ TransMod = ?V1_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+
+
+%% -- Version 2 --
+
+decode_message([{version3,_},driver|EC], 2, Binary) ->
+ AsnMod = ?V2_ASN1_MOD_DRV,
+ TransMod = ?V2_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([driver|EC], 2, Binary) ->
+ AsnMod = ?V2_ASN1_MOD_DRV,
+ TransMod = ?V2_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([{version3,_}|EC], 2, Binary) ->
+ AsnMod = ?V2_ASN1_MOD,
+ TransMod = ?V2_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+
+%% All values we need to take (special) care of has been delt with,
+%% so just pass the rest on
+decode_message(EC, 2, Binary) ->
+ AsnMod = ?V2_ASN1_MOD,
+ TransMod = ?V2_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+
+
+%% -- Version 3 --
+
+decode_message([{version3,v3},driver|EC], 3, Binary) ->
+ AsnMod = ?V3_ASN1_MOD_DRV,
+ TransMod = ?V3_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([{version3,prev3c},driver|EC], 3, Binary) ->
+ AsnMod = ?PREV3C_ASN1_MOD_DRV,
+ TransMod = ?PREV3C_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([{version3,prev3b},driver|EC], 3, Binary) ->
+ AsnMod = ?PREV3B_ASN1_MOD_DRV,
+ TransMod = ?PREV3B_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([{version3,prev3a},driver|EC], 3, Binary) ->
+ AsnMod = ?PREV3A_ASN1_MOD_DRV,
+ TransMod = ?PREV3A_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([{version3,v3}|EC], 3, Binary) ->
+ AsnMod = ?V3_ASN1_MOD,
+ TransMod = ?V3_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([{version3,prev3c}|EC], 3, Binary) ->
+ AsnMod = ?PREV3C_ASN1_MOD,
+ TransMod = ?PREV3C_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([{version3,prev3b}|EC], 3, Binary) ->
+ AsnMod = ?PREV3B_ASN1_MOD,
+ TransMod = ?PREV3B_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([{version3,prev3a}|EC], 3, Binary) ->
+ AsnMod = ?PREV3A_ASN1_MOD,
+ TransMod = ?PREV3A_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([driver|EC], 3, Binary) ->
+ AsnMod = ?V3_ASN1_MOD_DRV,
+ TransMod = ?V3_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+
+%% All values we need to take (special) care of has been delt with,
+%% so just pass the rest on
+decode_message(EC, 3, Binary) ->
+ AsnMod = ?V3_ASN1_MOD,
+ TransMod = ?V3_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary).
+
+
+decode_mini_message([{version3,v3},driver|EC], dynamic, Bin) ->
+ Mods = [?V1_ASN1_MOD_DRV,
+ ?V2_ASN1_MOD_DRV,
+ ?V3_ASN1_MOD_DRV],
+ ?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
+decode_mini_message([{version3,prev3c},driver|EC], dynamic, Bin) ->
+ Mods = [?V1_ASN1_MOD_DRV,
+ ?V2_ASN1_MOD_DRV,
+ ?PREV3C_ASN1_MOD_DRV],
+ ?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
+decode_mini_message([{version3,prev3b},driver|EC], dynamic, Bin) ->
+ Mods = [?V1_ASN1_MOD_DRV,
+ ?V2_ASN1_MOD_DRV,
+ ?PREV3B_ASN1_MOD_DRV],
+ ?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
+decode_mini_message([{version3,prev3a},driver|EC], dynamic, Bin) ->
+ Mods = [?V1_ASN1_MOD_DRV,
+ ?V2_ASN1_MOD_DRV,
+ ?PREV3A_ASN1_MOD_DRV],
+ ?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
+decode_mini_message([{version3,v3}|EC], dynamic, Bin) ->
+ Mods = [?V1_ASN1_MOD,
+ ?V2_ASN1_MOD,
+ ?V3_ASN1_MOD],
+ ?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
+decode_mini_message([{version3,prev3c}|EC], dynamic, Bin) ->
+ Mods = [?V1_ASN1_MOD,
+ ?V2_ASN1_MOD,
+ ?PREV3C_ASN1_MOD],
+ ?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
+decode_mini_message([{version3,prev3b}|EC], dynamic, Bin) ->
+ Mods = [?V1_ASN1_MOD,
+ ?V2_ASN1_MOD,
+ ?PREV3B_ASN1_MOD],
+ ?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
+decode_mini_message([{version3,prev3a}|EC], dynamic, Bin) ->
+ Mods = [?V1_ASN1_MOD,
+ ?V2_ASN1_MOD,
+ ?PREV3A_ASN1_MOD],
+ ?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
+decode_mini_message([driver|EC], dynamic, Bin) ->
+ Mods = [?V1_ASN1_MOD_DRV,
+ ?V2_ASN1_MOD_DRV,
+ ?V3_ASN1_MOD_DRV],
+ ?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
+decode_mini_message(EC, dynamic, Bin) ->
+ Mods = [?V1_ASN1_MOD,
+ ?V2_ASN1_MOD,
+ ?V3_ASN1_MOD],
+ ?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
+decode_mini_message([{version3,_},driver|EC], 1, Bin) ->
+ AsnMod = ?V1_ASN1_MOD_DRV,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message([{version3,_}|EC], 1, Bin) ->
+ AsnMod = ?V1_ASN1_MOD,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message([driver|EC], 1, Bin) ->
+ AsnMod = ?V1_ASN1_MOD_DRV,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message(EC, 1, Bin) ->
+ AsnMod = ?V1_ASN1_MOD,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message([{version3,_},driver|EC], 2, Bin) ->
+ AsnMod = ?V2_ASN1_MOD_DRV,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message([{version3,_}|EC], 2, Bin) ->
+ AsnMod = ?V2_ASN1_MOD,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message([driver|EC], 2, Bin) ->
+ AsnMod = ?V2_ASN1_MOD_DRV,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message(EC, 2, Bin) ->
+ AsnMod = ?V2_ASN1_MOD,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message([{version3,v3},driver|EC], 3, Bin) ->
+ AsnMod = ?V3_ASN1_MOD_DRV,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message([{version3,prev3c},driver|EC], 3, Bin) ->
+ AsnMod = ?PREV3C_ASN1_MOD_DRV,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message([{version3,prev3b},driver|EC], 3, Bin) ->
+ AsnMod = ?PREV3B_ASN1_MOD_DRV,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message([{version3,prev3a},driver|EC], 3, Bin) ->
+ AsnMod = ?PREV3A_ASN1_MOD_DRV,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message([{version3,v3}|EC], 3, Bin) ->
+ AsnMod = ?V3_ASN1_MOD,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message([{version3,prev3c}|EC], 3, Bin) ->
+ AsnMod = ?PREV3C_ASN1_MOD,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message([{version3,prev3b}|EC], 3, Bin) ->
+ AsnMod = ?PREV3B_ASN1_MOD,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message([{version3,prev3a}|EC], 3, Bin) ->
+ AsnMod = ?PREV3A_ASN1_MOD,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message([driver|EC], 3, Bin) ->
+ AsnMod = ?V3_ASN1_MOD_DRV,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message(EC, 3, Bin) ->
+ AsnMod = ?V3_ASN1_MOD,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary).
diff --git a/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_prev3a.asn1config b/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_prev3a.asn1config
new file mode 100644
index 0000000000..456ce750ad
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_prev3a.asn1config
@@ -0,0 +1,43 @@
+{exclusive_decode,
+ {'megaco_ber_bin_media_gateway_control_prev3a',
+ [
+ {decode_message_trans_partial,
+ [
+ 'MegacoMessage',[{mess,[{messageBody,[{transactions,parts}]}]}]
+ ]
+ },
+ {decode_message_acts_partial,
+ ['Transaction',
+ [
+ {transactionRequest,
+ [
+ {actions,parts}
+ ]
+ },
+ {transactionReply,
+ [
+ {transactionResult, [{actionReplies,parts}]}
+ ]
+ }
+ ]
+ ]
+ },
+ {decode_message_version,
+ ['MegacoMessage',
+ [
+ {authHeader,undecoded},
+ {mess,[{mId,undecoded},{messageBody,undecoded}]}
+ ]
+ ]
+ },
+ {decode_message_mId,
+ ['MegacoMessage',
+ [
+ {authHeader,undecoded},
+ {mess,[{messageBody,undecoded}]}
+ ]
+ ]
+ }
+ ]
+ }
+}.
diff --git a/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_prev3a.set.asn b/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_prev3a.set.asn
new file mode 100644
index 0000000000..b9ba7ffdb4
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_prev3a.set.asn
@@ -0,0 +1 @@
+MEDIA-GATEWAY-CONTROL-prev3a.asn
diff --git a/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_prev3b.asn1config b/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_prev3b.asn1config
new file mode 100644
index 0000000000..fa5cd80baf
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_prev3b.asn1config
@@ -0,0 +1,43 @@
+{exclusive_decode,
+ {'megaco_ber_bin_media_gateway_control_prev3b',
+ [
+ {decode_message_trans_partial,
+ [
+ 'MegacoMessage',[{mess,[{messageBody,[{transactions,parts}]}]}]
+ ]
+ },
+ {decode_message_acts_partial,
+ ['Transaction',
+ [
+ {transactionRequest,
+ [
+ {actions,parts}
+ ]
+ },
+ {transactionReply,
+ [
+ {transactionResult, [{actionReplies,parts}]}
+ ]
+ }
+ ]
+ ]
+ },
+ {decode_message_version,
+ ['MegacoMessage',
+ [
+ {authHeader,undecoded},
+ {mess,[{mId,undecoded},{messageBody,undecoded}]}
+ ]
+ ]
+ },
+ {decode_message_mId,
+ ['MegacoMessage',
+ [
+ {authHeader,undecoded},
+ {mess,[{messageBody,undecoded}]}
+ ]
+ ]
+ }
+ ]
+ }
+}.
diff --git a/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_prev3b.set.asn b/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_prev3b.set.asn
new file mode 100644
index 0000000000..0437bde310
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_prev3b.set.asn
@@ -0,0 +1 @@
+MEDIA-GATEWAY-CONTROL-prev3b.asn
diff --git a/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_prev3c.asn1config b/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_prev3c.asn1config
new file mode 100644
index 0000000000..c74422b9a2
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_prev3c.asn1config
@@ -0,0 +1,43 @@
+{exclusive_decode,
+ {'megaco_ber_bin_media_gateway_control_prev3c',
+ [
+ {decode_message_trans_partial,
+ [
+ 'MegacoMessage',[{mess,[{messageBody,[{transactions,parts}]}]}]
+ ]
+ },
+ {decode_message_acts_partial,
+ ['Transaction',
+ [
+ {transactionRequest,
+ [
+ {actions,parts}
+ ]
+ },
+ {transactionReply,
+ [
+ {transactionResult, [{actionReplies,parts}]}
+ ]
+ }
+ ]
+ ]
+ },
+ {decode_message_version,
+ ['MegacoMessage',
+ [
+ {authHeader,undecoded},
+ {mess,[{mId,undecoded},{messageBody,undecoded}]}
+ ]
+ ]
+ },
+ {decode_message_mId,
+ ['MegacoMessage',
+ [
+ {authHeader,undecoded},
+ {mess,[{messageBody,undecoded}]}
+ ]
+ ]
+ }
+ ]
+ }
+}.
diff --git a/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_prev3c.set.asn b/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_prev3c.set.asn
new file mode 100644
index 0000000000..e78055fbad
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_prev3c.set.asn
@@ -0,0 +1 @@
+MEDIA-GATEWAY-CONTROL-prev3c.asn
diff --git a/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_v1.asn1config b/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_v1.asn1config
new file mode 100644
index 0000000000..e815e90948
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_v1.asn1config
@@ -0,0 +1,44 @@
+{exclusive_decode,
+ {'megaco_ber_bin_media_gateway_control_v1',
+ [
+ {decode_message_trans_partial,
+ [
+ 'MegacoMessage',[{mess,[{messageBody,[{transactions,parts}]}]}]
+ ]
+ },
+ {decode_message_acts_partial,
+ ['Transaction',
+ [
+ {transactionRequest,
+ [
+ {actions,parts}
+ ]
+ },
+ {transactionReply,
+ [
+ {transactionResult, [{actionReplies,parts}]}
+ ]
+ }
+ ]
+ ]
+ },
+ {decode_message_version,
+ ['MegacoMessage',
+ [
+ {authHeader,undecoded},
+ {mess,[{mId,undecoded},{messageBody,undecoded}]}
+ ]
+ ]
+ },
+ {decode_message_mId,
+ ['MegacoMessage',
+ [
+ {authHeader,undecoded},
+ {mess,[{messageBody,undecoded}]}
+ ]
+ ]
+ }
+
+ ]
+ }
+}.
diff --git a/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_v1.set.asn b/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_v1.set.asn
new file mode 100644
index 0000000000..0f5a92dba1
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_v1.set.asn
@@ -0,0 +1 @@
+MEDIA-GATEWAY-CONTROL-v1.asn
diff --git a/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_v2.asn1config b/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_v2.asn1config
new file mode 100644
index 0000000000..cc072b30ee
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_v2.asn1config
@@ -0,0 +1,43 @@
+{exclusive_decode,
+ {'megaco_ber_bin_media_gateway_control_v2',
+ [
+ {decode_message_trans_partial,
+ [
+ 'MegacoMessage',[{mess,[{messageBody,[{transactions,parts}]}]}]
+ ]
+ },
+ {decode_message_acts_partial,
+ ['Transaction',
+ [
+ {transactionRequest,
+ [
+ {actions,parts}
+ ]
+ },
+ {transactionReply,
+ [
+ {transactionResult, [{actionReplies,parts}]}
+ ]
+ }
+ ]
+ ]
+ },
+ {decode_message_version,
+ ['MegacoMessage',
+ [
+ {authHeader,undecoded},
+ {mess,[{mId,undecoded},{messageBody,undecoded}]}
+ ]
+ ]
+ },
+ {decode_message_mId,
+ ['MegacoMessage',
+ [
+ {authHeader,undecoded},
+ {mess,[{messageBody,undecoded}]}
+ ]
+ ]
+ }
+ ]
+ }
+}.
diff --git a/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_v2.set.asn b/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_v2.set.asn
new file mode 100644
index 0000000000..7fc82b127f
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_v2.set.asn
@@ -0,0 +1 @@
+MEDIA-GATEWAY-CONTROL-v2.asn
diff --git a/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_v3.asn1config b/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_v3.asn1config
new file mode 100644
index 0000000000..deeb2b2da9
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_v3.asn1config
@@ -0,0 +1,43 @@
+{exclusive_decode,
+ {'megaco_ber_bin_media_gateway_control_v3',
+ [
+ {decode_message_trans_partial,
+ [
+ 'MegacoMessage',[{mess,[{messageBody,[{transactions,parts}]}]}]
+ ]
+ },
+ {decode_message_acts_partial,
+ ['Transaction',
+ [
+ {transactionRequest,
+ [
+ {actions,parts}
+ ]
+ },
+ {transactionReply,
+ [
+ {transactionResult, [{actionReplies,parts}]}
+ ]
+ }
+ ]
+ ]
+ },
+ {decode_message_version,
+ ['MegacoMessage',
+ [
+ {authHeader,undecoded},
+ {mess,[{mId,undecoded},{messageBody,undecoded}]}
+ ]
+ ]
+ },
+ {decode_message_mId,
+ ['MegacoMessage',
+ [
+ {authHeader,undecoded},
+ {mess,[{messageBody,undecoded}]}
+ ]
+ ]
+ }
+ ]
+ }
+}.
diff --git a/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_v3.set.asn b/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_v3.set.asn
new file mode 100644
index 0000000000..1d7950a283
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_v3.set.asn
@@ -0,0 +1 @@
+MEDIA-GATEWAY-CONTROL-v3.asn
diff --git a/lib/megaco/src/binary/megaco_ber_encoder.erl b/lib/megaco/src/binary/megaco_ber_encoder.erl
new file mode 100644
index 0000000000..ff65b5bf81
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_ber_encoder.erl
@@ -0,0 +1,346 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1999-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 : Handle ASN.1 BER encoding of Megaco/H.248
+%%----------------------------------------------------------------------
+
+-module(megaco_ber_encoder).
+
+-behaviour(megaco_encoder).
+
+-export([encode_message/3, decode_message/3,
+ decode_mini_message/3,
+
+ encode_transaction/3,
+ encode_action_requests/3,
+ encode_action_request/3,
+ encode_action_reply/3,
+
+ version_of/2]).
+
+%% Backward compatible functions:
+-export([encode_message/2, decode_message/2]).
+
+-include_lib("megaco/src/engine/megaco_message_internal.hrl").
+
+-define(V1_ASN1_MOD, megaco_ber_media_gateway_control_v1).
+-define(V2_ASN1_MOD, megaco_ber_media_gateway_control_v2).
+-define(V3_ASN1_MOD, megaco_ber_media_gateway_control_v3).
+-define(PREV3A_ASN1_MOD, megaco_ber_media_gateway_control_prev3a).
+-define(PREV3B_ASN1_MOD, megaco_ber_media_gateway_control_prev3b).
+-define(PREV3C_ASN1_MOD, megaco_ber_media_gateway_control_prev3c).
+
+-define(V1_TRANS_MOD, megaco_binary_transformer_v1).
+-define(V2_TRANS_MOD, megaco_binary_transformer_v2).
+-define(V3_TRANS_MOD, megaco_binary_transformer_v3).
+-define(PREV3A_TRANS_MOD, megaco_binary_transformer_prev3a).
+-define(PREV3B_TRANS_MOD, megaco_binary_transformer_prev3b).
+-define(PREV3C_TRANS_MOD, megaco_binary_transformer_prev3c).
+
+-define(BIN_LIB, megaco_binary_encoder_lib).
+
+
+%%----------------------------------------------------------------------
+%% Detect (check/get) message version
+%% Return {ok, Version} | {error, Reason}
+%%----------------------------------------------------------------------
+
+version_of([{version3,v3}|EC], Binary) ->
+ Decoders = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?V3_ASN1_MOD],
+ ?BIN_LIB:version_of(EC, Binary, 1, Decoders);
+version_of([{version3,prev3c}|EC], Binary) ->
+ Decoders = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?PREV3C_ASN1_MOD],
+ ?BIN_LIB:version_of(EC, Binary, 1, Decoders);
+version_of([{version3,prev3b}|EC], Binary) ->
+ Decoders = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?PREV3B_ASN1_MOD],
+ ?BIN_LIB:version_of(EC, Binary, 1, Decoders);
+version_of([{version3,prev3a}|EC], Binary) ->
+ Decoders = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?PREV3A_ASN1_MOD],
+ ?BIN_LIB:version_of(EC, Binary, 1, Decoders);
+version_of(EC, Binary) ->
+ Decoders = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?V3_ASN1_MOD],
+ ?BIN_LIB:version_of(EC, Binary, 1, Decoders).
+
+
+%%----------------------------------------------------------------------
+%% Convert a 'MegacoMessage' record into a binary
+%% Return {ok, Binary} | {error, Reason}
+%%----------------------------------------------------------------------
+
+encode_message(EC,
+ #'MegacoMessage'{mess = #'Message'{version = V}} = MegaMsg) ->
+ encode_message(EC, V, MegaMsg).
+
+
+%% -- Version 1 --
+
+encode_message([{version3,_}|EC], 1, MegaMsg) ->
+ AsnMod = ?V1_ASN1_MOD,
+ TransMod = ?V1_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message(EC, 1, MegaMsg) ->
+ AsnMod = ?V1_ASN1_MOD,
+ TransMod = ?V1_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+
+
+%% -- Version 2 --
+
+encode_message([{version3,_}|EC], 2, MegaMsg) ->
+ AsnMod = ?V2_ASN1_MOD,
+ TransMod = ?V2_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message(EC, 2, MegaMsg) ->
+ AsnMod = ?V2_ASN1_MOD,
+ TransMod = ?V2_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+
+
+%% -- Version 3 --
+
+encode_message([{version3,v3}|EC], 3, MegaMsg) ->
+ AsnMod = ?V3_ASN1_MOD,
+ TransMod = ?V3_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message([{version3,prev3c}|EC], 3, MegaMsg) ->
+ AsnMod = ?PREV3C_ASN1_MOD,
+ TransMod = ?PREV3C_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message([{version3,prev3b}|EC], 3, MegaMsg) ->
+ AsnMod = ?PREV3B_ASN1_MOD,
+ TransMod = ?PREV3B_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message([{version3,prev3a}|EC], 3, MegaMsg) ->
+ AsnMod = ?PREV3A_ASN1_MOD,
+ TransMod = ?PREV3A_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message(EC, 3, MegaMsg) ->
+ AsnMod = ?V3_ASN1_MOD,
+ TransMod = ?V3_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list).
+
+
+%%----------------------------------------------------------------------
+%% Convert a transaction (or transactions in the case of ack) record(s)
+%% into a binary
+%% Return {ok, Binary} | {error, Reason}
+%%----------------------------------------------------------------------
+
+encode_transaction(_EC, 1, _Trans) ->
+%% AsnMod = ?V1_ASN1_MOD,
+%% TransMod = ?V1_TRANS_MOD,
+%% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
+%% io_list);
+ {error, not_implemented};
+encode_transaction(_EC, 2, _Trans) ->
+%% AsnMod = ?V2_ASN1_MOD,
+%% TransMod = ?V2_TRANS_MOD,
+%% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
+%% io_list);
+ {error, not_implemented};
+encode_transaction(_EC, 3, _Trans) ->
+%% AsnMod = ?V3_ASN1_MOD,
+%% TransMod = ?V3_TRANS_MOD,
+%% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
+%% io_list);
+ {error, not_implemented}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a list of ActionRequest record's into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_requests(_EC, 1, ActReqs) when is_list(ActReqs) ->
+%% AsnMod = ?V1_ASN1_MOD,
+%% TransMod = ?V1_TRANS_MOD,
+%% ?BIN_LIB:encode_action_requests(EC, ActReqs,
+%% AsnMod, TransMod,
+%% io_list);
+ {error, not_implemented};
+encode_action_requests(_EC, 2, ActReqs) when is_list(ActReqs) ->
+%% AsnMod = ?V2_ASN1_MOD,
+%% TransMod = ?V2_TRANS_MOD,
+%% ?BIN_LIB:encode_action_requests(EC, ActReqs,
+%% AsnMod, TransMod,
+%% io_list);
+ {error, not_implemented};
+encode_action_requests(_EC, 3, ActReqs) when is_list(ActReqs) ->
+%% AsnMod = ?V3_ASN1_MOD,
+%% TransMod = ?V3_TRANS_MOD,
+%% ?BIN_LIB:encode_action_requests(EC, ActReqs,
+%% AsnMod, TransMod,
+%% io_list);
+ {error, not_implemented}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a ActionRequest record into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_request(_EC, 1, _ActReq) ->
+%% AsnMod = ?V1_ASN1_MOD,
+%% TransMod = ?V1_TRANS_MOD,
+%% ?BIN_LIB:encode_action_request(EC, ActReq,
+%% AsnMod, TransMod,
+%% io_list);
+ {error, not_implemented};
+encode_action_request(_EC, 2, _ActReq) ->
+%% AsnMod = ?V2_ASN1_MOD,
+%% TransMod = ?V2_TRANS_MOD,
+%% ?BIN_LIB:encode_action_request(EC, ActReq,
+%% AsnMod, TransMod,
+%% io_list);
+ {error, not_implemented};
+encode_action_request(_EC, 3, _ActReq) ->
+%% AsnMod = ?V3_ASN1_MOD,
+%% TransMod = ?V3_TRANS_MOD,
+%% ?BIN_LIB:encode_action_request(EC, ActReq,
+%% AsnMod, TransMod,
+%% io_list);
+ {error, not_implemented}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a action reply into a deep io list
+%% Not yest supported by this binary codec!
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+
+encode_action_reply(_EC, _V, _AcionReply) ->
+ {error, not_implemented}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a binary into a 'MegacoMessage' record
+%% Return {ok, MegacoMessageRecord} | {error, Reason}
+%%----------------------------------------------------------------------
+
+decode_message(EC, Binary) ->
+ decode_message(EC, 1, Binary).
+
+%% Not supported for this codec, revert to version 1
+decode_message(EC, dynamic, Binary) ->
+ decode_message(EC, 1, Binary);
+
+
+%% -- Version 1 --
+
+decode_message([{version3,_}|EC], 1, Binary) ->
+ AsnMod = ?V1_ASN1_MOD,
+ TransMod = ?V1_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message(EC, 1, Binary) ->
+ AsnMod = ?V1_ASN1_MOD,
+ TransMod = ?V1_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+
+
+%% -- Version 2 --
+
+decode_message([{version3,_}|EC], 2, Binary) ->
+ AsnMod = ?V2_ASN1_MOD,
+ TransMod = ?V2_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message(EC, 2, Binary) ->
+ AsnMod = ?V2_ASN1_MOD,
+ TransMod = ?V2_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+
+
+%% -- Version 3 --
+
+decode_message([{version3,v3}|EC], 3, Binary) ->
+ AsnMod = ?V3_ASN1_MOD,
+ TransMod = ?V3_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([{version3,prev3c}|EC], 3, Binary) ->
+ AsnMod = ?PREV3C_ASN1_MOD,
+ TransMod = ?PREV3C_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([{version3,prev3b}|EC], 3, Binary) ->
+ AsnMod = ?PREV3B_ASN1_MOD,
+ TransMod = ?PREV3B_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([{version3,prev3a}|EC], 3, Binary) ->
+ AsnMod = ?PREV3A_ASN1_MOD,
+ TransMod = ?PREV3A_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message(EC, 3, Binary) ->
+ AsnMod = ?V3_ASN1_MOD,
+ TransMod = ?V3_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary).
+
+
+decode_mini_message([{version3,v3}|EC], dynamic, Bin) ->
+ Mods = [?V1_ASN1_MOD,
+ ?V2_ASN1_MOD,
+ ?V3_ASN1_MOD],
+ ?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
+decode_mini_message([{version3,prev3c}|EC], dynamic, Bin) ->
+ Mods = [?V1_ASN1_MOD,
+ ?V2_ASN1_MOD,
+ ?PREV3C_ASN1_MOD],
+ ?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
+decode_mini_message([{version3,prev3b}|EC], dynamic, Bin) ->
+ Mods = [?V1_ASN1_MOD,
+ ?V2_ASN1_MOD,
+ ?PREV3B_ASN1_MOD],
+ ?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
+decode_mini_message([{version3,prev3a}|EC], dynamic, Bin) ->
+ Mods = [?V1_ASN1_MOD,
+ ?V2_ASN1_MOD,
+ ?PREV3A_ASN1_MOD],
+ ?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
+decode_mini_message(EC, dynamic, Bin) ->
+ Mods = [?V1_ASN1_MOD,
+ ?V2_ASN1_MOD,
+ ?V3_ASN1_MOD],
+ ?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
+
+decode_mini_message([{version3,_}|EC], 1, Bin) ->
+ AsnMod = ?V1_ASN1_MOD,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message(EC, 1, Bin) ->
+ AsnMod = ?V1_ASN1_MOD,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message([{version3,_}|EC], 2, Bin) ->
+ AsnMod = ?V2_ASN1_MOD,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message(EC, 2, Bin) ->
+ AsnMod = ?V2_ASN1_MOD,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message([{version3,v3}|EC], 3, Bin) ->
+ AsnMod = ?V3_ASN1_MOD,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message([{version3,prev3c}|EC], 3, Bin) ->
+ AsnMod = ?PREV3C_ASN1_MOD,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message([{version3,prev3b}|EC], 3, Bin) ->
+ AsnMod = ?PREV3B_ASN1_MOD,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message([{version3,prev3a}|EC], 3, Bin) ->
+ AsnMod = ?PREV3A_ASN1_MOD,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message(EC, 3, Bin) ->
+ AsnMod = ?V3_ASN1_MOD,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary).
+
+
diff --git a/lib/megaco/src/binary/megaco_ber_media_gateway_control_prev3a.set.asn b/lib/megaco/src/binary/megaco_ber_media_gateway_control_prev3a.set.asn
new file mode 100644
index 0000000000..b9ba7ffdb4
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_ber_media_gateway_control_prev3a.set.asn
@@ -0,0 +1 @@
+MEDIA-GATEWAY-CONTROL-prev3a.asn
diff --git a/lib/megaco/src/binary/megaco_ber_media_gateway_control_prev3b.set.asn b/lib/megaco/src/binary/megaco_ber_media_gateway_control_prev3b.set.asn
new file mode 100644
index 0000000000..0437bde310
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_ber_media_gateway_control_prev3b.set.asn
@@ -0,0 +1 @@
+MEDIA-GATEWAY-CONTROL-prev3b.asn
diff --git a/lib/megaco/src/binary/megaco_ber_media_gateway_control_prev3c.set.asn b/lib/megaco/src/binary/megaco_ber_media_gateway_control_prev3c.set.asn
new file mode 100644
index 0000000000..e78055fbad
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_ber_media_gateway_control_prev3c.set.asn
@@ -0,0 +1 @@
+MEDIA-GATEWAY-CONTROL-prev3c.asn
diff --git a/lib/megaco/src/binary/megaco_ber_media_gateway_control_v1.set.asn b/lib/megaco/src/binary/megaco_ber_media_gateway_control_v1.set.asn
new file mode 100644
index 0000000000..0f5a92dba1
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_ber_media_gateway_control_v1.set.asn
@@ -0,0 +1 @@
+MEDIA-GATEWAY-CONTROL-v1.asn
diff --git a/lib/megaco/src/binary/megaco_ber_media_gateway_control_v2.set.asn b/lib/megaco/src/binary/megaco_ber_media_gateway_control_v2.set.asn
new file mode 100644
index 0000000000..7fc82b127f
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_ber_media_gateway_control_v2.set.asn
@@ -0,0 +1 @@
+MEDIA-GATEWAY-CONTROL-v2.asn
diff --git a/lib/megaco/src/binary/megaco_ber_media_gateway_control_v3.set.asn b/lib/megaco/src/binary/megaco_ber_media_gateway_control_v3.set.asn
new file mode 100644
index 0000000000..1d7950a283
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_ber_media_gateway_control_v3.set.asn
@@ -0,0 +1 @@
+MEDIA-GATEWAY-CONTROL-v3.asn
diff --git a/lib/megaco/src/binary/megaco_binary_encoder.erl b/lib/megaco/src/binary/megaco_binary_encoder.erl
new file mode 100644
index 0000000000..f825f91a45
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_binary_encoder.erl
@@ -0,0 +1,588 @@
+%%
+%% %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 : Handle ASN.1 BER encoding of Megaco/H.248
+%%----------------------------------------------------------------------
+
+-module(megaco_binary_encoder).
+
+-behaviour(megaco_encoder).
+
+%% API
+-export([encode_message/3, decode_message/3,
+ decode_mini_message/3,
+
+ encode_transaction/3,
+ encode_action_requests/3,
+ encode_action_request/3,
+ encode_action_reply/3,
+
+ version_of/2]).
+
+%% Backward compatible functions:
+-export([encode_message/2, decode_message/2]).
+
+-include_lib("megaco/src/engine/megaco_message_internal.hrl").
+
+-define(BIN_LIB, megaco_binary_encoder_lib).
+
+
+%%----------------------------------------------------------------------
+%% Convert a 'MegacoMessage' record into a binary
+%% Return {ok, Binary} | {error, Reason}
+%%----------------------------------------------------------------------
+
+encode_message(EC,
+ #'MegacoMessage'{mess = #'Message'{version = V}} = MegaMsg) ->
+ encode_message(EC, V, MegaMsg).
+
+encode_message([{version3,_}|EC], 1, MegaMsg) ->
+ AsnMod = megaco_ber_media_gateway_control_v1,
+ TransMod = megaco_binary_transformer_v1,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message(EC, 1, MegaMsg) ->
+ AsnMod = megaco_ber_media_gateway_control_v1,
+ TransMod = megaco_binary_transformer_v1,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message([{version3,_}|EC], 2, MegaMsg) ->
+ AsnMod = megaco_ber_media_gateway_control_v2,
+ TransMod = megaco_binary_transformer_v2,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message(EC, 2, MegaMsg) ->
+ AsnMod = megaco_ber_media_gateway_control_v2,
+ TransMod = megaco_binary_transformer_v2,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message([{version3,v3}|EC], 3, MegaMsg) ->
+ AsnMod = megaco_ber_media_gateway_control_v3,
+ TransMod = megaco_binary_transformer_v3,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message([{version3,prev3c}|EC], 3, MegaMsg) ->
+ AsnMod = megaco_ber_media_gateway_control_prev3c,
+ TransMod = megaco_binary_transformer_prev3c,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message([{version3,prev3b}|EC], 3, MegaMsg) ->
+ AsnMod = megaco_ber_media_gateway_control_prev3b,
+ TransMod = megaco_binary_transformer_prev3b,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message([{version3,prev3a}|EC], 3, MegaMsg) ->
+ AsnMod = megaco_ber_media_gateway_control_prev3a,
+ TransMod = megaco_binary_transformer_prev3a,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message(EC, 3, MegaMsg) ->
+ AsnMod = megaco_ber_media_gateway_control_v3,
+ TransMod = megaco_binary_transformer_v3,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list).
+
+
+%%----------------------------------------------------------------------
+%% Convert a transaction (or transactions in the case of ack) record(s)
+%% into a binary
+%% Return {ok, Binary} | {error, Reason}
+%%----------------------------------------------------------------------
+
+encode_transaction([{version3,_}|EC], 1, Trans) ->
+ AsnMod = megaco_ber_media_gateway_control_v1,
+ TransMod = megaco_binary_transformer_v1,
+ ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod, io_list);
+encode_transaction(EC, 1, Trans) ->
+ AsnMod = megaco_ber_media_gateway_control_v1,
+ TransMod = megaco_binary_transformer_v1,
+ ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod, io_list);
+encode_transaction([{version3,_}|EC], 2, Trans) ->
+ AsnMod = megaco_ber_media_gateway_control_v2,
+ TransMod = megaco_binary_transformer_v2,
+ ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod, io_list);
+encode_transaction(EC, 2, Trans) ->
+ AsnMod = megaco_ber_media_gateway_control_v2,
+ TransMod = megaco_binary_transformer_v2,
+ ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod, io_list);
+encode_transaction([{version3,v3}|EC], 3, Trans) ->
+ AsnMod = megaco_ber_media_gateway_control_v3,
+ TransMod = megaco_binary_transformer_v3,
+ ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod, io_list);
+encode_transaction([{version3,prev3c}|EC], 3, Trans) ->
+ AsnMod = megaco_ber_media_gateway_control_prev3c,
+ TransMod = megaco_binary_transformer_prev3c,
+ ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod, io_list);
+encode_transaction([{version3,prev3b}|EC], 3, Trans) ->
+ AsnMod = megaco_ber_media_gateway_control_prev3b,
+ TransMod = megaco_binary_transformer_prev3b,
+ ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod, io_list);
+encode_transaction([{version3,prev3a}|EC], 3, Trans) ->
+ AsnMod = megaco_ber_media_gateway_control_prev3a,
+ TransMod = megaco_binary_transformer_prev3a,
+ ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod, io_list);
+encode_transaction(EC, 3, Trans) ->
+ AsnMod = megaco_ber_media_gateway_control_v3,
+ TransMod = megaco_binary_transformer_v3,
+ ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod, io_list).
+
+
+%%----------------------------------------------------------------------
+%% 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) ->
+ AsnMod = megaco_ber_media_gateway_control_v1,
+ TransMod = megaco_binary_transformer_v1,
+ ?BIN_LIB:encode_action_requests(EC, ActReqs, AsnMod, TransMod, io_list);
+encode_action_requests(EC, 1, ActReqs) when is_list(ActReqs) ->
+ AsnMod = megaco_ber_media_gateway_control_v1,
+ TransMod = megaco_binary_transformer_v1,
+ ?BIN_LIB:encode_action_requests(EC, ActReqs, AsnMod, TransMod, io_list);
+encode_action_requests([{version3,_}|EC], 2, ActReqs)
+ when is_list(ActReqs) ->
+ AsnMod = megaco_ber_media_gateway_control_v2,
+ TransMod = megaco_binary_transformer_v2,
+ ?BIN_LIB:encode_action_requests(EC, ActReqs, AsnMod, TransMod, io_list);
+encode_action_requests(EC, 2, ActReqs) when is_list(ActReqs) ->
+ AsnMod = megaco_ber_media_gateway_control_v2,
+ TransMod = megaco_binary_transformer_v2,
+ ?BIN_LIB:encode_action_requests(EC, ActReqs, AsnMod, TransMod, io_list);
+encode_action_requests([{version3,v3}|EC], 3, ActReqs)
+ when is_list(ActReqs) ->
+ AsnMod = megaco_ber_media_gateway_control_v3,
+ TransMod = megaco_binary_transformer_v3,
+ ?BIN_LIB:encode_action_requests(EC, ActReqs, AsnMod, TransMod, io_list);
+encode_action_requests([{version3,prev3c}|EC], 3, ActReqs)
+ when is_list(ActReqs) ->
+ AsnMod = megaco_ber_media_gateway_control_prev3c,
+ TransMod = megaco_binary_transformer_prev3c,
+ ?BIN_LIB:encode_action_requests(EC, ActReqs, AsnMod, TransMod, io_list);
+encode_action_requests([{version3,prev3b}|EC], 3, ActReqs)
+ when is_list(ActReqs) ->
+ AsnMod = megaco_ber_media_gateway_control_prev3b,
+ TransMod = megaco_binary_transformer_prev3b,
+ ?BIN_LIB:encode_action_requests(EC, ActReqs, AsnMod, TransMod, io_list);
+encode_action_requests([{version3,prev3a}|EC], 3, ActReqs)
+ when is_list(ActReqs) ->
+ AsnMod = megaco_ber_media_gateway_control_prev3a,
+ TransMod = megaco_binary_transformer_prev3a,
+ ?BIN_LIB:encode_action_requests(EC, ActReqs, AsnMod, TransMod, io_list);
+encode_action_requests(EC, 3, ActReqs) when is_list(ActReqs) ->
+ AsnMod = megaco_ber_media_gateway_control_v3,
+ TransMod = megaco_binary_transformer_v3,
+ ?BIN_LIB:encode_action_requests(EC, ActReqs, AsnMod, TransMod, io_list).
+
+
+%%----------------------------------------------------------------------
+%% Convert a ActionRequest record into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_request([{version3,_}|EC], 1, ActReq) ->
+ AsnMod = megaco_ber_media_gateway_control_v1,
+ TransMod = megaco_binary_transformer_v1,
+ ?BIN_LIB:encode_action_request(EC, ActReq, AsnMod, TransMod, io_list);
+encode_action_request(EC, 1, ActReq) ->
+ AsnMod = megaco_ber_media_gateway_control_v1,
+ TransMod = megaco_binary_transformer_v1,
+ ?BIN_LIB:encode_action_request(EC, ActReq, AsnMod, TransMod, io_list);
+encode_action_request([{version3,_}|EC], 2, ActReq) ->
+ AsnMod = megaco_ber_media_gateway_control_v2,
+ TransMod = megaco_binary_transformer_v2,
+ ?BIN_LIB:encode_action_request(EC, ActReq, AsnMod, TransMod, io_list);
+encode_action_request(EC, 2, ActReq) ->
+ AsnMod = megaco_ber_media_gateway_control_v2,
+ TransMod = megaco_binary_transformer_v2,
+ ?BIN_LIB:encode_action_request(EC, ActReq, AsnMod, TransMod, io_list);
+encode_action_request([{version3,v3}|EC], 3, ActReq) ->
+ AsnMod = megaco_ber_media_gateway_control_v3,
+ TransMod = megaco_binary_transformer_v3,
+ ?BIN_LIB:encode_action_request(EC, ActReq, AsnMod, TransMod, io_list);
+encode_action_request([{version3,prev3c}|EC], 3, ActReq) ->
+ AsnMod = megaco_ber_media_gateway_control_prev3c,
+ TransMod = megaco_binary_transformer_prev3c,
+ ?BIN_LIB:encode_action_request(EC, ActReq, AsnMod, TransMod, io_list);
+encode_action_request([{version3,prev3b}|EC], 3, ActReq) ->
+ AsnMod = megaco_ber_media_gateway_control_prev3b,
+ TransMod = megaco_binary_transformer_prev3b,
+ ?BIN_LIB:encode_action_request(EC, ActReq, AsnMod, TransMod, io_list);
+encode_action_request([{version3,prev3a}|EC], 3, ActReq) ->
+ AsnMod = megaco_ber_media_gateway_control_prev3a,
+ TransMod = megaco_binary_transformer_prev3a,
+ ?BIN_LIB:encode_action_request(EC, ActReq, AsnMod, TransMod, io_list);
+encode_action_request(EC, 3, ActReq) ->
+ AsnMod = megaco_ber_media_gateway_control_v3,
+ TransMod = megaco_binary_transformer_v3,
+ ?BIN_LIB:encode_action_request(EC, ActReq, AsnMod, TransMod, io_list).
+
+
+%%----------------------------------------------------------------------
+%% Convert a action reply into a deep io list
+%% Not yest supported by this binary codec!
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+
+encode_action_reply(_EC, _V, _AcionReply) ->
+ {error, not_implemented}.
+
+
+%%----------------------------------------------------------------------
+%% Detect (check) which version a message is
+%% Return {ok, Version} | {error, Reason}
+%%----------------------------------------------------------------------
+
+version_of([{version3,v3},driver|EC], Binary) ->
+ Decoders = [megaco_ber_bin_drv_media_gateway_control_v1,
+ megaco_ber_bin_drv_media_gateway_control_v2,
+ megaco_ber_bin_drv_media_gateway_control_v3],
+ ?BIN_LIB:version_of(EC, Binary, dynamic, Decoders);
+version_of([{version3,prev3c},driver|EC], Binary) ->
+ Decoders = [megaco_ber_bin_drv_media_gateway_control_v1,
+ megaco_ber_bin_drv_media_gateway_control_v2,
+ megaco_ber_bin_drv_media_gateway_control_prev3c],
+ ?BIN_LIB:version_of(EC, Binary, dynamic, Decoders);
+version_of([{version3,prev3b},driver|EC], Binary) ->
+ Decoders = [megaco_ber_bin_drv_media_gateway_control_v1,
+ megaco_ber_bin_drv_media_gateway_control_v2,
+ megaco_ber_bin_drv_media_gateway_control_prev3b],
+ ?BIN_LIB:version_of(EC, Binary, dynamic, Decoders);
+version_of([{version3,prev3a},driver|EC], Binary) ->
+ Decoders = [megaco_ber_bin_drv_media_gateway_control_v1,
+ megaco_ber_bin_drv_media_gateway_control_v2,
+ megaco_ber_bin_drv_media_gateway_control_prev3a],
+ ?BIN_LIB:version_of(EC, Binary, dynamic, Decoders);
+version_of([driver|EC], Binary) ->
+ Decoders = [megaco_ber_bin_drv_media_gateway_control_v1,
+ megaco_ber_bin_drv_media_gateway_control_v2,
+ megaco_ber_bin_drv_media_gateway_control_v3],
+ ?BIN_LIB:version_of(EC, Binary, dynamic, Decoders);
+version_of([{version3,v3}|EC], Binary) ->
+ Decoders = [megaco_ber_bin_media_gateway_control_v1,
+ megaco_ber_bin_media_gateway_control_v2,
+ megaco_ber_bin_media_gateway_control_v3],
+ ?BIN_LIB:version_of(EC, Binary, dynamic, Decoders);
+version_of([{version3,prev3c}|EC], Binary) ->
+ Decoders = [megaco_ber_bin_media_gateway_control_v1,
+ megaco_ber_bin_media_gateway_control_v2,
+ megaco_ber_bin_media_gateway_control_prev3c],
+ ?BIN_LIB:version_of(EC, Binary, dynamic, Decoders);
+version_of([{version3,prev3b}|EC], Binary) ->
+ Decoders = [megaco_ber_bin_media_gateway_control_v1,
+ megaco_ber_bin_media_gateway_control_v2,
+ megaco_ber_bin_media_gateway_control_prev3b],
+ ?BIN_LIB:version_of(EC, Binary, dynamic, Decoders);
+version_of([{version3,prev3a}|EC], Binary) ->
+ Decoders = [megaco_ber_bin_media_gateway_control_v1,
+ megaco_ber_bin_media_gateway_control_v2,
+ megaco_ber_bin_media_gateway_control_prev3a],
+ ?BIN_LIB:version_of(EC, Binary, dynamic, Decoders);
+version_of(EC, Binary) ->
+ Decoders = [megaco_ber_bin_media_gateway_control_v1,
+ megaco_ber_bin_media_gateway_control_v2,
+ megaco_ber_bin_media_gateway_control_v3],
+ ?BIN_LIB:version_of(EC, Binary, dynamic, Decoders).
+
+
+%%----------------------------------------------------------------------
+%% Convert a binary into a 'MegacoMessage' record
+%% Return {ok, MegacoMessageRecord} | {error, Reason}
+%%----------------------------------------------------------------------
+
+decode_message(EC, Binary) ->
+ decode_message(EC, 1, Binary).
+
+decode_message([{version3,v3},driver|EC], dynamic, Binary) ->
+ Decoders = [{megaco_ber_bin_drv_media_gateway_control_v1,
+ megaco_binary_transformer_v1},
+ {megaco_ber_bin_drv_media_gateway_control_v2,
+ megaco_binary_transformer_v2},
+ {megaco_ber_bin_drv_media_gateway_control_v3,
+ megaco_binary_transformer_v3}],
+ ?BIN_LIB:decode_message_dynamic(EC, Binary, Decoders, binary);
+decode_message([{version3,prev3c},driver|EC], dynamic, Binary) ->
+ Decoders = [{megaco_ber_bin_drv_media_gateway_control_v1,
+ megaco_binary_transformer_v1},
+ {megaco_ber_bin_drv_media_gateway_control_v2,
+ megaco_binary_transformer_v2},
+ {megaco_ber_bin_drv_media_gateway_control_prev3c,
+ megaco_binary_transformer_prev3c}],
+ ?BIN_LIB:decode_message_dynamic(EC, Binary, Decoders, binary);
+decode_message([{version3,prev3b},driver|EC], dynamic, Binary) ->
+ Decoders = [{megaco_ber_bin_drv_media_gateway_control_v1,
+ megaco_binary_transformer_v1},
+ {megaco_ber_bin_drv_media_gateway_control_v2,
+ megaco_binary_transformer_v2},
+ {megaco_ber_bin_drv_media_gateway_control_prev3b,
+ megaco_binary_transformer_prev3b}],
+ ?BIN_LIB:decode_message_dynamic(EC, Binary, Decoders, binary);
+decode_message([{version3,prev3a},driver|EC], dynamic, Binary) ->
+ Decoders = [{megaco_ber_bin_drv_media_gateway_control_v1,
+ megaco_binary_transformer_v1},
+ {megaco_ber_bin_drv_media_gateway_control_v2,
+ megaco_binary_transformer_v2},
+ {megaco_ber_bin_drv_media_gateway_control_prev3a,
+ megaco_binary_transformer_prev3a}],
+ ?BIN_LIB:decode_message_dynamic(EC, Binary, Decoders, binary);
+decode_message([driver|EC], dynamic, Binary) ->
+ Decoders = [{megaco_ber_bin_drv_media_gateway_control_v1,
+ megaco_binary_transformer_v1},
+ {megaco_ber_bin_drv_media_gateway_control_v2,
+ megaco_binary_transformer_v2},
+ {megaco_ber_bin_drv_media_gateway_control_v3,
+ megaco_binary_transformer_v3}],
+ ?BIN_LIB:decode_message_dynamic(EC, Binary, Decoders, binary);
+decode_message([{version3,v3}|EC], dynamic, Binary) ->
+ Decoders = [{megaco_ber_bin_media_gateway_control_v1,
+ megaco_binary_transformer_v1},
+ {megaco_ber_bin_media_gateway_control_v2,
+ megaco_binary_transformer_v2},
+ {megaco_ber_bin_media_gateway_control_v3,
+ megaco_binary_transformer_v3}],
+ ?BIN_LIB:decode_message_dynamic(EC, Binary, Decoders, binary);
+decode_message([{version3,prev3c}|EC], dynamic, Binary) ->
+ Decoders = [{megaco_ber_bin_media_gateway_control_v1,
+ megaco_binary_transformer_v1},
+ {megaco_ber_bin_media_gateway_control_v2,
+ megaco_binary_transformer_v2},
+ {megaco_ber_bin_media_gateway_control_prev3c,
+ megaco_binary_transformer_prev3c}],
+ ?BIN_LIB:decode_message_dynamic(EC, Binary, Decoders, binary);
+decode_message([{version3,prev3b}|EC], dynamic, Binary) ->
+ Decoders = [{megaco_ber_bin_media_gateway_control_v1,
+ megaco_binary_transformer_v1},
+ {megaco_ber_bin_media_gateway_control_v2,
+ megaco_binary_transformer_v2},
+ {megaco_ber_bin_media_gateway_control_prev3b,
+ megaco_binary_transformer_prev3b}],
+ ?BIN_LIB:decode_message_dynamic(EC, Binary, Decoders, binary);
+decode_message([{version3,prev3a}|EC], dynamic, Binary) ->
+ Decoders = [{megaco_ber_bin_media_gateway_control_v1,
+ megaco_binary_transformer_v1},
+ {megaco_ber_bin_media_gateway_control_v2,
+ megaco_binary_transformer_v2},
+ {megaco_ber_bin_media_gateway_control_prev3a,
+ megaco_binary_transformer_prev3a}],
+ ?BIN_LIB:decode_message_dynamic(EC, Binary, Decoders, binary);
+decode_message(EC, dynamic, Binary) ->
+ Decoders = [{megaco_ber_bin_media_gateway_control_v1,
+ megaco_binary_transformer_v1},
+ {megaco_ber_bin_media_gateway_control_v2,
+ megaco_binary_transformer_v2},
+ {megaco_ber_bin_media_gateway_control_v3,
+ megaco_binary_transformer_v3}],
+ ?BIN_LIB:decode_message_dynamic(EC, Binary, Decoders, binary);
+
+
+%% -- Version 1 --
+
+decode_message([{version3,_},driver|EC], 1, Binary) ->
+ AsnMod = megaco_ber_bin_drv_media_gateway_control_v1,
+ TransMod = megaco_binary_transformer_v1,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+
+decode_message([driver|EC], 1, Binary) ->
+ AsnMod = megaco_ber_bin_drv_media_gateway_control_v1,
+ TransMod = megaco_binary_transformer_v1,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+
+decode_message([{version3,_}|EC], 1, Binary) ->
+ AsnMod = megaco_ber_bin_media_gateway_control_v1,
+ TransMod = megaco_binary_transformer_v1,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+
+decode_message(EC, 1, Binary) ->
+ AsnMod = megaco_ber_bin_media_gateway_control_v1,
+ TransMod = megaco_binary_transformer_v1,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+
+
+%% -- Version 2 --
+
+decode_message([{version3,_},driver|EC], 2, Binary) ->
+ AsnMod = megaco_ber_bin_drv_media_gateway_control_v2,
+ TransMod = megaco_binary_transformer_v2,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+
+decode_message([driver|EC], 2, Binary) ->
+ AsnMod = megaco_ber_bin_drv_media_gateway_control_v2,
+ TransMod = megaco_binary_transformer_v2,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+
+decode_message([{version3,_}|EC], 2, Binary) ->
+ AsnMod = megaco_ber_bin_media_gateway_control_v2,
+ TransMod = megaco_binary_transformer_v2,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+
+decode_message(EC, 2, Binary) ->
+ AsnMod = megaco_ber_bin_media_gateway_control_v2,
+ TransMod = megaco_binary_transformer_v2,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+
+
+%% -- Version 3 --
+
+decode_message([{version3,v3},driver|EC], 3, Binary) ->
+ AsnMod = megaco_ber_bin_drv_media_gateway_control_v3,
+ TransMod = megaco_binary_transformer_v3,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([{version3,prev3c},driver|EC], 3, Binary) ->
+ AsnMod = megaco_ber_bin_drv_media_gateway_control_prev3c,
+ TransMod = megaco_binary_transformer_prev3c,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([{version3,prev3b},driver|EC], 3, Binary) ->
+ AsnMod = megaco_ber_bin_drv_media_gateway_control_prev3b,
+ TransMod = megaco_binary_transformer_prev3b,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([{version3,prev3a},driver|EC], 3, Binary) ->
+ AsnMod = megaco_ber_bin_drv_media_gateway_control_prev3a,
+ TransMod = megaco_binary_transformer_prev3a,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+
+decode_message([driver|EC], 3, Binary) ->
+ AsnMod = megaco_ber_bin_drv_media_gateway_control_v3,
+ TransMod = megaco_binary_transformer_v3,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+
+decode_message([{version3,v3}|EC], 3, Binary) ->
+ AsnMod = megaco_ber_bin_media_gateway_control_v3,
+ TransMod = megaco_binary_transformer_v3,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([{version3,prev3c}|EC], 3, Binary) ->
+ AsnMod = megaco_ber_bin_media_gateway_control_prev3c,
+ TransMod = megaco_binary_transformer_prev3c,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([{version3,prev3b}|EC], 3, Binary) ->
+ AsnMod = megaco_ber_bin_media_gateway_control_prev3b,
+ TransMod = megaco_binary_transformer_prev3b,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([{version3,prev3a}|EC], 3, Binary) ->
+ AsnMod = megaco_ber_bin_media_gateway_control_prev3a,
+ TransMod = megaco_binary_transformer_prev3a,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+
+decode_message(EC, 3, Binary) ->
+ AsnMod = megaco_ber_bin_media_gateway_control_v3,
+ TransMod = megaco_binary_transformer_v3,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary).
+
+
+decode_mini_message([{version3,v3},driver|EC], dynamic, Bin) ->
+ Mods = [megaco_ber_bin_drv_media_gateway_control_v1,
+ megaco_ber_bin_drv_media_gateway_control_v2,
+ megaco_ber_bin_drv_media_gateway_control_v3],
+ ?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
+decode_mini_message([{version3,prev3c},driver|EC], dynamic, Bin) ->
+ Mods = [megaco_ber_bin_drv_media_gateway_control_v1,
+ megaco_ber_bin_drv_media_gateway_control_v2,
+ megaco_ber_bin_drv_media_gateway_control_prev3c],
+ ?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
+decode_mini_message([{version3,prev3b},driver|EC], dynamic, Bin) ->
+ Mods = [megaco_ber_bin_drv_media_gateway_control_v1,
+ megaco_ber_bin_drv_media_gateway_control_v2,
+ megaco_ber_bin_drv_media_gateway_control_prev3b],
+ ?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
+decode_mini_message([{version3,prev3a},driver|EC], dynamic, Bin) ->
+ Mods = [megaco_ber_bin_drv_media_gateway_control_v1,
+ megaco_ber_bin_drv_media_gateway_control_v2,
+ megaco_ber_bin_drv_media_gateway_control_prev3a],
+ ?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
+decode_mini_message([driver|EC], dynamic, Bin) ->
+ Mods = [megaco_ber_bin_drv_media_gateway_control_v1,
+ megaco_ber_bin_drv_media_gateway_control_v2,
+ megaco_ber_bin_drv_media_gateway_control_v3],
+ ?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
+decode_mini_message([{version3,v3}|EC], dynamic, Bin) ->
+ Mods = [megaco_ber_bin_media_gateway_control_v1,
+ megaco_ber_bin_media_gateway_control_v2,
+ megaco_ber_bin_media_gateway_control_v3],
+ ?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
+decode_mini_message([{version3,prev3c}|EC], dynamic, Bin) ->
+ Mods = [megaco_ber_bin_media_gateway_control_v1,
+ megaco_ber_bin_media_gateway_control_v2,
+ megaco_ber_bin_media_gateway_control_prev3c],
+ ?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
+decode_mini_message([{version3,prev3b}|EC], dynamic, Bin) ->
+ Mods = [megaco_ber_bin_media_gateway_control_v1,
+ megaco_ber_bin_media_gateway_control_v2,
+ megaco_ber_bin_media_gateway_control_prev3b],
+ ?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
+decode_mini_message([{version3,prev3a}|EC], dynamic, Bin) ->
+ Mods = [megaco_ber_bin_media_gateway_control_v1,
+ megaco_ber_bin_media_gateway_control_v2,
+ megaco_ber_bin_media_gateway_control_prev3a],
+ ?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
+decode_mini_message(EC, dynamic, Bin) ->
+ Mods = [megaco_ber_bin_media_gateway_control_v1,
+ megaco_ber_bin_media_gateway_control_v2,
+ megaco_ber_bin_media_gateway_control_v3],
+ ?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
+
+decode_mini_message([{version3,_},driver|EC], 1, Bin) ->
+ AsnMod = megaco_ber_bin_drv_media_gateway_control_v1,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message([driver|EC], 1, Bin) ->
+ AsnMod = megaco_ber_bin_drv_media_gateway_control_v1,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message([{version3,_}|EC], 1, Bin) ->
+ AsnMod = megaco_ber_bin_media_gateway_control_v1,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message(EC, 1, Bin) ->
+ AsnMod = megaco_ber_bin_media_gateway_control_v1,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+
+decode_mini_message([{version3,_},driver|EC], 2, Bin) ->
+ AsnMod = megaco_ber_bin_drv_media_gateway_control_v2,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message([driver|EC], 2, Bin) ->
+ AsnMod = megaco_ber_bin_drv_media_gateway_control_v2,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message([{version3,_}|EC], 2, Bin) ->
+ AsnMod = megaco_ber_bin_media_gateway_control_v2,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message(EC, 2, Bin) ->
+ AsnMod = megaco_ber_bin_media_gateway_control_v2,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+
+decode_mini_message([{version3,v3},driver|EC], 3, Bin) ->
+ AsnMod = megaco_ber_bin_drv_media_gateway_control_v3,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message([{version3,prev3c},driver|EC], 3, Bin) ->
+ AsnMod = megaco_ber_bin_drv_media_gateway_control_prev3c,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message([{version3,prev3b},driver|EC], 3, Bin) ->
+ AsnMod = megaco_ber_bin_drv_media_gateway_control_prev3b,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message([{version3,prev3a},driver|EC], 3, Bin) ->
+ AsnMod = megaco_ber_bin_drv_media_gateway_control_prev3a,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message([driver|EC], 3, Bin) ->
+ AsnMod = megaco_ber_bin_drv_media_gateway_control_v3,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message([{version3,v3}|EC], 3, Bin) ->
+ AsnMod = megaco_ber_bin_media_gateway_control_v3,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message([{version3,prev3c}|EC], 3, Bin) ->
+ AsnMod = megaco_ber_bin_media_gateway_control_prev3c,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message([{version3,prev3b}|EC], 3, Bin) ->
+ AsnMod = megaco_ber_bin_media_gateway_control_prev3b,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message([{version3,prev3a}|EC], 3, Bin) ->
+ AsnMod = megaco_ber_bin_media_gateway_control_prev3a,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message(EC, 3, Bin) ->
+ AsnMod = megaco_ber_bin_media_gateway_control_v3,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary).
+
+
+
diff --git a/lib/megaco/src/binary/megaco_binary_encoder_lib.erl b/lib/megaco/src/binary/megaco_binary_encoder_lib.erl
new file mode 100644
index 0000000000..842d6b70d1
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_binary_encoder_lib.erl
@@ -0,0 +1,317 @@
+%%
+%% %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 : Handle ASN.1 BER encoding of Megaco/H.248
+%%----------------------------------------------------------------------
+
+-module(megaco_binary_encoder_lib).
+
+%% API
+-export([
+ version_of/4,
+ decode_message/5, decode_message_dynamic/4,
+ decode_mini_message/4, decode_mini_message_dynamic/4,
+ encode_message/5,
+ encode_transaction/5,
+ encode_action_requests/5,
+ encode_action_request/5,
+ encode_action_reply/5
+ ]).
+
+-include_lib("megaco/src/engine/megaco_message_internal.hrl").
+
+
+%%----------------------------------------------------------------------
+%% Detect (check) which version a message is
+%% Return {ok, Version} | {error, Reason}
+%%----------------------------------------------------------------------
+
+version_of(_EC, Binary, dynamic, [AsnModV1|_AsnMods])
+ when is_binary(Binary) andalso is_atom(AsnModV1) ->
+ case (catch AsnModV1:decode_message_version(Binary)) of
+ {ok, PartialMsg} ->
+ V = (PartialMsg#'MegacoMessage'.mess)#'Message'.version,
+ {ok, V};
+ Error ->
+ Error
+ end;
+version_of(_EC, Binary, 1, AsnMods)
+ when is_binary(Binary) andalso is_list(AsnMods) ->
+ version_of(AsnMods, Binary, []);
+version_of(_EC, Binary, 2, [AsnModV1, AsnModV2, AsnModV3])
+ when is_binary(Binary) ->
+ version_of([AsnModV2, AsnModV1, AsnModV3], Binary, []);
+version_of(_EC, Binary, 3, [AsnModV1, AsnModV2, AsnModV3])
+ when is_binary(Binary) ->
+ version_of([AsnModV3, AsnModV1, AsnModV2], Binary, []).
+
+version_of([], _Binary, Err) ->
+ {error, {decode_failed, lists:reverse(Err)}};
+version_of([AsnMod|AsnMods], Binary, Errs) when is_atom(AsnMod) ->
+ case (catch asn1rt:decode(AsnMod, 'MegacoMessage', Binary)) of
+ {ok, M} ->
+ V = (M#'MegacoMessage'.mess)#'Message'.version,
+ {ok, V};
+ Err ->
+ version_of(AsnMods, Binary, [Err|Errs])
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Convert a 'MegacoMessage' record into a binary
+%% Return {ok, Binary} | {error, Reason}
+%%----------------------------------------------------------------------
+
+encode_message([native], MegaMsg, AsnMod, _TransMod, binary)
+ when is_record(MegaMsg, 'MegacoMessage') ->
+ asn1rt:encode(AsnMod, 'MegacoMessage', MegaMsg);
+encode_message(EC, MegaMsg, AsnMod, TransMod, binary)
+ when is_list(EC) andalso is_record(MegaMsg, 'MegacoMessage') ->
+ case (catch TransMod:tr_message(MegaMsg, encode, EC)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ MegaMsg2 ->
+ asn1rt:encode(AsnMod, 'MegacoMessage', MegaMsg2)
+ end;
+encode_message(EC, MegaMsg, AsnMod, TransMod, io_list) ->
+ case encode_message(EC, MegaMsg, AsnMod, TransMod, binary) of
+ {ok, Bin} when is_binary(Bin) ->
+ {ok, Bin};
+ {ok, DeepIoList} ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin};
+ {error, Reason} ->
+ {error, Reason}
+ end;
+encode_message(EC, MegaMsg, _AsnMod, _TransMod, _Type)
+ when is_record(MegaMsg, 'MegacoMessage') ->
+ {error, {bad_encoding_config, EC}};
+encode_message(_EC, MegaMsg, _AsnMod, _TransMod, _Type) ->
+ {error, {no_megaco_message, MegaMsg}}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a transaction (or transactions in the case of ack) record(s)
+%% into a binary
+%% Return {ok, Binary} | {error, Reason}
+%%----------------------------------------------------------------------
+
+%% Should handle encoding of all types of transactions:
+%% TransactionAck, TransactionPending, TransactionRequest
+%% and TransactionReply
+encode_transaction(EC, {Tag, _} = Trans, AsnMod, TransMod, Type)
+ when (Tag == transactionResponseAck) ->
+ do_encode_transaction(EC, Trans, AsnMod, TransMod, Type);
+encode_transaction(EC, {Tag, _} = Trans, AsnMod, TransMod, Type)
+ when (Tag == transactionPending) ->
+ do_encode_transaction(EC, Trans, AsnMod, TransMod, Type);
+encode_transaction(EC, {Tag, _} = Trans, AsnMod, TransMod, Type)
+ when (Tag == transactionRequest) ->
+ do_encode_transaction(EC, Trans, AsnMod, TransMod, Type);
+%% TransactionReply has been changed as of v3 so we cannot use
+%% the record definition in this common module.
+encode_transaction(EC, {Tag, _} = Trans, AsnMod, TransMod, Type)
+ when (Tag == transactionReply) ->
+ do_encode_transaction(EC, Trans, AsnMod, TransMod, Type);
+encode_transaction(_EC, T, _AsnMod, _TransMod, _Type) ->
+ {error, {no_megaco_transaction, T}}.
+
+do_encode_transaction([native], _Trans, _AsnMod, _TransMod, binary) ->
+ %% asn1rt:encode(AsnMod, element(1, T), T);
+ {error, not_implemented};
+do_encode_transaction(EC, _Trans, _AsnMod, _TransMod, binary)
+ when is_list(EC) ->
+ %% T2 = TransMod:tr_transaction(Trans, encode, EC),
+ %% asn1rt:encode(AsnMod, element(1, T), T2);
+ {error, not_implemented};
+do_encode_transaction(EC, Trans, AsnMod, TransMod, io_list) ->
+ case do_encode_transaction(EC, Trans, AsnMod, TransMod, binary) of
+ {ok, Bin} when is_binary(Bin) ->
+ {ok, Bin};
+ {ok, DeepIoList} ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin};
+ {error, Reason} ->
+ {error, Reason}
+ end;
+do_encode_transaction(EC, _Trans, _AsnMod, _TransMod, _Type) ->
+ {error, {bad_encoding_config, EC}}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a list of ActionRequest record's into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_requests([native], _ARs, _AsnMod, _TransMod, binary) ->
+ %% asn1rt:encode(AsnMod, element(1, T), T);
+ {error, not_implemented};
+encode_action_requests(_EC, _ARs0, _AsnMod, _TransMod, binary) ->
+ {error, not_implemented};
+encode_action_requests(EC, ARs, AsnMod, TransMod, io_list) ->
+ case encode_action_requests(EC, ARs, AsnMod, TransMod, binary) of
+ {ok, Bin} when is_binary(Bin) ->
+ {ok, Bin};
+ {ok, DeepIoList} ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin};
+ {error, Reason} ->
+ {error, Reason}
+ end;
+encode_action_requests(EC, _ARs, _AsnMod, _TransMod, _Type) ->
+ {error, {bad_encoding_config, EC}}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a ActionRequest record into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_request([native], _ARs, _AsnMod, _TransMod, binary) ->
+ %% asn1rt:encode(AsnMod, element(1, T), T);
+ {error, not_implemented};
+encode_action_request(_EC, _ARs0, _AsnMod, _TransMod, binary) ->
+ {error, not_implemented};
+encode_action_request(EC, ARs, AsnMod, TransMod, io_list) ->
+ case encode_action_request(EC, ARs, AsnMod, TransMod, binary) of
+ {ok, Bin} when is_binary(Bin) ->
+ {ok, Bin};
+ {ok, DeepIoList} ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin};
+ {error, Reason} ->
+ {error, Reason}
+ end;
+encode_action_request(EC, _ARs, _AsnMod, _TransMod, _Type) ->
+ {error, {bad_encoding_config, EC}}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a ActionReply record into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_reply([native], _ARs, _AsnMod, _TransMod, binary) ->
+ %% asn1rt:encode(AsnMod, element(1, T), T);
+ {error, not_implemented};
+encode_action_reply(_EC, _ARs0, _AsnMod, _TransMod, binary) ->
+ {error, not_implemented};
+encode_action_reply(EC, ARs, AsnMod, TransMod, io_list) ->
+ case encode_action_reply(EC, ARs, AsnMod, TransMod, binary) of
+ {ok, Bin} when is_binary(Bin) ->
+ {ok, Bin};
+ {ok, DeepIoList} ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin};
+ {error, Reason} ->
+ {error, Reason}
+ end;
+encode_action_reply(EC, _ARs, _AsnMod, _TransMod, _Type) ->
+ {error, {bad_encoding_config, EC}}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a binary into a 'MegacoMessage' record
+%% Return {ok, MegacoMessageRecord} | {error, Reason}
+%%----------------------------------------------------------------------
+
+decode_message_dynamic(EC, Bin,
+ [{AsnModV1, TransModV1},
+ {AsnModV2, TransModV2},
+ {AsnModV3, TransModV3}], Form)
+ when is_list(EC) andalso is_binary(Bin) ->
+ case AsnModV1:decode_message_version(Bin) of
+ {ok, PartialMsg} ->
+ V = (PartialMsg#'MegacoMessage'.mess)#'Message'.version,
+ case V of
+ 1 ->
+ decode_message(EC, Bin, AsnModV1, TransModV1, Form);
+ 2 ->
+ decode_message(EC, Bin, AsnModV2, TransModV2, Form);
+ 3 ->
+ decode_message(EC, Bin, AsnModV3, TransModV3, Form)
+ end;
+ {error, Reason} ->
+ {error, Reason}
+ end;
+decode_message_dynamic(EC, Bin, _Mods, _Type)
+ when is_binary(Bin) ->
+ {error, {bad_encoding_config, EC}};
+decode_message_dynamic(_EC, _BadBin, _Mods, _Type) ->
+ {error, no_binary}.
+
+
+decode_message(EC, Bin, AsnMod, TransMod, binary) ->
+ case asn1rt:decode(AsnMod, 'MegacoMessage', Bin) of
+ {ok, MegaMsg} ->
+ case EC of
+ [native] ->
+ {ok, MegaMsg};
+ _ ->
+ {ok, TransMod:tr_message(MegaMsg, decode, EC)}
+ end;
+ {error, Reason} ->
+ {error, Reason}
+ end;
+decode_message(EC, Bin, AsnMod, TransMod, io_list) ->
+ ShallowIoList = erlang:binary_to_list(Bin),
+ case asn1rt:decode(AsnMod, 'MegacoMessage', ShallowIoList) of
+ {ok, MegaMsg} ->
+ case EC of
+ [native] ->
+ {ok, MegaMsg};
+ _ ->
+ {ok, TransMod:tr_message(MegaMsg, decode, EC)}
+ end;
+ {error, Reason} ->
+ {error, Reason}
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Convert a binary into a partial 'MegacoMessage' record
+%% I.e. only version and Mid is fully decoded.
+%% Return {ok, MegacoMessageRecord} | {error, Reason}
+%%----------------------------------------------------------------------
+
+decode_mini_message(_, Bin, Mod, _) ->
+ case (catch Mod:decode_message_mId(Bin)) of
+ {ok, #'MegacoMessage'{mess = Mess} = MegaMsg} ->
+ Mess2 = Mess#'Message'{messageBody = undefined},
+ {ok, MegaMsg#'MegacoMessage'{mess = Mess2}};
+ Error ->
+ Error
+ end.
+
+
+decode_mini_message_dynamic(EC, Bin, [Mod1, Mod2, Mod3], Form) ->
+ case Mod1:decode_message_version(Bin) of
+ {ok, PartialMsg} ->
+ V = (PartialMsg#'MegacoMessage'.mess)#'Message'.version,
+ case V of
+ 1 ->
+ decode_mini_message(EC, Bin, Mod1, Form);
+ 2 ->
+ decode_mini_message(EC, Bin, Mod2, Form);
+ 3 ->
+ decode_mini_message(EC, Bin, Mod3, Form)
+ end;
+ Error ->
+ Error
+ end.
+
diff --git a/lib/megaco/src/binary/megaco_binary_name_resolver_prev3a.erl b/lib/megaco/src/binary/megaco_binary_name_resolver_prev3a.erl
new file mode 100644
index 0000000000..72b3112053
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_binary_name_resolver_prev3a.erl
@@ -0,0 +1,2003 @@
+%%
+%% %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: Handle meta data about packages
+%%----------------------------------------------------------------------
+
+-module(megaco_binary_name_resolver_prev3a).
+
+-include_lib("megaco/src/engine/megaco_message_internal.hrl").
+-include_lib("megaco/src/app/megaco_internal.hrl").
+
+
+-define(LOWER(Char),
+ if
+ Char >= $A, Char =< $Z ->
+ Char - ($A - $a);
+ true ->
+ Char
+ end).
+
+-export([packages/0,
+ capabilities/0,
+ capabilities/1,
+ decode_name/3,
+ encode_name/3
+ ]).
+
+encode_name(Config, term_id, TermId) ->
+ case megaco:encode_binary_term_id(Config, TermId) of
+ {ok, TermId2} ->
+ TermId2;
+ {error, _Reason} ->
+ exit({bad_term_id, TermId})
+ end;
+encode_name(_Config, Scope, Item) ->
+ ?d("encode_name(~p) -> entry with"
+ "~n Item: ~p", [Scope, Item]),
+ encode(Scope, Item).
+
+decode_name(Config, term_id, TermId) ->
+ case megaco:decode_binary_term_id(Config, TermId) of
+ {ok, TermId2} ->
+ TermId2;
+ {error, _Reason} ->
+ exit({bad_term_id, TermId})
+ end;
+decode_name(_Config, Scope, Item) ->
+ ?d("decode_name(~p) -> entry with"
+ "~n Item: ~p", [Scope, Item]),
+ decode(Scope, Item).
+
+
+
+%%----------------------------------------------------------------------
+%% 12.1.1 Package
+%%
+%% Overall description of the package, specifying:
+%%
+%% Package Name: only descriptive
+%%
+%% PackageID: is an identifier
+%%
+%% Description: is a description of the package
+%%
+%% Version:
+%%
+%% A new version of a package can only add additional Properties,
+%% Events, Signals, Statistics and new possible values for an
+%% existing parameter described in the original package. No
+%% deletions or modifications shall be allowed. A version is an
+%% integer in the range from 1 to 99.
+%%
+%% Designed to be extended only (Optional): Yes
+%%
+%% This indicates that the package has been expressly designed to
+%% be extended by others, not to be directly referenced. For
+%% example, the package may not have any function on its own or be
+%% nonsensical on its own. The MG SHOULD NOT publish this PackageID
+%% when reporting packages.
+%%
+%% Extends: existing package Descriptor
+%%
+%% A package may extend an existing package. The version of the
+%% original package must be specified. When a package extends
+%% another package it shall only add additional Properties, Events,
+%% Signals, Statistics and new possible values for an existing
+%% parameter described in the original package. An extended package
+%% shall not redefine or overload an identifier defined in the
+%% original package and packages it may have extended (multiple
+%% levels of extension). Hence, if package B version 1 extends
+%% package A version 1, version 2 of B will not be able to extend
+%% the A version 2 if A version 2 defines a name already in B
+%% version 1. If the package does not extend another package, it
+%% shall specify "none".
+%%
+%%
+%% 12.1.2 Properties
+%%
+%% Properties defined by the package, specifying:
+%%
+%% Property Name: only descriptive
+%%
+%% PropertyID: is an identifier
+%%
+%% Description: is a description of the function of the property
+%%
+%% Type: One of:
+%%
+%% Boolean
+%%
+%% String: UTF-8 string
+%%
+%% Octet String: A number of octets. See Annex A and B.3 for
+%% encoding
+%%
+%% Integer: 4 byte signed integer
+%%
+%% Double: 8 byte signed integer
+%%
+%% Character: unicode UTF-8 encoding of a single letter.
+%% Could be more than one octet.
+%%
+%% Enumeration: one of a list of possible unique values (see 12.3)
+%%
+%% Sub-list: a list of several values from a list.
+%% The type of sub-list SHALL also be specified.
+%% The type shall be chosen from the types specified in
+%% this section (with the exception of sub-list). For
+%% example, Type: sub-list of enumeration. The encoding
+%% of sub-lists is specified in Annexes A and B.3.
+%%
+%% Possible values:
+%%
+%% A package MUST specify either a specific set of values or a
+%% description of how values are determined. A package MUST also
+%% specify a default value or the default behaviour when the value
+%% is omitted from its descriptor. For example, a package may
+%% specify that procedures related to the property are suspended
+%% when its value is omitted.
+%%
+%% Default:
+%%
+%% A default value (but not procedures) may be specified as
+%% provisionable.
+%%
+%% Defined in:
+%%
+%% Which H.248.1 descriptor the property is defined in.
+%% LocalControl is for stream-dependent properties.
+%% TerminationState is for stream-independent properties.
+%% ContextAttribute is for properties that affect the context as
+%% a whole, i.e., mixing properties. These are expected to be the
+%% most common cases, but it is possible for properties to be
+%% defined in other descriptors. Context properties MUST be defined
+%% in the ContextAttribute descriptor.
+%%
+%% Characteristics: Read/Write or both, and (optionally), global:
+%%
+%% Indicates whether a property is read-only, or read-write, and
+%% if it is global. If Global is omitted, the property is not
+%% global. If a property is declared as global, the value of the
+%% property is shared by all Terminations realizing the package.
+%% If a context property is declared as global, the property is
+%% shared by all contexts realizing the package.
+%%
+%%
+%% 12.1.3 Events
+%%
+%% Events defined by the package, specifying:
+%%
+%% Event name: only descriptive
+%%
+%% EventID: is an identifier
+%%
+%% Description: a description of the function of the event
+%%
+%% EventsDescriptor Parameters:
+%%
+%% Parameters used by the MGC to configure the event, and found in
+%% the EventsDescriptor. See 12.2. If there are no parameters for
+%% the Events Descriptor, then "none" shall be specified.
+%%
+%% ObservedEventsDescriptor Parameters:
+%%
+%% Parameters returned to the MGC in Notify requests and in replies
+%% to command requests from the MGC that audit
+%% ObservedEventsDescriptor, and found in the
+%% ObservedEventsDescriptor. See 12.2. If there are no parameters
+%% for the ObservedEvents Descriptor, then �none� shall be specified.
+%%
+%%
+%% 12.1.4 Signals
+%%
+%% Signals defined by the package, specifying:
+%%
+%% Signal Name: only descriptive
+%%
+%% SignalID: is an identifier. SignalID is used in a SignalsDescriptor
+%%
+%% Description: a description of the function of the signal
+%%
+%% SignalType: one of:
+%%
+%% OO (On/Off)
+%%
+%% TO (TimeOut)
+%%
+%% BR (Brief)
+%%
+%% NOTE -�SignalType may be defined such that it is dependent on
+%% the value of one or more parameters. The package MUST specify a
+%% default signal type. If the default type is TO, the package MUST
+%% specify a default duration which may be provisioned. A default
+%% duration is meaningless for BR.
+%%
+%% Duration: in hundredths of seconds
+%%
+%% Additional Parameters: see 12.2
+%%
+%%
+%% 12.1.5 Statistics
+%%
+%% Statistics defined by the package, specifying:
+%%
+%% Statistic name: only descriptive
+%%
+%% StatisticID: is an identifier
+%%
+%% StatisticID is used in a StatisticsDescriptor
+%%
+%% Description: a description of the statistic
+%%
+%% Type: One of:
+%%
+%% Boolean
+%%
+%% String: UTF-8 string
+%%
+%% Octet String: A number of octets.
+%% See Annex A and Annex B.3 for encoding
+%%
+%% Integer: 4 byte signed integer
+%%
+%% Double: 8 byte signed integer
+%%
+%% Character: Unicode UTF-8 encoding of a single letter.
+%% Could be more than one octet.
+%%
+%% Enumeration: One of a list of possible unique values (See 12.3)
+%%
+%% Sub-list: A list of several values from a list.
+%% The type of sub-list SHALL also be specified.
+%% The type shall be chosen from the types specified in
+%% this section (with the exception of sub-list).
+%% For example, Type: sub-list of enumeration.
+%% The encoding of sub-lists is specified in Annexes A
+%% and B.3.
+%%
+%% Possible Values:
+%%
+%% A package must indicate the unit of measure, e.g. milliseconds,
+%% packets, either here or along with the type above, as well as
+%% indicating any restriction on the range.
+%%
+%% Level: Specify if the statistic can be kept at the Termination
+%% level, Stream level or Either.
+%%
+%%
+%% 12.1.6 Error Codes
+%%
+%% If the package does not define any error codes, this section may be omitted.
+%% Otherwise, it describes error codes defined by the package, specifying:
+%%
+%% Error Code #: The error code number.
+%%
+%% Name: Name of the error
+%%
+%% Definition: A description of the error code.
+%%
+%% Error Text in the Error Descriptor:
+%%
+%% A description of what text to return in the Error Descriptor.
+%%
+%% Comment: Any further comments on the use of the error code.
+%%
+%%
+%% 12.1.7 Procedures
+%%
+%% Additional guidance on the use of the package.
+%%
+%%
+%% 12.2 Guidelines to defining parameters to events and signals
+%%
+%% Parameter Name: only descriptive
+%%
+%% ParameterID: is an identifier. The textual ParameterID of
+%% parameters to Events and Signals shall not start with "EPA" and
+%% "SPA", respectively. The textual ParameterID shall also not be
+%% "ST", "Stream", "SY", "SignalType", "DR", "Duration", "NC",
+%% "NotifyCompletion", "KA", "KeepActive", "EB", "Embed", "DM",
+%% "DigitMap", "DI", "Direction", "RQ" or "RequestID".
+%%
+%% Description: a description of the function of the parameter.
+%%
+%% Type: One of:
+%%
+%% Boolean
+%%
+%% String: UTF-8 octet string
+%%
+%% Octet String: A number of octets. See Annex A and B.3 for
+%% encoding
+%%
+%% Integer: 4-octet signed integer
+%%
+%% Double: 8-octet signed integer
+%%
+%% Character: Unicode UTF-8 encoding of a single letter. Could be
+%% more than one octet.
+%%
+%% Enumeration: one of a list of possible unique values (see 12.3)
+%%
+%% Sub-list: a list of several values from a list (not supported
+%% for statistics). The type of sub-list SHALL also be
+%% specified The type shall be chosen from the types
+%% specified in this section (with the exception of
+%% sub-list). For example, Type: sub-list of enumeration.
+%% The encoding of sub-lists is specified in Annex A
+%% and B.3.
+%%
+%% Optional: Yes/No
+%%
+%% Describes if the parameter may be omitted from the signal or
+%% event.
+%%
+%% Possible values:
+%%
+%% A package MUST specify either a specific set of values or a
+%% description of how values are determined. A package MUST
+%% also specify a default value or the default behavior when the
+%% value is omitted from its descriptor. For example, a package
+%% may specify that procedures related to the parameter are
+%% suspended when its value is omitted.
+%%
+%% Default:
+%%
+%% A default value (but not procedures) may be specified as
+%% provisionable.
+%%
+%%
+%% 12.3 Lists
+%%
+%% Possible values for parameters include enumerations. Enumerations may be
+%% defined in a list. It is recommended that the list be IANA registered so
+%% that packages that extend the list can be defined without concern for
+%% conflicting names.
+%%
+%%
+%% 12.4 Identifiers
+%%
+%% Identifiers in text encoding shall be strings of up to 64 characters,
+%% containing no spaces, starting with an alphabetic character and consisting
+%% of alphanumeric characters and/or digits, and possibly including the
+%% special character underscore ("_").
+%%
+%% Identifiers in binary encoding are 2 octets long.
+%%
+%% Both text and binary values shall be specified for each identifier,
+%% including identifiers used as values in enumerated types.
+%%
+%%
+%% 12.5 Package registration
+%%
+%% A package can be registered with IANA for interoperability reasons. See
+%% clause 14 for IANA considerations.
+%%
+%%----------------------------------------------------------------------
+
+capabilities() ->
+ [{P, capabilities(P)} || P <- packages()].
+
+%% -record(property, {name, type, values, defined_in, characteristics}).
+
+%%----------------------------------------------------------------------
+%% List all known packages
+%% 'native' and 'all' are not real packages
+%%----------------------------------------------------------------------
+
+packages() ->
+ [
+ "g", % Generic
+ "root", % Base Root Package
+ "tonegen", % Tone Generator Package
+ "tonedet", % Tone Detection Package
+ "dg", % Basic DTMF Generator Package
+ "dd", % DTMF detection Package
+ "cg", % Call Progress Tones Generator Package
+ "cd", % Call Progress Tones Detection Package
+ "al", % Analog Line Supervision Package
+ "ct", % Basic Continuity Package
+ "nt", % Network Package
+ "rtp", % RTP Package
+ "swb", % SwitchBoard Package
+ "tdmc", % TDM Circuit Package
+ "" % Native pseudo package
+ ].
+
+%%----------------------------------------------------------------------
+%% List all matching capabilities
+%%----------------------------------------------------------------------
+
+capabilities(Package) ->
+ case Package of
+ "g" -> capabilities_g();
+ "root" -> capabilities_root();
+ "tonegen" -> capabilities_tonegen();
+ "tonedet" -> capabilities_tonedet();
+ "dg" -> capabilities_dg();
+ "dd" -> capabilities_dd();
+ "cg" -> capabilities_cg();
+ "cd" -> capabilities_cd();
+ "al" -> capabilities_al();
+ "ct" -> capabilities_ct();
+ "nt" -> capabilities_nt();
+ "rtp" -> capabilities_rtp();
+ "swb" -> capabilities_swb();
+ "tdmc" -> capabilities_tdmc();
+ "" -> capabilities_native()
+ end.
+
+%%----------------------------------------------------------------------
+%% Decode package name to internal form
+%% Scope ::= property | event | signal | statistics
+%%----------------------------------------------------------------------
+
+decode(mid, Package) ->
+ decode_mid(Package);
+decode(package, Package) ->
+ decode_package(Package);
+decode(profile, Package) ->
+ decode_profile(Package);
+decode(dialplan, Dialplan) ->
+ decode_dialplan(Dialplan);
+decode(Scope, [A, B | Item]) when is_atom(Scope) ->
+ ?d("decode(~p) -> entry with"
+ "~n A: ~p"
+ "~n B: ~p"
+ "~n Item: ~p", [Scope, A, B, Item]),
+ case decode_package([A, B]) of
+ "" ->
+ ?d("decode -> \"no\" package",[]),
+ decode_item(Scope, [A, B], Item);
+ Package ->
+ ?d("decode -> Package: ~p", [Package]),
+ Package ++ "/" ++ decode_item(Scope, [A, B], Item)
+ end;
+decode({Scope, [A, B | Item]}, SubItem) when is_atom(Scope) ->
+ ?d("decode(~p) -> entry with"
+ "~n A: ~p"
+ "~n B: ~p"
+ "~n Item: ~p"
+ "~n SubItem: ~p", [Scope, A, B, Item, SubItem]),
+ decode_item({Scope, Item}, [A, B], SubItem).
+
+decode_item(Scope, [A, B], Item) ->
+ ?d("decode_item -> entry",[]),
+ case A of
+ 16#00 ->
+ case B of
+ 16#01 -> decode_g(Scope, Item);
+ 16#02 -> decode_root(Scope, Item);
+ 16#03 -> decode_tonegen(Scope, Item);
+ 16#04 -> decode_tonedet(Scope, Item);
+ 16#05 -> decode_dg(Scope, Item);
+ 16#06 -> decode_dd(Scope, Item);
+ 16#07 -> decode_cg(Scope, Item);
+ 16#08 -> decode_cd(Scope, Item);
+ 16#09 -> decode_al(Scope, Item);
+ 16#0a -> decode_ct(Scope, Item);
+ 16#0b -> decode_nt(Scope, Item);
+ 16#0c -> decode_rtp(Scope, Item);
+ 16#0d -> decode_tdmc(Scope, Item);
+ 16#00 -> decode_native(Scope, Item)
+ end;
+ 16#fe ->
+ case B of
+ %% Proprietary extension
+ 16#fe -> decode_swb(Scope, Item)
+ end;
+ 16#ff ->
+ case B of
+ 16#ff when Item =:= [16#ff, 16#ff] -> "*"
+ end
+ end.
+
+decode_package(Package) ->
+ ?d("decode_package -> entry with"
+ "~n Package: ~p", [Package]),
+ [A, B] = Package,
+ case A of
+ 16#00 ->
+ case B of
+ 16#01 -> "g";
+ 16#02 -> "root";
+ 16#03 -> "tonegen";
+ 16#04 -> "tonedet";
+ 16#05 -> "dg";
+ 16#06 -> "dd";
+ 16#07 -> "cg";
+ 16#08 -> "cd";
+ 16#09 -> "al";
+ 16#0a -> "ct";
+ 16#0b -> "nt";
+ 16#0c -> "rtp";
+ 16#0d -> "tdmc";
+ 16#00 -> ""
+ end;
+ 16#fe ->
+ case B of
+ 16#fe -> "swb"
+ end;
+ 16#ff ->
+ case B of
+ 16#ff -> "*"
+ end
+ end.
+
+decode_profile([A, B]) ->
+ case A of
+ 16#00 ->
+ case B of
+ 16#fe -> "resgw";
+ _ -> "profile" ++ [A + $0, B + $0]
+ end;
+ _ ->
+ "profile" ++ [A + $0, B + $0]
+ end.
+
+decode_dialplan([A, B]) ->
+ "dialplan" ++ [A + $0, B + $0].
+
+decode_mid(Mid) ->
+ case Mid of
+ {domainName, DN} ->
+ Lower = to_lower(DN#'DomainName'.name),
+ {domainName, DN#'DomainName'{name = Lower}};
+ {deviceName, PathName} ->
+ Lower = to_lower(PathName),
+ {deviceName, Lower};
+ Other ->
+ Other
+ end.
+
+to_lower(Chars) ->
+ [?LOWER(Char) || Char <- Chars].
+
+%%----------------------------------------------------------------------
+%% Encode package name from internal form
+%% Scope ::= property | event | signal | statistics
+%%----------------------------------------------------------------------
+
+encode(mid, Package) ->
+ encode_mid(Package);
+encode(package, Package) ->
+ encode_package(Package);
+encode(profile, Profile) ->
+ encode_profile(Profile);
+encode(dialplan, Dialplan) ->
+ encode_dialplan(Dialplan);
+encode(Scope, PackageItem) when is_atom(Scope) ->
+ ?d("encode(~p) -> entry with"
+ "~n PackageItem: ~p", [Scope, PackageItem]),
+ case string:tokens(PackageItem, [$/]) of
+ [Package, Item] ->
+ ?d("encode -> "
+ "~n Package: ~p"
+ "~n Item: ~p", [Package, Item]),
+ encode_package(Package) ++ encode_item(Scope, Package, Item);
+ [Item] ->
+ ?d("encode -> Item: ~p", [Item]),
+ [16#00, 16#00 | encode_native(Scope, Item)]
+ end;
+encode({Scope, PackageItem}, SubItem) when is_atom(Scope) ->
+ ?d("encode(~p) -> entry with"
+ "~n PackageItem: ~p"
+ "~n SubItem: ~p", [Scope, PackageItem, SubItem]),
+ case string:tokens(PackageItem, [$/]) of
+ [Package, Item] ->
+ ?d("encode -> "
+ "~n Package: ~p"
+ "~n Item: ~p", [Package, Item]),
+ encode_item({Scope, Item}, Package, SubItem);
+ [_Item] ->
+ ?d("encode -> _Item: ~p", [_Item]),
+ encode_native(Scope, SubItem)
+ end.
+
+encode_item(_Scope, _Package, "*") ->
+ [16#ff, 16#ff];
+encode_item(Scope, Package, Item) ->
+ ?d("encode_item(~s) -> entry", [Package]),
+ case Package of
+ "g" -> encode_g(Scope, Item);
+ "root" -> encode_root(Scope, Item);
+ "tonegen" -> encode_tonegen(Scope, Item);
+ "tonedet" -> encode_tonedet(Scope, Item);
+ "dg" -> encode_dg(Scope, Item);
+ "dd" -> encode_dd(Scope, Item);
+ "cg" -> encode_cg(Scope, Item);
+ "cd" -> encode_cd(Scope, Item);
+ "al" -> encode_al(Scope, Item);
+ "ct" -> encode_ct(Scope, Item);
+ "nt" -> encode_nt(Scope, Item);
+ "rtp" -> encode_rtp(Scope, Item);
+ "tdmc" -> encode_tdmc(Scope, Item);
+ "swb" -> encode_swb(Scope, Item)
+ end.
+
+encode_package(Package) ->
+ case Package of
+ "g" -> [16#00, 16#01];
+ "root" -> [16#00, 16#02];
+ "tonegen" -> [16#00, 16#03];
+ "tonedet" -> [16#00, 16#04];
+ "dg" -> [16#00, 16#05];
+ "dd" -> [16#00, 16#06];
+ "cg" -> [16#00, 16#07];
+ "cd" -> [16#00, 16#08];
+ "al" -> [16#00, 16#09];
+ "ct" -> [16#00, 16#0a];
+ "nt" -> [16#00, 16#0b];
+ "rtp" -> [16#00, 16#0c];
+ "tdmc" -> [16#00, 16#0d];
+ "" -> [16#00, 16#00];
+ "*" -> [16#ff, 16#ff];
+ "swb" -> [16#fe, 16#fe]
+ end.
+
+encode_profile(Profile) ->
+ case Profile of
+ "resgw" ->
+ [16#00, 16#fe];
+ [$p, $r, $o, $f, $i, $l, $e | Name] ->
+ case Name of
+ [A, B] -> [A - $0, B - $0];
+ [B] -> [0, B - $0];
+ [] -> [0, 0]
+ end
+ end.
+
+encode_dialplan(Dialplan) ->
+ case Dialplan of
+ [$d, $i, $a, $l, $p, $l, $a, $n | Name] ->
+ case Name of
+ [A, B] -> [A - $0, B - $0];
+ [B] -> [0, B - $0];
+ [] -> [0, 0]
+ end
+ end.
+
+encode_mid(Mid) ->
+ Mid.
+
+
+%%----------------------------------------------------------------------
+%% Name: g - Generic
+%% Version: 1
+%% Extends: None
+%% Purpose: Generic package for commonly encountered items
+%%----------------------------------------------------------------------
+
+capabilities_g() ->
+ [
+ {event, "cause"},
+ {event, "sc"}
+ ].
+
+encode_g(event, Item) ->
+ case Item of
+ "cause" -> [16#00, 16#01];
+ "sc" -> [16#00, 16#02]
+ end;
+
+encode_g({event_parameter, Item}, SubItem) ->
+ case Item of
+ "cause" ->
+ case SubItem of
+ "Generalcause" -> [16#00, 16#01];
+ "Failurecause" -> [16#00, 16#02]
+ end;
+ "sc" ->
+ case SubItem of
+ "SigID" -> [16#00, 16#01];
+ "Meth" -> [16#00, 16#02];
+ "SLID" -> [16#00, 16#03];
+ "RID" -> [16#00, 16#04]
+ end
+ end.
+
+decode_g(event, Item) ->
+ case Item of
+ [16#00, 16#01] -> "cause";
+ [16#00, 16#02] -> "sc"
+ end;
+
+decode_g({event_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#01] -> % Event: cause
+ case SubItem of
+ [16#00, 16#01] -> "Generalcause";
+ [16#00, 16#02] -> "Failurecause"
+ end;
+
+ [16#00, 16#02] -> % Event: sc
+ case SubItem of
+ [16#00, 16#01] -> "SigID";
+ [16#00, 16#02] -> "Meth";
+ [16#00, 16#03] -> "SLID";
+ [16#00, 16#04] -> "RID"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: root - Base Root Package
+%% Version: 2
+%% Extends: None
+%% Purpose: This package defines Gateway wide properties.
+%%----------------------------------------------------------------------
+
+capabilities_root() ->
+ [
+ {property, "maxNumberOfContexts"},
+ {property, "maxTerminationsPerContext"},
+ {property, "normalMGExecutionTime"},
+ {property, "normalMGCExecutionTime"},
+ {property, "MGProvisionalResponseTimerValue"},
+ {property, "MGCProvisionalResponseTimerValue"},
+ {property, "MGCOriginatedPendingLimit"},
+ {property, "MGOriginatedPendingLimit"}
+ ].
+
+encode_root(Scope, Item) ->
+ case Scope of
+ property ->
+ case Item of
+ "maxNumberOfContexts" -> [16#00, 16#01];
+ "maxTerminationsPerContext" -> [16#00, 16#02];
+ "normalMGExecutionTime" -> [16#00, 16#03];
+ "normalMGCExecutionTime" -> [16#00, 16#04];
+ "MGProvisionalResponseTimerValue" -> [16#00, 16#05];
+ "MGCProvisionalResponseTimerValue" -> [16#00, 16#06];
+ "MGCOriginatedPendingLimit" -> [16#00, 16#07];
+ "MGOriginatedPendingLimit" -> [16#00, 16#08]
+ end
+ end.
+
+decode_root(Scope, Item) ->
+ case Scope of
+ property ->
+ case Item of
+ [16#00, 16#01] -> "maxNumberOfContexts";
+ [16#00, 16#02] -> "maxTerminationsPerContext";
+ [16#00, 16#03] -> "normalMGExecutionTime";
+ [16#00, 16#04] -> "normalMGCExecutionTime";
+ [16#00, 16#05] -> "MGProvisionalResponseTimerValue";
+ [16#00, 16#06] -> "MGCProvisionalResponseTimerValue";
+ [16#00, 16#07] -> "MGCOriginatedPendingLimit";
+ [16#00, 16#08] -> "MGOriginatedPendingLimit"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: tonegen - Tone Generator Package
+%% Version: 2
+%% Extends: None
+%% Purpose: This package defines signals to generate audio tones.
+%% This package does not specify parameter values. It is
+%% intended to be extendable. Generally, tones are defined
+%% as an individual signal with a parameter, ind,
+%% representing "interdigit" time delay, and a tone id to
+%% be used with playtones. A tone id should be kept
+%% consistent with any tone generation for the same tone.
+%% MGs are expected to be provisioned with the characteristics
+%% of appropriate tones for the country in which the MG is located.
+%%----------------------------------------------------------------------
+
+capabilities_tonegen() ->
+ [
+ {signal, "pt"}
+ ].
+
+encode_tonegen(signal, Item) ->
+ case Item of
+ "pt" -> [16#00, 16#01]
+ end;
+
+encode_tonegen({signal_parameter, Item}, SubItem) ->
+ case Item of
+ "pt" ->
+ case SubItem of
+ "tl" -> [16#00, 16#01];
+ "ind" -> [16#00, 16#02];
+ "btd" -> [16#00, 16#03]
+ end
+ end.
+
+decode_tonegen(signal, Item) ->
+ case Item of
+ [16#00, 16#01] -> "pt"
+ end;
+
+decode_tonegen({signal_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#01] -> % Event: pt
+ case SubItem of
+ [16#00, 16#01] -> "tl";
+ [16#00, 16#02] -> "ind";
+ [16#00, 16#03] -> "btd"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: tonedet - Tone Detection Package
+%% Version: 1
+%% Extends: None
+%% Purpose: This Package defines events for audio tone detection.
+%% Tones are selected by name (tone id). MGs are expected
+%% to be provisioned with the characteristics of appropriate
+%% tones for the country in which the MG is located.
+%%
+%% This package does not specify parameter values.
+%% It is intended to be extendable.
+%%----------------------------------------------------------------------
+
+capabilities_tonedet() ->
+ [
+ {event, "std"},
+ {event, "etd"},
+ {event, "ltd"}
+ ].
+
+encode_tonedet(event, Item) ->
+ case Item of
+ "std" -> [16#00, 16#01];
+ "etd" -> [16#00, 16#02];
+ "ltd" -> [16#00, 16#03]
+ end;
+
+encode_tonedet({event_parameter, Item}, SubItem) ->
+ case Item of
+ "std" ->
+ case SubItem of
+ "tl" -> [16#00, 16#01];
+ "tid" -> [16#00, 16#03]
+ end;
+ "etd" ->
+ case SubItem of
+ "tl" -> [16#00, 16#01];
+ "tid" -> [16#00, 16#03];
+ "dur" -> [16#00, 16#02]
+ end;
+ "ltd" ->
+ case SubItem of
+ "tl" -> [16#00, 16#01];
+ "dur" -> [16#00, 16#02];
+ "tid" -> [16#00, 16#03]
+ end
+ end.
+
+decode_tonedet(event, Item) ->
+ case Item of
+ [16#00, 16#01] -> "std";
+ [16#00, 16#02] -> "etd";
+ [16#00, 16#03] -> "ltd"
+ end;
+
+decode_tonedet({event_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#01] -> % Event std
+ case SubItem of
+ [16#00, 16#01] -> "tl";
+ [16#00, 16#03] -> "tid"
+ end;
+ [16#00, 16#02] -> % Event etd
+ case SubItem of
+ [16#00, 16#01] -> "tl";
+ [16#00, 16#03] -> "tid";
+ [16#00, 16#02] -> "dur"
+ end;
+ [16#00, 16#03] -> % Event ltd
+ case SubItem of
+ [16#00, 16#01] -> "tl";
+ [16#00, 16#02] -> "dur";
+ [16#00, 16#03] -> "tid"
+ end
+ end.
+
+%%----------------------------------------------------------------------
+%% Name: dg - Basic DTMF Generator Package
+%% Version: 1
+%% Extends: tonegen version 1
+%% Purpose: This package defines the basic DTMF tones as signals and
+%% extends the allowed values of parameter tl of playtone
+%% in tonegen.
+%%----------------------------------------------------------------------
+
+capabilities_dg() ->
+ [
+ {signal, "d0"},
+ {signal, "d1"},
+ {signal, "d2"},
+ {signal, "d3"},
+ {signal, "d4"},
+ {signal, "d5"},
+ {signal, "d6"},
+ {signal, "d7"},
+ {signal, "d8"},
+ {signal, "d9"},
+ {signal, "ds"},
+ {signal, "do"},
+ {signal, "da"},
+ {signal, "db"},
+ {signal, "dc"},
+ {signal, "dd"}
+ ].
+
+encode_dg(signal, Item) ->
+ case Item of
+ "d0" -> [16#00, 16#10];
+ "d1" -> [16#00, 16#11];
+ "d2" -> [16#00, 16#12];
+ "d3" -> [16#00, 16#13];
+ "d4" -> [16#00, 16#14];
+ "d5" -> [16#00, 16#15];
+ "d6" -> [16#00, 16#16];
+ "d7" -> [16#00, 16#17];
+ "d8" -> [16#00, 16#18];
+ "d9" -> [16#00, 16#19];
+ "ds" -> [16#00, 16#20];
+ "do" -> [16#00, 16#21];
+ "da" -> [16#00, 16#1a];
+ "db" -> [16#00, 16#1b];
+ "dc" -> [16#00, 16#1c];
+ "dd" -> [16#00, 16#1d]
+ end;
+
+encode_dg({signal_parameter, Item}, SubItem) ->
+ case Item of
+ "d0" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d1" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d2" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d3" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d4" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d5" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d6" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d7" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d8" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d9" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "ds" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "do" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "da" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "db" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "dc" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "dd" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end
+ end.
+
+decode_dg(signal, Item) ->
+ case Item of
+ [16#00, 16#10] -> "d0";
+ [16#00, 16#11] -> "d1";
+ [16#00, 16#12] -> "d2";
+ [16#00, 16#13] -> "d3";
+ [16#00, 16#14] -> "d4";
+ [16#00, 16#15] -> "d5";
+ [16#00, 16#16] -> "d6";
+ [16#00, 16#17] -> "d7";
+ [16#00, 16#18] -> "d8";
+ [16#00, 16#19] -> "d9";
+ [16#00, 16#20] -> "ds";
+ [16#00, 16#21] -> "do";
+ [16#00, 16#1a] -> "da";
+ [16#00, 16#1b] -> "db";
+ [16#00, 16#1c] -> "dc";
+ [16#00, 16#1d] -> "dd"
+ end;
+
+decode_dg({signal_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#10] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#11] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#12] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#13] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#14] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#15] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#16] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#17] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#18] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#19] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#20] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#21] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#1a] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#1b] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#1c] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#1d] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: dd - DTMF detection Package
+%% Version: 1
+%% Extends: tonedet version 1
+%% Purpose: This package defines the basic DTMF tones detection.
+%% Tones are selected by name (tone id). MGs are expected
+%% to be provisioned with the characteristics of appropriate
+%% tones for the country in which the MG is located.
+%%
+%% This package does not specify parameter values.
+%% It is intended to be extendable.
+%%
+%% Additional tone id values are all tone ids described in package dg
+%% (basic DTMF generator package).
+%%
+%% The following table maps DTMF events to digit map symbols as described
+%% in section 7.1.14.
+%%
+%% _________________________________
+%% | DTMF Event | Symbol |
+%% | d0 | "0" |
+%% | d1 | "1" |
+%% | d2 | "2" |
+%% | d3 | "3" |
+%% | d4 | "4" |
+%% | d5 | "5" |
+%% | d6 | "6" |
+%% | d7 | "7" |
+%% | d8 | "8" |
+%% | d9 | "9" |
+%% | da | "A" or "a"|
+%% | db | "B" or "b"|
+%% | dc | "C" or "c"|
+%% | dd | "D" or "d"|
+%% | ds | "E" or "e"|
+%% | do | "F" or "f"|
+%% |___________________|____________|
+%%
+%%----------------------------------------------------------------------
+
+capabilities_dd() ->
+ [
+ {event, "ce"},
+ {event, "d0"},
+ {event, "d1"},
+ {event, "d2"},
+ {event, "d3"},
+ {event, "d4"},
+ {event, "d5"},
+ {event, "d6"},
+ {event, "d7"},
+ {event, "d8"},
+ {event, "d9"},
+ {event, "ds"},
+ {event, "do"},
+ {event, "da"},
+ {event, "db"},
+ {event, "dc"},
+ {event, "dd"}
+ ].
+
+encode_dd(event, Item) ->
+ case Item of
+ "ce" -> [16#00, 16#04];
+ "d0" -> [16#00, 16#10];
+ "d1" -> [16#00, 16#11];
+ "d2" -> [16#00, 16#12];
+ "d3" -> [16#00, 16#13];
+ "d4" -> [16#00, 16#14];
+ "d5" -> [16#00, 16#15];
+ "d6" -> [16#00, 16#16];
+ "d7" -> [16#00, 16#17];
+ "d8" -> [16#00, 16#18];
+ "d9" -> [16#00, 16#19];
+ "ds" -> [16#00, 16#20];
+ "do" -> [16#00, 16#21];
+ "da" -> [16#00, 16#1a];
+ "db" -> [16#00, 16#1b];
+ "dc" -> [16#00, 16#1c];
+ "dd" -> [16#00, 16#1d]
+ end;
+
+encode_dd({event_parameter, Item}, SubItem) ->
+ case Item of
+ "ce" ->
+ case SubItem of
+ "ds" -> [16#00, 16#01];
+ "Meth" -> [16#00, 16#03]
+ end;
+ "d0" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d1" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d2" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d3" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d4" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d5" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d6" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d7" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d8" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d9" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "ds" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "do" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "da" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "db" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "dc" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "dd" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end
+ end.
+
+decode_dd(event, Item) ->
+ case Item of
+ [16#00, 16#04] -> "ce";
+ [16#00, 16#10] -> "d0";
+ [16#00, 16#11] -> "d1";
+ [16#00, 16#12] -> "d2";
+ [16#00, 16#13] -> "d3";
+ [16#00, 16#14] -> "d4";
+ [16#00, 16#15] -> "d5";
+ [16#00, 16#16] -> "d6";
+ [16#00, 16#17] -> "d7";
+ [16#00, 16#18] -> "d8";
+ [16#00, 16#19] -> "d9";
+ [16#00, 16#20] -> "ds";
+ [16#00, 16#21] -> "do";
+ [16#00, 16#1a] -> "da";
+ [16#00, 16#1b] -> "db";
+ [16#00, 16#1c] -> "dc";
+ [16#00, 16#1d] -> "dd"
+ end;
+
+decode_dd({event_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#04] -> % Event ce
+ case SubItem of
+ [16#00, 16#01] -> "ds";
+ [16#00, 16#03] -> "Meth"
+ end;
+ [16#00, 16#10] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#11] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#12] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#13] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#14] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#15] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#16] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#17] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#18] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#19] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#20] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#21] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#1a] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#1b] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#1c] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#1d] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end
+ end.
+
+%%----------------------------------------------------------------------
+%% Name: cg - Call Progress Tones Generator Package
+%% Version: 1
+%% Extends: tonegen version 1
+%% Purpose: This package defines the basic call progress tones as signals
+%% and extends the allowed values of the tl parameter of
+%% playtone in tonegen.
+%%----------------------------------------------------------------------
+
+capabilities_cg() ->
+ [
+ {signal, "dt"},
+ {signal, "rt"},
+ {signal, "bt"},
+ {signal, "ct"},
+ {signal, "sit"},
+ {signal, "wt"},
+ {signal, "prt"},
+ {signal, "cw"},
+ {signal, "cr"}
+ ].
+
+
+encode_cg(Scope, Item) ->
+ case Scope of
+ signal ->
+ case Item of
+ "dt" -> [16#00, 16#30];
+ "rt" -> [16#00, 16#31];
+ "bt" -> [16#00, 16#32];
+ "ct" -> [16#00, 16#33];
+ "sit" -> [16#00, 16#34];
+ "wt" -> [16#00, 16#35];
+ "prt" -> [16#00, 16#36];
+ "cw" -> [16#00, 16#37];
+ "cr" -> [16#00, 16#38]
+ end
+ end.
+
+decode_cg(Scope, Item) ->
+ case Scope of
+ signal ->
+ case Item of
+ [16#00, 16#30] -> "dt";
+ [16#00, 16#31] -> "rt";
+ [16#00, 16#32] -> "bt";
+ [16#00, 16#33] -> "ct";
+ [16#00, 16#34] -> "sit";
+ [16#00, 16#35] -> "wt";
+ [16#00, 16#36] -> "prt";
+ [16#00, 16#37] -> "cw";
+ [16#00, 16#38] -> "cr"
+ end
+ end.
+
+%%----------------------------------------------------------------------
+%% Name: cd - Call Progress Tones Detection Package
+%% Version: 1
+%% Extends: tonedet version 1
+%% Purpose: This package defines the basic call progress detection tones.
+%% This Package extends the possible values of tone id
+%% in the "start tone detected", "end tone detected" and
+%% "long tone detected" events.
+%% Additional values
+%% tone id values are defined for start tone detected,
+%% end tone detected and long tone detected with
+%% the same values as those in package cg (call
+%% progress tones generation package).
+%%
+%% The required set of tone ids corresponds to Recommendation E.180/Q.35
+%% [ITU-T Recommendation E.180/Q.35 (1998)]. See Recommendation E.180/Q.35
+%% for definition of the meanings of these tones.
+%%----------------------------------------------------------------------
+
+capabilities_cd() ->
+ [
+ {event, "dt"},
+ {event, "rt"},
+ {event, "bt"},
+ {event, "ct"},
+ {event, "sit"},
+ {event, "wt"},
+ {event, "prt"},
+ {event, "cw"},
+ {event, "cr"}
+ ].
+
+
+encode_cd(Scope, Item) ->
+ case Scope of
+ event ->
+ case Item of
+ "dt" -> [16#00, 16#30];
+ "rt" -> [16#00, 16#31];
+ "bt" -> [16#00, 16#32];
+ "ct" -> [16#00, 16#33];
+ "sit"-> [16#00, 16#34];
+ "wt" -> [16#00, 16#35];
+ "prt"-> [16#00, 16#36];
+ "cw" -> [16#00, 16#37];
+ "cr" -> [16#00, 16#38]
+ end
+ end.
+
+decode_cd(Scope, Item) ->
+ case Scope of
+ event ->
+ case Item of
+ [16#00, 16#30] -> "dt";
+ [16#00, 16#31] -> "rt";
+ [16#00, 16#32] -> "bt";
+ [16#00, 16#33] -> "ct";
+ [16#00, 16#34] -> "sit";
+ [16#00, 16#35] -> "wt";
+ [16#00, 16#36] -> "prt";
+ [16#00, 16#37] -> "cw";
+ [16#00, 16#38] -> "cr"
+ end
+ end.
+
+%%----------------------------------------------------------------------
+%% Name: al - Analog Line Supervision Package
+%% Version: 1
+%% Extends: None
+%% Purpose: This package defines events and signals for an analog line.
+%%----------------------------------------------------------------------
+
+capabilities_al() ->
+ [
+ {event, "on"},
+ {event, "of"},
+ {event, "fl"},
+ {signal, "ri"}
+ ].
+
+encode_al(event, Item) ->
+ ?d("encode_al(event) -> entry with"
+ "~n Item: ~p", [Item]),
+ case Item of
+ "on" -> [16#00, 16#04];
+ "of" -> [16#00, 16#05];
+ "fl" -> [16#00, 16#06]
+ end;
+
+encode_al({event_parameter, Item}, SubItem) ->
+ ?d("encode_al({event_parameter,~p}) -> entry with"
+ "~n SubItem: ~p", [Item, SubItem]),
+ case Item of
+ "on" ->
+ case SubItem of
+ "strict" -> [16#00, 16#01];
+ "init" -> [16#00, 16#02]
+ end;
+ "of" ->
+ case SubItem of
+ "strict" -> [16#00, 16#01];
+ "init" -> [16#00, 16#02]
+ end;
+ "fl" ->
+ case SubItem of
+ "mindur" -> [16#00, 16#04];
+ "maxdur" -> [16#00, 16#05]
+ end
+ end;
+
+encode_al(signal, Item) ->
+ ?d("encode_al(signal) -> entry with"
+ "~n Item: ~p", [Item]),
+ case Item of
+ "ri" -> [16#00, 16#02]
+ end;
+
+encode_al({signal_parameter, Item}, SubItem) ->
+ ?d("encode_al({signal_parameter,~p}) -> entry with"
+ "~n SubItem: ~p", [Item, SubItem]),
+ case Item of
+ "ri" ->
+ case SubItem of
+ "cad" -> [16#00, 16#06];
+ "freq" -> [16#00, 16#07]
+ end
+ end.
+
+decode_al(event, SubItem) ->
+ ?d("decode_al(event) -> entry with"
+ "~n SubItem: ~p", [SubItem]),
+ case SubItem of
+ [16#00, 16#04] -> "on";
+ [16#00, 16#05] -> "of";
+ [16#00, 16#06] -> "fl"
+ end;
+
+decode_al({event_parameter, Item}, SubItem) ->
+ ?d("decode_al({event_parameter,~p}) -> entry with"
+ "~n SubItem: ~p", [Item, SubItem]),
+ case Item of
+ [16#00,16#04] -> %% Event: on
+ case SubItem of
+ [16#00, 16#01] -> "strict";
+ [16#00, 16#02] -> "init"
+ end;
+ [16#00,16#05] -> %% Event: of
+ case SubItem of
+ [16#00, 16#01] -> "strict";
+ [16#00, 16#02] -> "init"
+ end;
+ [16#00,16#06] -> %% Event: fl
+ case SubItem of
+ [16#00, 16#04] -> "mindur";
+ [16#00, 16#05] -> "maxdur"
+ end
+ end;
+
+decode_al(signal, SubItem) ->
+ ?d("decode_al(signal) -> entry with"
+ "~n SubItem: ~p", [SubItem]),
+ case SubItem of
+ [16#00, 16#02] -> "ri"
+ end;
+
+decode_al({signal_parameter, Item}, SubItem) ->
+ ?d("decode_al({signal_parameter,~p}) -> entry with"
+ "~n SubItem: ~p", [Item, SubItem]),
+ case Item of
+ [16#00,16#02] -> %% Event: ri
+ case SubItem of
+ [16#00, 16#06] -> "cad";
+ [16#00, 16#07] -> "freq"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: ct - Basic Continuity Package
+%% Version: 1
+%% Extends: None
+%% Purpose: This package defines events and signals for continuity test.
+%% The continuity test includes provision of either a loopback
+%% or transceiver functionality.
+%%----------------------------------------------------------------------
+
+capabilities_ct() ->
+ [
+ {event, "cmp"},
+ {signal, "ct"},
+ {signal, "rsp"}
+ ].
+
+encode_ct(event, Item) ->
+ case Item of
+ "cmp" -> [16#00, 16#05]
+ end;
+encode_ct({event_parameter, Item}, SubItem) ->
+ case Item of
+ "cmp" ->
+ case SubItem of
+ "res" -> [16#00, 16#08]
+ end
+ end;
+encode_ct(signal, Item) ->
+ case Item of
+ "ct" -> [16#00, 16#03];
+ "rsp" -> [16#00, 16#04]
+ end.
+
+decode_ct(event, Item) ->
+ case Item of
+ [16#00, 16#05] -> "cmp"
+ end;
+decode_ct({event_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#05] -> % Event cmp
+ case SubItem of
+ [16#00, 16#08] -> "res"
+ end
+ end;
+decode_ct(signal, Item) ->
+ case Item of
+ [16#00, 16#03] -> "ct";
+ [16#00, 16#04] -> "rsp"
+ end.
+
+%%----------------------------------------------------------------------
+%% Name: nt - Network Package
+%% Version: 1
+%% Extends: None
+%% Purpose: This package defines properties of network terminations
+%% independent of network type.
+%%----------------------------------------------------------------------
+
+capabilities_nt() ->
+ [
+ {property, "jit"},
+ {event, "netfail"},
+ {event, "qualert"},
+ {statistics, "dur"},
+ {statistics, "os"},
+ {statistics, "or"}
+ ].
+
+encode_nt(property, Item) ->
+ case Item of
+ "jit" -> [16#00, 16#07]
+ end;
+encode_nt(event, Item) ->
+ case Item of
+ "netfail" -> [16#00, 16#05];
+ "qualert" -> [16#00, 16#06]
+ end;
+encode_nt({event_parameter, Item}, SubItem) ->
+ case Item of
+ "netfail" ->
+ case SubItem of
+ "cs" -> [16#00, 16#01]
+ end;
+ "qualert" ->
+ case SubItem of
+ "th" -> [16#00, 16#01]
+ end
+ end;
+encode_nt(statistics, Item) ->
+ case Item of
+ "dur" -> [16#00, 16#01];
+ "os" -> [16#00, 16#02];
+ "or" -> [16#00, 16#03]
+ end.
+
+decode_nt(property, Item) ->
+ case Item of
+ [16#00, 16#07] -> "jit"
+ end;
+decode_nt(event, Item) ->
+ case Item of
+ [16#00, 16#05] -> "netfail";
+ [16#00, 16#06] -> "qualert"
+ end;
+decode_nt({event_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#05] -> % Event netfail
+ case SubItem of
+ [16#00, 16#01] -> "cs"
+ end;
+ [16#00, 16#06] -> % Event qualert
+ case Item of
+ [16#00, 16#01] -> "th"
+ end
+ end;
+decode_nt(statistics, Item) ->
+ case Item of
+ [16#00, 16#01] -> "dur";
+ [16#00, 16#02] -> "os";
+ [16#00, 16#03] -> "or"
+ end.
+
+%%----------------------------------------------------------------------
+%% Name: rtp - RTP Package
+%% Version: 1
+%% Extends: nt version 1
+%% Purpose: This package is used to support packet based multimedia
+%% data transfer by means of the Real-time Transport Protocol
+%% (RTP) [RFC 1889].
+%%----------------------------------------------------------------------
+
+capabilities_rtp() ->
+ [
+ {event, "pltrans"},
+ {statistics, "ps"},
+ {statistics, "pr"},
+ {statistics, "pl"},
+ {statistics, "jit"},
+ {statistics, "delay"}
+ ].
+
+encode_rtp(event, Item) ->
+ case Item of
+ "pltrans" -> [16#00, 16#01]
+ end;
+encode_rtp({event_parameter, Item}, SubItem) ->
+ case Item of
+ "pltrans" ->
+ case SubItem of
+ "rtppltype" -> [16#00, 16#01]
+ end
+ end;
+encode_rtp(statistics, Item) ->
+ case Item of
+ "ps" -> [16#00, 16#04];
+ "pr" -> [16#00, 16#05];
+ "pl" -> [16#00, 16#06];
+ "jit" -> [16#00, 16#07];
+ "delay" -> [16#00, 16#08]
+ end.
+
+decode_rtp(event, Item) ->
+ case Item of
+ [16#00, 16#01] -> "pltrans"
+ end;
+decode_rtp({event_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#01] -> % Event pltrans
+ case SubItem of
+ [16#00, 16#01] -> "rtppltype"
+ end
+ end;
+decode_rtp(statistics, Item) ->
+ case Item of
+ [16#00, 16#04] -> "ps";
+ [16#00, 16#05] -> "pr";
+ [16#00, 16#06] -> "pl";
+ [16#00, 16#07] -> "jit";
+ [16#00, 16#08] -> "delay"
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: tdmc - TDM Circuit Package
+%% Version: 1
+%% Extends: nt version 1
+%% Purpose: This package is used to support TDM circuit terminations.
+%%----------------------------------------------------------------------
+
+capabilities_tdmc() ->
+ [
+ {property, "ec"},
+ {property, "gain"}
+ ].
+
+encode_tdmc(Scope, Item) ->
+ case Scope of
+ property ->
+ case Item of
+ "ec" -> [16#00, 16#08];
+ "gain" -> [16#00, 16#0a]
+ end
+ end.
+
+decode_tdmc(Scope, Item) ->
+ case Scope of
+ property ->
+ case Item of
+ [16#00, 16#08] -> "ec";
+ [16#00, 16#0a] -> "gain"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: swb - SwitchBoard Package
+%% Version: 1
+%% Extends: none
+%% Purpose: This package is used to support SwitchBoard specials
+%%----------------------------------------------------------------------
+
+capabilities_swb() ->
+ [
+ {statistics, "fs"}, % Free slots
+ {statistics, "as"} % Allocated slots
+ ].
+
+encode_swb(Scope, Item) ->
+ case Scope of
+ statistics ->
+ case Item of
+ "fs" -> [16#00, 16#00];
+ "as" -> [16#00, 16#01]
+ end
+ end.
+
+decode_swb(Scope, Item) ->
+ case Scope of
+ statistics ->
+ case Item of
+ [16#00, 16#00] -> "fs";
+ [16#00, 16#01] -> "as"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: native - Pseudo package
+%% Version: 1
+%% Extends: None
+%% Purpose: Native tags for media stream properties
+%%
+%% Parameters for Local descriptors and Remote descriptors are
+%% specified as tag-value pairs if binary encoding is used for the
+%% protocol. This annex contains the property names (PropertyID), the
+%% tags (Property Tag), type of the property (Type) and the values
+%% (Value).Values presented in the Value field when the field contains
+%% references shall be regarded as "information". The reference
+%% contains the normative values. If a value field does not contain a
+%% reference then the values in that field can be considered as
+%% "normative".
+%%
+%% Tags are given as hexadecimal numbers in this annex. When setting
+%% the value of a property, a MGC may underspecify the value according
+%% to one of the mechanisms specified in section 7.1.1.
+%%
+%% For type "enumeration" the value is represented by the value in brack-
+%% ets, e.g., Send(0), Receive(1).
+%%----------------------------------------------------------------------
+%%
+%% C.6. IP
+%%
+%% ________________________________________________________________
+%% | PropertyID| Tag | Type | Value |
+%% | IPv4 | 6001 | 32 BITS | Ipv4Address |
+%% | IPv6 | 6002 | 128 BITS | IPv6 Address |
+%% | Port | 6003 | Unsigned Int| Port |
+%% | Porttype | 6004 | Enumerated | TCP(0),UDP(1),SCTP(2)|
+%% |___________|____________|______________|_______________________|
+%%
+%%
+%% C.11. SDP Equivalents
+%%
+%% ______________________________________________________________
+%% | PropertyID| Tag | Type | Value |
+%% | SDP_V | B001| STRING| Protocol Version |
+%% | SDP_O | B002| STRING| Owner-creator and session ID |
+%% | SDP_S | B003| STRING| Sesson name |
+%% | SDP_I | B004| STRING| Session identifier |
+%% | SDP_U | B005| STRING| URI of descriptor |
+%% | SDC_E | B006| STRING| email address |
+%% | SDP_P | B007| STRING| phone number |
+%% | SDP_C | B008| STRING| Connection information |
+%% | SDP_B | B009| STRING| Bandwidth Information |
+%% | SDP_Z | B00A| STRING| time zone adjustment |
+%% | SDP_K | B00B| STRING| Encryption Key |
+%% | SDP_A | B00C| STRING| Zero or more session attributes|
+%% | SDP_T | B00D| STRING| Active Session Time |
+%% | SDP_R | B00E| STRING| Zero or more repeat times |
+%% | SDP_M | B00F| STRING| Media name and transport addr |
+%% | | | | Reference: IETF RFC 2327 |
+%% |___________|______|________|_________________________________|
+%%
+%%----------------------------------------------------------------------
+
+capabilities_native() ->
+ [
+ %% C.6. IP
+ {property, "IPv4"},
+ {property, "IPv6"},
+ {property, "Port"},
+ {property, "Porttype"},
+
+ %% C.11. SDP Equivalents
+ {property, "v"},
+ {property, "o"},
+ {property, "s"},
+ {property, "i"},
+ {property, "u"},
+ {property, "e"},
+ {property, "p"},
+ {property, "c"},
+ {property, "b"},
+ {property, "z"},
+ {property, "k"},
+ {property, "a"},
+ {property, "t"},
+ {property, "r"},
+ {property, "m"}
+ ].
+
+encode_native(Scope, Item) ->
+ case Scope of
+ property ->
+ case Item of
+ %% IP
+ "IPv4" -> [16#60, 16#01];
+ "IPv6" -> [16#60, 16#02];
+ "Port" -> [16#60, 16#03];
+ "Porttype" -> [16#60, 16#04];
+
+ %% SDP
+ "v" -> [16#b0, 16#01];
+ "o" -> [16#b0, 16#02];
+ "s" -> [16#b0, 16#03];
+ "i" -> [16#b0, 16#04];
+ "u" -> [16#b0, 16#05];
+ "e" -> [16#b0, 16#06];
+ "p" -> [16#b0, 16#07];
+ "c" -> [16#b0, 16#08];
+ "b" -> [16#b0, 16#09];
+ "z" -> [16#b0, 16#0a];
+ "k" -> [16#b0, 16#0b];
+ "a" -> [16#b0, 16#0c];
+ "t" -> [16#b0, 16#0d];
+ "r" -> [16#b0, 16#0e];
+ "m" -> [16#b0, 16#0f]
+ end
+ end.
+
+decode_native(Scope, [Type, Item]) ->
+ case Scope of
+ property ->
+ case Type of
+ 16#60 ->
+ case Item of
+ 16#01 -> "IPv4";
+ 16#02 -> "IPv6";
+ 16#03 -> "Port";
+ 16#04 -> "Porttype"
+ end;
+
+ 16#b0 ->
+ case Item of
+ 16#01 -> "v";
+ 16#02 -> "o";
+ 16#03 -> "s";
+ 16#04 -> "i";
+ 16#05 -> "u";
+ 16#06 -> "e";
+ 16#07 -> "p";
+ 16#08 -> "c";
+ 16#09 -> "b";
+ 16#0a -> "z";
+ 16#0b -> "k";
+ 16#0c -> "a";
+ 16#0d -> "t";
+ 16#0e -> "r";
+ 16#0f -> "m"
+ end
+ end
+ end.
+
+%% -------------------------------------------------------------------
+
+% error(Reason) ->
+% erlang:error(Reason).
+
diff --git a/lib/megaco/src/binary/megaco_binary_name_resolver_prev3b.erl b/lib/megaco/src/binary/megaco_binary_name_resolver_prev3b.erl
new file mode 100644
index 0000000000..12e673ac81
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_binary_name_resolver_prev3b.erl
@@ -0,0 +1,2003 @@
+%%
+%% %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: Handle meta data about packages
+%%----------------------------------------------------------------------
+
+-module(megaco_binary_name_resolver_prev3b).
+
+-include_lib("megaco/src/engine/megaco_message_internal.hrl").
+-include_lib("megaco/src/app/megaco_internal.hrl").
+
+
+-define(LOWER(Char),
+ if
+ Char >= $A, Char =< $Z ->
+ Char - ($A - $a);
+ true ->
+ Char
+ end).
+
+-export([packages/0,
+ capabilities/0,
+ capabilities/1,
+ decode_name/3,
+ encode_name/3
+ ]).
+
+encode_name(Config, term_id, TermId) ->
+ case megaco:encode_binary_term_id(Config, TermId) of
+ {ok, TermId2} ->
+ TermId2;
+ {error, _Reason} ->
+ exit({bad_term_id, TermId})
+ end;
+encode_name(_Config, Scope, Item) ->
+ ?d("encode_name(~p) -> entry with"
+ "~n Item: ~p", [Scope, Item]),
+ encode(Scope, Item).
+
+decode_name(Config, term_id, TermId) ->
+ case megaco:decode_binary_term_id(Config, TermId) of
+ {ok, TermId2} ->
+ TermId2;
+ {error, _Reason} ->
+ exit({bad_term_id, TermId})
+ end;
+decode_name(_Config, Scope, Item) ->
+ ?d("decode_name(~p) -> entry with"
+ "~n Item: ~p", [Scope, Item]),
+ decode(Scope, Item).
+
+
+
+%%----------------------------------------------------------------------
+%% 12.1.1 Package
+%%
+%% Overall description of the package, specifying:
+%%
+%% Package Name: only descriptive
+%%
+%% PackageID: is an identifier
+%%
+%% Description: is a description of the package
+%%
+%% Version:
+%%
+%% A new version of a package can only add additional Properties,
+%% Events, Signals, Statistics and new possible values for an
+%% existing parameter described in the original package. No
+%% deletions or modifications shall be allowed. A version is an
+%% integer in the range from 1 to 99.
+%%
+%% Designed to be extended only (Optional): Yes
+%%
+%% This indicates that the package has been expressly designed to
+%% be extended by others, not to be directly referenced. For
+%% example, the package may not have any function on its own or be
+%% nonsensical on its own. The MG SHOULD NOT publish this PackageID
+%% when reporting packages.
+%%
+%% Extends: existing package Descriptor
+%%
+%% A package may extend an existing package. The version of the
+%% original package must be specified. When a package extends
+%% another package it shall only add additional Properties, Events,
+%% Signals, Statistics and new possible values for an existing
+%% parameter described in the original package. An extended package
+%% shall not redefine or overload an identifier defined in the
+%% original package and packages it may have extended (multiple
+%% levels of extension). Hence, if package B version 1 extends
+%% package A version 1, version 2 of B will not be able to extend
+%% the A version 2 if A version 2 defines a name already in B
+%% version 1. If the package does not extend another package, it
+%% shall specify "none".
+%%
+%%
+%% 12.1.2 Properties
+%%
+%% Properties defined by the package, specifying:
+%%
+%% Property Name: only descriptive
+%%
+%% PropertyID: is an identifier
+%%
+%% Description: is a description of the function of the property
+%%
+%% Type: One of:
+%%
+%% Boolean
+%%
+%% String: UTF-8 string
+%%
+%% Octet String: A number of octets. See Annex A and B.3 for
+%% encoding
+%%
+%% Integer: 4 byte signed integer
+%%
+%% Double: 8 byte signed integer
+%%
+%% Character: unicode UTF-8 encoding of a single letter.
+%% Could be more than one octet.
+%%
+%% Enumeration: one of a list of possible unique values (see 12.3)
+%%
+%% Sub-list: a list of several values from a list.
+%% The type of sub-list SHALL also be specified.
+%% The type shall be chosen from the types specified in
+%% this section (with the exception of sub-list). For
+%% example, Type: sub-list of enumeration. The encoding
+%% of sub-lists is specified in Annexes A and B.3.
+%%
+%% Possible values:
+%%
+%% A package MUST specify either a specific set of values or a
+%% description of how values are determined. A package MUST also
+%% specify a default value or the default behaviour when the value
+%% is omitted from its descriptor. For example, a package may
+%% specify that procedures related to the property are suspended
+%% when its value is omitted.
+%%
+%% Default:
+%%
+%% A default value (but not procedures) may be specified as
+%% provisionable.
+%%
+%% Defined in:
+%%
+%% Which H.248.1 descriptor the property is defined in.
+%% LocalControl is for stream-dependent properties.
+%% TerminationState is for stream-independent properties.
+%% ContextAttribute is for properties that affect the context as
+%% a whole, i.e., mixing properties. These are expected to be the
+%% most common cases, but it is possible for properties to be
+%% defined in other descriptors. Context properties MUST be defined
+%% in the ContextAttribute descriptor.
+%%
+%% Characteristics: Read/Write or both, and (optionally), global:
+%%
+%% Indicates whether a property is read-only, or read-write, and
+%% if it is global. If Global is omitted, the property is not
+%% global. If a property is declared as global, the value of the
+%% property is shared by all Terminations realizing the package.
+%% If a context property is declared as global, the property is
+%% shared by all contexts realizing the package.
+%%
+%%
+%% 12.1.3 Events
+%%
+%% Events defined by the package, specifying:
+%%
+%% Event name: only descriptive
+%%
+%% EventID: is an identifier
+%%
+%% Description: a description of the function of the event
+%%
+%% EventsDescriptor Parameters:
+%%
+%% Parameters used by the MGC to configure the event, and found in
+%% the EventsDescriptor. See 12.2. If there are no parameters for
+%% the Events Descriptor, then "none" shall be specified.
+%%
+%% ObservedEventsDescriptor Parameters:
+%%
+%% Parameters returned to the MGC in Notify requests and in replies
+%% to command requests from the MGC that audit
+%% ObservedEventsDescriptor, and found in the
+%% ObservedEventsDescriptor. See 12.2. If there are no parameters
+%% for the ObservedEvents Descriptor, then �none� shall be specified.
+%%
+%%
+%% 12.1.4 Signals
+%%
+%% Signals defined by the package, specifying:
+%%
+%% Signal Name: only descriptive
+%%
+%% SignalID: is an identifier. SignalID is used in a SignalsDescriptor
+%%
+%% Description: a description of the function of the signal
+%%
+%% SignalType: one of:
+%%
+%% OO (On/Off)
+%%
+%% TO (TimeOut)
+%%
+%% BR (Brief)
+%%
+%% NOTE -�SignalType may be defined such that it is dependent on
+%% the value of one or more parameters. The package MUST specify a
+%% default signal type. If the default type is TO, the package MUST
+%% specify a default duration which may be provisioned. A default
+%% duration is meaningless for BR.
+%%
+%% Duration: in hundredths of seconds
+%%
+%% Additional Parameters: see 12.2
+%%
+%%
+%% 12.1.5 Statistics
+%%
+%% Statistics defined by the package, specifying:
+%%
+%% Statistic name: only descriptive
+%%
+%% StatisticID: is an identifier
+%%
+%% StatisticID is used in a StatisticsDescriptor
+%%
+%% Description: a description of the statistic
+%%
+%% Type: One of:
+%%
+%% Boolean
+%%
+%% String: UTF-8 string
+%%
+%% Octet String: A number of octets.
+%% See Annex A and Annex B.3 for encoding
+%%
+%% Integer: 4 byte signed integer
+%%
+%% Double: 8 byte signed integer
+%%
+%% Character: Unicode UTF-8 encoding of a single letter.
+%% Could be more than one octet.
+%%
+%% Enumeration: One of a list of possible unique values (See 12.3)
+%%
+%% Sub-list: A list of several values from a list.
+%% The type of sub-list SHALL also be specified.
+%% The type shall be chosen from the types specified in
+%% this section (with the exception of sub-list).
+%% For example, Type: sub-list of enumeration.
+%% The encoding of sub-lists is specified in Annexes A
+%% and B.3.
+%%
+%% Possible Values:
+%%
+%% A package must indicate the unit of measure, e.g. milliseconds,
+%% packets, either here or along with the type above, as well as
+%% indicating any restriction on the range.
+%%
+%% Level: Specify if the statistic can be kept at the Termination
+%% level, Stream level or Either.
+%%
+%%
+%% 12.1.6 Error Codes
+%%
+%% If the package does not define any error codes, this section may be omitted.
+%% Otherwise, it describes error codes defined by the package, specifying:
+%%
+%% Error Code #: The error code number.
+%%
+%% Name: Name of the error
+%%
+%% Definition: A description of the error code.
+%%
+%% Error Text in the Error Descriptor:
+%%
+%% A description of what text to return in the Error Descriptor.
+%%
+%% Comment: Any further comments on the use of the error code.
+%%
+%%
+%% 12.1.7 Procedures
+%%
+%% Additional guidance on the use of the package.
+%%
+%%
+%% 12.2 Guidelines to defining parameters to events and signals
+%%
+%% Parameter Name: only descriptive
+%%
+%% ParameterID: is an identifier. The textual ParameterID of
+%% parameters to Events and Signals shall not start with "EPA" and
+%% "SPA", respectively. The textual ParameterID shall also not be
+%% "ST", "Stream", "SY", "SignalType", "DR", "Duration", "NC",
+%% "NotifyCompletion", "KA", "KeepActive", "EB", "Embed", "DM",
+%% "DigitMap", "DI", "Direction", "RQ" or "RequestID".
+%%
+%% Description: a description of the function of the parameter.
+%%
+%% Type: One of:
+%%
+%% Boolean
+%%
+%% String: UTF-8 octet string
+%%
+%% Octet String: A number of octets. See Annex A and B.3 for
+%% encoding
+%%
+%% Integer: 4-octet signed integer
+%%
+%% Double: 8-octet signed integer
+%%
+%% Character: Unicode UTF-8 encoding of a single letter. Could be
+%% more than one octet.
+%%
+%% Enumeration: one of a list of possible unique values (see 12.3)
+%%
+%% Sub-list: a list of several values from a list (not supported
+%% for statistics). The type of sub-list SHALL also be
+%% specified The type shall be chosen from the types
+%% specified in this section (with the exception of
+%% sub-list). For example, Type: sub-list of enumeration.
+%% The encoding of sub-lists is specified in Annex A
+%% and B.3.
+%%
+%% Optional: Yes/No
+%%
+%% Describes if the parameter may be omitted from the signal or
+%% event.
+%%
+%% Possible values:
+%%
+%% A package MUST specify either a specific set of values or a
+%% description of how values are determined. A package MUST
+%% also specify a default value or the default behavior when the
+%% value is omitted from its descriptor. For example, a package
+%% may specify that procedures related to the parameter are
+%% suspended when its value is omitted.
+%%
+%% Default:
+%%
+%% A default value (but not procedures) may be specified as
+%% provisionable.
+%%
+%%
+%% 12.3 Lists
+%%
+%% Possible values for parameters include enumerations. Enumerations may be
+%% defined in a list. It is recommended that the list be IANA registered so
+%% that packages that extend the list can be defined without concern for
+%% conflicting names.
+%%
+%%
+%% 12.4 Identifiers
+%%
+%% Identifiers in text encoding shall be strings of up to 64 characters,
+%% containing no spaces, starting with an alphabetic character and consisting
+%% of alphanumeric characters and/or digits, and possibly including the
+%% special character underscore ("_").
+%%
+%% Identifiers in binary encoding are 2 octets long.
+%%
+%% Both text and binary values shall be specified for each identifier,
+%% including identifiers used as values in enumerated types.
+%%
+%%
+%% 12.5 Package registration
+%%
+%% A package can be registered with IANA for interoperability reasons. See
+%% clause 14 for IANA considerations.
+%%
+%%----------------------------------------------------------------------
+
+capabilities() ->
+ [{P, capabilities(P)} || P <- packages()].
+
+%% -record(property, {name, type, values, defined_in, characteristics}).
+
+%%----------------------------------------------------------------------
+%% List all known packages
+%% 'native' and 'all' are not real packages
+%%----------------------------------------------------------------------
+
+packages() ->
+ [
+ "g", % Generic
+ "root", % Base Root Package
+ "tonegen", % Tone Generator Package
+ "tonedet", % Tone Detection Package
+ "dg", % Basic DTMF Generator Package
+ "dd", % DTMF detection Package
+ "cg", % Call Progress Tones Generator Package
+ "cd", % Call Progress Tones Detection Package
+ "al", % Analog Line Supervision Package
+ "ct", % Basic Continuity Package
+ "nt", % Network Package
+ "rtp", % RTP Package
+ "swb", % SwitchBoard Package
+ "tdmc", % TDM Circuit Package
+ "" % Native pseudo package
+ ].
+
+%%----------------------------------------------------------------------
+%% List all matching capabilities
+%%----------------------------------------------------------------------
+
+capabilities(Package) ->
+ case Package of
+ "g" -> capabilities_g();
+ "root" -> capabilities_root();
+ "tonegen" -> capabilities_tonegen();
+ "tonedet" -> capabilities_tonedet();
+ "dg" -> capabilities_dg();
+ "dd" -> capabilities_dd();
+ "cg" -> capabilities_cg();
+ "cd" -> capabilities_cd();
+ "al" -> capabilities_al();
+ "ct" -> capabilities_ct();
+ "nt" -> capabilities_nt();
+ "rtp" -> capabilities_rtp();
+ "swb" -> capabilities_swb();
+ "tdmc" -> capabilities_tdmc();
+ "" -> capabilities_native()
+ end.
+
+%%----------------------------------------------------------------------
+%% Decode package name to internal form
+%% Scope ::= property | event | signal | statistics
+%%----------------------------------------------------------------------
+
+decode(mid, Package) ->
+ decode_mid(Package);
+decode(package, Package) ->
+ decode_package(Package);
+decode(profile, Package) ->
+ decode_profile(Package);
+decode(dialplan, Dialplan) ->
+ decode_dialplan(Dialplan);
+decode(Scope, [A, B | Item]) when is_atom(Scope) ->
+ ?d("decode(~p) -> entry with"
+ "~n A: ~p"
+ "~n B: ~p"
+ "~n Item: ~p", [Scope, A, B, Item]),
+ case decode_package([A, B]) of
+ "" ->
+ ?d("decode -> \"no\" package",[]),
+ decode_item(Scope, [A, B], Item);
+ Package ->
+ ?d("decode -> Package: ~p", [Package]),
+ Package ++ "/" ++ decode_item(Scope, [A, B], Item)
+ end;
+decode({Scope, [A, B | Item]}, SubItem) when is_atom(Scope) ->
+ ?d("decode(~p) -> entry with"
+ "~n A: ~p"
+ "~n B: ~p"
+ "~n Item: ~p"
+ "~n SubItem: ~p", [Scope, A, B, Item, SubItem]),
+ decode_item({Scope, Item}, [A, B], SubItem).
+
+decode_item(Scope, [A, B], Item) ->
+ ?d("decode_item -> entry",[]),
+ case A of
+ 16#00 ->
+ case B of
+ 16#01 -> decode_g(Scope, Item);
+ 16#02 -> decode_root(Scope, Item);
+ 16#03 -> decode_tonegen(Scope, Item);
+ 16#04 -> decode_tonedet(Scope, Item);
+ 16#05 -> decode_dg(Scope, Item);
+ 16#06 -> decode_dd(Scope, Item);
+ 16#07 -> decode_cg(Scope, Item);
+ 16#08 -> decode_cd(Scope, Item);
+ 16#09 -> decode_al(Scope, Item);
+ 16#0a -> decode_ct(Scope, Item);
+ 16#0b -> decode_nt(Scope, Item);
+ 16#0c -> decode_rtp(Scope, Item);
+ 16#0d -> decode_tdmc(Scope, Item);
+ 16#00 -> decode_native(Scope, Item)
+ end;
+ 16#fe ->
+ case B of
+ %% Proprietary extension
+ 16#fe -> decode_swb(Scope, Item)
+ end;
+ 16#ff ->
+ case B of
+ 16#ff when Item =:= [16#ff, 16#ff] -> "*"
+ end
+ end.
+
+decode_package(Package) ->
+ ?d("decode_package -> entry with"
+ "~n Package: ~p", [Package]),
+ [A, B] = Package,
+ case A of
+ 16#00 ->
+ case B of
+ 16#01 -> "g";
+ 16#02 -> "root";
+ 16#03 -> "tonegen";
+ 16#04 -> "tonedet";
+ 16#05 -> "dg";
+ 16#06 -> "dd";
+ 16#07 -> "cg";
+ 16#08 -> "cd";
+ 16#09 -> "al";
+ 16#0a -> "ct";
+ 16#0b -> "nt";
+ 16#0c -> "rtp";
+ 16#0d -> "tdmc";
+ 16#00 -> ""
+ end;
+ 16#fe ->
+ case B of
+ 16#fe -> "swb"
+ end;
+ 16#ff ->
+ case B of
+ 16#ff -> "*"
+ end
+ end.
+
+decode_profile([A, B]) ->
+ case A of
+ 16#00 ->
+ case B of
+ 16#fe -> "resgw";
+ _ -> "profile" ++ [A + $0, B + $0]
+ end;
+ _ ->
+ "profile" ++ [A + $0, B + $0]
+ end.
+
+decode_dialplan([A, B]) ->
+ "dialplan" ++ [A + $0, B + $0].
+
+decode_mid(Mid) ->
+ case Mid of
+ {domainName, DN} ->
+ Lower = to_lower(DN#'DomainName'.name),
+ {domainName, DN#'DomainName'{name = Lower}};
+ {deviceName, PathName} ->
+ Lower = to_lower(PathName),
+ {deviceName, Lower};
+ Other ->
+ Other
+ end.
+
+to_lower(Chars) ->
+ [?LOWER(Char) || Char <- Chars].
+
+%%----------------------------------------------------------------------
+%% Encode package name from internal form
+%% Scope ::= property | event | signal | statistics
+%%----------------------------------------------------------------------
+
+encode(mid, Package) ->
+ encode_mid(Package);
+encode(package, Package) ->
+ encode_package(Package);
+encode(profile, Profile) ->
+ encode_profile(Profile);
+encode(dialplan, Dialplan) ->
+ encode_dialplan(Dialplan);
+encode(Scope, PackageItem) when is_atom(Scope) ->
+ ?d("encode(~p) -> entry with"
+ "~n PackageItem: ~p", [Scope, PackageItem]),
+ case string:tokens(PackageItem, [$/]) of
+ [Package, Item] ->
+ ?d("encode -> "
+ "~n Package: ~p"
+ "~n Item: ~p", [Package, Item]),
+ encode_package(Package) ++ encode_item(Scope, Package, Item);
+ [Item] ->
+ ?d("encode -> Item: ~p", [Item]),
+ [16#00, 16#00 | encode_native(Scope, Item)]
+ end;
+encode({Scope, PackageItem}, SubItem) when is_atom(Scope) ->
+ ?d("encode(~p) -> entry with"
+ "~n PackageItem: ~p"
+ "~n SubItem: ~p", [Scope, PackageItem, SubItem]),
+ case string:tokens(PackageItem, [$/]) of
+ [Package, Item] ->
+ ?d("encode -> "
+ "~n Package: ~p"
+ "~n Item: ~p", [Package, Item]),
+ encode_item({Scope, Item}, Package, SubItem);
+ [_Item] ->
+ ?d("encode -> _Item: ~p", [_Item]),
+ encode_native(Scope, SubItem)
+ end.
+
+encode_item(_Scope, _Package, "*") ->
+ [16#ff, 16#ff];
+encode_item(Scope, Package, Item) ->
+ ?d("encode_item(~s) -> entry", [Package]),
+ case Package of
+ "g" -> encode_g(Scope, Item);
+ "root" -> encode_root(Scope, Item);
+ "tonegen" -> encode_tonegen(Scope, Item);
+ "tonedet" -> encode_tonedet(Scope, Item);
+ "dg" -> encode_dg(Scope, Item);
+ "dd" -> encode_dd(Scope, Item);
+ "cg" -> encode_cg(Scope, Item);
+ "cd" -> encode_cd(Scope, Item);
+ "al" -> encode_al(Scope, Item);
+ "ct" -> encode_ct(Scope, Item);
+ "nt" -> encode_nt(Scope, Item);
+ "rtp" -> encode_rtp(Scope, Item);
+ "tdmc" -> encode_tdmc(Scope, Item);
+ "swb" -> encode_swb(Scope, Item)
+ end.
+
+encode_package(Package) ->
+ case Package of
+ "g" -> [16#00, 16#01];
+ "root" -> [16#00, 16#02];
+ "tonegen" -> [16#00, 16#03];
+ "tonedet" -> [16#00, 16#04];
+ "dg" -> [16#00, 16#05];
+ "dd" -> [16#00, 16#06];
+ "cg" -> [16#00, 16#07];
+ "cd" -> [16#00, 16#08];
+ "al" -> [16#00, 16#09];
+ "ct" -> [16#00, 16#0a];
+ "nt" -> [16#00, 16#0b];
+ "rtp" -> [16#00, 16#0c];
+ "tdmc" -> [16#00, 16#0d];
+ "" -> [16#00, 16#00];
+ "*" -> [16#ff, 16#ff];
+ "swb" -> [16#fe, 16#fe]
+ end.
+
+encode_profile(Profile) ->
+ case Profile of
+ "resgw" ->
+ [16#00, 16#fe];
+ [$p, $r, $o, $f, $i, $l, $e | Name] ->
+ case Name of
+ [A, B] -> [A - $0, B - $0];
+ [B] -> [0, B - $0];
+ [] -> [0, 0]
+ end
+ end.
+
+encode_dialplan(Dialplan) ->
+ case Dialplan of
+ [$d, $i, $a, $l, $p, $l, $a, $n | Name] ->
+ case Name of
+ [A, B] -> [A - $0, B - $0];
+ [B] -> [0, B - $0];
+ [] -> [0, 0]
+ end
+ end.
+
+encode_mid(Mid) ->
+ Mid.
+
+
+%%----------------------------------------------------------------------
+%% Name: g - Generic
+%% Version: 1
+%% Extends: None
+%% Purpose: Generic package for commonly encountered items
+%%----------------------------------------------------------------------
+
+capabilities_g() ->
+ [
+ {event, "cause"},
+ {event, "sc"}
+ ].
+
+encode_g(event, Item) ->
+ case Item of
+ "cause" -> [16#00, 16#01];
+ "sc" -> [16#00, 16#02]
+ end;
+
+encode_g({event_parameter, Item}, SubItem) ->
+ case Item of
+ "cause" ->
+ case SubItem of
+ "Generalcause" -> [16#00, 16#01];
+ "Failurecause" -> [16#00, 16#02]
+ end;
+ "sc" ->
+ case SubItem of
+ "SigID" -> [16#00, 16#01];
+ "Meth" -> [16#00, 16#02];
+ "SLID" -> [16#00, 16#03];
+ "RID" -> [16#00, 16#04]
+ end
+ end.
+
+decode_g(event, Item) ->
+ case Item of
+ [16#00, 16#01] -> "cause";
+ [16#00, 16#02] -> "sc"
+ end;
+
+decode_g({event_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#01] -> % Event: cause
+ case SubItem of
+ [16#00, 16#01] -> "Generalcause";
+ [16#00, 16#02] -> "Failurecause"
+ end;
+
+ [16#00, 16#02] -> % Event: sc
+ case SubItem of
+ [16#00, 16#01] -> "SigID";
+ [16#00, 16#02] -> "Meth";
+ [16#00, 16#03] -> "SLID";
+ [16#00, 16#04] -> "RID"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: root - Base Root Package
+%% Version: 2
+%% Extends: None
+%% Purpose: This package defines Gateway wide properties.
+%%----------------------------------------------------------------------
+
+capabilities_root() ->
+ [
+ {property, "maxNumberOfContexts"},
+ {property, "maxTerminationsPerContext"},
+ {property, "normalMGExecutionTime"},
+ {property, "normalMGCExecutionTime"},
+ {property, "MGProvisionalResponseTimerValue"},
+ {property, "MGCProvisionalResponseTimerValue"},
+ {property, "MGCOriginatedPendingLimit"},
+ {property, "MGOriginatedPendingLimit"}
+ ].
+
+encode_root(Scope, Item) ->
+ case Scope of
+ property ->
+ case Item of
+ "maxNumberOfContexts" -> [16#00, 16#01];
+ "maxTerminationsPerContext" -> [16#00, 16#02];
+ "normalMGExecutionTime" -> [16#00, 16#03];
+ "normalMGCExecutionTime" -> [16#00, 16#04];
+ "MGProvisionalResponseTimerValue" -> [16#00, 16#05];
+ "MGCProvisionalResponseTimerValue" -> [16#00, 16#06];
+ "MGCOriginatedPendingLimit" -> [16#00, 16#07];
+ "MGOriginatedPendingLimit" -> [16#00, 16#08]
+ end
+ end.
+
+decode_root(Scope, Item) ->
+ case Scope of
+ property ->
+ case Item of
+ [16#00, 16#01] -> "maxNumberOfContexts";
+ [16#00, 16#02] -> "maxTerminationsPerContext";
+ [16#00, 16#03] -> "normalMGExecutionTime";
+ [16#00, 16#04] -> "normalMGCExecutionTime";
+ [16#00, 16#05] -> "MGProvisionalResponseTimerValue";
+ [16#00, 16#06] -> "MGCProvisionalResponseTimerValue";
+ [16#00, 16#07] -> "MGCOriginatedPendingLimit";
+ [16#00, 16#08] -> "MGOriginatedPendingLimit"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: tonegen - Tone Generator Package
+%% Version: 2
+%% Extends: None
+%% Purpose: This package defines signals to generate audio tones.
+%% This package does not specify parameter values. It is
+%% intended to be extendable. Generally, tones are defined
+%% as an individual signal with a parameter, ind,
+%% representing "interdigit" time delay, and a tone id to
+%% be used with playtones. A tone id should be kept
+%% consistent with any tone generation for the same tone.
+%% MGs are expected to be provisioned with the characteristics
+%% of appropriate tones for the country in which the MG is located.
+%%----------------------------------------------------------------------
+
+capabilities_tonegen() ->
+ [
+ {signal, "pt"}
+ ].
+
+encode_tonegen(signal, Item) ->
+ case Item of
+ "pt" -> [16#00, 16#01]
+ end;
+
+encode_tonegen({signal_parameter, Item}, SubItem) ->
+ case Item of
+ "pt" ->
+ case SubItem of
+ "tl" -> [16#00, 16#01];
+ "ind" -> [16#00, 16#02];
+ "btd" -> [16#00, 16#03]
+ end
+ end.
+
+decode_tonegen(signal, Item) ->
+ case Item of
+ [16#00, 16#01] -> "pt"
+ end;
+
+decode_tonegen({signal_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#01] -> % Event: pt
+ case SubItem of
+ [16#00, 16#01] -> "tl";
+ [16#00, 16#02] -> "ind";
+ [16#00, 16#03] -> "btd"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: tonedet - Tone Detection Package
+%% Version: 1
+%% Extends: None
+%% Purpose: This Package defines events for audio tone detection.
+%% Tones are selected by name (tone id). MGs are expected
+%% to be provisioned with the characteristics of appropriate
+%% tones for the country in which the MG is located.
+%%
+%% This package does not specify parameter values.
+%% It is intended to be extendable.
+%%----------------------------------------------------------------------
+
+capabilities_tonedet() ->
+ [
+ {event, "std"},
+ {event, "etd"},
+ {event, "ltd"}
+ ].
+
+encode_tonedet(event, Item) ->
+ case Item of
+ "std" -> [16#00, 16#01];
+ "etd" -> [16#00, 16#02];
+ "ltd" -> [16#00, 16#03]
+ end;
+
+encode_tonedet({event_parameter, Item}, SubItem) ->
+ case Item of
+ "std" ->
+ case SubItem of
+ "tl" -> [16#00, 16#01];
+ "tid" -> [16#00, 16#03]
+ end;
+ "etd" ->
+ case SubItem of
+ "tl" -> [16#00, 16#01];
+ "tid" -> [16#00, 16#03];
+ "dur" -> [16#00, 16#02]
+ end;
+ "ltd" ->
+ case SubItem of
+ "tl" -> [16#00, 16#01];
+ "dur" -> [16#00, 16#02];
+ "tid" -> [16#00, 16#03]
+ end
+ end.
+
+decode_tonedet(event, Item) ->
+ case Item of
+ [16#00, 16#01] -> "std";
+ [16#00, 16#02] -> "etd";
+ [16#00, 16#03] -> "ltd"
+ end;
+
+decode_tonedet({event_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#01] -> % Event std
+ case SubItem of
+ [16#00, 16#01] -> "tl";
+ [16#00, 16#03] -> "tid"
+ end;
+ [16#00, 16#02] -> % Event etd
+ case SubItem of
+ [16#00, 16#01] -> "tl";
+ [16#00, 16#03] -> "tid";
+ [16#00, 16#02] -> "dur"
+ end;
+ [16#00, 16#03] -> % Event ltd
+ case SubItem of
+ [16#00, 16#01] -> "tl";
+ [16#00, 16#02] -> "dur";
+ [16#00, 16#03] -> "tid"
+ end
+ end.
+
+%%----------------------------------------------------------------------
+%% Name: dg - Basic DTMF Generator Package
+%% Version: 1
+%% Extends: tonegen version 1
+%% Purpose: This package defines the basic DTMF tones as signals and
+%% extends the allowed values of parameter tl of playtone
+%% in tonegen.
+%%----------------------------------------------------------------------
+
+capabilities_dg() ->
+ [
+ {signal, "d0"},
+ {signal, "d1"},
+ {signal, "d2"},
+ {signal, "d3"},
+ {signal, "d4"},
+ {signal, "d5"},
+ {signal, "d6"},
+ {signal, "d7"},
+ {signal, "d8"},
+ {signal, "d9"},
+ {signal, "ds"},
+ {signal, "do"},
+ {signal, "da"},
+ {signal, "db"},
+ {signal, "dc"},
+ {signal, "dd"}
+ ].
+
+encode_dg(signal, Item) ->
+ case Item of
+ "d0" -> [16#00, 16#10];
+ "d1" -> [16#00, 16#11];
+ "d2" -> [16#00, 16#12];
+ "d3" -> [16#00, 16#13];
+ "d4" -> [16#00, 16#14];
+ "d5" -> [16#00, 16#15];
+ "d6" -> [16#00, 16#16];
+ "d7" -> [16#00, 16#17];
+ "d8" -> [16#00, 16#18];
+ "d9" -> [16#00, 16#19];
+ "ds" -> [16#00, 16#20];
+ "do" -> [16#00, 16#21];
+ "da" -> [16#00, 16#1a];
+ "db" -> [16#00, 16#1b];
+ "dc" -> [16#00, 16#1c];
+ "dd" -> [16#00, 16#1d]
+ end;
+
+encode_dg({signal_parameter, Item}, SubItem) ->
+ case Item of
+ "d0" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d1" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d2" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d3" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d4" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d5" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d6" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d7" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d8" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d9" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "ds" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "do" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "da" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "db" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "dc" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "dd" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end
+ end.
+
+decode_dg(signal, Item) ->
+ case Item of
+ [16#00, 16#10] -> "d0";
+ [16#00, 16#11] -> "d1";
+ [16#00, 16#12] -> "d2";
+ [16#00, 16#13] -> "d3";
+ [16#00, 16#14] -> "d4";
+ [16#00, 16#15] -> "d5";
+ [16#00, 16#16] -> "d6";
+ [16#00, 16#17] -> "d7";
+ [16#00, 16#18] -> "d8";
+ [16#00, 16#19] -> "d9";
+ [16#00, 16#20] -> "ds";
+ [16#00, 16#21] -> "do";
+ [16#00, 16#1a] -> "da";
+ [16#00, 16#1b] -> "db";
+ [16#00, 16#1c] -> "dc";
+ [16#00, 16#1d] -> "dd"
+ end;
+
+decode_dg({signal_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#10] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#11] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#12] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#13] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#14] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#15] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#16] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#17] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#18] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#19] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#20] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#21] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#1a] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#1b] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#1c] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#1d] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: dd - DTMF detection Package
+%% Version: 1
+%% Extends: tonedet version 1
+%% Purpose: This package defines the basic DTMF tones detection.
+%% Tones are selected by name (tone id). MGs are expected
+%% to be provisioned with the characteristics of appropriate
+%% tones for the country in which the MG is located.
+%%
+%% This package does not specify parameter values.
+%% It is intended to be extendable.
+%%
+%% Additional tone id values are all tone ids described in package dg
+%% (basic DTMF generator package).
+%%
+%% The following table maps DTMF events to digit map symbols as described
+%% in section 7.1.14.
+%%
+%% _________________________________
+%% | DTMF Event | Symbol |
+%% | d0 | "0" |
+%% | d1 | "1" |
+%% | d2 | "2" |
+%% | d3 | "3" |
+%% | d4 | "4" |
+%% | d5 | "5" |
+%% | d6 | "6" |
+%% | d7 | "7" |
+%% | d8 | "8" |
+%% | d9 | "9" |
+%% | da | "A" or "a"|
+%% | db | "B" or "b"|
+%% | dc | "C" or "c"|
+%% | dd | "D" or "d"|
+%% | ds | "E" or "e"|
+%% | do | "F" or "f"|
+%% |___________________|____________|
+%%
+%%----------------------------------------------------------------------
+
+capabilities_dd() ->
+ [
+ {event, "ce"},
+ {event, "d0"},
+ {event, "d1"},
+ {event, "d2"},
+ {event, "d3"},
+ {event, "d4"},
+ {event, "d5"},
+ {event, "d6"},
+ {event, "d7"},
+ {event, "d8"},
+ {event, "d9"},
+ {event, "ds"},
+ {event, "do"},
+ {event, "da"},
+ {event, "db"},
+ {event, "dc"},
+ {event, "dd"}
+ ].
+
+encode_dd(event, Item) ->
+ case Item of
+ "ce" -> [16#00, 16#04];
+ "d0" -> [16#00, 16#10];
+ "d1" -> [16#00, 16#11];
+ "d2" -> [16#00, 16#12];
+ "d3" -> [16#00, 16#13];
+ "d4" -> [16#00, 16#14];
+ "d5" -> [16#00, 16#15];
+ "d6" -> [16#00, 16#16];
+ "d7" -> [16#00, 16#17];
+ "d8" -> [16#00, 16#18];
+ "d9" -> [16#00, 16#19];
+ "ds" -> [16#00, 16#20];
+ "do" -> [16#00, 16#21];
+ "da" -> [16#00, 16#1a];
+ "db" -> [16#00, 16#1b];
+ "dc" -> [16#00, 16#1c];
+ "dd" -> [16#00, 16#1d]
+ end;
+
+encode_dd({event_parameter, Item}, SubItem) ->
+ case Item of
+ "ce" ->
+ case SubItem of
+ "ds" -> [16#00, 16#01];
+ "Meth" -> [16#00, 16#03]
+ end;
+ "d0" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d1" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d2" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d3" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d4" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d5" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d6" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d7" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d8" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d9" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "ds" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "do" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "da" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "db" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "dc" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "dd" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end
+ end.
+
+decode_dd(event, Item) ->
+ case Item of
+ [16#00, 16#04] -> "ce";
+ [16#00, 16#10] -> "d0";
+ [16#00, 16#11] -> "d1";
+ [16#00, 16#12] -> "d2";
+ [16#00, 16#13] -> "d3";
+ [16#00, 16#14] -> "d4";
+ [16#00, 16#15] -> "d5";
+ [16#00, 16#16] -> "d6";
+ [16#00, 16#17] -> "d7";
+ [16#00, 16#18] -> "d8";
+ [16#00, 16#19] -> "d9";
+ [16#00, 16#20] -> "ds";
+ [16#00, 16#21] -> "do";
+ [16#00, 16#1a] -> "da";
+ [16#00, 16#1b] -> "db";
+ [16#00, 16#1c] -> "dc";
+ [16#00, 16#1d] -> "dd"
+ end;
+
+decode_dd({event_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#04] -> % Event ce
+ case SubItem of
+ [16#00, 16#01] -> "ds";
+ [16#00, 16#03] -> "Meth"
+ end;
+ [16#00, 16#10] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#11] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#12] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#13] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#14] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#15] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#16] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#17] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#18] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#19] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#20] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#21] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#1a] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#1b] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#1c] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#1d] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end
+ end.
+
+%%----------------------------------------------------------------------
+%% Name: cg - Call Progress Tones Generator Package
+%% Version: 1
+%% Extends: tonegen version 1
+%% Purpose: This package defines the basic call progress tones as signals
+%% and extends the allowed values of the tl parameter of
+%% playtone in tonegen.
+%%----------------------------------------------------------------------
+
+capabilities_cg() ->
+ [
+ {signal, "dt"},
+ {signal, "rt"},
+ {signal, "bt"},
+ {signal, "ct"},
+ {signal, "sit"},
+ {signal, "wt"},
+ {signal, "prt"},
+ {signal, "cw"},
+ {signal, "cr"}
+ ].
+
+
+encode_cg(Scope, Item) ->
+ case Scope of
+ signal ->
+ case Item of
+ "dt" -> [16#00, 16#30];
+ "rt" -> [16#00, 16#31];
+ "bt" -> [16#00, 16#32];
+ "ct" -> [16#00, 16#33];
+ "sit" -> [16#00, 16#34];
+ "wt" -> [16#00, 16#35];
+ "prt" -> [16#00, 16#36];
+ "cw" -> [16#00, 16#37];
+ "cr" -> [16#00, 16#38]
+ end
+ end.
+
+decode_cg(Scope, Item) ->
+ case Scope of
+ signal ->
+ case Item of
+ [16#00, 16#30] -> "dt";
+ [16#00, 16#31] -> "rt";
+ [16#00, 16#32] -> "bt";
+ [16#00, 16#33] -> "ct";
+ [16#00, 16#34] -> "sit";
+ [16#00, 16#35] -> "wt";
+ [16#00, 16#36] -> "prt";
+ [16#00, 16#37] -> "cw";
+ [16#00, 16#38] -> "cr"
+ end
+ end.
+
+%%----------------------------------------------------------------------
+%% Name: cd - Call Progress Tones Detection Package
+%% Version: 1
+%% Extends: tonedet version 1
+%% Purpose: This package defines the basic call progress detection tones.
+%% This Package extends the possible values of tone id
+%% in the "start tone detected", "end tone detected" and
+%% "long tone detected" events.
+%% Additional values
+%% tone id values are defined for start tone detected,
+%% end tone detected and long tone detected with
+%% the same values as those in package cg (call
+%% progress tones generation package).
+%%
+%% The required set of tone ids corresponds to Recommendation E.180/Q.35
+%% [ITU-T Recommendation E.180/Q.35 (1998)]. See Recommendation E.180/Q.35
+%% for definition of the meanings of these tones.
+%%----------------------------------------------------------------------
+
+capabilities_cd() ->
+ [
+ {event, "dt"},
+ {event, "rt"},
+ {event, "bt"},
+ {event, "ct"},
+ {event, "sit"},
+ {event, "wt"},
+ {event, "prt"},
+ {event, "cw"},
+ {event, "cr"}
+ ].
+
+
+encode_cd(Scope, Item) ->
+ case Scope of
+ event ->
+ case Item of
+ "dt" -> [16#00, 16#30];
+ "rt" -> [16#00, 16#31];
+ "bt" -> [16#00, 16#32];
+ "ct" -> [16#00, 16#33];
+ "sit"-> [16#00, 16#34];
+ "wt" -> [16#00, 16#35];
+ "prt"-> [16#00, 16#36];
+ "cw" -> [16#00, 16#37];
+ "cr" -> [16#00, 16#38]
+ end
+ end.
+
+decode_cd(Scope, Item) ->
+ case Scope of
+ event ->
+ case Item of
+ [16#00, 16#30] -> "dt";
+ [16#00, 16#31] -> "rt";
+ [16#00, 16#32] -> "bt";
+ [16#00, 16#33] -> "ct";
+ [16#00, 16#34] -> "sit";
+ [16#00, 16#35] -> "wt";
+ [16#00, 16#36] -> "prt";
+ [16#00, 16#37] -> "cw";
+ [16#00, 16#38] -> "cr"
+ end
+ end.
+
+%%----------------------------------------------------------------------
+%% Name: al - Analog Line Supervision Package
+%% Version: 1
+%% Extends: None
+%% Purpose: This package defines events and signals for an analog line.
+%%----------------------------------------------------------------------
+
+capabilities_al() ->
+ [
+ {event, "on"},
+ {event, "of"},
+ {event, "fl"},
+ {signal, "ri"}
+ ].
+
+encode_al(event, Item) ->
+ ?d("encode_al(event) -> entry with"
+ "~n Item: ~p", [Item]),
+ case Item of
+ "on" -> [16#00, 16#04];
+ "of" -> [16#00, 16#05];
+ "fl" -> [16#00, 16#06]
+ end;
+
+encode_al({event_parameter, Item}, SubItem) ->
+ ?d("encode_al({event_parameter,~p}) -> entry with"
+ "~n SubItem: ~p", [Item, SubItem]),
+ case Item of
+ "on" ->
+ case SubItem of
+ "strict" -> [16#00, 16#01];
+ "init" -> [16#00, 16#02]
+ end;
+ "of" ->
+ case SubItem of
+ "strict" -> [16#00, 16#01];
+ "init" -> [16#00, 16#02]
+ end;
+ "fl" ->
+ case SubItem of
+ "mindur" -> [16#00, 16#04];
+ "maxdur" -> [16#00, 16#05]
+ end
+ end;
+
+encode_al(signal, Item) ->
+ ?d("encode_al(signal) -> entry with"
+ "~n Item: ~p", [Item]),
+ case Item of
+ "ri" -> [16#00, 16#02]
+ end;
+
+encode_al({signal_parameter, Item}, SubItem) ->
+ ?d("encode_al({signal_parameter,~p}) -> entry with"
+ "~n SubItem: ~p", [Item, SubItem]),
+ case Item of
+ "ri" ->
+ case SubItem of
+ "cad" -> [16#00, 16#06];
+ "freq" -> [16#00, 16#07]
+ end
+ end.
+
+decode_al(event, SubItem) ->
+ ?d("decode_al(event) -> entry with"
+ "~n SubItem: ~p", [SubItem]),
+ case SubItem of
+ [16#00, 16#04] -> "on";
+ [16#00, 16#05] -> "of";
+ [16#00, 16#06] -> "fl"
+ end;
+
+decode_al({event_parameter, Item}, SubItem) ->
+ ?d("decode_al({event_parameter,~p}) -> entry with"
+ "~n SubItem: ~p", [Item, SubItem]),
+ case Item of
+ [16#00,16#04] -> %% Event: on
+ case SubItem of
+ [16#00, 16#01] -> "strict";
+ [16#00, 16#02] -> "init"
+ end;
+ [16#00,16#05] -> %% Event: of
+ case SubItem of
+ [16#00, 16#01] -> "strict";
+ [16#00, 16#02] -> "init"
+ end;
+ [16#00,16#06] -> %% Event: fl
+ case SubItem of
+ [16#00, 16#04] -> "mindur";
+ [16#00, 16#05] -> "maxdur"
+ end
+ end;
+
+decode_al(signal, SubItem) ->
+ ?d("decode_al(signal) -> entry with"
+ "~n SubItem: ~p", [SubItem]),
+ case SubItem of
+ [16#00, 16#02] -> "ri"
+ end;
+
+decode_al({signal_parameter, Item}, SubItem) ->
+ ?d("decode_al({signal_parameter,~p}) -> entry with"
+ "~n SubItem: ~p", [Item, SubItem]),
+ case Item of
+ [16#00,16#02] -> %% Event: ri
+ case SubItem of
+ [16#00, 16#06] -> "cad";
+ [16#00, 16#07] -> "freq"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: ct - Basic Continuity Package
+%% Version: 1
+%% Extends: None
+%% Purpose: This package defines events and signals for continuity test.
+%% The continuity test includes provision of either a loopback
+%% or transceiver functionality.
+%%----------------------------------------------------------------------
+
+capabilities_ct() ->
+ [
+ {event, "cmp"},
+ {signal, "ct"},
+ {signal, "rsp"}
+ ].
+
+encode_ct(event, Item) ->
+ case Item of
+ "cmp" -> [16#00, 16#05]
+ end;
+encode_ct({event_parameter, Item}, SubItem) ->
+ case Item of
+ "cmp" ->
+ case SubItem of
+ "res" -> [16#00, 16#08]
+ end
+ end;
+encode_ct(signal, Item) ->
+ case Item of
+ "ct" -> [16#00, 16#03];
+ "rsp" -> [16#00, 16#04]
+ end.
+
+decode_ct(event, Item) ->
+ case Item of
+ [16#00, 16#05] -> "cmp"
+ end;
+decode_ct({event_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#05] -> % Event cmp
+ case SubItem of
+ [16#00, 16#08] -> "res"
+ end
+ end;
+decode_ct(signal, Item) ->
+ case Item of
+ [16#00, 16#03] -> "ct";
+ [16#00, 16#04] -> "rsp"
+ end.
+
+%%----------------------------------------------------------------------
+%% Name: nt - Network Package
+%% Version: 1
+%% Extends: None
+%% Purpose: This package defines properties of network terminations
+%% independent of network type.
+%%----------------------------------------------------------------------
+
+capabilities_nt() ->
+ [
+ {property, "jit"},
+ {event, "netfail"},
+ {event, "qualert"},
+ {statistics, "dur"},
+ {statistics, "os"},
+ {statistics, "or"}
+ ].
+
+encode_nt(property, Item) ->
+ case Item of
+ "jit" -> [16#00, 16#07]
+ end;
+encode_nt(event, Item) ->
+ case Item of
+ "netfail" -> [16#00, 16#05];
+ "qualert" -> [16#00, 16#06]
+ end;
+encode_nt({event_parameter, Item}, SubItem) ->
+ case Item of
+ "netfail" ->
+ case SubItem of
+ "cs" -> [16#00, 16#01]
+ end;
+ "qualert" ->
+ case SubItem of
+ "th" -> [16#00, 16#01]
+ end
+ end;
+encode_nt(statistics, Item) ->
+ case Item of
+ "dur" -> [16#00, 16#01];
+ "os" -> [16#00, 16#02];
+ "or" -> [16#00, 16#03]
+ end.
+
+decode_nt(property, Item) ->
+ case Item of
+ [16#00, 16#07] -> "jit"
+ end;
+decode_nt(event, Item) ->
+ case Item of
+ [16#00, 16#05] -> "netfail";
+ [16#00, 16#06] -> "qualert"
+ end;
+decode_nt({event_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#05] -> % Event netfail
+ case SubItem of
+ [16#00, 16#01] -> "cs"
+ end;
+ [16#00, 16#06] -> % Event qualert
+ case Item of
+ [16#00, 16#01] -> "th"
+ end
+ end;
+decode_nt(statistics, Item) ->
+ case Item of
+ [16#00, 16#01] -> "dur";
+ [16#00, 16#02] -> "os";
+ [16#00, 16#03] -> "or"
+ end.
+
+%%----------------------------------------------------------------------
+%% Name: rtp - RTP Package
+%% Version: 1
+%% Extends: nt version 1
+%% Purpose: This package is used to support packet based multimedia
+%% data transfer by means of the Real-time Transport Protocol
+%% (RTP) [RFC 1889].
+%%----------------------------------------------------------------------
+
+capabilities_rtp() ->
+ [
+ {event, "pltrans"},
+ {statistics, "ps"},
+ {statistics, "pr"},
+ {statistics, "pl"},
+ {statistics, "jit"},
+ {statistics, "delay"}
+ ].
+
+encode_rtp(event, Item) ->
+ case Item of
+ "pltrans" -> [16#00, 16#01]
+ end;
+encode_rtp({event_parameter, Item}, SubItem) ->
+ case Item of
+ "pltrans" ->
+ case SubItem of
+ "rtppltype" -> [16#00, 16#01]
+ end
+ end;
+encode_rtp(statistics, Item) ->
+ case Item of
+ "ps" -> [16#00, 16#04];
+ "pr" -> [16#00, 16#05];
+ "pl" -> [16#00, 16#06];
+ "jit" -> [16#00, 16#07];
+ "delay" -> [16#00, 16#08]
+ end.
+
+decode_rtp(event, Item) ->
+ case Item of
+ [16#00, 16#01] -> "pltrans"
+ end;
+decode_rtp({event_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#01] -> % Event pltrans
+ case SubItem of
+ [16#00, 16#01] -> "rtppltype"
+ end
+ end;
+decode_rtp(statistics, Item) ->
+ case Item of
+ [16#00, 16#04] -> "ps";
+ [16#00, 16#05] -> "pr";
+ [16#00, 16#06] -> "pl";
+ [16#00, 16#07] -> "jit";
+ [16#00, 16#08] -> "delay"
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: tdmc - TDM Circuit Package
+%% Version: 1
+%% Extends: nt version 1
+%% Purpose: This package is used to support TDM circuit terminations.
+%%----------------------------------------------------------------------
+
+capabilities_tdmc() ->
+ [
+ {property, "ec"},
+ {property, "gain"}
+ ].
+
+encode_tdmc(Scope, Item) ->
+ case Scope of
+ property ->
+ case Item of
+ "ec" -> [16#00, 16#08];
+ "gain" -> [16#00, 16#0a]
+ end
+ end.
+
+decode_tdmc(Scope, Item) ->
+ case Scope of
+ property ->
+ case Item of
+ [16#00, 16#08] -> "ec";
+ [16#00, 16#0a] -> "gain"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: swb - SwitchBoard Package
+%% Version: 1
+%% Extends: none
+%% Purpose: This package is used to support SwitchBoard specials
+%%----------------------------------------------------------------------
+
+capabilities_swb() ->
+ [
+ {statistics, "fs"}, % Free slots
+ {statistics, "as"} % Allocated slots
+ ].
+
+encode_swb(Scope, Item) ->
+ case Scope of
+ statistics ->
+ case Item of
+ "fs" -> [16#00, 16#00];
+ "as" -> [16#00, 16#01]
+ end
+ end.
+
+decode_swb(Scope, Item) ->
+ case Scope of
+ statistics ->
+ case Item of
+ [16#00, 16#00] -> "fs";
+ [16#00, 16#01] -> "as"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: native - Pseudo package
+%% Version: 1
+%% Extends: None
+%% Purpose: Native tags for media stream properties
+%%
+%% Parameters for Local descriptors and Remote descriptors are
+%% specified as tag-value pairs if binary encoding is used for the
+%% protocol. This annex contains the property names (PropertyID), the
+%% tags (Property Tag), type of the property (Type) and the values
+%% (Value).Values presented in the Value field when the field contains
+%% references shall be regarded as "information". The reference
+%% contains the normative values. If a value field does not contain a
+%% reference then the values in that field can be considered as
+%% "normative".
+%%
+%% Tags are given as hexadecimal numbers in this annex. When setting
+%% the value of a property, a MGC may underspecify the value according
+%% to one of the mechanisms specified in section 7.1.1.
+%%
+%% For type "enumeration" the value is represented by the value in brack-
+%% ets, e.g., Send(0), Receive(1).
+%%----------------------------------------------------------------------
+%%
+%% C.6. IP
+%%
+%% ________________________________________________________________
+%% | PropertyID| Tag | Type | Value |
+%% | IPv4 | 6001 | 32 BITS | Ipv4Address |
+%% | IPv6 | 6002 | 128 BITS | IPv6 Address |
+%% | Port | 6003 | Unsigned Int| Port |
+%% | Porttype | 6004 | Enumerated | TCP(0),UDP(1),SCTP(2)|
+%% |___________|____________|______________|_______________________|
+%%
+%%
+%% C.11. SDP Equivalents
+%%
+%% ______________________________________________________________
+%% | PropertyID| Tag | Type | Value |
+%% | SDP_V | B001| STRING| Protocol Version |
+%% | SDP_O | B002| STRING| Owner-creator and session ID |
+%% | SDP_S | B003| STRING| Sesson name |
+%% | SDP_I | B004| STRING| Session identifier |
+%% | SDP_U | B005| STRING| URI of descriptor |
+%% | SDC_E | B006| STRING| email address |
+%% | SDP_P | B007| STRING| phone number |
+%% | SDP_C | B008| STRING| Connection information |
+%% | SDP_B | B009| STRING| Bandwidth Information |
+%% | SDP_Z | B00A| STRING| time zone adjustment |
+%% | SDP_K | B00B| STRING| Encryption Key |
+%% | SDP_A | B00C| STRING| Zero or more session attributes|
+%% | SDP_T | B00D| STRING| Active Session Time |
+%% | SDP_R | B00E| STRING| Zero or more repeat times |
+%% | SDP_M | B00F| STRING| Media name and transport addr |
+%% | | | | Reference: IETF RFC 2327 |
+%% |___________|______|________|_________________________________|
+%%
+%%----------------------------------------------------------------------
+
+capabilities_native() ->
+ [
+ %% C.6. IP
+ {property, "IPv4"},
+ {property, "IPv6"},
+ {property, "Port"},
+ {property, "Porttype"},
+
+ %% C.11. SDP Equivalents
+ {property, "v"},
+ {property, "o"},
+ {property, "s"},
+ {property, "i"},
+ {property, "u"},
+ {property, "e"},
+ {property, "p"},
+ {property, "c"},
+ {property, "b"},
+ {property, "z"},
+ {property, "k"},
+ {property, "a"},
+ {property, "t"},
+ {property, "r"},
+ {property, "m"}
+ ].
+
+encode_native(Scope, Item) ->
+ case Scope of
+ property ->
+ case Item of
+ %% IP
+ "IPv4" -> [16#60, 16#01];
+ "IPv6" -> [16#60, 16#02];
+ "Port" -> [16#60, 16#03];
+ "Porttype" -> [16#60, 16#04];
+
+ %% SDP
+ "v" -> [16#b0, 16#01];
+ "o" -> [16#b0, 16#02];
+ "s" -> [16#b0, 16#03];
+ "i" -> [16#b0, 16#04];
+ "u" -> [16#b0, 16#05];
+ "e" -> [16#b0, 16#06];
+ "p" -> [16#b0, 16#07];
+ "c" -> [16#b0, 16#08];
+ "b" -> [16#b0, 16#09];
+ "z" -> [16#b0, 16#0a];
+ "k" -> [16#b0, 16#0b];
+ "a" -> [16#b0, 16#0c];
+ "t" -> [16#b0, 16#0d];
+ "r" -> [16#b0, 16#0e];
+ "m" -> [16#b0, 16#0f]
+ end
+ end.
+
+decode_native(Scope, [Type, Item]) ->
+ case Scope of
+ property ->
+ case Type of
+ 16#60 ->
+ case Item of
+ 16#01 -> "IPv4";
+ 16#02 -> "IPv6";
+ 16#03 -> "Port";
+ 16#04 -> "Porttype"
+ end;
+
+ 16#b0 ->
+ case Item of
+ 16#01 -> "v";
+ 16#02 -> "o";
+ 16#03 -> "s";
+ 16#04 -> "i";
+ 16#05 -> "u";
+ 16#06 -> "e";
+ 16#07 -> "p";
+ 16#08 -> "c";
+ 16#09 -> "b";
+ 16#0a -> "z";
+ 16#0b -> "k";
+ 16#0c -> "a";
+ 16#0d -> "t";
+ 16#0e -> "r";
+ 16#0f -> "m"
+ end
+ end
+ end.
+
+%% -------------------------------------------------------------------
+
+% error(Reason) ->
+% erlang:error(Reason).
+
diff --git a/lib/megaco/src/binary/megaco_binary_name_resolver_prev3c.erl b/lib/megaco/src/binary/megaco_binary_name_resolver_prev3c.erl
new file mode 100644
index 0000000000..d08231caac
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_binary_name_resolver_prev3c.erl
@@ -0,0 +1,2004 @@
+%%
+%% %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: Handle meta data about packages
+%%----------------------------------------------------------------------
+
+-module(megaco_binary_name_resolver_prev3c).
+
+-include_lib("megaco/src/engine/megaco_message_internal.hrl").
+-include_lib("megaco/src/app/megaco_internal.hrl").
+
+
+-define(LOWER(Char),
+ if
+ Char >= $A, Char =< $Z ->
+ Char - ($A - $a);
+ true ->
+ Char
+ end).
+
+-export([packages/0,
+ capabilities/0,
+ capabilities/1,
+ decode_name/3,
+ encode_name/3
+ ]).
+
+encode_name(Config, term_id, TermId) ->
+ case megaco:encode_binary_term_id(Config, TermId) of
+ {ok, TermId2} ->
+ TermId2;
+ {error, Reason} ->
+ exit({bad_term_id, TermId, Reason})
+ end;
+encode_name(_Config, Scope, Item) ->
+ ?d("encode_name(~p) -> entry with"
+ "~n Item: ~p", [Scope, Item]),
+ encode(Scope, Item).
+
+decode_name(Config, term_id, TermId) ->
+ case megaco:decode_binary_term_id(Config, TermId) of
+ {ok, TermId2} ->
+ TermId2;
+ {error, Reason} ->
+ exit({bad_term_id, TermId, Reason})
+ end;
+decode_name(_Config, Scope, Item) ->
+ ?d("decode_name(~p) -> entry with"
+ "~n Item: ~p", [Scope, Item]),
+ decode(Scope, Item).
+
+
+
+%%----------------------------------------------------------------------
+%% 12.1.1 Package
+%%
+%% Overall description of the package, specifying:
+%%
+%% Package Name: only descriptive
+%%
+%% PackageID: is an identifier
+%%
+%% Description: is a description of the package
+%%
+%% Version:
+%%
+%% A new version of a package can only add additional Properties,
+%% Events, Signals, Statistics and new possible values for an
+%% existing parameter described in the original package. No
+%% deletions or modifications shall be allowed. A version is an
+%% integer in the range from 1 to 99.
+%%
+%% Designed to be extended only (Optional): Yes
+%%
+%% This indicates that the package has been expressly designed to
+%% be extended by others, not to be directly referenced. For
+%% example, the package may not have any function on its own or be
+%% nonsensical on its own. The MG SHOULD NOT publish this PackageID
+%% when reporting packages.
+%%
+%% Extends: existing package Descriptor
+%%
+%% A package may extend an existing package. The version of the
+%% original package must be specified. When a package extends
+%% another package it shall only add additional Properties, Events,
+%% Signals, Statistics and new possible values for an existing
+%% parameter described in the original package. An extended package
+%% shall not redefine or overload an identifier defined in the
+%% original package and packages it may have extended (multiple
+%% levels of extension). Hence, if package B version 1 extends
+%% package A version 1, version 2 of B will not be able to extend
+%% the A version 2 if A version 2 defines a name already in B
+%% version 1. If the package does not extend another package, it
+%% shall specify "none".
+%%
+%%
+%% 12.1.2 Properties
+%%
+%% Properties defined by the package, specifying:
+%%
+%% Property Name: only descriptive
+%%
+%% PropertyID: is an identifier
+%%
+%% Description: is a description of the function of the property
+%%
+%% Type: One of:
+%%
+%% Boolean
+%%
+%% String: UTF-8 string
+%%
+%% Octet String: A number of octets. See Annex A and B.3 for
+%% encoding
+%%
+%% Integer: 4 byte signed integer
+%%
+%% Double: 8 byte signed integer
+%%
+%% Character: unicode UTF-8 encoding of a single letter.
+%% Could be more than one octet.
+%%
+%% Enumeration: one of a list of possible unique values (see 12.3)
+%%
+%% Sub-list: a list of several values from a list.
+%% The type of sub-list SHALL also be specified.
+%% The type shall be chosen from the types specified in
+%% this section (with the exception of sub-list). For
+%% example, Type: sub-list of enumeration. The encoding
+%% of sub-lists is specified in Annexes A and B.3.
+%%
+%% Possible values:
+%%
+%% A package MUST specify either a specific set of values or a
+%% description of how values are determined. A package MUST also
+%% specify a default value or the default behaviour when the value
+%% is omitted from its descriptor. For example, a package may
+%% specify that procedures related to the property are suspended
+%% when its value is omitted.
+%%
+%% Default:
+%%
+%% A default value (but not procedures) may be specified as
+%% provisionable.
+%%
+%% Defined in:
+%%
+%% Which H.248.1 descriptor the property is defined in.
+%% LocalControl is for stream-dependent properties.
+%% TerminationState is for stream-independent properties.
+%% ContextAttribute is for properties that affect the context as
+%% a whole, i.e., mixing properties. These are expected to be the
+%% most common cases, but it is possible for properties to be
+%% defined in other descriptors. Context properties MUST be defined
+%% in the ContextAttribute descriptor.
+%%
+%% Characteristics: Read/Write or both, and (optionally), global:
+%%
+%% Indicates whether a property is read-only, or read-write, and
+%% if it is global. If Global is omitted, the property is not
+%% global. If a property is declared as global, the value of the
+%% property is shared by all Terminations realizing the package.
+%% If a context property is declared as global, the property is
+%% shared by all contexts realizing the package.
+%%
+%%
+%% 12.1.3 Events
+%%
+%% Events defined by the package, specifying:
+%%
+%% Event name: only descriptive
+%%
+%% EventID: is an identifier
+%%
+%% Description: a description of the function of the event
+%%
+%% EventsDescriptor Parameters:
+%%
+%% Parameters used by the MGC to configure the event, and found in
+%% the EventsDescriptor. See 12.2. If there are no parameters for
+%% the Events Descriptor, then "none" shall be specified.
+%%
+%% ObservedEventsDescriptor Parameters:
+%%
+%% Parameters returned to the MGC in Notify requests and in replies
+%% to command requests from the MGC that audit
+%% ObservedEventsDescriptor, and found in the
+%% ObservedEventsDescriptor. See 12.2. If there are no parameters
+%% for the ObservedEvents Descriptor, then �none� shall be specified.
+%%
+%%
+%% 12.1.4 Signals
+%%
+%% Signals defined by the package, specifying:
+%%
+%% Signal Name: only descriptive
+%%
+%% SignalID: is an identifier. SignalID is used in a SignalsDescriptor
+%%
+%% Description: a description of the function of the signal
+%%
+%% SignalType: one of:
+%%
+%% OO (On/Off)
+%%
+%% TO (TimeOut)
+%%
+%% BR (Brief)
+%%
+%% NOTE -�SignalType may be defined such that it is dependent on
+%% the value of one or more parameters. The package MUST specify a
+%% default signal type. If the default type is TO, the package MUST
+%% specify a default duration which may be provisioned. A default
+%% duration is meaningless for BR.
+%%
+%% Duration: in hundredths of seconds
+%%
+%% Additional Parameters: see 12.2
+%%
+%%
+%% 12.1.5 Statistics
+%%
+%% Statistics defined by the package, specifying:
+%%
+%% Statistic name: only descriptive
+%%
+%% StatisticID: is an identifier
+%%
+%% StatisticID is used in a StatisticsDescriptor
+%%
+%% Description: a description of the statistic
+%%
+%% Type: One of:
+%%
+%% Boolean
+%%
+%% String: UTF-8 string
+%%
+%% Octet String: A number of octets.
+%% See Annex A and Annex B.3 for encoding
+%%
+%% Integer: 4 byte signed integer
+%%
+%% Double: 8 byte signed integer
+%%
+%% Character: Unicode UTF-8 encoding of a single letter.
+%% Could be more than one octet.
+%%
+%% Enumeration: One of a list of possible unique values (See 12.3)
+%%
+%% Sub-list: A list of several values from a list.
+%% The type of sub-list SHALL also be specified.
+%% The type shall be chosen from the types specified in
+%% this section (with the exception of sub-list).
+%% For example, Type: sub-list of enumeration.
+%% The encoding of sub-lists is specified in Annexes A
+%% and B.3.
+%%
+%% Possible Values:
+%%
+%% A package must indicate the unit of measure, e.g. milliseconds,
+%% packets, either here or along with the type above, as well as
+%% indicating any restriction on the range.
+%%
+%% Level: Specify if the statistic can be kept at the Termination
+%% level, Stream level or Either.
+%%
+%%
+%% 12.1.6 Error Codes
+%%
+%% If the package does not define any error codes, this section may be omitted.
+%% Otherwise, it describes error codes defined by the package, specifying:
+%%
+%% Error Code #: The error code number.
+%%
+%% Name: Name of the error
+%%
+%% Definition: A description of the error code.
+%%
+%% Error Text in the Error Descriptor:
+%%
+%% A description of what text to return in the Error Descriptor.
+%%
+%% Comment: Any further comments on the use of the error code.
+%%
+%%
+%% 12.1.7 Procedures
+%%
+%% Additional guidance on the use of the package.
+%%
+%%
+%% 12.2 Guidelines to defining parameters to events and signals
+%%
+%% Parameter Name: only descriptive
+%%
+%% ParameterID: is an identifier. The textual ParameterID of
+%% parameters to Events and Signals shall not start with "EPA" and
+%% "SPA", respectively. The textual ParameterID shall also not be
+%% "ST", "Stream", "SY", "SignalType", "DR", "Duration", "NC",
+%% "NotifyCompletion", "KA", "KeepActive", "EB", "Embed", "DM",
+%% "DigitMap", "DI", "Direction", "RQ" or "RequestID".
+%%
+%% Description: a description of the function of the parameter.
+%%
+%% Type: One of:
+%%
+%% Boolean
+%%
+%% String: UTF-8 octet string
+%%
+%% Octet String: A number of octets. See Annex A and B.3 for
+%% encoding
+%%
+%% Integer: 4-octet signed integer
+%%
+%% Double: 8-octet signed integer
+%%
+%% Character: Unicode UTF-8 encoding of a single letter. Could be
+%% more than one octet.
+%%
+%% Enumeration: one of a list of possible unique values (see 12.3)
+%%
+%% Sub-list: a list of several values from a list (not supported
+%% for statistics). The type of sub-list SHALL also be
+%% specified The type shall be chosen from the types
+%% specified in this section (with the exception of
+%% sub-list). For example, Type: sub-list of enumeration.
+%% The encoding of sub-lists is specified in Annex A
+%% and B.3.
+%%
+%% Optional: Yes/No
+%%
+%% Describes if the parameter may be omitted from the signal or
+%% event.
+%%
+%% Possible values:
+%%
+%% A package MUST specify either a specific set of values or a
+%% description of how values are determined. A package MUST
+%% also specify a default value or the default behavior when the
+%% value is omitted from its descriptor. For example, a package
+%% may specify that procedures related to the parameter are
+%% suspended when its value is omitted.
+%%
+%% Default:
+%%
+%% A default value (but not procedures) may be specified as
+%% provisionable.
+%%
+%%
+%% 12.3 Lists
+%%
+%% Possible values for parameters include enumerations. Enumerations may be
+%% defined in a list. It is recommended that the list be IANA registered so
+%% that packages that extend the list can be defined without concern for
+%% conflicting names.
+%%
+%%
+%% 12.4 Identifiers
+%%
+%% Identifiers in text encoding shall be strings of up to 64 characters,
+%% containing no spaces, starting with an alphabetic character and consisting
+%% of alphanumeric characters and/or digits, and possibly including the
+%% special character underscore ("_").
+%%
+%% Identifiers in binary encoding are 2 octets long.
+%%
+%% Both text and binary values shall be specified for each identifier,
+%% including identifiers used as values in enumerated types.
+%%
+%%
+%% 12.5 Package registration
+%%
+%% A package can be registered with IANA for interoperability reasons. See
+%% clause 14 for IANA considerations.
+%%
+%%----------------------------------------------------------------------
+
+capabilities() ->
+ [{P, capabilities(P)} || P <- packages()].
+
+%% -record(property, {name, type, values, defined_in, characteristics}).
+
+%%----------------------------------------------------------------------
+%% List all known packages
+%% 'native' and 'all' are not real packages
+%%----------------------------------------------------------------------
+
+packages() ->
+ [
+ "g", % Generic
+ "root", % Base Root Package
+ "tonegen", % Tone Generator Package
+ "tonedet", % Tone Detection Package
+ "dg", % Basic DTMF Generator Package
+ "dd", % DTMF detection Package
+ "cg", % Call Progress Tones Generator Package
+ "cd", % Call Progress Tones Detection Package
+ "al", % Analog Line Supervision Package
+ "ct", % Basic Continuity Package
+ "nt", % Network Package
+ "rtp", % RTP Package
+ "swb", % SwitchBoard Package
+ "tdmc", % TDM Circuit Package
+ "" % Native pseudo package
+ ].
+
+%%----------------------------------------------------------------------
+%% List all matching capabilities
+%%----------------------------------------------------------------------
+
+capabilities(Package) ->
+ case Package of
+ "g" -> capabilities_g();
+ "root" -> capabilities_root();
+ "tonegen" -> capabilities_tonegen();
+ "tonedet" -> capabilities_tonedet();
+ "dg" -> capabilities_dg();
+ "dd" -> capabilities_dd();
+ "cg" -> capabilities_cg();
+ "cd" -> capabilities_cd();
+ "al" -> capabilities_al();
+ "ct" -> capabilities_ct();
+ "nt" -> capabilities_nt();
+ "rtp" -> capabilities_rtp();
+ "swb" -> capabilities_swb();
+ "tdmc" -> capabilities_tdmc();
+ "" -> capabilities_native()
+ end.
+
+%%----------------------------------------------------------------------
+%% Decode package name to internal form
+%% Scope ::= property | event | signal | statistics
+%%----------------------------------------------------------------------
+
+decode(mid, Package) ->
+ decode_mid(Package);
+decode(package, Package) ->
+ decode_package(Package);
+decode(profile, Package) ->
+ decode_profile(Package);
+decode(dialplan, Dialplan) ->
+ decode_dialplan(Dialplan);
+decode(Scope, [A, B | Item]) when is_atom(Scope) ->
+ ?d("decode(~p) -> entry with"
+ "~n A: ~p"
+ "~n B: ~p"
+ "~n Item: ~p", [Scope, A, B, Item]),
+ case decode_package([A, B]) of
+ "" ->
+ ?d("decode -> \"no\" package",[]),
+ decode_item(Scope, [A, B], Item);
+ Package ->
+ ?d("decode -> Package: ~p", [Package]),
+ Package ++ "/" ++ decode_item(Scope, [A, B], Item)
+ end;
+decode({Scope, [A, B | Item]}, SubItem) when is_atom(Scope) ->
+ ?d("decode(~p) -> entry with"
+ "~n A: ~p"
+ "~n B: ~p"
+ "~n Item: ~p"
+ "~n SubItem: ~p", [Scope, A, B, Item, SubItem]),
+ decode_item({Scope, Item}, [A, B], SubItem).
+
+decode_item(Scope, [A, B], Item) ->
+ ?d("decode_item -> entry",[]),
+ case A of
+ 16#00 ->
+ case B of
+ 16#01 -> decode_g(Scope, Item);
+ 16#02 -> decode_root(Scope, Item);
+ 16#03 -> decode_tonegen(Scope, Item);
+ 16#04 -> decode_tonedet(Scope, Item);
+ 16#05 -> decode_dg(Scope, Item);
+ 16#06 -> decode_dd(Scope, Item);
+ 16#07 -> decode_cg(Scope, Item);
+ 16#08 -> decode_cd(Scope, Item);
+ 16#09 -> decode_al(Scope, Item);
+ 16#0a -> decode_ct(Scope, Item);
+ 16#0b -> decode_nt(Scope, Item);
+ 16#0c -> decode_rtp(Scope, Item);
+ 16#0d -> decode_tdmc(Scope, Item);
+ 16#00 -> decode_native(Scope, Item)
+ end;
+ 16#fe ->
+ case B of
+ %% Proprietary extension
+ 16#fe -> decode_swb(Scope, Item)
+ end;
+ 16#ff ->
+ case B of
+ 16#ff when Item =:= [16#ff, 16#ff] -> "*"
+ end
+ end.
+
+decode_package(Package) ->
+ ?d("decode_package -> entry with"
+ "~n Package: ~p", [Package]),
+ [A, B] = Package,
+ case A of
+ 16#00 ->
+ case B of
+ 16#01 -> "g";
+ 16#02 -> "root";
+ 16#03 -> "tonegen";
+ 16#04 -> "tonedet";
+ 16#05 -> "dg";
+ 16#06 -> "dd";
+ 16#07 -> "cg";
+ 16#08 -> "cd";
+ 16#09 -> "al";
+ 16#0a -> "ct";
+ 16#0b -> "nt";
+ 16#0c -> "rtp";
+ 16#0d -> "tdmc";
+ 16#00 -> ""
+ end;
+ 16#fe ->
+ case B of
+ 16#fe -> "swb"
+ end;
+ 16#ff ->
+ case B of
+ 16#ff -> "*"
+ end
+ end.
+
+decode_profile([A, B]) ->
+ case A of
+ 16#00 ->
+ case B of
+ 16#fe -> "resgw";
+ _ -> "profile" ++ [A + $0, B + $0]
+ end;
+ _ ->
+ "profile" ++ [A + $0, B + $0]
+ end.
+
+decode_dialplan([A, B]) ->
+ "dialplan" ++ [A + $0, B + $0].
+
+decode_mid(Mid) ->
+ case Mid of
+ {domainName, DN} ->
+ Lower = to_lower(DN#'DomainName'.name),
+ {domainName, DN#'DomainName'{name = Lower}};
+ {deviceName, PathName} ->
+ Lower = to_lower(PathName),
+ {deviceName, Lower};
+ Other ->
+ Other
+ end.
+
+to_lower(Chars) ->
+ [?LOWER(Char) || Char <- Chars].
+
+%%----------------------------------------------------------------------
+%% Encode package name from internal form
+%% Scope ::= property | event | signal | statistics
+%%----------------------------------------------------------------------
+
+encode(mid, Package) ->
+ encode_mid(Package);
+encode(package, Package) ->
+ encode_package(Package);
+encode(profile, Profile) ->
+ encode_profile(Profile);
+encode(dialplan, Dialplan) ->
+ encode_dialplan(Dialplan);
+encode(Scope, PackageItem) when is_atom(Scope) ->
+ ?d("encode(~p) -> entry with"
+ "~n PackageItem: ~p", [Scope, PackageItem]),
+ case string:tokens(PackageItem, [$/]) of
+ [Package, Item] ->
+ ?d("encode -> "
+ "~n Package: ~p"
+ "~n Item: ~p", [Package, Item]),
+ encode_package(Package) ++ encode_item(Scope, Package, Item);
+ [Item] ->
+ ?d("encode -> Item: ~p", [Item]),
+ [16#00, 16#00 | encode_native(Scope, Item)]
+ end;
+encode({Scope, PackageItem}, SubItem) when is_atom(Scope) ->
+ ?d("encode(~p) -> entry with"
+ "~n PackageItem: ~p"
+ "~n SubItem: ~p", [Scope, PackageItem, SubItem]),
+ case string:tokens(PackageItem, [$/]) of
+ [Package, Item] ->
+ ?d("encode -> "
+ "~n Package: ~p"
+ "~n Item: ~p", [Package, Item]),
+ encode_item({Scope, Item}, Package, SubItem);
+ [_Item] ->
+ ?d("encode -> _Item: ~p", [_Item]),
+ encode_native(Scope, SubItem)
+ end.
+
+encode_item(_Scope, _Package, "*") ->
+ [16#ff, 16#ff];
+encode_item(Scope, Package, Item) ->
+ ?d("encode_item(~s) -> entry", [Package]),
+ case Package of
+ "g" -> encode_g(Scope, Item);
+ "root" -> encode_root(Scope, Item);
+ "tonegen" -> encode_tonegen(Scope, Item);
+ "tonedet" -> encode_tonedet(Scope, Item);
+ "dg" -> encode_dg(Scope, Item);
+ "dd" -> encode_dd(Scope, Item);
+ "cg" -> encode_cg(Scope, Item);
+ "cd" -> encode_cd(Scope, Item);
+ "al" -> encode_al(Scope, Item);
+ "ct" -> encode_ct(Scope, Item);
+ "nt" -> encode_nt(Scope, Item);
+ "rtp" -> encode_rtp(Scope, Item);
+ "tdmc" -> encode_tdmc(Scope, Item);
+ "swb" -> encode_swb(Scope, Item)
+ end.
+
+encode_package(Package) ->
+ case Package of
+ "g" -> [16#00, 16#01];
+ "root" -> [16#00, 16#02];
+ "tonegen" -> [16#00, 16#03];
+ "tonedet" -> [16#00, 16#04];
+ "dg" -> [16#00, 16#05];
+ "dd" -> [16#00, 16#06];
+ "cg" -> [16#00, 16#07];
+ "cd" -> [16#00, 16#08];
+ "al" -> [16#00, 16#09];
+ "ct" -> [16#00, 16#0a];
+ "nt" -> [16#00, 16#0b];
+ "rtp" -> [16#00, 16#0c];
+ "tdmc" -> [16#00, 16#0d];
+ "" -> [16#00, 16#00];
+ "*" -> [16#ff, 16#ff];
+ "swb" -> [16#fe, 16#fe]
+ end.
+
+encode_profile(Profile) ->
+ case Profile of
+ "resgw" ->
+ [16#00, 16#fe];
+ [$p, $r, $o, $f, $i, $l, $e | Name] ->
+ case Name of
+ [A, B] -> [A - $0, B - $0];
+ [B] -> [0, B - $0];
+ [] -> [0, 0]
+ end
+ end.
+
+encode_dialplan(Dialplan) ->
+ case Dialplan of
+ [$d, $i, $a, $l, $p, $l, $a, $n | Name] ->
+ case Name of
+ [A, B] -> [A - $0, B - $0];
+ [B] -> [0, B - $0];
+ [] -> [0, 0]
+ end
+ end.
+
+encode_mid(Mid) ->
+ Mid.
+
+
+%%----------------------------------------------------------------------
+%% Name: g - Generic
+%% Version: 1
+%% Extends: None
+%% Purpose: Generic package for commonly encountered items
+%%----------------------------------------------------------------------
+
+capabilities_g() ->
+ [
+ {event, "cause"},
+ {event, "sc"}
+ ].
+
+encode_g(event, Item) ->
+ case Item of
+ "cause" -> [16#00, 16#01];
+ "sc" -> [16#00, 16#02]
+ end;
+
+encode_g({event_parameter, Item}, SubItem) ->
+ case Item of
+ "cause" ->
+ case SubItem of
+ "Generalcause" -> [16#00, 16#01];
+ "Failurecause" -> [16#00, 16#02]
+ end;
+ "sc" ->
+ case SubItem of
+ "SigID" -> [16#00, 16#01];
+ "Meth" -> [16#00, 16#02];
+ "SLID" -> [16#00, 16#03];
+ "RID" -> [16#00, 16#04]
+ end
+ end.
+
+decode_g(event, Item) ->
+ case Item of
+ [16#00, 16#01] -> "cause";
+ [16#00, 16#02] -> "sc"
+ end;
+
+decode_g({event_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#01] -> % Event: cause
+ case SubItem of
+ [16#00, 16#01] -> "Generalcause";
+ [16#00, 16#02] -> "Failurecause"
+ end;
+
+ [16#00, 16#02] -> % Event: sc
+ case SubItem of
+ [16#00, 16#01] -> "SigID";
+ [16#00, 16#02] -> "Meth";
+ [16#00, 16#03] -> "SLID";
+ [16#00, 16#04] -> "RID"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: root - Base Root Package
+%% Version: 2
+%% Extends: None
+%% Purpose: This package defines Gateway wide properties.
+%%----------------------------------------------------------------------
+
+capabilities_root() ->
+ [
+ {property, "maxNumberOfContexts"},
+ {property, "maxTerminationsPerContext"},
+ {property, "normalMGExecutionTime"},
+ {property, "normalMGCExecutionTime"},
+ {property, "MGProvisionalResponseTimerValue"},
+ {property, "MGCProvisionalResponseTimerValue"},
+ {property, "MGCOriginatedPendingLimit"},
+ {property, "MGOriginatedPendingLimit"}
+ ].
+
+encode_root(Scope, Item) ->
+ case Scope of
+ property ->
+ case Item of
+ "maxNumberOfContexts" -> [16#00, 16#01];
+ "maxTerminationsPerContext" -> [16#00, 16#02];
+ "normalMGExecutionTime" -> [16#00, 16#03];
+ "normalMGCExecutionTime" -> [16#00, 16#04];
+ "MGProvisionalResponseTimerValue" -> [16#00, 16#05];
+ "MGCProvisionalResponseTimerValue" -> [16#00, 16#06];
+ "MGCOriginatedPendingLimit" -> [16#00, 16#07];
+ "MGOriginatedPendingLimit" -> [16#00, 16#08]
+ end
+ end.
+
+decode_root(Scope, Item) ->
+ case Scope of
+ property ->
+ case Item of
+ [16#00, 16#01] -> "maxNumberOfContexts";
+ [16#00, 16#02] -> "maxTerminationsPerContext";
+ [16#00, 16#03] -> "normalMGExecutionTime";
+ [16#00, 16#04] -> "normalMGCExecutionTime";
+ [16#00, 16#05] -> "MGProvisionalResponseTimerValue";
+ [16#00, 16#06] -> "MGCProvisionalResponseTimerValue";
+ [16#00, 16#07] -> "MGCOriginatedPendingLimit";
+ [16#00, 16#08] -> "MGOriginatedPendingLimit"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: tonegen - Tone Generator Package
+%% Version: 2
+%% Extends: None
+%% Purpose: This package defines signals to generate audio tones.
+%% This package does not specify parameter values. It is
+%% intended to be extendable. Generally, tones are defined
+%% as an individual signal with a parameter, ind,
+%% representing "interdigit" time delay, and a tone id to
+%% be used with playtones. A tone id should be kept
+%% consistent with any tone generation for the same tone.
+%% MGs are expected to be provisioned with the characteristics
+%% of appropriate tones for the country in which the MG is located.
+%%----------------------------------------------------------------------
+
+capabilities_tonegen() ->
+ [
+ {signal, "pt"}
+ ].
+
+encode_tonegen(signal, Item) ->
+ case Item of
+ "pt" -> [16#00, 16#01]
+ end;
+
+encode_tonegen({signal_parameter, Item}, SubItem) ->
+ case Item of
+ "pt" ->
+ case SubItem of
+ "tl" -> [16#00, 16#01];
+ "ind" -> [16#00, 16#02];
+ "btd" -> [16#00, 16#03]
+ end
+ end.
+
+decode_tonegen(signal, Item) ->
+ case Item of
+ [16#00, 16#01] -> "pt"
+ end;
+
+decode_tonegen({signal_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#01] -> % Event: pt
+ case SubItem of
+ [16#00, 16#01] -> "tl";
+ [16#00, 16#02] -> "ind";
+ [16#00, 16#03] -> "btd"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: tonedet - Tone Detection Package
+%% Version: 1
+%% Extends: None
+%% Purpose: This Package defines events for audio tone detection.
+%% Tones are selected by name (tone id). MGs are expected
+%% to be provisioned with the characteristics of appropriate
+%% tones for the country in which the MG is located.
+%%
+%% This package does not specify parameter values.
+%% It is intended to be extendable.
+%%----------------------------------------------------------------------
+
+capabilities_tonedet() ->
+ [
+ {event, "std"},
+ {event, "etd"},
+ {event, "ltd"}
+ ].
+
+encode_tonedet(event, Item) ->
+ case Item of
+ "std" -> [16#00, 16#01];
+ "etd" -> [16#00, 16#02];
+ "ltd" -> [16#00, 16#03]
+ end;
+
+encode_tonedet({event_parameter, Item}, SubItem) ->
+ case Item of
+ "std" ->
+ case SubItem of
+ "tl" -> [16#00, 16#01];
+ "tid" -> [16#00, 16#03]
+ end;
+ "etd" ->
+ case SubItem of
+ "tl" -> [16#00, 16#01];
+ "tid" -> [16#00, 16#03];
+ "dur" -> [16#00, 16#02]
+ end;
+ "ltd" ->
+ case SubItem of
+ "tl" -> [16#00, 16#01];
+ "dur" -> [16#00, 16#02];
+ "tid" -> [16#00, 16#03]
+ end
+ end.
+
+decode_tonedet(event, Item) ->
+ case Item of
+ [16#00, 16#01] -> "std";
+ [16#00, 16#02] -> "etd";
+ [16#00, 16#03] -> "ltd"
+ end;
+
+decode_tonedet({event_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#01] -> % Event std
+ case SubItem of
+ [16#00, 16#01] -> "tl";
+ [16#00, 16#03] -> "tid"
+ end;
+ [16#00, 16#02] -> % Event etd
+ case SubItem of
+ [16#00, 16#01] -> "tl";
+ [16#00, 16#03] -> "tid";
+ [16#00, 16#02] -> "dur"
+ end;
+ [16#00, 16#03] -> % Event ltd
+ case SubItem of
+ [16#00, 16#01] -> "tl";
+ [16#00, 16#02] -> "dur";
+ [16#00, 16#03] -> "tid"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: dg - Basic DTMF Generator Package
+%% Version: 1
+%% Extends: tonegen version 1
+%% Purpose: This package defines the basic DTMF tones as signals and
+%% extends the allowed values of parameter tl of playtone
+%% in tonegen.
+%%----------------------------------------------------------------------
+
+capabilities_dg() ->
+ [
+ {signal, "d0"},
+ {signal, "d1"},
+ {signal, "d2"},
+ {signal, "d3"},
+ {signal, "d4"},
+ {signal, "d5"},
+ {signal, "d6"},
+ {signal, "d7"},
+ {signal, "d8"},
+ {signal, "d9"},
+ {signal, "ds"},
+ {signal, "do"},
+ {signal, "da"},
+ {signal, "db"},
+ {signal, "dc"},
+ {signal, "dd"}
+ ].
+
+encode_dg(signal, Item) ->
+ case Item of
+ "d0" -> [16#00, 16#10];
+ "d1" -> [16#00, 16#11];
+ "d2" -> [16#00, 16#12];
+ "d3" -> [16#00, 16#13];
+ "d4" -> [16#00, 16#14];
+ "d5" -> [16#00, 16#15];
+ "d6" -> [16#00, 16#16];
+ "d7" -> [16#00, 16#17];
+ "d8" -> [16#00, 16#18];
+ "d9" -> [16#00, 16#19];
+ "ds" -> [16#00, 16#20];
+ "do" -> [16#00, 16#21];
+ "da" -> [16#00, 16#1a];
+ "db" -> [16#00, 16#1b];
+ "dc" -> [16#00, 16#1c];
+ "dd" -> [16#00, 16#1d]
+ end;
+
+encode_dg({signal_parameter, Item}, SubItem) ->
+ case Item of
+ "d0" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d1" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d2" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d3" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d4" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d5" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d6" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d7" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d8" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d9" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "ds" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "do" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "da" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "db" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "dc" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "dd" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end
+ end.
+
+decode_dg(signal, Item) ->
+ case Item of
+ [16#00, 16#10] -> "d0";
+ [16#00, 16#11] -> "d1";
+ [16#00, 16#12] -> "d2";
+ [16#00, 16#13] -> "d3";
+ [16#00, 16#14] -> "d4";
+ [16#00, 16#15] -> "d5";
+ [16#00, 16#16] -> "d6";
+ [16#00, 16#17] -> "d7";
+ [16#00, 16#18] -> "d8";
+ [16#00, 16#19] -> "d9";
+ [16#00, 16#20] -> "ds";
+ [16#00, 16#21] -> "do";
+ [16#00, 16#1a] -> "da";
+ [16#00, 16#1b] -> "db";
+ [16#00, 16#1c] -> "dc";
+ [16#00, 16#1d] -> "dd"
+ end;
+
+decode_dg({signal_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#10] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#11] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#12] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#13] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#14] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#15] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#16] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#17] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#18] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#19] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#20] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#21] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#1a] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#1b] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#1c] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#1d] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: dd - DTMF detection Package
+%% Version: 1
+%% Extends: tonedet version 1
+%% Purpose: This package defines the basic DTMF tones detection.
+%% Tones are selected by name (tone id). MGs are expected
+%% to be provisioned with the characteristics of appropriate
+%% tones for the country in which the MG is located.
+%%
+%% This package does not specify parameter values.
+%% It is intended to be extendable.
+%%
+%% Additional tone id values are all tone ids described in package dg
+%% (basic DTMF generator package).
+%%
+%% The following table maps DTMF events to digit map symbols as described
+%% in section 7.1.14.
+%%
+%% _________________________________
+%% | DTMF Event | Symbol |
+%% | d0 | "0" |
+%% | d1 | "1" |
+%% | d2 | "2" |
+%% | d3 | "3" |
+%% | d4 | "4" |
+%% | d5 | "5" |
+%% | d6 | "6" |
+%% | d7 | "7" |
+%% | d8 | "8" |
+%% | d9 | "9" |
+%% | da | "A" or "a"|
+%% | db | "B" or "b"|
+%% | dc | "C" or "c"|
+%% | dd | "D" or "d"|
+%% | ds | "E" or "e"|
+%% | do | "F" or "f"|
+%% |___________________|____________|
+%%
+%%----------------------------------------------------------------------
+
+capabilities_dd() ->
+ [
+ {event, "ce"},
+ {event, "d0"},
+ {event, "d1"},
+ {event, "d2"},
+ {event, "d3"},
+ {event, "d4"},
+ {event, "d5"},
+ {event, "d6"},
+ {event, "d7"},
+ {event, "d8"},
+ {event, "d9"},
+ {event, "ds"},
+ {event, "do"},
+ {event, "da"},
+ {event, "db"},
+ {event, "dc"},
+ {event, "dd"}
+ ].
+
+encode_dd(event, Item) ->
+ case Item of
+ "ce" -> [16#00, 16#04];
+ "d0" -> [16#00, 16#10];
+ "d1" -> [16#00, 16#11];
+ "d2" -> [16#00, 16#12];
+ "d3" -> [16#00, 16#13];
+ "d4" -> [16#00, 16#14];
+ "d5" -> [16#00, 16#15];
+ "d6" -> [16#00, 16#16];
+ "d7" -> [16#00, 16#17];
+ "d8" -> [16#00, 16#18];
+ "d9" -> [16#00, 16#19];
+ "ds" -> [16#00, 16#20];
+ "do" -> [16#00, 16#21];
+ "da" -> [16#00, 16#1a];
+ "db" -> [16#00, 16#1b];
+ "dc" -> [16#00, 16#1c];
+ "dd" -> [16#00, 16#1d]
+ end;
+
+encode_dd({event_parameter, Item}, SubItem) ->
+ case Item of
+ "ce" ->
+ case SubItem of
+ "ds" -> [16#00, 16#01];
+ "Meth" -> [16#00, 16#03]
+ end;
+ "d0" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d1" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d2" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d3" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d4" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d5" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d6" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d7" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d8" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d9" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "ds" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "do" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "da" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "db" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "dc" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "dd" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end
+ end.
+
+decode_dd(event, Item) ->
+ case Item of
+ [16#00, 16#04] -> "ce";
+ [16#00, 16#10] -> "d0";
+ [16#00, 16#11] -> "d1";
+ [16#00, 16#12] -> "d2";
+ [16#00, 16#13] -> "d3";
+ [16#00, 16#14] -> "d4";
+ [16#00, 16#15] -> "d5";
+ [16#00, 16#16] -> "d6";
+ [16#00, 16#17] -> "d7";
+ [16#00, 16#18] -> "d8";
+ [16#00, 16#19] -> "d9";
+ [16#00, 16#20] -> "ds";
+ [16#00, 16#21] -> "do";
+ [16#00, 16#1a] -> "da";
+ [16#00, 16#1b] -> "db";
+ [16#00, 16#1c] -> "dc";
+ [16#00, 16#1d] -> "dd"
+ end;
+
+decode_dd({event_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#04] -> % Event ce
+ case SubItem of
+ [16#00, 16#01] -> "ds";
+ [16#00, 16#03] -> "Meth"
+ end;
+ [16#00, 16#10] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#11] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#12] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#13] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#14] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#15] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#16] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#17] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#18] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#19] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#20] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#21] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#1a] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#1b] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#1c] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#1d] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end
+ end.
+
+%%----------------------------------------------------------------------
+%% Name: cg - Call Progress Tones Generator Package
+%% Version: 1
+%% Extends: tonegen version 1
+%% Purpose: This package defines the basic call progress tones as signals
+%% and extends the allowed values of the tl parameter of
+%% playtone in tonegen.
+%%----------------------------------------------------------------------
+
+capabilities_cg() ->
+ [
+ {signal, "dt"},
+ {signal, "rt"},
+ {signal, "bt"},
+ {signal, "ct"},
+ {signal, "sit"},
+ {signal, "wt"},
+ {signal, "prt"},
+ {signal, "cw"},
+ {signal, "cr"}
+ ].
+
+
+encode_cg(Scope, Item) ->
+ case Scope of
+ signal ->
+ case Item of
+ "dt" -> [16#00, 16#30];
+ "rt" -> [16#00, 16#31];
+ "bt" -> [16#00, 16#32];
+ "ct" -> [16#00, 16#33];
+ "sit" -> [16#00, 16#34];
+ "wt" -> [16#00, 16#35];
+ "prt" -> [16#00, 16#36];
+ "cw" -> [16#00, 16#37];
+ "cr" -> [16#00, 16#38]
+ end
+ end.
+
+decode_cg(Scope, Item) ->
+ case Scope of
+ signal ->
+ case Item of
+ [16#00, 16#30] -> "dt";
+ [16#00, 16#31] -> "rt";
+ [16#00, 16#32] -> "bt";
+ [16#00, 16#33] -> "ct";
+ [16#00, 16#34] -> "sit";
+ [16#00, 16#35] -> "wt";
+ [16#00, 16#36] -> "prt";
+ [16#00, 16#37] -> "cw";
+ [16#00, 16#38] -> "cr"
+ end
+ end.
+
+%%----------------------------------------------------------------------
+%% Name: cd - Call Progress Tones Detection Package
+%% Version: 1
+%% Extends: tonedet version 1
+%% Purpose: This package defines the basic call progress detection tones.
+%% This Package extends the possible values of tone id
+%% in the "start tone detected", "end tone detected" and
+%% "long tone detected" events.
+%% Additional values
+%% tone id values are defined for start tone detected,
+%% end tone detected and long tone detected with
+%% the same values as those in package cg (call
+%% progress tones generation package).
+%%
+%% The required set of tone ids corresponds to Recommendation E.180/Q.35
+%% [ITU-T Recommendation E.180/Q.35 (1998)]. See Recommendation E.180/Q.35
+%% for definition of the meanings of these tones.
+%%----------------------------------------------------------------------
+
+capabilities_cd() ->
+ [
+ {event, "dt"},
+ {event, "rt"},
+ {event, "bt"},
+ {event, "ct"},
+ {event, "sit"},
+ {event, "wt"},
+ {event, "prt"},
+ {event, "cw"},
+ {event, "cr"}
+ ].
+
+
+encode_cd(Scope, Item) ->
+ case Scope of
+ event ->
+ case Item of
+ "dt" -> [16#00, 16#30];
+ "rt" -> [16#00, 16#31];
+ "bt" -> [16#00, 16#32];
+ "ct" -> [16#00, 16#33];
+ "sit"-> [16#00, 16#34];
+ "wt" -> [16#00, 16#35];
+ "prt"-> [16#00, 16#36];
+ "cw" -> [16#00, 16#37];
+ "cr" -> [16#00, 16#38]
+ end
+ end.
+
+decode_cd(Scope, Item) ->
+ case Scope of
+ event ->
+ case Item of
+ [16#00, 16#30] -> "dt";
+ [16#00, 16#31] -> "rt";
+ [16#00, 16#32] -> "bt";
+ [16#00, 16#33] -> "ct";
+ [16#00, 16#34] -> "sit";
+ [16#00, 16#35] -> "wt";
+ [16#00, 16#36] -> "prt";
+ [16#00, 16#37] -> "cw";
+ [16#00, 16#38] -> "cr"
+ end
+ end.
+
+%%----------------------------------------------------------------------
+%% Name: al - Analog Line Supervision Package
+%% Version: 1
+%% Extends: None
+%% Purpose: This package defines events and signals for an analog line.
+%%----------------------------------------------------------------------
+
+capabilities_al() ->
+ [
+ {event, "on"},
+ {event, "of"},
+ {event, "fl"},
+ {signal, "ri"}
+ ].
+
+encode_al(event, Item) ->
+ ?d("encode_al(event) -> entry with"
+ "~n Item: ~p", [Item]),
+ case Item of
+ "on" -> [16#00, 16#04];
+ "of" -> [16#00, 16#05];
+ "fl" -> [16#00, 16#06]
+ end;
+
+encode_al({event_parameter, Item}, SubItem) ->
+ ?d("encode_al({event_parameter,~p}) -> entry with"
+ "~n SubItem: ~p", [Item, SubItem]),
+ case Item of
+ "on" ->
+ case SubItem of
+ "strict" -> [16#00, 16#01];
+ "init" -> [16#00, 16#02]
+ end;
+ "of" ->
+ case SubItem of
+ "strict" -> [16#00, 16#01];
+ "init" -> [16#00, 16#02]
+ end;
+ "fl" ->
+ case SubItem of
+ "mindur" -> [16#00, 16#04];
+ "maxdur" -> [16#00, 16#05]
+ end
+ end;
+
+encode_al(signal, Item) ->
+ ?d("encode_al(signal) -> entry with"
+ "~n Item: ~p", [Item]),
+ case Item of
+ "ri" -> [16#00, 16#02]
+ end;
+
+encode_al({signal_parameter, Item}, SubItem) ->
+ ?d("encode_al({signal_parameter,~p}) -> entry with"
+ "~n SubItem: ~p", [Item, SubItem]),
+ case Item of
+ "ri" ->
+ case SubItem of
+ "cad" -> [16#00, 16#06];
+ "freq" -> [16#00, 16#07]
+ end
+ end.
+
+decode_al(event, SubItem) ->
+ ?d("decode_al(event) -> entry with"
+ "~n SubItem: ~p", [SubItem]),
+ case SubItem of
+ [16#00, 16#04] -> "on";
+ [16#00, 16#05] -> "of";
+ [16#00, 16#06] -> "fl"
+ end;
+
+decode_al({event_parameter, Item}, SubItem) ->
+ ?d("decode_al({event_parameter,~p}) -> entry with"
+ "~n SubItem: ~p", [Item, SubItem]),
+ case Item of
+ [16#00,16#04] -> %% Event: on
+ case SubItem of
+ [16#00, 16#01] -> "strict";
+ [16#00, 16#02] -> "init"
+ end;
+ [16#00,16#05] -> %% Event: of
+ case SubItem of
+ [16#00, 16#01] -> "strict";
+ [16#00, 16#02] -> "init"
+ end;
+ [16#00,16#06] -> %% Event: fl
+ case SubItem of
+ [16#00, 16#04] -> "mindur";
+ [16#00, 16#05] -> "maxdur"
+ end
+ end;
+
+decode_al(signal, SubItem) ->
+ ?d("decode_al(signal) -> entry with"
+ "~n SubItem: ~p", [SubItem]),
+ case SubItem of
+ [16#00, 16#02] -> "ri"
+ end;
+
+decode_al({signal_parameter, Item}, SubItem) ->
+ ?d("decode_al({signal_parameter,~p}) -> entry with"
+ "~n SubItem: ~p", [Item, SubItem]),
+ case Item of
+ [16#00,16#02] -> %% Event: ri
+ case SubItem of
+ [16#00, 16#06] -> "cad";
+ [16#00, 16#07] -> "freq"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: ct - Basic Continuity Package
+%% Version: 1
+%% Extends: None
+%% Purpose: This package defines events and signals for continuity test.
+%% The continuity test includes provision of either a loopback
+%% or transceiver functionality.
+%%----------------------------------------------------------------------
+
+capabilities_ct() ->
+ [
+ {event, "cmp"},
+ {signal, "ct"},
+ {signal, "rsp"}
+ ].
+
+encode_ct(event, Item) ->
+ case Item of
+ "cmp" -> [16#00, 16#05]
+ end;
+encode_ct({event_parameter, Item}, SubItem) ->
+ case Item of
+ "cmp" ->
+ case SubItem of
+ "res" -> [16#00, 16#08]
+ end
+ end;
+encode_ct(signal, Item) ->
+ case Item of
+ "ct" -> [16#00, 16#03];
+ "rsp" -> [16#00, 16#04]
+ end.
+
+decode_ct(event, Item) ->
+ case Item of
+ [16#00, 16#05] -> "cmp"
+ end;
+decode_ct({event_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#05] -> % Event cmp
+ case SubItem of
+ [16#00, 16#08] -> "res"
+ end
+ end;
+decode_ct(signal, Item) ->
+ case Item of
+ [16#00, 16#03] -> "ct";
+ [16#00, 16#04] -> "rsp"
+ end.
+
+%%----------------------------------------------------------------------
+%% Name: nt - Network Package
+%% Version: 1
+%% Extends: None
+%% Purpose: This package defines properties of network terminations
+%% independent of network type.
+%%----------------------------------------------------------------------
+
+capabilities_nt() ->
+ [
+ {property, "jit"},
+ {event, "netfail"},
+ {event, "qualert"},
+ {statistics, "dur"},
+ {statistics, "os"},
+ {statistics, "or"}
+ ].
+
+encode_nt(property, Item) ->
+ case Item of
+ "jit" -> [16#00, 16#07]
+ end;
+encode_nt(event, Item) ->
+ case Item of
+ "netfail" -> [16#00, 16#05];
+ "qualert" -> [16#00, 16#06]
+ end;
+encode_nt({event_parameter, Item}, SubItem) ->
+ case Item of
+ "netfail" ->
+ case SubItem of
+ "cs" -> [16#00, 16#01]
+ end;
+ "qualert" ->
+ case SubItem of
+ "th" -> [16#00, 16#01]
+ end
+ end;
+encode_nt(statistics, Item) ->
+ case Item of
+ "dur" -> [16#00, 16#01];
+ "os" -> [16#00, 16#02];
+ "or" -> [16#00, 16#03]
+ end.
+
+decode_nt(property, Item) ->
+ case Item of
+ [16#00, 16#07] -> "jit"
+ end;
+decode_nt(event, Item) ->
+ case Item of
+ [16#00, 16#05] -> "netfail";
+ [16#00, 16#06] -> "qualert"
+ end;
+decode_nt({event_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#05] -> % Event netfail
+ case SubItem of
+ [16#00, 16#01] -> "cs"
+ end;
+ [16#00, 16#06] -> % Event qualert
+ case Item of
+ [16#00, 16#01] -> "th"
+ end
+ end;
+decode_nt(statistics, Item) ->
+ case Item of
+ [16#00, 16#01] -> "dur";
+ [16#00, 16#02] -> "os";
+ [16#00, 16#03] -> "or"
+ end.
+
+%%----------------------------------------------------------------------
+%% Name: rtp - RTP Package
+%% Version: 1
+%% Extends: nt version 1
+%% Purpose: This package is used to support packet based multimedia
+%% data transfer by means of the Real-time Transport Protocol
+%% (RTP) [RFC 1889].
+%%----------------------------------------------------------------------
+
+capabilities_rtp() ->
+ [
+ {event, "pltrans"},
+ {statistics, "ps"},
+ {statistics, "pr"},
+ {statistics, "pl"},
+ {statistics, "jit"},
+ {statistics, "delay"}
+ ].
+
+encode_rtp(event, Item) ->
+ case Item of
+ "pltrans" -> [16#00, 16#01]
+ end;
+encode_rtp({event_parameter, Item}, SubItem) ->
+ case Item of
+ "pltrans" ->
+ case SubItem of
+ "rtppltype" -> [16#00, 16#01]
+ end
+ end;
+encode_rtp(statistics, Item) ->
+ case Item of
+ "ps" -> [16#00, 16#04];
+ "pr" -> [16#00, 16#05];
+ "pl" -> [16#00, 16#06];
+ "jit" -> [16#00, 16#07];
+ "delay" -> [16#00, 16#08]
+ end.
+
+decode_rtp(event, Item) ->
+ case Item of
+ [16#00, 16#01] -> "pltrans"
+ end;
+decode_rtp({event_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#01] -> % Event pltrans
+ case SubItem of
+ [16#00, 16#01] -> "rtppltype"
+ end
+ end;
+decode_rtp(statistics, Item) ->
+ case Item of
+ [16#00, 16#04] -> "ps";
+ [16#00, 16#05] -> "pr";
+ [16#00, 16#06] -> "pl";
+ [16#00, 16#07] -> "jit";
+ [16#00, 16#08] -> "delay"
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: tdmc - TDM Circuit Package
+%% Version: 1
+%% Extends: nt version 1
+%% Purpose: This package is used to support TDM circuit terminations.
+%%----------------------------------------------------------------------
+
+capabilities_tdmc() ->
+ [
+ {property, "ec"},
+ {property, "gain"}
+ ].
+
+encode_tdmc(Scope, Item) ->
+ case Scope of
+ property ->
+ case Item of
+ "ec" -> [16#00, 16#08];
+ "gain" -> [16#00, 16#0a]
+ end
+ end.
+
+decode_tdmc(Scope, Item) ->
+ case Scope of
+ property ->
+ case Item of
+ [16#00, 16#08] -> "ec";
+ [16#00, 16#0a] -> "gain"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: swb - SwitchBoard Package
+%% Version: 1
+%% Extends: none
+%% Purpose: This package is used to support SwitchBoard specials
+%%----------------------------------------------------------------------
+
+capabilities_swb() ->
+ [
+ {statistics, "fs"}, % Free slots
+ {statistics, "as"} % Allocated slots
+ ].
+
+encode_swb(Scope, Item) ->
+ case Scope of
+ statistics ->
+ case Item of
+ "fs" -> [16#00, 16#00];
+ "as" -> [16#00, 16#01]
+ end
+ end.
+
+decode_swb(Scope, Item) ->
+ case Scope of
+ statistics ->
+ case Item of
+ [16#00, 16#00] -> "fs";
+ [16#00, 16#01] -> "as"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: native - Pseudo package
+%% Version: 1
+%% Extends: None
+%% Purpose: Native tags for media stream properties
+%%
+%% Parameters for Local descriptors and Remote descriptors are
+%% specified as tag-value pairs if binary encoding is used for the
+%% protocol. This annex contains the property names (PropertyID), the
+%% tags (Property Tag), type of the property (Type) and the values
+%% (Value).Values presented in the Value field when the field contains
+%% references shall be regarded as "information". The reference
+%% contains the normative values. If a value field does not contain a
+%% reference then the values in that field can be considered as
+%% "normative".
+%%
+%% Tags are given as hexadecimal numbers in this annex. When setting
+%% the value of a property, a MGC may underspecify the value according
+%% to one of the mechanisms specified in section 7.1.1.
+%%
+%% For type "enumeration" the value is represented by the value in brack-
+%% ets, e.g., Send(0), Receive(1).
+%%----------------------------------------------------------------------
+%%
+%% C.6. IP
+%%
+%% ________________________________________________________________
+%% | PropertyID| Tag | Type | Value |
+%% | IPv4 | 6001 | 32 BITS | Ipv4Address |
+%% | IPv6 | 6002 | 128 BITS | IPv6 Address |
+%% | Port | 6003 | Unsigned Int| Port |
+%% | Porttype | 6004 | Enumerated | TCP(0),UDP(1),SCTP(2)|
+%% |___________|____________|______________|_______________________|
+%%
+%%
+%% C.11. SDP Equivalents
+%%
+%% ______________________________________________________________
+%% | PropertyID| Tag | Type | Value |
+%% | SDP_V | B001| STRING| Protocol Version |
+%% | SDP_O | B002| STRING| Owner-creator and session ID |
+%% | SDP_S | B003| STRING| Sesson name |
+%% | SDP_I | B004| STRING| Session identifier |
+%% | SDP_U | B005| STRING| URI of descriptor |
+%% | SDC_E | B006| STRING| email address |
+%% | SDP_P | B007| STRING| phone number |
+%% | SDP_C | B008| STRING| Connection information |
+%% | SDP_B | B009| STRING| Bandwidth Information |
+%% | SDP_Z | B00A| STRING| time zone adjustment |
+%% | SDP_K | B00B| STRING| Encryption Key |
+%% | SDP_A | B00C| STRING| Zero or more session attributes|
+%% | SDP_T | B00D| STRING| Active Session Time |
+%% | SDP_R | B00E| STRING| Zero or more repeat times |
+%% | SDP_M | B00F| STRING| Media name and transport addr |
+%% | | | | Reference: IETF RFC 2327 |
+%% |___________|______|________|_________________________________|
+%%
+%%----------------------------------------------------------------------
+
+capabilities_native() ->
+ [
+ %% C.6. IP
+ {property, "IPv4"},
+ {property, "IPv6"},
+ {property, "Port"},
+ {property, "Porttype"},
+
+ %% C.11. SDP Equivalents
+ {property, "v"},
+ {property, "o"},
+ {property, "s"},
+ {property, "i"},
+ {property, "u"},
+ {property, "e"},
+ {property, "p"},
+ {property, "c"},
+ {property, "b"},
+ {property, "z"},
+ {property, "k"},
+ {property, "a"},
+ {property, "t"},
+ {property, "r"},
+ {property, "m"}
+ ].
+
+encode_native(Scope, Item) ->
+ case Scope of
+ property ->
+ case Item of
+ %% IP
+ "IPv4" -> [16#60, 16#01];
+ "IPv6" -> [16#60, 16#02];
+ "Port" -> [16#60, 16#03];
+ "Porttype" -> [16#60, 16#04];
+
+ %% SDP
+ "v" -> [16#b0, 16#01];
+ "o" -> [16#b0, 16#02];
+ "s" -> [16#b0, 16#03];
+ "i" -> [16#b0, 16#04];
+ "u" -> [16#b0, 16#05];
+ "e" -> [16#b0, 16#06];
+ "p" -> [16#b0, 16#07];
+ "c" -> [16#b0, 16#08];
+ "b" -> [16#b0, 16#09];
+ "z" -> [16#b0, 16#0a];
+ "k" -> [16#b0, 16#0b];
+ "a" -> [16#b0, 16#0c];
+ "t" -> [16#b0, 16#0d];
+ "r" -> [16#b0, 16#0e];
+ "m" -> [16#b0, 16#0f]
+ end
+ end.
+
+decode_native(Scope, [Type, Item]) ->
+ case Scope of
+ property ->
+ case Type of
+ 16#60 ->
+ case Item of
+ 16#01 -> "IPv4";
+ 16#02 -> "IPv6";
+ 16#03 -> "Port";
+ 16#04 -> "Porttype"
+ end;
+
+ 16#b0 ->
+ case Item of
+ 16#01 -> "v";
+ 16#02 -> "o";
+ 16#03 -> "s";
+ 16#04 -> "i";
+ 16#05 -> "u";
+ 16#06 -> "e";
+ 16#07 -> "p";
+ 16#08 -> "c";
+ 16#09 -> "b";
+ 16#0a -> "z";
+ 16#0b -> "k";
+ 16#0c -> "a";
+ 16#0d -> "t";
+ 16#0e -> "r";
+ 16#0f -> "m"
+ end
+ end
+ end.
+
+%% -------------------------------------------------------------------
+
+% error(Reason) ->
+% erlang:error(Reason).
+
diff --git a/lib/megaco/src/binary/megaco_binary_name_resolver_v1.erl b/lib/megaco/src/binary/megaco_binary_name_resolver_v1.erl
new file mode 100644
index 0000000000..a748a1d0cc
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_binary_name_resolver_v1.erl
@@ -0,0 +1,1613 @@
+%%
+%% %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: Handle meta data about packages
+%%----------------------------------------------------------------------
+
+-module(megaco_binary_name_resolver_v1).
+
+-include_lib("megaco/src/engine/megaco_message_internal.hrl").
+-include_lib("megaco/src/app/megaco_internal.hrl").
+
+-define(LOWER(Char),
+ if
+ Char >= $A, Char =< $Z ->
+ Char - ($A - $a);
+ true ->
+ Char
+ end).
+
+-export([packages/0,
+ capabilities/0,
+ capabilities/1,
+ decode_name/3,
+ encode_name/3
+ ]).
+
+encode_name(Config, term_id, TermId) ->
+ case megaco:encode_binary_term_id(Config, TermId) of
+ {ok, TermId2} ->
+ TermId2;
+ {error, _Reason} ->
+ exit({bad_term_id, TermId})
+ end;
+encode_name(_Config, Scope, Item) ->
+ ?d("encode_name(~p) -> entry with"
+ "~n Item: ~p", [Scope, Item]),
+ encode(Scope, Item).
+
+decode_name(Config, term_id, TermId) ->
+ case megaco:decode_binary_term_id(Config, TermId) of
+ {ok, TermId2} ->
+ TermId2;
+ {error, _Reason} ->
+ exit({bad_term_id, TermId})
+ end;
+decode_name(_Config, Scope, Item) ->
+ ?d("decode_name(~p) -> entry with"
+ "~n Item: ~p", [Scope, Item]),
+ decode(Scope, Item).
+
+
+
+
+%%----------------------------------------------------------------------
+%% 12.1.1 Package
+%%
+%% Overall description of the package, specifying:
+%%
+%% Package Name: only descriptive
+%%
+%% PackageID: is an identifier
+%%
+%% Description:
+%%
+%% Version:
+%%
+%% A new version of a package can only add additional Properties,
+%% Events, Signals, Statistics and new possible values for an
+%% existing parameter described in the original package. No
+%% deletions or modifications shall be allowed. A version is an
+%% integer in the range from 1 to 99.
+%%
+%% Designed to be extended only (Optional):
+%%
+%% This indicates that the package has been expressly designed to
+%% be extended by others, not to be directly referenced. For
+%% example, the package may not have any function on its own or be
+%% nonsensical on its own. The MG SHOULD NOT publish this
+%% PackageID when reporting packages.
+%%
+%% Extends (Optional): existing package Descriptor
+%%
+%% A package may extend an existing package. The version of the
+%% original package must be specified. When a package extends
+%% another package it shall only add additional Properties,
+%% Events, Signals, Statistics and new possible values for an
+%% existing parameter described in the original package. An
+%% extended package shall not redefine or overload an identifier
+%% defined in the original package and packages it may have
+%% extended (multiple levels of extension). Hence, if package B
+%% version 1 extends package A version 1, version 2 of B will not
+%% be able to extend the A version 2 if A version 2 defines a name
+%% already in B version 1.
+%%
+%%
+%% 12.1.2 Properties
+%%
+%% Properties defined by the package, specifying:
+%%
+%% Property Name: only descriptive
+%%
+%% PropertyID: is an identifier
+%%
+%% Description:
+%%
+%% Type: One of:
+%%
+%% Boolean
+%%
+%% String: UTF-8 string
+%%
+%% Octet String: A number of octets. See Annex A and Annex B.3
+%% for encoding
+%%
+%% Integer: 4 byte signed integer
+%%
+%% Double: 8 byte signed integer
+%%
+%% Character: unicode UTF-8 encoding of a single letter. Could be
+%% more than one octet.
+%%
+%% Enumeration: one of a list of possible unique values (see 12.3)
+%%
+%% Sub-list: a list of several values from a list. The type of
+%% sub-list SHALL also be specified. The type shall be chosen
+%% from the types specified in this section (with the exception of
+%% sub-list). For example, Type: sub-list of enumeration. The
+%% encoding of sub-lists is specified in Annexes A and B.3.
+%%
+%% Possible values:
+%%
+%% A package MUST specify either a specific set of values or a
+%% description of how values are determined. A package MUST also
+%% specify a default value or the default behaviour when the value
+%% is omitted from its descriptor. For example, a package may
+%% specify that procedures related to the property are suspended
+%% when its value is omitted. A default value (but not
+%% procedures) may be specified as provisionable.
+%%
+%% Defined in:
+%%
+%% Which H.248.1 descriptor the property is defined in.
+%% LocalControl is for stream dependent properties.
+%% TerminationState is for stream independent properties. These
+%% are expected to be the most common cases, but it is possible
+%% for properties to be defined in other descriptors.
+%%
+%% Characteristics: Read/Write or both, and (optionally), global:
+%%
+%% Indicates whether a property is read-only, or read-write, and
+%% if it is global. If Global is omitted, the property is not
+%% global. If a property is declared as global, the value of the
+%% property is shared by all Terminations realizing the package.
+%%
+%%
+%% 12.1.3 Events
+%%
+%% Events defined by the package, specifying:
+%%
+%% Event name: only descriptive
+%%
+%% EventID: is an identifier
+%%
+%% Description:
+%%
+%% EventsDescriptor Parameters:
+%%
+%% Parameters used by the MGC to configure the event, and found in
+%% the EventsDescriptor. See 12.2.
+%%
+%% ObservedEventsDescriptor Parameters:
+%%
+%% Parameters returned to the MGC in Notify requests and in
+%% replies to command requests from the MGC that audit
+%% ObservedEventsDescriptor, and found in the
+%% ObservedEventsDescriptor. See 12.2.
+%%
+%%
+%% 12.1.4 Signals
+%%
+%% Signals defined by the package, specifying:
+%%
+%% Signal Name: only descriptive
+%%
+%% SignalID: is an identifier. SignalID is used in a
+%% SignalsDescriptor
+%%
+%% Description
+%%
+%% SignalType: one of:
+%%
+%% OO (On/Off)
+%%
+%% TO (TimeOut)
+%%
+%% BR (Brief)
+%%
+%% NOTE - SignalType may be defined such that it is dependent on the
+%% value of one or more parameters. The package MUST specify a
+%% default signal type. If the default type is TO, the package MUST
+%% specify a default duration which may be provisioned. A default
+%% duration is meaningless for BR.
+%%
+%% Duration: in hundredths of seconds
+%%
+%% Additional Parameters: see 12.2
+%%
+%%
+%% 12.1.5 Statistics
+%%
+%% Statistics defined by the package, specifying:
+%%
+%% Statistic name: only descriptive
+%%
+%% StatisticID: is an identifier
+%%
+%% StatisticID is used in a StatisticsDescriptor
+%%
+%% Description:
+%%
+%% Units: unit of measure, e.g., milliseconds, packets
+%%
+%%
+%% 12.1.6 Procedures
+%%
+%% Additional guidance on the use of the package.
+%%
+%%
+%% 12.2 Guidelines to defining Parameters to Events and Signals
+%%
+%% Parameter Name: only descriptive
+%%
+%% ParameterID: is an identifier. The textual ParameterID of parameters
+%% to Events and Signals shall not start with "EPA" and "SPA",
+%% respectively. The textual ParameterID shall also not be "ST",
+%% "Stream", "SY", "SignalType", "DR", "Duration", "NC",
+%% "NotifyCompletion", "KA", "Keepactive", "EB", "Embed", "DM" or
+%% "DigitMap".
+%%
+%% Type: One of:
+%%
+%% Boolean
+%%
+%% String: UTF-8 octet string
+%% Octet String: A number of octets. See Annex A and Annex B.3 for
+%% encoding
+%%
+%% Integer: 4-octet signed integer
+%%
+%% Double: 8-octet signed integer
+%%
+%% Character: unicode UTF-8 encoding of a single letter. Could be
+%% more than one octet.
+%%
+%% Enumeration: one of a list of possible unique values (see 12.3)
+%%
+%% Sub-list: a list of several values from a list (not supported for
+%% statistics). The type of sub-list SHALL also be specified. The
+%% type shall be chosen from the types specified in this section
+%% (with the exception of sub-list). For example, Type: sub-list of
+%% enumeration. The encoding of sub-lists is specified in Annexes A
+%% and B.3.
+%%
+%% Possible values:
+%%
+%% A package MUST specify either a specific set of values or a
+%% description of how values are determined. A package MUST also
+%% specify a default value or the default behavior when the value is
+%% omitted from its descriptor. For example, a package may specify
+%% that procedures related to the parameter are suspended when it
+%% value is omitted. A default value (but not procedures) may be
+%% specified as provisionable.
+%%
+%% Description:
+%%
+%%
+%% 12.3 Lists
+%%
+%% Possible values for parameters include enumerations. Enumerations
+%% may be defined in a list. It is recommended that the list be IANA
+%% registered so that packages that extend the list can be defined
+%% without concern for conflicting names.
+%%
+%%
+%% 12.4 Identifiers
+%%
+%% Identifiers in text encoding shall be strings of up to 64 characters,
+%% containing no spaces, starting with an alphabetic character and
+%% consisting of alphanumeric characters and/or digits, and possibly
+%% including the special character underscore ("_").
+%%
+%% Identifiers in binary encoding are 2 octets long.
+%%
+%% Both text and binary values shall be specified for each identifier,
+%% including identifiers used as values in enumerated types.
+%%
+%%
+%% 12.5 Package registration
+%%
+%% A package can be registered with IANA for interoperability reasons.
+%% See clause 13 for IANA Considerations.
+%%
+%%----------------------------------------------------------------------
+
+capabilities() ->
+ [{P, capabilities(P)} || P <- packages()].
+
+%% -record(property, {name, type, values, defined_in, characteristics}).
+
+%%----------------------------------------------------------------------
+%% List all known packages
+%% 'native' and 'all' are not real packages
+%%----------------------------------------------------------------------
+
+packages() ->
+ [
+ "g", % Generic
+ "root", % Base Root Package
+ "tonegen", % Tone Generator Package
+ "tonedet", % Tone Detection Package
+ "dg", % Basic DTMF Generator Package
+ "dd", % DTMF detection Package
+ "cg", % Call Progress Tones Generator Package
+ "cd", % Call Progress Tones Detection Package
+ "al", % Analog Line Supervision Package
+ "ct", % Basic Continuity Package
+ "nt", % Network Package
+ "rtp", % RTP Package
+ "swb", % SwitchBoard Package
+ "tdmc", % TDM Circuit Package
+ "" % Native pseudo package
+ ].
+
+%%----------------------------------------------------------------------
+%% List all matching capabilities
+%%----------------------------------------------------------------------
+
+capabilities(Package) ->
+ case Package of
+ "g" -> capabilities_g();
+ "root" -> capabilities_root();
+ "tonegen" -> capabilities_tonegen();
+ "tonedet" -> capabilities_tonedet();
+ "dg" -> capabilities_dg();
+ "dd" -> capabilities_dd();
+ "cg" -> capabilities_cg();
+ "cd" -> capabilities_cd();
+ "al" -> capabilities_al();
+ "ct" -> capabilities_ct();
+ "nt" -> capabilities_nt();
+ "rtp" -> capabilities_rtp();
+ "swb" -> capabilities_swb();
+ "tdmc" -> capabilities_tdmc();
+ "" -> capabilities_native()
+ end.
+
+%%----------------------------------------------------------------------
+%% Decode package name to internal form
+%% Scope ::= property | event | signal | statistics
+%%----------------------------------------------------------------------
+
+decode(mid, Package) ->
+ decode_mid(Package);
+decode(package, Package) ->
+ decode_package(Package);
+decode(profile, Package) ->
+ decode_profile(Package);
+decode(dialplan, Dialplan) ->
+ decode_dialplan(Dialplan);
+decode(Scope, [A, B | Item]) when is_atom(Scope) ->
+ ?d("decode(~p) -> entry with"
+ "~n A: ~p"
+ "~n B: ~p"
+ "~n Item: ~p", [Scope, A, B, Item]),
+ case decode_package([A, B]) of
+ "" ->
+ ?d("decode -> \"no\" package",[]),
+ decode_item(Scope, [A, B], Item);
+ Package ->
+ ?d("decode -> Package: ~p", [Package]),
+ Package ++ "/" ++ decode_item(Scope, [A, B], Item)
+ end;
+decode({Scope, [A, B | Item]}, SubItem) when is_atom(Scope) ->
+ ?d("decode(~p) -> entry with"
+ "~n A: ~p"
+ "~n B: ~p"
+ "~n Item: ~p"
+ "~n SubItem: ~p", [Scope, A, B, Item, SubItem]),
+ decode_item({Scope, Item}, [A, B], SubItem).
+
+decode_item(Scope, [A, B], Item) ->
+ ?d("decode_item -> entry",[]),
+ case A of
+ 16#00 ->
+ case B of
+ 16#01 -> decode_g(Scope, Item);
+ 16#02 -> decode_root(Scope, Item);
+ 16#03 -> decode_tonegen(Scope, Item);
+ 16#04 -> decode_tonedet(Scope, Item);
+ 16#05 -> decode_dg(Scope, Item);
+ 16#06 -> decode_dd(Scope, Item);
+ 16#07 -> decode_cg(Scope, Item);
+ 16#08 -> decode_cd(Scope, Item);
+ 16#09 -> decode_al(Scope, Item);
+ 16#0a -> decode_ct(Scope, Item);
+ 16#0b -> decode_nt(Scope, Item);
+ 16#0c -> decode_rtp(Scope, Item);
+ 16#0d -> decode_tdmc(Scope, Item);
+ 16#00 -> decode_native(Scope, Item)
+ end;
+ 16#fe ->
+ case B of
+ %% Proprietary extension
+ 16#fe -> decode_swb(Scope, Item)
+ end;
+ 16#ff ->
+ case B of
+ 16#ff when Item =:= [16#ff, 16#ff] -> "*"
+ end
+ end.
+
+decode_package(Package) ->
+ ?d("decode_package -> entry with"
+ "~n Package: ~p", [Package]),
+ [A, B] = Package,
+ case A of
+ 16#00 ->
+ case B of
+ 16#01 -> "g";
+ 16#02 -> "root";
+ 16#03 -> "tonegen";
+ 16#04 -> "tonedet";
+ 16#05 -> "dg";
+ 16#06 -> "dd";
+ 16#07 -> "cg";
+ 16#08 -> "cd";
+ 16#09 -> "al";
+ 16#0a -> "ct";
+ 16#0b -> "nt";
+ 16#0c -> "rtp";
+ 16#0d -> "tdmc";
+ 16#00 -> ""
+ end;
+ 16#fe ->
+ case B of
+ 16#fe -> "swb"
+ end;
+ 16#ff ->
+ case B of
+ 16#ff -> "*"
+ end
+ end.
+
+decode_profile([A, B]) ->
+ case A of
+ 16#00 ->
+ case B of
+ 16#fe -> "resgw";
+ _ -> "profile" ++ [A + $0, B + $0]
+ end;
+ _ ->
+ "profile" ++ [A + $0, B + $0]
+ end.
+
+decode_dialplan([A, B]) ->
+ "dialplan" ++ [A + $0, B + $0].
+
+decode_mid(Mid) ->
+ case Mid of
+ {domainName, DN} ->
+ Lower = to_lower(DN#'DomainName'.name),
+ {domainName, DN#'DomainName'{name = Lower}};
+ {deviceName, PathName} ->
+ Lower = to_lower(PathName),
+ {deviceName, Lower};
+ Other ->
+ Other
+ end.
+
+to_lower(Chars) ->
+ [?LOWER(Char) || Char <- Chars].
+
+%%----------------------------------------------------------------------
+%% Encode package name from internal form
+%% Scope ::= property | event | signal | statistics
+%%----------------------------------------------------------------------
+
+encode(mid, Package) ->
+ encode_mid(Package);
+encode(package, Package) ->
+ encode_package(Package);
+encode(profile, Profile) ->
+ encode_profile(Profile);
+encode(dialplan, Dialplan) ->
+ encode_dialplan(Dialplan);
+encode(Scope, PackageItem) when is_atom(Scope) ->
+ ?d("encode(~p) -> entry with"
+ "~n PackageItem: ~p", [Scope, PackageItem]),
+ case string:tokens(PackageItem, [$/]) of
+ [Package, Item] ->
+ ?d("encode -> "
+ "~n Package: ~p"
+ "~n Item: ~p", [Package, Item]),
+ encode_package(Package) ++ encode_item(Scope, Package, Item);
+ [Item] ->
+ ?d("encode -> Item: ~p", [Item]),
+ [16#00, 16#00 | encode_native(Scope, Item)]
+ end;
+encode({Scope, PackageItem}, SubItem) when is_atom(Scope) ->
+ ?d("encode(~p) -> entry with"
+ "~n PackageItem: ~p"
+ "~n SubItem: ~p", [Scope, PackageItem, SubItem]),
+ case string:tokens(PackageItem, [$/]) of
+ [Package, Item] ->
+ ?d("encode -> "
+ "~n Package: ~p"
+ "~n Item: ~p", [Package, Item]),
+ encode_item({Scope, Item}, Package, SubItem);
+ [_Item] ->
+ ?d("encode -> _Item: ~p", [_Item]),
+ encode_native(Scope, SubItem)
+ end.
+
+encode_item(_Scope, _Package, "*") ->
+ [16#ff, 16#ff];
+encode_item(Scope, Package, Item) ->
+ ?d("encode_item(~s) -> entry", [Package]),
+ case Package of
+ "g" -> encode_g(Scope, Item);
+ "root" -> encode_root(Scope, Item);
+ "tonegen" -> encode_tonegen(Scope, Item);
+ "tonedet" -> encode_tonedet(Scope, Item);
+ "dg" -> encode_dg(Scope, Item);
+ "dd" -> encode_dd(Scope, Item);
+ "cg" -> encode_cg(Scope, Item);
+ "cd" -> encode_cd(Scope, Item);
+ "al" -> encode_al(Scope, Item);
+ "ct" -> encode_ct(Scope, Item);
+ "nt" -> encode_nt(Scope, Item);
+ "rtp" -> encode_rtp(Scope, Item);
+ "tdmc" -> encode_tdmc(Scope, Item);
+ "swb" -> encode_swb(Scope, Item)
+ end.
+
+encode_package(Package) ->
+ case Package of
+ "g" -> [16#00, 16#01];
+ "root" -> [16#00, 16#02];
+ "tonegen" -> [16#00, 16#03];
+ "tonedet" -> [16#00, 16#04];
+ "dg" -> [16#00, 16#05];
+ "dd" -> [16#00, 16#06];
+ "cg" -> [16#00, 16#07];
+ "cd" -> [16#00, 16#08];
+ "al" -> [16#00, 16#09];
+ "ct" -> [16#00, 16#0a];
+ "nt" -> [16#00, 16#0b];
+ "rtp" -> [16#00, 16#0c];
+ "tdmc" -> [16#00, 16#0d];
+ "" -> [16#00, 16#00];
+ "*" -> [16#ff, 16#ff];
+ "swb" -> [16#fe, 16#fe]
+ end.
+
+encode_profile(Profile) ->
+ case Profile of
+ "resgw" ->
+ [16#00, 16#fe];
+ [$p, $r, $o, $f, $i, $l, $e | Name] ->
+ case Name of
+ [A, B] -> [A - $0, B - $0];
+ [B] -> [0, B - $0];
+ [] -> [0, 0]
+ end
+ end.
+
+encode_dialplan(Dialplan) ->
+ case Dialplan of
+ [$d, $i, $a, $l, $p, $l, $a, $n | Name] ->
+ case Name of
+ [A, B] -> [A - $0, B - $0];
+ [B] -> [0, B - $0];
+ [] -> [0, 0]
+ end
+ end.
+
+encode_mid(Mid) ->
+ Mid.
+
+
+%%----------------------------------------------------------------------
+%% Name: g - Generic
+%% Version: 1
+%% Extends: None
+%% Purpose: Generic package for commonly encountered items
+%%----------------------------------------------------------------------
+
+capabilities_g() ->
+ [
+ {event, "cause"},
+ {event, "sc"}
+ ].
+
+encode_g(event, Item) ->
+ case Item of
+ "cause" -> [16#00, 16#01];
+ "sc" -> [16#00, 16#02]
+ end;
+
+encode_g({event_parameter, Item}, SubItem) ->
+ case Item of
+ "cause" ->
+ case SubItem of
+ "Generalcause" -> [16#00, 16#01];
+ "Failurecause" -> [16#00, 16#02]
+ end;
+ "sc" ->
+ case SubItem of
+ "SigID" -> [16#00, 16#01];
+ "Meth" -> [16#00, 16#02];
+ "SLID" -> [16#00, 16#03]
+ end
+ end.
+
+decode_g(event, Item) ->
+ case Item of
+ [16#00, 16#01] -> "cause";
+ [16#00, 16#02] -> "sc"
+ end;
+
+decode_g({event_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#01] -> % Event: cause
+ case SubItem of
+ [16#00, 16#01] -> "Generalcause";
+ [16#00, 16#02] -> "Failurecause"
+ end;
+
+ [16#00, 16#02] -> % Event: sc
+ case SubItem of
+ [16#00, 16#01] -> "SigID";
+ [16#00, 16#02] -> "Meth";
+ [16#00, 16#03] -> "SLID"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: root - Base Root Package
+%% Version: 1
+%% Extends: None
+%% Purpose: This package defines Gateway wide properties.
+%%----------------------------------------------------------------------
+
+capabilities_root() ->
+ [
+ {property, "maxNumberOfContexts"},
+ {property, "maxTerminationsPerContext"},
+ {property, "normalMGExecutionTime"},
+ {property, "normalMGCExecutionTime"},
+ {property, "MGProvisionalResponseTimerValue"},
+ {property, "MGCProvisionalResponseTimerValue"}
+ ].
+
+encode_root(Scope, Item) ->
+ case Scope of
+ property ->
+ case Item of
+ "maxNumberOfContexts" -> [16#00, 16#01];
+ "maxTerminationsPerContext" -> [16#00, 16#02];
+ "normalMGExecutionTime" -> [16#00, 16#03];
+ "normalMGCExecutionTime" -> [16#00, 16#04];
+ "MGProvisionalResponseTimerValue" -> [16#00, 16#05];
+ "MGCProvisionalResponseTimerValue" -> [16#00, 16#06]
+ end
+ end.
+
+decode_root(Scope, Item) ->
+ case Scope of
+ property ->
+ case Item of
+ [16#00, 16#01] -> "maxNumberOfContexts";
+ [16#00, 16#02] -> "maxTerminationsPerContext";
+ [16#00, 16#03] -> "normalMGExecutionTime";
+ [16#00, 16#04] -> "normalMGCExecutionTime";
+ [16#00, 16#05] -> "MGProvisionalResponseTimerValue";
+ [16#00, 16#06] -> "MGCProvisionalResponseTimerValue"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: tonegen - Tone Generator Package
+%% Version: 1
+%% Extends: None
+%% Purpose: This package defines signals to generate audio tones.
+%% This package does not specify parameter values. It is
+%% intended to be extendable. Generally, tones are defined
+%% as an individual signal with a parameter, ind,
+%% representing "interdigit" time delay, and a tone id to
+%% be used with playtones. A tone id should be kept
+%% consistent with any tone generation for the same tone.
+%% MGs are expected to be provisioned with the characteristics
+%% of appropriate tones for the country in which the MG is located.
+%%----------------------------------------------------------------------
+
+capabilities_tonegen() ->
+ [
+ {signal, "pt"}
+ ].
+
+encode_tonegen(signal, Item) ->
+ case Item of
+ "pt" -> [16#00, 16#01]
+ end;
+
+encode_tonegen({signal_parameter, Item}, SubItem) ->
+ case Item of
+ "pt" ->
+ case SubItem of
+ "tl" -> [16#00, 16#01];
+ "ind" -> [16#00, 16#02]
+ end
+ end.
+
+decode_tonegen(signal, Item) ->
+ case Item of
+ [16#00, 16#01] -> "pt"
+ end;
+
+decode_tonegen({signal_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#01] -> % Event: pt
+ case SubItem of
+ [16#00, 16#01] -> "tl";
+ [16#00, 16#02] -> "ind"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: tonedet - Tone Detection Package
+%% Version: 1
+%% Extends: None
+%% Purpose: This Package defines events for audio tone detection.
+%% Tones are selected by name (tone id). MGs are expected
+%% to be provisioned with the characteristics of appropriate
+%% tones for the country in which the MG is located.
+%%
+%% This package does not specify parameter values.
+%% It is intended to be extendable.
+%%----------------------------------------------------------------------
+
+capabilities_tonedet() ->
+ [
+ {event, "std"},
+ {event, "etd"},
+ {event, "ltd"}
+ ].
+
+encode_tonedet(event, Item) ->
+ case Item of
+ "std" -> [16#00, 16#01];
+ "etd" -> [16#00, 16#02];
+ "ltd" -> [16#00, 16#03]
+ end;
+
+encode_tonedet({event_parameter, Item}, SubItem) ->
+ case Item of
+ "std" ->
+ case SubItem of
+ "tl" -> [16#00, 16#01];
+ "tid" -> [16#00, 16#03]
+ end;
+ "etd" ->
+ case SubItem of
+ "tl" -> [16#00, 16#01];
+ "tid" -> [16#00, 16#03];
+ "dur" -> [16#00, 16#02]
+ end;
+ "ltd" ->
+ case SubItem of
+ "tl" -> [16#00, 16#01];
+ "dur" -> [16#00, 16#02];
+ "tid" -> [16#00, 16#03]
+ end
+ end.
+
+decode_tonedet(event, Item) ->
+ case Item of
+ [16#00, 16#01] -> "std";
+ [16#00, 16#02] -> "etd";
+ [16#00, 16#03] -> "ltd"
+ end;
+
+decode_tonedet({event_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#01] -> % Event std
+ case SubItem of
+ [16#00, 16#01] -> "tl";
+ [16#00, 16#03] -> "tid"
+ end;
+ [16#00, 16#02] -> % Event etd
+ case SubItem of
+ [16#00, 16#01] -> "tl";
+ [16#00, 16#03] -> "tid";
+ [16#00, 16#02] -> "dur"
+ end;
+ [16#00, 16#03] -> % Event ltd
+ case SubItem of
+ [16#00, 16#01] -> "tl";
+ [16#00, 16#02] -> "dur";
+ [16#00, 16#03] -> "tid"
+ end
+ end.
+
+%%----------------------------------------------------------------------
+%% Name: dg - Basic DTMF Generator Package
+%% Version: 1
+%% Extends: tonegen version 1
+%% Purpose: This package defines the basic DTMF tones as signals and
+%% extends the allowed values of parameter tl of playtone
+%% in tonegen.
+%%----------------------------------------------------------------------
+
+capabilities_dg() ->
+ [
+ {signal, "d0"},
+ {signal, "d1"},
+ {signal, "d2"},
+ {signal, "d3"},
+ {signal, "d4"},
+ {signal, "d5"},
+ {signal, "d6"},
+ {signal, "d7"},
+ {signal, "d8"},
+ {signal, "d9"},
+ {signal, "ds"},
+ {signal, "do"},
+ {signal, "da"},
+ {signal, "db"},
+ {signal, "dc"},
+ {signal, "dd"}
+ ].
+
+encode_dg(Scope, Item) ->
+ case Scope of
+ signal ->
+ case Item of
+ "d0" -> [16#00, 16#10];
+ "d1" -> [16#00, 16#11];
+ "d2" -> [16#00, 16#12];
+ "d3" -> [16#00, 16#13];
+ "d4" -> [16#00, 16#14];
+ "d5" -> [16#00, 16#15];
+ "d6" -> [16#00, 16#16];
+ "d7" -> [16#00, 16#17];
+ "d8" -> [16#00, 16#18];
+ "d9" -> [16#00, 16#19];
+ "ds" -> [16#00, 16#20];
+ "do" -> [16#00, 16#21];
+ "da" -> [16#00, 16#1a];
+ "db" -> [16#00, 16#1b];
+ "dc" -> [16#00, 16#1c];
+ "dd" -> [16#00, 16#1d]
+ end
+ end.
+
+decode_dg(Scope, Item) ->
+ case Scope of
+ signal ->
+ case Item of
+ [16#00, 16#10] -> "d0";
+ [16#00, 16#11] -> "d1";
+ [16#00, 16#12] -> "d2";
+ [16#00, 16#13] -> "d3";
+ [16#00, 16#14] -> "d4";
+ [16#00, 16#15] -> "d5";
+ [16#00, 16#16] -> "d6";
+ [16#00, 16#17] -> "d7";
+ [16#00, 16#18] -> "d8";
+ [16#00, 16#19] -> "d9";
+ [16#00, 16#20] -> "ds";
+ [16#00, 16#21] -> "do";
+ [16#00, 16#1a] -> "da";
+ [16#00, 16#1b] -> "db";
+ [16#00, 16#1c] -> "dc";
+ [16#00, 16#1d] -> "dd"
+ end
+ end.
+
+%%----------------------------------------------------------------------
+%% Name: dd - DTMF detection Package
+%% Version: 1
+%% Extends: tonedet version 1
+%% Purpose: This package defines the basic DTMF tones detection.
+%% Tones are selected by name (tone id). MGs are expected
+%% to be provisioned with the characteristics of appropriate
+%% tones for the country in which the MG is located.
+%%
+%% This package does not specify parameter values.
+%% It is intended to be extendable.
+%%
+%% Additional tone id values are all tone ids described in package dg
+%% (basic DTMF generator package).
+%%
+%% The following table maps DTMF events to digit map symbols as described
+%% in section 7.1.14.
+%%
+%% _________________________________
+%% | DTMF Event | Symbol |
+%% | d0 | "0" |
+%% | d1 | "1" |
+%% | d2 | "2" |
+%% | d3 | "3" |
+%% | d4 | "4" |
+%% | d5 | "5" |
+%% | d6 | "6" |
+%% | d7 | "7" |
+%% | d8 | "8" |
+%% | d9 | "9" |
+%% | da | "A" or "a"|
+%% | db | "B" or "b"|
+%% | dc | "C" or "c"|
+%% | dd | "D" or "d"|
+%% | ds | "E" or "e"|
+%% | do | "F" or "f"|
+%% |___________________|____________|
+%%
+%%----------------------------------------------------------------------
+
+capabilities_dd() ->
+ [
+ {event, "ce"}
+ ].
+
+encode_dd(event, Item) ->
+ case Item of
+ "ce" -> [16#00, 16#04]
+ end;
+
+encode_dd({event_parameter, Item}, SubItem) ->
+ case Item of
+ "ce" ->
+ case SubItem of
+ "ds" -> [16#00, 16#01];
+ "Meth" -> [16#00, 16#03]
+ end
+ end.
+
+decode_dd(event, Item) ->
+ case Item of
+ [16#00, 16#04] -> "ce"
+ end;
+
+decode_dd({event_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#04] -> % Event ce
+ case SubItem of
+ [16#00, 16#01] -> "ds";
+ [16#00, 16#03] -> "Meth"
+ end
+ end.
+
+%%----------------------------------------------------------------------
+%% Name: cg - Call Progress Tones Generator Package
+%% Version: 1
+%% Extends: tonegen version 1
+%% Purpose: This package defines the basic call progress tones as signals
+%% and extends the allowed values of the tl parameter of
+%% playtone in tonegen.
+%%----------------------------------------------------------------------
+
+capabilities_cg() ->
+ [
+ {signal, "dt"},
+ {signal, "rt"},
+ {signal, "bt"},
+ {signal, "ct"},
+ {signal, "sit"},
+ {signal, "wt"},
+ {signal, "prt"},
+ {signal, "cw"},
+ {signal, "cr"}
+ ].
+
+
+encode_cg(Scope, Item) ->
+ case Scope of
+ signal ->
+ case Item of
+ "dt" -> [16#00, 16#30];
+ "rt" -> [16#00, 16#31];
+ "bt" -> [16#00, 16#32];
+ "ct" -> [16#00, 16#33];
+ "sit" -> [16#00, 16#34];
+ "wt" -> [16#00, 16#35];
+ "prt" -> [16#00, 16#36];
+ "cw" -> [16#00, 16#37];
+ "cr" -> [16#00, 16#38]
+ end
+ end.
+
+decode_cg(Scope, Item) ->
+ case Scope of
+ signal ->
+ case Item of
+ [16#00, 16#30] -> "dt";
+ [16#00, 16#31] -> "rt";
+ [16#00, 16#32] -> "bt";
+ [16#00, 16#33] -> "ct";
+ [16#00, 16#34] -> "sit";
+ [16#00, 16#35] -> "wt";
+ [16#00, 16#36] -> "prt";
+ [16#00, 16#37] -> "cw";
+ [16#00, 16#38] -> "cr"
+ end
+ end.
+
+%%----------------------------------------------------------------------
+%% Name: cd - Call Progress Tones Detection Package
+%% Version: 1
+%% Extends: tonedet version 1
+%% Purpose: This package defines the basic call progress detection tones.
+%% This Package extends the possible values of tone id
+%% in the "start tone detected", "end tone detected" and
+%% "long tone detected" events.
+%% Additional values
+%% tone id values are defined for start tone detected,
+%% end tone detected and long tone detected with
+%% the same values as those in package cg (call
+%% progress tones generation package).
+%%
+%% The required set of tone ids corresponds to Recommendation E.180/Q.35
+%% [ITU-T Recommendation E.180/Q.35 (1998)]. See Recommendation E.180/Q.35
+%% for definition of the meanings of these tones.
+%%----------------------------------------------------------------------
+
+capabilities_cd() ->
+ [
+ {event, "dt"},
+ {event, "rt"},
+ {event, "bt"},
+ {event, "ct"},
+ {event, "sit"},
+ {event, "wt"},
+ {event, "prt"},
+ {event, "cw"},
+ {event, "cr"}
+ ].
+
+
+encode_cd(Scope, Item) ->
+ case Scope of
+ event ->
+ case Item of
+ "dt" -> [16#00, 16#30];
+ "rt" -> [16#00, 16#31];
+ "bt" -> [16#00, 16#32];
+ "ct" -> [16#00, 16#33];
+ "sit"-> [16#00, 16#34];
+ "wt" -> [16#00, 16#35];
+ "prt"-> [16#00, 16#36];
+ "cw" -> [16#00, 16#37];
+ "cr" -> [16#00, 16#38]
+ end
+ end.
+
+decode_cd(Scope, Item) ->
+ case Scope of
+ event ->
+ case Item of
+ [16#00, 16#30] -> "dt";
+ [16#00, 16#31] -> "rt";
+ [16#00, 16#32] -> "bt";
+ [16#00, 16#33] -> "ct";
+ [16#00, 16#34] -> "sit";
+ [16#00, 16#35] -> "wt";
+ [16#00, 16#36] -> "prt";
+ [16#00, 16#37] -> "cw";
+ [16#00, 16#38] -> "cr"
+ end
+ end.
+
+%%----------------------------------------------------------------------
+%% Name: al - Analog Line Supervision Package
+%% Version: 1
+%% Extends: None
+%% Purpose: This package defines events and signals for an analog line.
+%%----------------------------------------------------------------------
+
+capabilities_al() ->
+ [
+ {event, "on"},
+ {event, "of"},
+ {event, "fl"},
+ {signal, "ri"}
+ ].
+
+encode_al(event, Item) ->
+ ?d("encode_al(event) -> entry with"
+ "~n Item: ~p", [Item]),
+ case Item of
+ "on" -> [16#00, 16#04];
+ "of" -> [16#00, 16#05];
+ "fl" -> [16#00, 16#06]
+ end;
+
+encode_al({event_parameter, Item}, SubItem) ->
+ ?d("encode_al({event_parameter,~p}) -> entry with"
+ "~n SubItem: ~p", [Item, SubItem]),
+ case Item of
+ "on" ->
+ case SubItem of
+ "strict" -> [16#00, 16#01];
+ "init" -> [16#00, 16#02]
+ end;
+ "of" ->
+ case SubItem of
+ "strict" -> [16#00, 16#01];
+ "init" -> [16#00, 16#02]
+ end;
+ "fl" ->
+ case SubItem of
+ "mindur" -> [16#00, 16#04];
+ "maxdur" -> [16#00, 16#05]
+ end
+ end;
+
+encode_al(signal, Item) ->
+ ?d("encode_al(signal) -> entry with"
+ "~n Item: ~p", [Item]),
+ case Item of
+ "ri" -> [16#00, 16#02]
+ end;
+
+encode_al({signal_parameter, Item}, SubItem) ->
+ ?d("encode_al({signal_parameter,~p}) -> entry with"
+ "~n SubItem: ~p", [Item, SubItem]),
+ case Item of
+ "ri" ->
+ case SubItem of
+ "cad" -> [16#00, 16#06];
+ "freq" -> [16#00, 16#07]
+ end
+ end.
+
+decode_al(event, SubItem) ->
+ ?d("decode_al(event) -> entry with"
+ "~n SubItem: ~p", [SubItem]),
+ case SubItem of
+ [16#00, 16#04] -> "on";
+ [16#00, 16#05] -> "of";
+ [16#00, 16#06] -> "fl"
+ end;
+
+decode_al({event_parameter, Item}, SubItem) ->
+ ?d("decode_al({event_parameter,~p}) -> entry with"
+ "~n SubItem: ~p", [Item, SubItem]),
+ case Item of
+ [16#00,16#04] -> %% Event: on
+ case SubItem of
+ [16#00, 16#01] -> "strict";
+ [16#00, 16#02] -> "init"
+ end;
+ [16#00,16#05] -> %% Event: of
+ case SubItem of
+ [16#00, 16#01] -> "strict";
+ [16#00, 16#02] -> "init"
+ end;
+ [16#00,16#06] -> %% Event: fl
+ case SubItem of
+ [16#00, 16#04] -> "mindur";
+ [16#00, 16#05] -> "maxdur"
+ end
+ end;
+
+decode_al(signal, SubItem) ->
+ ?d("decode_al(signal) -> entry with"
+ "~n SubItem: ~p", [SubItem]),
+ case SubItem of
+ [16#00, 16#02] -> "ri"
+ end;
+
+decode_al({signal_parameter, Item}, SubItem) ->
+ ?d("decode_al({signal_parameter,~p}) -> entry with"
+ "~n SubItem: ~p", [Item, SubItem]),
+ case Item of
+ [16#00,16#02] -> %% Event: ri
+ case SubItem of
+ [16#00, 16#06] -> "cad";
+ [16#00, 16#07] -> "freq"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: ct - Basic Continuity Package
+%% Version: 1
+%% Extends: None
+%% Purpose: This package defines events and signals for continuity test.
+%% The continuity test includes provision of either a loopback
+%% or transceiver functionality.
+%%----------------------------------------------------------------------
+
+capabilities_ct() ->
+ [
+ {event, "cmp"},
+ {signal, "ct"},
+ {signal, "rsp"}
+ ].
+
+encode_ct(event, Item) ->
+ case Item of
+ "cmp" -> [16#00, 16#05]
+ end;
+encode_ct({event_parameter, Item}, SubItem) ->
+ case Item of
+ "cmp" ->
+ case SubItem of
+ "res" -> [16#00, 16#08]
+ end
+ end;
+encode_ct(signal, Item) ->
+ case Item of
+ "ct" -> [16#00, 16#03];
+ "rsp" -> [16#00, 16#04]
+ end.
+
+decode_ct(event, Item) ->
+ case Item of
+ [16#00, 16#05] -> "cmp"
+ end;
+decode_ct({event_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#05] -> % Event cmp
+ case SubItem of
+ [16#00, 16#08] -> "res"
+ end
+ end;
+decode_ct(signal, Item) ->
+ case Item of
+ [16#00, 16#03] -> "ct";
+ [16#00, 16#04] -> "rsp"
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: nt - Network Package
+%% Version: 1
+%% Extends: None
+%% Purpose: This package defines properties of network terminations
+%% independent of network type.
+%%----------------------------------------------------------------------
+
+capabilities_nt() ->
+ [
+ {property, "jit"},
+ {event, "netfail"},
+ {event, "qualert"},
+ {statistics, "dur"},
+ {statistics, "os"},
+ {statistics, "or"}
+ ].
+
+encode_nt(property, Item) ->
+ case Item of
+ "jit" -> [16#00, 16#07]
+ end;
+encode_nt(event, Item) ->
+ case Item of
+ "netfail" -> [16#00, 16#05];
+ "qualert" -> [16#00, 16#06]
+ end;
+encode_nt({event_parameter, Item}, SubItem) ->
+ case Item of
+ "netfail" ->
+ case SubItem of
+ "cs" -> [16#00, 16#01]
+ end;
+ "qualert" ->
+ case SubItem of
+ "th" -> [16#00, 16#01]
+ end
+ end;
+encode_nt(statistics, Item) ->
+ case Item of
+ "dur" -> [16#00, 16#01];
+ "os" -> [16#00, 16#02];
+ "or" -> [16#00, 16#03]
+ end.
+
+decode_nt(property, Item) ->
+ case Item of
+ [16#00, 16#07] -> "jit"
+ end;
+decode_nt(event, Item) ->
+ case Item of
+ [16#00, 16#05] -> "netfail";
+ [16#00, 16#06] -> "qualert"
+ end;
+decode_nt({event_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#05] -> % Event netfail
+ case SubItem of
+ [16#00, 16#01] -> "cs"
+ end;
+ [16#00, 16#06] -> % Event qualert
+ case Item of
+ [16#00, 16#01] -> "th"
+ end
+ end;
+decode_nt(statistics, Item) ->
+ case Item of
+ [16#00, 16#01] -> "dur";
+ [16#00, 16#02] -> "os";
+ [16#00, 16#03] -> "or"
+ end.
+
+%%----------------------------------------------------------------------
+%% Name: rtp - RTP Package
+%% Version: 1
+%% Extends: nt version 1
+%% Purpose: This package is used to support packet based multimedia
+%% data transfer by means of the Real-time Transport Protocol
+%% (RTP) [RFC 1889].
+%%----------------------------------------------------------------------
+
+capabilities_rtp() ->
+ [
+ {event, "pltrans"},
+ {statistics, "ps"},
+ {statistics, "pr"},
+ {statistics, "pl"},
+ {statistics, "jit"},
+ {statistics, "delay"}
+ ].
+
+encode_rtp(event, Item) ->
+ case Item of
+ "pltrans" -> [16#00, 16#01]
+ end;
+encode_rtp({event_parameter, Item}, SubItem) ->
+ case Item of
+ "pltrans" ->
+ case SubItem of
+ "rtppltype" -> [16#00, 16#01]
+ end
+ end;
+encode_rtp(statistics, Item) ->
+ case Item of
+ "ps" -> [16#00, 16#04];
+ "pr" -> [16#00, 16#05];
+ "pl" -> [16#00, 16#06];
+ "jit" -> [16#00, 16#07];
+ "delay" -> [16#00, 16#08]
+ end.
+
+decode_rtp(event, Item) ->
+ case Item of
+ [16#00, 16#01] -> "pltrans"
+ end;
+decode_rtp({event_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#01] -> % Event pltrans
+ case SubItem of
+ [16#00, 16#01] -> "rtppltype"
+ end
+ end;
+decode_rtp(statistics, Item) ->
+ case Item of
+ [16#00, 16#04] -> "ps";
+ [16#00, 16#05] -> "pr";
+ [16#00, 16#06] -> "pl";
+ [16#00, 16#07] -> "jit";
+ [16#00, 16#08] -> "delay"
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: tdmc - TDM Circuit Package
+%% Version: 1
+%% Extends: nt version 1
+%% Purpose: This package is used to support TDM circuit terminations.
+%%----------------------------------------------------------------------
+
+capabilities_tdmc() ->
+ [
+ {property, "ec"},
+ {property, "gain"}
+ ].
+
+encode_tdmc(Scope, Item) ->
+ case Scope of
+ property ->
+ case Item of
+ "ec" -> [16#00, 16#08];
+ "gain" -> [16#00, 16#0a]
+ end
+ end.
+
+decode_tdmc(Scope, Item) ->
+ case Scope of
+ property ->
+ case Item of
+ [16#00, 16#08] -> "ec";
+ [16#00, 16#0a] -> "gain"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: swb - SwitchBoard Package
+%% Version: 1
+%% Extends: none
+%% Purpose: This package is used to support SwitchBoard specials
+%%----------------------------------------------------------------------
+
+capabilities_swb() ->
+ [
+ {statistics, "fs"}, % Free slots
+ {statistics, "as"} % Allocated slots
+ ].
+
+encode_swb(Scope, Item) ->
+ case Scope of
+ statistics ->
+ case Item of
+ "fs" -> [16#00, 16#00];
+ "as" -> [16#00, 16#01]
+ end
+ end.
+
+decode_swb(Scope, Item) ->
+ case Scope of
+ statistics ->
+ case Item of
+ [16#00, 16#00] -> "fs";
+ [16#00, 16#01] -> "as"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: native - Pseudo package
+%% Version: 1
+%% Extends: None
+%% Purpose: Native tags for media stream properties
+%%
+%% Parameters for Local descriptors and Remote descriptors are
+%% specified as tag-value pairs if binary encoding is used for the
+%% protocol. This annex contains the property names (PropertyID), the
+%% tags (Property Tag), type of the property (Type) and the values
+%% (Value).Values presented in the Value field when the field contains
+%% references shall be regarded as "information". The reference
+%% contains the normative values. If a value field does not contain a
+%% reference then the values in that field can be considered as
+%% "normative".
+%%
+%% Tags are given as hexadecimal numbers in this annex. When setting
+%% the value of a property, a MGC may underspecify the value according
+%% to one of the mechanisms specified in section 7.1.1.
+%%
+%% For type "enumeration" the value is represented by the value in brack-
+%% ets, e.g., Send(0), Receive(1).
+%%----------------------------------------------------------------------
+%%
+%% C.6. IP
+%%
+%% ________________________________________________________________
+%% | PropertyID| Tag | Type | Value |
+%% | IPv4 | 6001 | 32 BITS | Ipv4Address |
+%% | IPv6 | 6002 | 128 BITS | IPv6 Address |
+%% | Port | 6003 | Unsigned Int| Port |
+%% | Porttype | 6004 | Enumerated | TCP(0),UDP(1),SCTP(2)|
+%% |___________|____________|______________|_______________________|
+%%
+%%
+%% C.11. SDP Equivalents
+%%
+%% ______________________________________________________________
+%% | PropertyID| Tag | Type | Value |
+%% | SDP_V | B001| STRING| Protocol Version |
+%% | SDP_O | B002| STRING| Owner-creator and session ID |
+%% | SDP_S | B003| STRING| Sesson name |
+%% | SDP_I | B004| STRING| Session identifier |
+%% | SDP_U | B005| STRING| URI of descriptor |
+%% | SDC_E | B006| STRING| email address |
+%% | SDP_P | B007| STRING| phone number |
+%% | SDP_C | B008| STRING| Connection information |
+%% | SDP_B | B009| STRING| Bandwidth Information |
+%% | SDP_Z | B00A| STRING| time zone adjustment |
+%% | SDP_K | B00B| STRING| Encryption Key |
+%% | SDP_A | B00C| STRING| Zero or more session attributes|
+%% | SDP_T | B00D| STRING| Active Session Time |
+%% | SDP_R | B00E| STRING| Zero or more repeat times |
+%% | SDP_M | B00F| STRING| Media name and transport addr |
+%% | | | | Reference: IETF RFC 2327 |
+%% |___________|______|________|_________________________________|
+%%
+%%----------------------------------------------------------------------
+
+capabilities_native() ->
+ [
+ %% C.6. IP
+ {property, "IPv4"},
+ {property, "IPv6"},
+ {property, "Port"},
+ {property, "Porttype"},
+
+ %% C.11. SDP Equivalents
+ {property, "v"},
+ {property, "o"},
+ {property, "s"},
+ {property, "i"},
+ {property, "u"},
+ {property, "e"},
+ {property, "p"},
+ {property, "c"},
+ {property, "b"},
+ {property, "z"},
+ {property, "k"},
+ {property, "a"},
+ {property, "t"},
+ {property, "r"},
+ {property, "m"}
+ ].
+
+encode_native(Scope, Item) ->
+ case Scope of
+ property ->
+ case Item of
+ %% IP
+ "IPv4" -> [16#60, 16#01];
+ "IPv6" -> [16#60, 16#02];
+ "Port" -> [16#60, 16#03];
+ "Porttype" -> [16#60, 16#04];
+
+ %% SDP
+ "v" -> [16#b0, 16#01];
+ "o" -> [16#b0, 16#02];
+ "s" -> [16#b0, 16#03];
+ "i" -> [16#b0, 16#04];
+ "u" -> [16#b0, 16#05];
+ "e" -> [16#b0, 16#06];
+ "p" -> [16#b0, 16#07];
+ "c" -> [16#b0, 16#08];
+ "b" -> [16#b0, 16#09];
+ "z" -> [16#b0, 16#0a];
+ "k" -> [16#b0, 16#0b];
+ "a" -> [16#b0, 16#0c];
+ "t" -> [16#b0, 16#0d];
+ "r" -> [16#b0, 16#0e];
+ "m" -> [16#b0, 16#0f]
+ end
+ end.
+
+decode_native(Scope, [Type, Item]) ->
+ case Scope of
+ property ->
+ case Type of
+ 16#60 ->
+ case Item of
+ 16#01 -> "IPv4";
+ 16#02 -> "IPv6";
+ 16#03 -> "Port";
+ 16#04 -> "Porttype"
+ end;
+
+ 16#b0 ->
+ case Item of
+ 16#01 -> "v";
+ 16#02 -> "o";
+ 16#03 -> "s";
+ 16#04 -> "i";
+ 16#05 -> "u";
+ 16#06 -> "e";
+ 16#07 -> "p";
+ 16#08 -> "c";
+ 16#09 -> "b";
+ 16#0a -> "z";
+ 16#0b -> "k";
+ 16#0c -> "a";
+ 16#0d -> "t";
+ 16#0e -> "r";
+ 16#0f -> "m"
+ end
+ end
+ end.
+
+%% -------------------------------------------------------------------
+
+% error(Reason) ->
+% erlang:error(Reason).
+
diff --git a/lib/megaco/src/binary/megaco_binary_name_resolver_v2.erl b/lib/megaco/src/binary/megaco_binary_name_resolver_v2.erl
new file mode 100644
index 0000000000..53891a26f2
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_binary_name_resolver_v2.erl
@@ -0,0 +1,1681 @@
+%%
+%% %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: Handle meta data about packages
+%%----------------------------------------------------------------------
+
+-module(megaco_binary_name_resolver_v2).
+
+-include_lib("megaco/src/engine/megaco_message_internal.hrl").
+-include_lib("megaco/src/app/megaco_internal.hrl").
+
+-define(LOWER(Char),
+ if
+ Char >= $A, Char =< $Z ->
+ Char - ($A - $a);
+ true ->
+ Char
+ end).
+
+-export([packages/0,
+ capabilities/0,
+ capabilities/1,
+ decode_name/3,
+ encode_name/3
+ ]).
+
+encode_name(Config, term_id, TermId) ->
+ case megaco:encode_binary_term_id(Config, TermId) of
+ {ok, TermId2} ->
+ TermId2;
+ {error, _Reason} ->
+ exit({bad_term_id, TermId})
+ end;
+encode_name(_Config, Scope, Item) ->
+ ?d("encode_name(~p) -> entry with"
+ "~n Item: ~p", [Scope, Item]),
+ encode(Scope, Item).
+
+decode_name(Config, term_id, TermId) ->
+ case megaco:decode_binary_term_id(Config, TermId) of
+ {ok, TermId2} ->
+ TermId2;
+ {error, _Reason} ->
+ exit({bad_term_id, TermId})
+ end;
+decode_name(_Config, Scope, Item) ->
+ ?d("decode_name(~p) -> entry with"
+ "~n Item: ~p", [Scope, Item]),
+ decode(Scope, Item).
+
+%%----------------------------------------------------------------------
+%% 12.1.1 Package
+%%
+%% Overall description of the package, specifying:
+%%
+%% Package Name: only descriptive
+%%
+%% PackageID: is an identifier
+%%
+%% Description:
+%%
+%% Version:
+%%
+%% A new version of a package can only add additional Properties,
+%% Events, Signals, Statistics and new possible values for an existing
+%% parameter described in the original package. No deletions or
+%% modifications shall be allowed. A version is an integer in the range
+%% from 1 to 99.
+%%
+%% Designed to be extended only (Optional): Yes
+%%
+%% This indicates that the package has been expressly designed to be
+%% extended by others, not to be directly referenced. For example, the
+%% package may not have any function on its own or be nonsensical on its
+%% own. The MG SHOULD NOT publish this PackageID when reporting
+%% packages.
+%%
+%% Extends (Optional): existing package Descriptor
+%%
+%% A package may extend an existing package. The version of the original
+%% package must be specified. When a package extends another package it
+%% shall only add additional Properties, Events, Signals, Statistics and
+%% new possible values for an existing parameter described in the
+%% original package. An extended package shall not redefine or overload
+%% an identifier defined in the original package and packages it may
+%% have extended (multiple levels of extension). Hence, if package B
+%% version 1 extends package A version 1, version 2 of B will not be
+%% able to extend the A version 2 if A version 2 defines a name already
+%% in B version 1.
+%%
+%%
+%% 12.1.2 Properties
+%%
+%% Properties defined by the package, specifying:
+%%
+%% Property Name: only descriptive
+%%
+%% PropertyID: is an identifier
+%%
+%% Description:
+%%
+%% Type: One of:
+%%
+%% Boolean
+%%
+%% String: UTF-8 string
+%%
+%% Octet String: A number of octets. See Annex A and Annex B.3
+%% for encoding
+%%
+%% Integer: 4 byte signed integer
+%%
+%% Double: 8 byte signed integer
+%%
+%% Character: unicode UTF-8 encoding of a single letter. Could be
+%% more than one octet.
+%%
+%% Enumeration: one of a list of possible unique values (see 12.3)
+%%
+%% Sub-list: a list of several values from a list. The type of
+%% sub-list SHALL also be specified. The type shall be chosen
+%% from the types specified in this section (with the exception of
+%% sub-list). For example, Type: sub-list of enumeration. The
+%% encoding of sub-lists is specified in Annexes A and B.3.
+%%
+%% Possible values:
+%%
+%% A package MUST specify either a specific set of values or a
+%% description of how values are determined. A package MUST also
+%% specify a default value or the default behaviour when the value is
+%% omitted from its descriptor. For example, a package may specify that
+%% procedures related to the property are suspended when it value is
+%% omitted. A default value (but not procedures) may be specified as
+%% provisionable.
+%%
+%% Defined in:
+%%
+%% Which H.248.1 descriptor the property is defined in. LocalControl is
+%% for stream dependent properties. TerminationState is for stream
+%% independent properties. These are expected to be the most common
+%% cases, but it is possible for properties to be defined in other
+%% descriptors.
+%%
+%% Characteristics: Read/Write or both, and (optionally), global:
+%%
+%% Indicates whether a property is read-only, or read-write, and if it
+%% is global. If Global is omitted, the property is not global. If a
+%% property is declared as global, the value of the property is shared
+%% by all Terminations realizing the package.
+%%
+%%
+%% 12.1.3 Events
+%%
+%% Events defined by the package, specifying:
+%%
+%% Event name: only descriptive
+%%
+%% EventID: is an identifier
+%%
+%% Description:
+%%
+%% EventsDescriptor Parameters:
+%%
+%% Parameters used by the MGC to configure the event, and found in the
+%% EventsDescriptor. See 12.2.
+%%
+%% ObservedEventsDescriptor Parameters:
+%%
+%% Parameters returned to the MGC in Notify requests and in replies to
+%% command requests from the MGC that audit ObservedEventsDescriptor,
+%% and found in the ObservedEventsDescriptor. See 12.2.
+%%
+%%
+%% 12.1.4 Signals
+%%
+%% Signals defined by the package, specifying:
+%%
+%% Signal Name: only descriptive
+%%
+%% SignalID: is an identifier. SignalID is used in a
+%% SignalsDescriptor
+%%
+%% Description
+%%
+%% SignalType: one of:
+%%
+%% OO (On/Off)
+%%
+%% TO (TimeOut)
+%%
+%% BR (Brief)
+%%
+%% NOTE - SignalType may be defined such that it is dependent on the
+%% value of one or more parameters. The package MUST specify a default
+%% signal type. If the default type is TO, the package MUST specify a
+%% default duration which may be provisioned. A default duration is
+%% meaningless for BR.
+%%
+%% Duration: in hundredths of seconds
+%%
+%% Additional Parameters: see 12.2
+%%
+%%
+%% 12.1.5 Statistics
+%%
+%% Statistics defined by the package, specifying:
+%%
+%% Statistic name: only descriptive
+%%
+%% StatisticID: is an identifier
+%%
+%% StatisticID is used in a StatisticsDescriptor
+%%
+%% Description:
+%%
+%% Type: One of:
+%% Boolean
+%% String: UTF-8 string
+%% Octet String: A number of octets. See Annex A and B.3 for encoding
+%% Integer: 4 byte signed integer
+%% Double: 8 byte signed integer
+%% Character: Unicode UTF-8 encoding of a single letter.
+%% Could be more than one octet.
+%% Enumeration: One of a list of possible unique values (see 12.3)
+%% Sub-list: A list of several values from a list.
+%% The type of sub-list SHALL also be specified.
+%% The type shall be chosen from the types specified
+%% in this clause (with the exception of sub-list).
+%% For example, Type: sub-list of enumeration.
+%% The encoding of sub-lists is specified in
+%% Annex A and B.3.
+%% Possible Values:
+%% A package must indicate the unit of measure, e.g.,
+%% milliseconds, packets, either here or along with the type
+%% above, as well as indicating any restriction on the range.
+%%
+%%
+%% 12.1.6 Procedures
+%%
+%% Additional guidance on the use of the package.
+%%
+%%
+%% 12.2 Guidelines to defining Parameters to Events and Signals
+%%
+%% Parameter Name: only descriptive
+%%
+%% ParameterID: is an identifier. The textual ParameterID of
+%% parameters to Events and Signals shall not start with "EPA" and
+%% "SPA", respectively. The textual ParameterID shall also not be
+%% "ST", "Stream", "SY", "SignalType", "DR", "Duration", "NC",
+%% "NotifyCompletion", "KA", "Keepactive", "EB", "Embed", "DM" or
+%% "DigitMap".
+%%
+%% Type: One of:
+%%
+%% Boolean
+%%
+%% String: UTF-8 octet string
+%%
+%% Octet String: A number of octets. See Annex A and Annex B.3
+%% for encoding
+%%
+%% Integer: 4-octet signed integer
+%%
+%% Double: 8-octet signed integer
+%%
+%% Character: unicode UTF-8 encoding of a single letter. Could be
+%% more than one octet.
+%%
+%% Enumeration: one of a list of possible unique values (see 12.3)
+%%
+%% Sub-list: a list of several values from a list (not supported
+%% for statistics). The type of sub-list SHALL also be specified.
+%% The type shall be chosen from the types specified in this
+%% section (with the exception of sub-list). For example, Type:
+%% sub-list of enumeration. The encoding of sub-lists is
+%% specified in Annexes A and B.3.
+%%
+%% Possible values:
+%%
+%% A package MUST specify either a specific set of values or a
+%% description of how values are determined. A package MUST also
+%% specify a default value or the default behavior when the value is
+%% omitted from its descriptor. For example, a package may specify that
+%% procedures related to the parameter are suspended when it value is
+%% omitted. A default value (but not procedures) may be specified as
+%% provisionable.
+%%
+%% Description:
+%%
+%%
+%% 12.3 Lists
+%%
+%% Possible values for parameters include enumerations. Enumerations may
+%% be defined in a list. It is recommended that the list be IANA
+%% registered so that packages that extend the list can be defined
+%% without concern for conflicting names.
+%%
+%%
+%% 12.4 Identifiers
+%%
+%% Identifiers in text encoding shall be strings of up to 64 characters,
+%% containing no spaces, starting with an alphabetic character and
+%% consisting of alphanumeric characters and/or digits, and possibly
+%% including the special character underscore ("_").
+%%
+%% Identifiers in binary encoding are 2 octets long.
+%%
+%% Both text and binary values shall be specified for each identifier,
+%% including identifiers used as values in enumerated types.
+%%
+%%
+%% 12.5 Package registration
+%%
+%% A package can be registered with IANA for interoperability reasons.
+%% See clause 14 for IANA considerations.
+%%
+%%----------------------------------------------------------------------
+
+capabilities() ->
+ [{P, capabilities(P)} || P <- packages()].
+
+%% -record(property, {name, type, values, defined_in, characteristics}).
+
+%%----------------------------------------------------------------------
+%% List all known packages
+%% 'native' and 'all' are not real packages
+%%----------------------------------------------------------------------
+
+packages() ->
+ [
+ "g", % Generic
+ "root", % Base Root Package
+ "tonegen", % Tone Generator Package
+ "tonedet", % Tone Detection Package
+ "dg", % Basic DTMF Generator Package
+ "dd", % DTMF detection Package
+ "cg", % Call Progress Tones Generator Package
+ "cd", % Call Progress Tones Detection Package
+ "al", % Analog Line Supervision Package
+ "ct", % Basic Continuity Package
+ "nt", % Network Package
+ "rtp", % RTP Package
+ "swb", % SwitchBoard Package
+ "tdmc", % TDM Circuit Package
+ "" % Native pseudo package
+ ].
+
+%%----------------------------------------------------------------------
+%% List all matching capabilities
+%%----------------------------------------------------------------------
+
+capabilities(Package) ->
+ case Package of
+ "g" -> capabilities_g();
+ "root" -> capabilities_root();
+ "tonegen" -> capabilities_tonegen();
+ "tonedet" -> capabilities_tonedet();
+ "dg" -> capabilities_dg();
+ "dd" -> capabilities_dd();
+ "cg" -> capabilities_cg();
+ "cd" -> capabilities_cd();
+ "al" -> capabilities_al();
+ "ct" -> capabilities_ct();
+ "nt" -> capabilities_nt();
+ "rtp" -> capabilities_rtp();
+ "swb" -> capabilities_swb();
+ "tdmc" -> capabilities_tdmc();
+ "" -> capabilities_native()
+ end.
+
+%%----------------------------------------------------------------------
+%% Decode package name to internal form
+%% Scope ::= property | event | signal | statistics
+%%----------------------------------------------------------------------
+
+decode(mid, Package) ->
+ decode_mid(Package);
+decode(package, Package) ->
+ decode_package(Package);
+decode(profile, Package) ->
+ decode_profile(Package);
+decode(dialplan, Dialplan) ->
+ decode_dialplan(Dialplan);
+decode(Scope, [A, B | Item]) when is_atom(Scope) ->
+ ?d("decode(~p) -> entry with"
+ "~n A: ~p"
+ "~n B: ~p"
+ "~n Item: ~p", [Scope, A, B, Item]),
+ case decode_package([A, B]) of
+ "" ->
+ ?d("decode -> \"no\" package",[]),
+ decode_item(Scope, [A, B], Item);
+ Package ->
+ ?d("decode -> Package: ~p", [Package]),
+ Package ++ "/" ++ decode_item(Scope, [A, B], Item)
+ end;
+decode({Scope, [A, B | Item]}, SubItem) when is_atom(Scope) ->
+ ?d("decode(~p) -> entry with"
+ "~n A: ~p"
+ "~n B: ~p"
+ "~n Item: ~p"
+ "~n SubItem: ~p", [Scope, A, B, Item, SubItem]),
+ decode_item({Scope, Item}, [A, B], SubItem).
+
+decode_item(Scope, [A, B], Item) ->
+ ?d("decode_item -> entry",[]),
+ case A of
+ 16#00 ->
+ case B of
+ 16#01 -> decode_g(Scope, Item);
+ 16#02 -> decode_root(Scope, Item);
+ 16#03 -> decode_tonegen(Scope, Item);
+ 16#04 -> decode_tonedet(Scope, Item);
+ 16#05 -> decode_dg(Scope, Item);
+ 16#06 -> decode_dd(Scope, Item);
+ 16#07 -> decode_cg(Scope, Item);
+ 16#08 -> decode_cd(Scope, Item);
+ 16#09 -> decode_al(Scope, Item);
+ 16#0a -> decode_ct(Scope, Item);
+ 16#0b -> decode_nt(Scope, Item);
+ 16#0c -> decode_rtp(Scope, Item);
+ 16#0d -> decode_tdmc(Scope, Item);
+ 16#00 -> decode_native(Scope, Item)
+ end;
+ 16#fe ->
+ case B of
+ %% Proprietary extension
+ 16#fe -> decode_swb(Scope, Item)
+ end;
+ 16#ff ->
+ case B of
+ 16#ff when Item =:= [16#ff, 16#ff] -> "*"
+ end
+ end.
+
+decode_package(Package) ->
+ ?d("decode_package -> entry with"
+ "~n Package: ~p", [Package]),
+ [A, B] = Package,
+ case A of
+ 16#00 ->
+ case B of
+ 16#01 -> "g";
+ 16#02 -> "root";
+ 16#03 -> "tonegen";
+ 16#04 -> "tonedet";
+ 16#05 -> "dg";
+ 16#06 -> "dd";
+ 16#07 -> "cg";
+ 16#08 -> "cd";
+ 16#09 -> "al";
+ 16#0a -> "ct";
+ 16#0b -> "nt";
+ 16#0c -> "rtp";
+ 16#0d -> "tdmc";
+ 16#00 -> ""
+ end;
+ 16#fe ->
+ case B of
+ 16#fe -> "swb"
+ end;
+ 16#ff ->
+ case B of
+ 16#ff -> "*"
+ end
+ end.
+
+decode_profile([A, B]) ->
+ case A of
+ 16#00 ->
+ case B of
+ 16#fe -> "resgw";
+ _ -> "profile" ++ [A + $0, B + $0]
+ end;
+ _ ->
+ "profile" ++ [A + $0, B + $0]
+ end.
+
+decode_dialplan([A, B]) ->
+ "dialplan" ++ [A + $0, B + $0].
+
+decode_mid(Mid) ->
+ case Mid of
+ {domainName, DN} ->
+ Lower = to_lower(DN#'DomainName'.name),
+ {domainName, DN#'DomainName'{name = Lower}};
+ {deviceName, PathName} ->
+ Lower = to_lower(PathName),
+ {deviceName, Lower};
+ Other ->
+ Other
+ end.
+
+to_lower(Chars) ->
+ [?LOWER(Char) || Char <- Chars].
+
+%%----------------------------------------------------------------------
+%% Encode package name from internal form
+%% Scope ::= property | event | signal | statistics
+%%----------------------------------------------------------------------
+
+encode(mid, Package) ->
+ encode_mid(Package);
+encode(package, Package) ->
+ encode_package(Package);
+encode(profile, Profile) ->
+ encode_profile(Profile);
+encode(dialplan, Dialplan) ->
+ encode_dialplan(Dialplan);
+encode(Scope, PackageItem) when is_atom(Scope) ->
+ ?d("encode(~p) -> entry with"
+ "~n PackageItem: ~p", [Scope, PackageItem]),
+ case string:tokens(PackageItem, [$/]) of
+ [Package, Item] ->
+ ?d("encode -> "
+ "~n Package: ~p"
+ "~n Item: ~p", [Package, Item]),
+ encode_package(Package) ++ encode_item(Scope, Package, Item);
+ [Item] ->
+ ?d("encode -> Item: ~p", [Item]),
+ [16#00, 16#00 | encode_native(Scope, Item)]
+ end;
+encode({Scope, PackageItem}, SubItem) when is_atom(Scope) ->
+ ?d("encode(~p) -> entry with"
+ "~n PackageItem: ~p"
+ "~n SubItem: ~p", [Scope, PackageItem, SubItem]),
+ case string:tokens(PackageItem, [$/]) of
+ [Package, Item] ->
+ ?d("encode -> "
+ "~n Package: ~p"
+ "~n Item: ~p", [Package, Item]),
+ encode_item({Scope, Item}, Package, SubItem);
+ [_Item] ->
+ ?d("encode -> _Item: ~p", [_Item]),
+ encode_native(Scope, SubItem)
+ end.
+
+encode_item(_Scope, _Package, "*") ->
+ [16#ff, 16#ff];
+encode_item(Scope, Package, Item) ->
+ ?d("encode_item(~s) -> entry", [Package]),
+ case Package of
+ "g" -> encode_g(Scope, Item);
+ "root" -> encode_root(Scope, Item);
+ "tonegen" -> encode_tonegen(Scope, Item);
+ "tonedet" -> encode_tonedet(Scope, Item);
+ "dg" -> encode_dg(Scope, Item);
+ "dd" -> encode_dd(Scope, Item);
+ "cg" -> encode_cg(Scope, Item);
+ "cd" -> encode_cd(Scope, Item);
+ "al" -> encode_al(Scope, Item);
+ "ct" -> encode_ct(Scope, Item);
+ "nt" -> encode_nt(Scope, Item);
+ "rtp" -> encode_rtp(Scope, Item);
+ "tdmc" -> encode_tdmc(Scope, Item);
+ "swb" -> encode_swb(Scope, Item)
+ end.
+
+encode_package(Package) ->
+ case Package of
+ "g" -> [16#00, 16#01];
+ "root" -> [16#00, 16#02];
+ "tonegen" -> [16#00, 16#03];
+ "tonedet" -> [16#00, 16#04];
+ "dg" -> [16#00, 16#05];
+ "dd" -> [16#00, 16#06];
+ "cg" -> [16#00, 16#07];
+ "cd" -> [16#00, 16#08];
+ "al" -> [16#00, 16#09];
+ "ct" -> [16#00, 16#0a];
+ "nt" -> [16#00, 16#0b];
+ "rtp" -> [16#00, 16#0c];
+ "tdmc" -> [16#00, 16#0d];
+ "" -> [16#00, 16#00];
+ "*" -> [16#ff, 16#ff];
+ "swb" -> [16#fe, 16#fe]
+ end.
+
+encode_profile(Profile) ->
+ case Profile of
+ "resgw" ->
+ [16#00, 16#fe];
+ [$p, $r, $o, $f, $i, $l, $e | Name] ->
+ case Name of
+ [A, B] -> [A - $0, B - $0];
+ [B] -> [0, B - $0];
+ [] -> [0, 0]
+ end
+ end.
+
+encode_dialplan(Dialplan) ->
+ case Dialplan of
+ [$d, $i, $a, $l, $p, $l, $a, $n | Name] ->
+ case Name of
+ [A, B] -> [A - $0, B - $0];
+ [B] -> [0, B - $0];
+ [] -> [0, 0]
+ end
+ end.
+
+encode_mid(Mid) ->
+ Mid.
+
+
+%%----------------------------------------------------------------------
+%% Name: g - Generic
+%% Version: 1
+%% Extends: None
+%% Purpose: Generic package for commonly encountered items
+%%----------------------------------------------------------------------
+
+capabilities_g() ->
+ [
+ {event, "cause"},
+ {event, "sc"}
+ ].
+
+encode_g(event, Item) ->
+ case Item of
+ "cause" -> [16#00, 16#01];
+ "sc" -> [16#00, 16#02]
+ end;
+
+encode_g({event_parameter, Item}, SubItem) ->
+ case Item of
+ "cause" ->
+ case SubItem of
+ "Generalcause" -> [16#00, 16#01];
+ "Failurecause" -> [16#00, 16#02]
+ end;
+ "sc" ->
+ case SubItem of
+ "SigID" -> [16#00, 16#01];
+ "Meth" -> [16#00, 16#02];
+ "SLID" -> [16#00, 16#03]
+ end
+ end.
+
+decode_g(event, Item) ->
+ case Item of
+ [16#00, 16#01] -> "cause";
+ [16#00, 16#02] -> "sc"
+ end;
+
+decode_g({event_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#01] -> % Event: cause
+ case SubItem of
+ [16#00, 16#01] -> "Generalcause";
+ [16#00, 16#02] -> "Failurecause"
+ end;
+
+ [16#00, 16#02] -> % Event: sc
+ case SubItem of
+ [16#00, 16#01] -> "SigID";
+ [16#00, 16#02] -> "Meth";
+ [16#00, 16#03] -> "SLID"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: root - Base Root Package
+%% Version: 1
+%% Extends: None
+%% Purpose: This package defines Gateway wide properties.
+%%----------------------------------------------------------------------
+
+capabilities_root() ->
+ [
+ {property, "maxNumberOfContexts"},
+ {property, "maxTerminationsPerContext"},
+ {property, "normalMGExecutionTime"},
+ {property, "normalMGCExecutionTime"},
+ {property, "MGProvisionalResponseTimerValue"},
+ {property, "MGCProvisionalResponseTimerValue"},
+ {property, "MGCOriginatedPendingLimit"},
+ {property, "MGOriginatedPendingLimit"}
+ ].
+
+encode_root(Scope, Item) ->
+ case Scope of
+ property ->
+ case Item of
+ "maxNumberOfContexts" -> [16#00, 16#01];
+ "maxTerminationsPerContext" -> [16#00, 16#02];
+ "normalMGExecutionTime" -> [16#00, 16#03];
+ "normalMGCExecutionTime" -> [16#00, 16#04];
+ "MGProvisionalResponseTimerValue" -> [16#00, 16#05];
+ "MGCProvisionalResponseTimerValue" -> [16#00, 16#06];
+ "MGCOriginatedPendingLimit" -> [16#00, 16#07];
+ "MGOriginatedPendingLimit" -> [16#00, 16#08]
+ end
+ end.
+
+decode_root(Scope, Item) ->
+ case Scope of
+ property ->
+ case Item of
+ [16#00, 16#01] -> "maxNumberOfContexts";
+ [16#00, 16#02] -> "maxTerminationsPerContext";
+ [16#00, 16#03] -> "normalMGExecutionTime";
+ [16#00, 16#04] -> "normalMGCExecutionTime";
+ [16#00, 16#05] -> "MGProvisionalResponseTimerValue";
+ [16#00, 16#06] -> "MGCProvisionalResponseTimerValue";
+ [16#00, 16#07] -> "MGCOriginatedPendingLimit";
+ [16#00, 16#08] -> "MGOriginatedPendingLimit"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: tonegen - Tone Generator Package
+%% Version: 1
+%% Extends: None
+%% Purpose: This package defines signals to generate audio tones.
+%% This package does not specify parameter values. It is
+%% intended to be extendable. Generally, tones are defined
+%% as an individual signal with a parameter, ind,
+%% representing "interdigit" time delay, and a tone id to
+%% be used with playtones. A tone id should be kept
+%% consistent with any tone generation for the same tone.
+%% MGs are expected to be provisioned with the characteristics
+%% of appropriate tones for the country in which the MG is located.
+%%----------------------------------------------------------------------
+
+capabilities_tonegen() ->
+ [
+ {signal, "pt"}
+ ].
+
+encode_tonegen(signal, Item) ->
+ case Item of
+ "pt" -> [16#00, 16#01]
+ end;
+
+encode_tonegen({signal_parameter, Item}, SubItem) ->
+ case Item of
+ "pt" ->
+ case SubItem of
+ "tl" -> [16#00, 16#01];
+ "ind" -> [16#00, 16#02]
+ end
+ end.
+
+decode_tonegen(signal, Item) ->
+ case Item of
+ [16#00, 16#01] -> "pt"
+ end;
+
+decode_tonegen({signal_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#01] -> % Event: pt
+ case SubItem of
+ [16#00, 16#01] -> "tl";
+ [16#00, 16#02] -> "ind"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: tonedet - Tone Detection Package
+%% Version: 1
+%% Extends: None
+%% Purpose: This Package defines events for audio tone detection.
+%% Tones are selected by name (tone id). MGs are expected
+%% to be provisioned with the characteristics of appropriate
+%% tones for the country in which the MG is located.
+%%
+%% This package does not specify parameter values.
+%% It is intended to be extendable.
+%%----------------------------------------------------------------------
+
+capabilities_tonedet() ->
+ [
+ {event, "std"},
+ {event, "etd"},
+ {event, "ltd"}
+ ].
+
+encode_tonedet(event, Item) ->
+ case Item of
+ "std" -> [16#00, 16#01];
+ "etd" -> [16#00, 16#02];
+ "ltd" -> [16#00, 16#03]
+ end;
+
+encode_tonedet({event_parameter, Item}, SubItem) ->
+ case Item of
+ "std" ->
+ case SubItem of
+ "tl" -> [16#00, 16#01];
+ "tid" -> [16#00, 16#03]
+ end;
+ "etd" ->
+ case SubItem of
+ "tl" -> [16#00, 16#01];
+ "tid" -> [16#00, 16#03];
+ "dur" -> [16#00, 16#02]
+ end;
+ "ltd" ->
+ case SubItem of
+ "tl" -> [16#00, 16#01];
+ "dur" -> [16#00, 16#02];
+ "tid" -> [16#00, 16#03]
+ end
+ end.
+
+decode_tonedet(event, Item) ->
+ case Item of
+ [16#00, 16#01] -> "std";
+ [16#00, 16#02] -> "etd";
+ [16#00, 16#03] -> "ltd"
+ end;
+
+decode_tonedet({event_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#01] -> % Event std
+ case SubItem of
+ [16#00, 16#01] -> "tl";
+ [16#00, 16#03] -> "tid"
+ end;
+ [16#00, 16#02] -> % Event etd
+ case SubItem of
+ [16#00, 16#01] -> "tl";
+ [16#00, 16#03] -> "tid";
+ [16#00, 16#02] -> "dur"
+ end;
+ [16#00, 16#03] -> % Event ltd
+ case SubItem of
+ [16#00, 16#01] -> "tl";
+ [16#00, 16#02] -> "dur";
+ [16#00, 16#03] -> "tid"
+ end
+ end.
+
+%%----------------------------------------------------------------------
+%% Name: dg - Basic DTMF Generator Package
+%% Version: 1
+%% Extends: tonegen version 1
+%% Purpose: This package defines the basic DTMF tones as signals and
+%% extends the allowed values of parameter tl of playtone
+%% in tonegen.
+%%----------------------------------------------------------------------
+
+capabilities_dg() ->
+ [
+ {signal, "d0"},
+ {signal, "d1"},
+ {signal, "d2"},
+ {signal, "d3"},
+ {signal, "d4"},
+ {signal, "d5"},
+ {signal, "d6"},
+ {signal, "d7"},
+ {signal, "d8"},
+ {signal, "d9"},
+ {signal, "ds"},
+ {signal, "do"},
+ {signal, "da"},
+ {signal, "db"},
+ {signal, "dc"},
+ {signal, "dd"}
+ ].
+
+encode_dg(Scope, Item) ->
+ case Scope of
+ signal ->
+ case Item of
+ "d0" -> [16#00, 16#10];
+ "d1" -> [16#00, 16#11];
+ "d2" -> [16#00, 16#12];
+ "d3" -> [16#00, 16#13];
+ "d4" -> [16#00, 16#14];
+ "d5" -> [16#00, 16#15];
+ "d6" -> [16#00, 16#16];
+ "d7" -> [16#00, 16#17];
+ "d8" -> [16#00, 16#18];
+ "d9" -> [16#00, 16#19];
+ "ds" -> [16#00, 16#20];
+ "do" -> [16#00, 16#21];
+ "da" -> [16#00, 16#1a];
+ "db" -> [16#00, 16#1b];
+ "dc" -> [16#00, 16#1c];
+ "dd" -> [16#00, 16#1d]
+ end
+ end.
+
+decode_dg(Scope, Item) ->
+ case Scope of
+ signal ->
+ case Item of
+ [16#00, 16#10] -> "d0";
+ [16#00, 16#11] -> "d1";
+ [16#00, 16#12] -> "d2";
+ [16#00, 16#13] -> "d3";
+ [16#00, 16#14] -> "d4";
+ [16#00, 16#15] -> "d5";
+ [16#00, 16#16] -> "d6";
+ [16#00, 16#17] -> "d7";
+ [16#00, 16#18] -> "d8";
+ [16#00, 16#19] -> "d9";
+ [16#00, 16#20] -> "ds";
+ [16#00, 16#21] -> "do";
+ [16#00, 16#1a] -> "da";
+ [16#00, 16#1b] -> "db";
+ [16#00, 16#1c] -> "dc";
+ [16#00, 16#1d] -> "dd"
+ end
+ end.
+
+%%----------------------------------------------------------------------
+%% Name: dd - DTMF detection Package
+%% Version: 1
+%% Extends: tonedet version 1
+%% Purpose: This package defines the basic DTMF tones detection.
+%% Tones are selected by name (tone id). MGs are expected
+%% to be provisioned with the characteristics of appropriate
+%% tones for the country in which the MG is located.
+%%
+%% This package does not specify parameter values.
+%% It is intended to be extendable.
+%%
+%% Additional tone id values are all tone ids described in package dg
+%% (basic DTMF generator package).
+%%
+%% The following table maps DTMF events to digit map symbols as described
+%% in section 7.1.14.
+%%
+%% _________________________________
+%% | DTMF Event | Symbol |
+%% | d0 | "0" |
+%% | d1 | "1" |
+%% | d2 | "2" |
+%% | d3 | "3" |
+%% | d4 | "4" |
+%% | d5 | "5" |
+%% | d6 | "6" |
+%% | d7 | "7" |
+%% | d8 | "8" |
+%% | d9 | "9" |
+%% | da | "A" or "a"|
+%% | db | "B" or "b"|
+%% | dc | "C" or "c"|
+%% | dd | "D" or "d"|
+%% | ds | "E" or "e"|
+%% | do | "F" or "f"|
+%% |___________________|____________|
+%%
+%%----------------------------------------------------------------------
+
+capabilities_dd() ->
+ [
+ {event, "ce"},
+ {event, "d0"},
+ {event, "d1"},
+ {event, "d2"},
+ {event, "d3"},
+ {event, "d4"},
+ {event, "d5"},
+ {event, "d6"},
+ {event, "d7"},
+ {event, "d8"},
+ {event, "d9"},
+ {event, "ds"},
+ {event, "do"},
+ {event, "da"},
+ {event, "db"},
+ {event, "dc"},
+ {event, "dd"}
+ ].
+
+encode_dd(event, Item) ->
+ case Item of
+ "ce" -> [16#00, 16#04];
+ "d0" -> [16#00, 16#10];
+ "d1" -> [16#00, 16#11];
+ "d2" -> [16#00, 16#12];
+ "d3" -> [16#00, 16#13];
+ "d4" -> [16#00, 16#14];
+ "d5" -> [16#00, 16#15];
+ "d6" -> [16#00, 16#16];
+ "d7" -> [16#00, 16#17];
+ "d8" -> [16#00, 16#18];
+ "d9" -> [16#00, 16#19];
+ "ds" -> [16#00, 16#20];
+ "do" -> [16#00, 16#21];
+ "da" -> [16#00, 16#1a];
+ "db" -> [16#00, 16#1b];
+ "dc" -> [16#00, 16#1c];
+ "dd" -> [16#00, 16#1d]
+ end;
+
+encode_dd({event_parameter, Item}, SubItem) ->
+ case Item of
+ "ce" ->
+ case SubItem of
+ "ds" -> [16#00, 16#01];
+ "Meth" -> [16#00, 16#03]
+ end
+ end.
+
+decode_dd(event, Item) ->
+ case Item of
+ [16#00, 16#04] -> "ce";
+ [16#00, 16#10] -> "d0";
+ [16#00, 16#11] -> "d1";
+ [16#00, 16#12] -> "d2";
+ [16#00, 16#13] -> "d3";
+ [16#00, 16#14] -> "d4";
+ [16#00, 16#15] -> "d5";
+ [16#00, 16#16] -> "d6";
+ [16#00, 16#17] -> "d7";
+ [16#00, 16#18] -> "d8";
+ [16#00, 16#19] -> "d9";
+ [16#00, 16#20] -> "ds";
+ [16#00, 16#21] -> "do";
+ [16#00, 16#1a] -> "da";
+ [16#00, 16#1b] -> "db";
+ [16#00, 16#1c] -> "dc";
+ [16#00, 16#1d] -> "dd"
+ end;
+
+decode_dd({event_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#04] -> % Event ce
+ case SubItem of
+ [16#00, 16#01] -> "ds";
+ [16#00, 16#03] -> "Meth"
+ end
+ end.
+
+%%----------------------------------------------------------------------
+%% Name: cg - Call Progress Tones Generator Package
+%% Version: 1
+%% Extends: tonegen version 1
+%% Purpose: This package defines the basic call progress tones as signals
+%% and extends the allowed values of the tl parameter of
+%% playtone in tonegen.
+%%----------------------------------------------------------------------
+
+capabilities_cg() ->
+ [
+ {signal, "dt"},
+ {signal, "rt"},
+ {signal, "bt"},
+ {signal, "ct"},
+ {signal, "sit"},
+ {signal, "wt"},
+ {signal, "prt"},
+ {signal, "cw"},
+ {signal, "cr"}
+ ].
+
+
+encode_cg(Scope, Item) ->
+ case Scope of
+ signal ->
+ case Item of
+ "dt" -> [16#00, 16#30];
+ "rt" -> [16#00, 16#31];
+ "bt" -> [16#00, 16#32];
+ "ct" -> [16#00, 16#33];
+ "sit" -> [16#00, 16#34];
+ "wt" -> [16#00, 16#35];
+ "prt" -> [16#00, 16#36];
+ "cw" -> [16#00, 16#37];
+ "cr" -> [16#00, 16#38]
+ end
+ end.
+
+decode_cg(Scope, Item) ->
+ case Scope of
+ signal ->
+ case Item of
+ [16#00, 16#30] -> "dt";
+ [16#00, 16#31] -> "rt";
+ [16#00, 16#32] -> "bt";
+ [16#00, 16#33] -> "ct";
+ [16#00, 16#34] -> "sit";
+ [16#00, 16#35] -> "wt";
+ [16#00, 16#36] -> "prt";
+ [16#00, 16#37] -> "cw";
+ [16#00, 16#38] -> "cr"
+ end
+ end.
+
+%%----------------------------------------------------------------------
+%% Name: cd - Call Progress Tones Detection Package
+%% Version: 1
+%% Extends: tonedet version 1
+%% Purpose: This package defines the basic call progress detection tones.
+%% This Package extends the possible values of tone id
+%% in the "start tone detected", "end tone detected" and
+%% "long tone detected" events.
+%% Additional values
+%% tone id values are defined for start tone detected,
+%% end tone detected and long tone detected with
+%% the same values as those in package cg (call
+%% progress tones generation package).
+%%
+%% The required set of tone ids corresponds to Recommendation E.180/Q.35
+%% [ITU-T Recommendation E.180/Q.35 (1998)]. See Recommendation E.180/Q.35
+%% for definition of the meanings of these tones.
+%%----------------------------------------------------------------------
+
+capabilities_cd() ->
+ [
+ {event, "dt"},
+ {event, "rt"},
+ {event, "bt"},
+ {event, "ct"},
+ {event, "sit"},
+ {event, "wt"},
+ {event, "prt"},
+ {event, "cw"},
+ {event, "cr"}
+ ].
+
+
+encode_cd(Scope, Item) ->
+ case Scope of
+ event ->
+ case Item of
+ "dt" -> [16#00, 16#30];
+ "rt" -> [16#00, 16#31];
+ "bt" -> [16#00, 16#32];
+ "ct" -> [16#00, 16#33];
+ "sit"-> [16#00, 16#34];
+ "wt" -> [16#00, 16#35];
+ "prt"-> [16#00, 16#36];
+ "cw" -> [16#00, 16#37];
+ "cr" -> [16#00, 16#38]
+ end
+ end.
+
+decode_cd(Scope, Item) ->
+ case Scope of
+ event ->
+ case Item of
+ [16#00, 16#30] -> "dt";
+ [16#00, 16#31] -> "rt";
+ [16#00, 16#32] -> "bt";
+ [16#00, 16#33] -> "ct";
+ [16#00, 16#34] -> "sit";
+ [16#00, 16#35] -> "wt";
+ [16#00, 16#36] -> "prt";
+ [16#00, 16#37] -> "cw";
+ [16#00, 16#38] -> "cr"
+ end
+ end.
+
+%%----------------------------------------------------------------------
+%% Name: al - Analog Line Supervision Package
+%% Version: 1
+%% Extends: None
+%% Purpose: This package defines events and signals for an analog line.
+%%----------------------------------------------------------------------
+
+capabilities_al() ->
+ [
+ {event, "on"},
+ {event, "of"},
+ {event, "fl"},
+ {signal, "ri"}
+ ].
+
+encode_al(event, Item) ->
+ ?d("encode_al(event) -> entry with"
+ "~n Item: ~p", [Item]),
+ case Item of
+ "on" -> [16#00, 16#04];
+ "of" -> [16#00, 16#05];
+ "fl" -> [16#00, 16#06]
+ end;
+
+encode_al({event_parameter, Item}, SubItem) ->
+ ?d("encode_al({event_parameter,~p}) -> entry with"
+ "~n SubItem: ~p", [Item, SubItem]),
+ case Item of
+ "on" ->
+ case SubItem of
+ "strict" -> [16#00, 16#01];
+ "init" -> [16#00, 16#02]
+ end;
+ "of" ->
+ case SubItem of
+ "strict" -> [16#00, 16#01];
+ "init" -> [16#00, 16#02]
+ end;
+ "fl" ->
+ case SubItem of
+ "mindur" -> [16#00, 16#04];
+ "maxdur" -> [16#00, 16#05]
+ end
+ end;
+
+encode_al(signal, Item) ->
+ ?d("encode_al(signal) -> entry with"
+ "~n Item: ~p", [Item]),
+ case Item of
+ "ri" -> [16#00, 16#02]
+ end;
+
+encode_al({signal_parameter, Item}, SubItem) ->
+ ?d("encode_al({signal_parameter,~p}) -> entry with"
+ "~n SubItem: ~p", [Item, SubItem]),
+ case Item of
+ "ri" ->
+ case SubItem of
+ "cad" -> [16#00, 16#06];
+ "freq" -> [16#00, 16#07]
+ end
+ end.
+
+decode_al(event, SubItem) ->
+ ?d("decode_al(event) -> entry with"
+ "~n SubItem: ~p", [SubItem]),
+ case SubItem of
+ [16#00, 16#04] -> "on";
+ [16#00, 16#05] -> "of";
+ [16#00, 16#06] -> "fl"
+ end;
+
+decode_al({event_parameter, Item}, SubItem) ->
+ ?d("decode_al({event_parameter,~p}) -> entry with"
+ "~n SubItem: ~p", [Item, SubItem]),
+ case Item of
+ [16#00,16#04] -> %% Event: on
+ case SubItem of
+ [16#00, 16#01] -> "strict";
+ [16#00, 16#02] -> "init"
+ end;
+ [16#00,16#05] -> %% Event: of
+ case SubItem of
+ [16#00, 16#01] -> "strict";
+ [16#00, 16#02] -> "init"
+ end;
+ [16#00,16#06] -> %% Event: fl
+ case SubItem of
+ [16#00, 16#04] -> "mindur";
+ [16#00, 16#05] -> "maxdur"
+ end
+ end;
+
+decode_al(signal, SubItem) ->
+ ?d("decode_al(signal) -> entry with"
+ "~n SubItem: ~p", [SubItem]),
+ case SubItem of
+ [16#00, 16#02] -> "ri"
+ end;
+
+decode_al({signal_parameter, Item}, SubItem) ->
+ ?d("decode_al({signal_parameter,~p}) -> entry with"
+ "~n SubItem: ~p", [Item, SubItem]),
+ case Item of
+ [16#00,16#02] -> %% Event: ri
+ case SubItem of
+ [16#00, 16#06] -> "cad";
+ [16#00, 16#07] -> "freq"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: ct - Basic Continuity Package
+%% Version: 1
+%% Extends: None
+%% Purpose: This package defines events and signals for continuity test.
+%% The continuity test includes provision of either a loopback
+%% or transceiver functionality.
+%%----------------------------------------------------------------------
+
+capabilities_ct() ->
+ [
+ {event, "cmp"},
+ {signal, "ct"},
+ {signal, "rsp"}
+ ].
+
+encode_ct(event, Item) ->
+ case Item of
+ "cmp" -> [16#00, 16#05]
+ end;
+encode_ct({event_parameter, Item}, SubItem) ->
+ case Item of
+ "cmp" ->
+ case SubItem of
+ "res" -> [16#00, 16#08]
+ end
+ end;
+encode_ct(signal, Item) ->
+ case Item of
+ "ct" -> [16#00, 16#03];
+ "rsp" -> [16#00, 16#04]
+ end.
+
+decode_ct(event, Item) ->
+ case Item of
+ [16#00, 16#05] -> "cmp"
+ end;
+decode_ct({event_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#05] -> % Event cmp
+ case SubItem of
+ [16#00, 16#08] -> "res"
+ end
+ end;
+decode_ct(signal, Item) ->
+ case Item of
+ [16#00, 16#03] -> "ct";
+ [16#00, 16#04] -> "rsp"
+ end.
+
+%%----------------------------------------------------------------------
+%% Name: nt - Network Package
+%% Version: 1
+%% Extends: None
+%% Purpose: This package defines properties of network terminations
+%% independent of network type.
+%%----------------------------------------------------------------------
+
+capabilities_nt() ->
+ [
+ {property, "jit"},
+ {event, "netfail"},
+ {event, "qualert"},
+ {statistics, "dur"},
+ {statistics, "os"},
+ {statistics, "or"}
+ ].
+
+encode_nt(property, Item) ->
+ case Item of
+ "jit" -> [16#00, 16#07]
+ end;
+encode_nt(event, Item) ->
+ case Item of
+ "netfail" -> [16#00, 16#05];
+ "qualert" -> [16#00, 16#06]
+ end;
+encode_nt({event_parameter, Item}, SubItem) ->
+ case Item of
+ "netfail" ->
+ case SubItem of
+ "cs" -> [16#00, 16#01]
+ end;
+ "qualert" ->
+ case SubItem of
+ "th" -> [16#00, 16#01]
+ end
+ end;
+encode_nt(statistics, Item) ->
+ case Item of
+ "dur" -> [16#00, 16#01];
+ "os" -> [16#00, 16#02];
+ "or" -> [16#00, 16#03]
+ end.
+
+decode_nt(property, Item) ->
+ case Item of
+ [16#00, 16#07] -> "jit"
+ end;
+decode_nt(event, Item) ->
+ case Item of
+ [16#00, 16#05] -> "netfail";
+ [16#00, 16#06] -> "qualert"
+ end;
+decode_nt({event_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#05] -> % Event netfail
+ case SubItem of
+ [16#00, 16#01] -> "cs"
+ end;
+ [16#00, 16#06] -> % Event qualert
+ case Item of
+ [16#00, 16#01] -> "th"
+ end
+ end;
+decode_nt(statistics, Item) ->
+ case Item of
+ [16#00, 16#01] -> "dur";
+ [16#00, 16#02] -> "os";
+ [16#00, 16#03] -> "or"
+ end.
+
+%%----------------------------------------------------------------------
+%% Name: rtp - RTP Package
+%% Version: 1
+%% Extends: nt version 1
+%% Purpose: This package is used to support packet based multimedia
+%% data transfer by means of the Real-time Transport Protocol
+%% (RTP) [RFC 1889].
+%%----------------------------------------------------------------------
+
+capabilities_rtp() ->
+ [
+ {event, "pltrans"},
+ {statistics, "ps"},
+ {statistics, "pr"},
+ {statistics, "pl"},
+ {statistics, "jit"},
+ {statistics, "delay"}
+ ].
+
+encode_rtp(event, Item) ->
+ case Item of
+ "pltrans" -> [16#00, 16#01]
+ end;
+encode_rtp({event_parameter, Item}, SubItem) ->
+ case Item of
+ "pltrans" ->
+ case SubItem of
+ "rtppltype" -> [16#00, 16#01]
+ end
+ end;
+encode_rtp(statistics, Item) ->
+ case Item of
+ "ps" -> [16#00, 16#04];
+ "pr" -> [16#00, 16#05];
+ "pl" -> [16#00, 16#06];
+ "jit" -> [16#00, 16#07];
+ "delay" -> [16#00, 16#08]
+ end.
+
+decode_rtp(event, Item) ->
+ case Item of
+ [16#00, 16#01] -> "pltrans"
+ end;
+decode_rtp({event_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#01] -> % Event pltrans
+ case SubItem of
+ [16#00, 16#01] -> "rtppltype"
+ end
+ end;
+decode_rtp(statistics, Item) ->
+ case Item of
+ [16#00, 16#04] -> "ps";
+ [16#00, 16#05] -> "pr";
+ [16#00, 16#06] -> "pl";
+ [16#00, 16#07] -> "jit";
+ [16#00, 16#08] -> "delay"
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: tdmc - TDM Circuit Package
+%% Version: 1
+%% Extends: nt version 1
+%% Purpose: This package is used to support TDM circuit terminations.
+%%----------------------------------------------------------------------
+
+capabilities_tdmc() ->
+ [
+ {property, "ec"},
+ {property, "gain"}
+ ].
+
+encode_tdmc(Scope, Item) ->
+ case Scope of
+ property ->
+ case Item of
+ "ec" -> [16#00, 16#08];
+ "gain" -> [16#00, 16#0a]
+ end
+ end.
+
+decode_tdmc(Scope, Item) ->
+ case Scope of
+ property ->
+ case Item of
+ [16#00, 16#08] -> "ec";
+ [16#00, 16#0a] -> "gain"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: swb - SwitchBoard Package
+%% Version: 1
+%% Extends: none
+%% Purpose: This package is used to support SwitchBoard specials
+%%----------------------------------------------------------------------
+
+capabilities_swb() ->
+ [
+ {statistics, "fs"}, % Free slots
+ {statistics, "as"} % Allocated slots
+ ].
+
+encode_swb(Scope, Item) ->
+ case Scope of
+ statistics ->
+ case Item of
+ "fs" -> [16#00, 16#00];
+ "as" -> [16#00, 16#01]
+ end
+ end.
+
+decode_swb(Scope, Item) ->
+ case Scope of
+ statistics ->
+ case Item of
+ [16#00, 16#00] -> "fs";
+ [16#00, 16#01] -> "as"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: native - Pseudo package
+%% Version: 1
+%% Extends: None
+%% Purpose: Native tags for media stream properties
+%%
+%% Parameters for Local descriptors and Remote descriptors are
+%% specified as tag-value pairs if binary encoding is used for the
+%% protocol. This annex contains the property names (PropertyID), the
+%% tags (Property Tag), type of the property (Type) and the values
+%% (Value).Values presented in the Value field when the field contains
+%% references shall be regarded as "information". The reference
+%% contains the normative values. If a value field does not contain a
+%% reference then the values in that field can be considered as
+%% "normative".
+%%
+%% Tags are given as hexadecimal numbers in this annex. When setting
+%% the value of a property, a MGC may underspecify the value according
+%% to one of the mechanisms specified in section 7.1.1.
+%%
+%% For type "enumeration" the value is represented by the value in brack-
+%% ets, e.g., Send(0), Receive(1).
+%%----------------------------------------------------------------------
+%%
+%% C.6. IP
+%%
+%% ________________________________________________________________
+%% | PropertyID| Tag | Type | Value |
+%% | IPv4 | 6001 | 32 BITS | Ipv4Address |
+%% | IPv6 | 6002 | 128 BITS | IPv6 Address |
+%% | Port | 6003 | Unsigned Int| Port |
+%% | Porttype | 6004 | Enumerated | TCP(0),UDP(1),SCTP(2)|
+%% |___________|____________|______________|_______________________|
+%%
+%%
+%% C.11. SDP Equivalents
+%%
+%% ______________________________________________________________
+%% | PropertyID| Tag | Type | Value |
+%% | SDP_V | B001| STRING| Protocol Version |
+%% | SDP_O | B002| STRING| Owner-creator and session ID |
+%% | SDP_S | B003| STRING| Sesson name |
+%% | SDP_I | B004| STRING| Session identifier |
+%% | SDP_U | B005| STRING| URI of descriptor |
+%% | SDC_E | B006| STRING| email address |
+%% | SDP_P | B007| STRING| phone number |
+%% | SDP_C | B008| STRING| Connection information |
+%% | SDP_B | B009| STRING| Bandwidth Information |
+%% | SDP_Z | B00A| STRING| time zone adjustment |
+%% | SDP_K | B00B| STRING| Encryption Key |
+%% | SDP_A | B00C| STRING| Zero or more session attributes|
+%% | SDP_T | B00D| STRING| Active Session Time |
+%% | SDP_R | B00E| STRING| Zero or more repeat times |
+%% | SDP_M | B00F| STRING| Media name and transport addr |
+%% | | | | Reference: IETF RFC 2327 |
+%% |___________|______|________|_________________________________|
+%%
+%%----------------------------------------------------------------------
+
+capabilities_native() ->
+ [
+ %% C.6. IP
+ {property, "IPv4"},
+ {property, "IPv6"},
+ {property, "Port"},
+ {property, "Porttype"},
+
+ %% C.11. SDP Equivalents
+ {property, "v"},
+ {property, "o"},
+ {property, "s"},
+ {property, "i"},
+ {property, "u"},
+ {property, "e"},
+ {property, "p"},
+ {property, "c"},
+ {property, "b"},
+ {property, "z"},
+ {property, "k"},
+ {property, "a"},
+ {property, "t"},
+ {property, "r"},
+ {property, "m"}
+ ].
+
+encode_native(Scope, Item) ->
+ case Scope of
+ property ->
+ case Item of
+ %% IP
+ "IPv4" -> [16#60, 16#01];
+ "IPv6" -> [16#60, 16#02];
+ "Port" -> [16#60, 16#03];
+ "Porttype" -> [16#60, 16#04];
+
+ %% SDP
+ "v" -> [16#b0, 16#01];
+ "o" -> [16#b0, 16#02];
+ "s" -> [16#b0, 16#03];
+ "i" -> [16#b0, 16#04];
+ "u" -> [16#b0, 16#05];
+ "e" -> [16#b0, 16#06];
+ "p" -> [16#b0, 16#07];
+ "c" -> [16#b0, 16#08];
+ "b" -> [16#b0, 16#09];
+ "z" -> [16#b0, 16#0a];
+ "k" -> [16#b0, 16#0b];
+ "a" -> [16#b0, 16#0c];
+ "t" -> [16#b0, 16#0d];
+ "r" -> [16#b0, 16#0e];
+ "m" -> [16#b0, 16#0f]
+ end
+ end.
+
+decode_native(Scope, [Type, Item]) ->
+ case Scope of
+ property ->
+ case Type of
+ 16#60 ->
+ case Item of
+ 16#01 -> "IPv4";
+ 16#02 -> "IPv6";
+ 16#03 -> "Port";
+ 16#04 -> "Porttype"
+ end;
+
+ 16#b0 ->
+ case Item of
+ 16#01 -> "v";
+ 16#02 -> "o";
+ 16#03 -> "s";
+ 16#04 -> "i";
+ 16#05 -> "u";
+ 16#06 -> "e";
+ 16#07 -> "p";
+ 16#08 -> "c";
+ 16#09 -> "b";
+ 16#0a -> "z";
+ 16#0b -> "k";
+ 16#0c -> "a";
+ 16#0d -> "t";
+ 16#0e -> "r";
+ 16#0f -> "m"
+ end
+ end
+ end.
+
+%% -------------------------------------------------------------------
+
+% error(Reason) ->
+% erlang:error(Reason).
+
diff --git a/lib/megaco/src/binary/megaco_binary_name_resolver_v3.erl b/lib/megaco/src/binary/megaco_binary_name_resolver_v3.erl
new file mode 100644
index 0000000000..c101aa15bc
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_binary_name_resolver_v3.erl
@@ -0,0 +1,2016 @@
+%%
+%% %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: Handle meta data about packages
+%%----------------------------------------------------------------------
+
+-module(megaco_binary_name_resolver_v3).
+
+-include_lib("megaco/src/engine/megaco_message_internal.hrl").
+-include_lib("megaco/src/app/megaco_internal.hrl").
+
+
+-define(LOWER(Char),
+ if
+ Char >= $A, Char =< $Z ->
+ Char - ($A - $a);
+ true ->
+ Char
+ end).
+
+-export([packages/0,
+ capabilities/0,
+ capabilities/1,
+ decode_name/3,
+ encode_name/3
+ ]).
+
+encode_name(Config, term_id, TermId) ->
+ case megaco:encode_binary_term_id(Config, TermId) of
+ {ok, TermId2} ->
+ TermId2;
+ {error, Reason} ->
+ exit({bad_term_id, TermId, Reason})
+ end;
+encode_name(_Config, Scope, Item) ->
+ ?d("encode_name(~p) -> entry with"
+ "~n Item: ~p", [Scope, Item]),
+ encode(Scope, Item).
+
+decode_name(Config, term_id, TermId) ->
+ case megaco:decode_binary_term_id(Config, TermId) of
+ {ok, TermId2} ->
+ TermId2;
+ {error, Reason} ->
+ exit({bad_term_id, TermId, Reason})
+ end;
+decode_name(_Config, Scope, Item) ->
+ ?d("decode_name(~p) -> entry with"
+ "~n Item: ~p", [Scope, Item]),
+ decode(Scope, Item).
+
+
+
+%%----------------------------------------------------------------------
+%% 12.1.1 Package
+%%
+%% Overall description of the package, specifying:
+%%
+%% Package Name: only descriptive
+%%
+%% PackageID: is an identifier
+%%
+%% Description: is a description of the package
+%%
+%% Version:
+%%
+%% A new version of a package can only add additional Properties,
+%% Events, Signals, Statistics and new possible values for an
+%% existing parameter described in the original package. No
+%% deletions or modifications shall be allowed. A version is an
+%% integer in the range from 1 to 99.
+%%
+%% Designed to be extended only (Optional): Yes
+%%
+%% This indicates that the package has been expressly designed to
+%% be extended by others, not to be directly referenced. For
+%% example, the package may not have any function on its own or be
+%% nonsensical on its own. The MG SHOULD NOT publish this PackageID
+%% when reporting packages.
+%%
+%% Extends: existing package Descriptor
+%%
+%% A package may extend an existing package. The version of the
+%% original package must be specified. When a package extends
+%% another package it shall only add additional Properties, Events,
+%% Signals, Statistics and new possible values for an existing
+%% parameter described in the original package. An extended package
+%% shall not redefine or overload an identifier defined in the
+%% original package and packages it may have extended (multiple
+%% levels of extension). Hence, if package B version 1 extends
+%% package A version 1, version 2 of B will not be able to extend
+%% the A version 2 if A version 2 defines a name already in B
+%% version 1. If the package does not extend another package, it
+%% shall specify "none".
+%%
+%%
+%% 12.1.2 Properties
+%%
+%% Properties defined by the package, specifying:
+%%
+%% Property Name: only descriptive
+%%
+%% PropertyID: is an identifier
+%%
+%% Description: is a description of the function of the property
+%%
+%% Type: One of:
+%%
+%% Boolean
+%%
+%% String: UTF-8 string
+%%
+%% Octet String: A number of octets. See Annex A and B.3 for
+%% encoding
+%%
+%% Integer: 4 byte signed integer
+%%
+%% Double: 8 byte signed integer
+%%
+%% Character: unicode UTF-8 encoding of a single letter.
+%% Could be more than one octet.
+%%
+%% Enumeration: one of a list of possible unique values (see 12.3)
+%%
+%% Sub-list: a list of several values from a list.
+%% The type of sub-list SHALL also be specified.
+%% The type shall be chosen from the types specified in
+%% this section (with the exception of sub-list). For
+%% example, Type: sub-list of enumeration. The encoding
+%% of sub-lists is specified in Annexes A and B.3.
+%%
+%% Possible values:
+%%
+%% A package MUST specify either a specific set of values or a
+%% description of how values are determined. A package MUST also
+%% specify a default value or the default behaviour when the value
+%% is omitted from its descriptor. For example, a package may
+%% specify that procedures related to the property are suspended
+%% when its value is omitted.
+%%
+%% Default:
+%%
+%% A default value (but not procedures) may be specified as
+%% provisionable.
+%%
+%% Defined in:
+%%
+%% Which H.248.1 descriptor the property is defined in.
+%% LocalControl is for stream-dependent properties.
+%% TerminationState is for stream-independent properties.
+%% ContextAttribute is for properties that affect the context as
+%% a whole, i.e., mixing properties. These are expected to be the
+%% most common cases, but it is possible for properties to be
+%% defined in other descriptors. Context properties MUST be defined
+%% in the ContextAttribute descriptor.
+%%
+%% Characteristics: Read/Write or both, and (optionally), global:
+%%
+%% Indicates whether a property is read-only, or read-write, and
+%% if it is global. If Global is omitted, the property is not
+%% global. If a property is declared as global, the value of the
+%% property is shared by all Terminations realizing the package.
+%% If a context property is declared as global, the property is
+%% shared by all contexts realizing the package.
+%%
+%%
+%% 12.1.3 Events
+%%
+%% Events defined by the package, specifying:
+%%
+%% Event name: only descriptive
+%%
+%% EventID: is an identifier
+%%
+%% Description: a description of the function of the event
+%%
+%% EventsDescriptor Parameters:
+%%
+%% Parameters used by the MGC to configure the event, and found in
+%% the EventsDescriptor. See 12.2. If there are no parameters for
+%% the Events Descriptor, then "none" shall be specified.
+%%
+%% ObservedEventsDescriptor Parameters:
+%%
+%% Parameters returned to the MGC in Notify requests and in replies
+%% to command requests from the MGC that audit
+%% ObservedEventsDescriptor, and found in the
+%% ObservedEventsDescriptor. See 12.2. If there are no parameters
+%% for the ObservedEvents Descriptor, then �none� shall be specified.
+%%
+%%
+%% 12.1.4 Signals
+%%
+%% Signals defined by the package, specifying:
+%%
+%% Signal Name: only descriptive
+%%
+%% SignalID: is an identifier. SignalID is used in a SignalsDescriptor
+%%
+%% Description: a description of the function of the signal
+%%
+%% SignalType: one of:
+%%
+%% OO (On/Off)
+%%
+%% TO (TimeOut)
+%%
+%% BR (Brief)
+%%
+%% NOTE -�SignalType may be defined such that it is dependent on
+%% the value of one or more parameters. The package MUST specify a
+%% default signal type. If the default type is TO, the package MUST
+%% specify a default duration which may be provisioned. A default
+%% duration is meaningless for BR.
+%%
+%% Duration: in hundredths of seconds
+%%
+%% Additional Parameters: see 12.2
+%%
+%%
+%% 12.1.5 Statistics
+%%
+%% Statistics defined by the package, specifying:
+%%
+%% Statistic name: only descriptive
+%%
+%% StatisticID: is an identifier
+%%
+%% StatisticID is used in a StatisticsDescriptor
+%%
+%% Description: a description of the statistic
+%%
+%% Type: One of:
+%%
+%% Boolean
+%%
+%% String: UTF-8 string
+%%
+%% Octet String: A number of octets.
+%% See Annex A and Annex B.3 for encoding
+%%
+%% Integer: 4 byte signed integer
+%%
+%% Double: 8 byte signed integer
+%%
+%% Character: Unicode UTF-8 encoding of a single letter.
+%% Could be more than one octet.
+%%
+%% Enumeration: One of a list of possible unique values (See 12.3)
+%%
+%% Sub-list: A list of several values from a list.
+%% The type of sub-list SHALL also be specified.
+%% The type shall be chosen from the types specified in
+%% this section (with the exception of sub-list).
+%% For example, Type: sub-list of enumeration.
+%% The encoding of sub-lists is specified in Annexes A
+%% and B.3.
+%%
+%% Possible Values:
+%%
+%% A package must indicate the unit of measure, e.g. milliseconds,
+%% packets, either here or along with the type above, as well as
+%% indicating any restriction on the range.
+%%
+%% Level: Specify if the statistic can be kept at the Termination
+%% level, Stream level or Either.
+%%
+%%
+%% 12.1.6 Error Codes
+%%
+%% If the package does not define any error codes, this section may be omitted.
+%% Otherwise, it describes error codes defined by the package, specifying:
+%%
+%% Error Code #: The error code number.
+%%
+%% Name: Name of the error
+%%
+%% Definition: A description of the error code.
+%%
+%% Error Text in the Error Descriptor:
+%%
+%% A description of what text to return in the Error Descriptor.
+%%
+%% Comment: Any further comments on the use of the error code.
+%%
+%%
+%% 12.1.7 Procedures
+%%
+%% Additional guidance on the use of the package.
+%%
+%%
+%% 12.2 Guidelines to defining parameters to events and signals
+%%
+%% Parameter Name: only descriptive
+%%
+%% ParameterID: is an identifier. The textual ParameterID of
+%% parameters to Events and Signals shall not start with "EPA" and
+%% "SPA", respectively. The textual ParameterID shall also not be
+%% "ST", "Stream", "SY", "SignalType", "DR", "Duration", "NC",
+%% "NotifyCompletion", "KA", "KeepActive", "EB", "Embed", "DM",
+%% "DigitMap", "DI", "Direction", "RQ" or "RequestID".
+%%
+%% Description: a description of the function of the parameter.
+%%
+%% Type: One of:
+%%
+%% Boolean
+%%
+%% String: UTF-8 octet string
+%%
+%% Octet String: A number of octets. See Annex A and B.3 for
+%% encoding
+%%
+%% Integer: 4-octet signed integer
+%%
+%% Double: 8-octet signed integer
+%%
+%% Character: Unicode UTF-8 encoding of a single letter. Could be
+%% more than one octet.
+%%
+%% Enumeration: one of a list of possible unique values (see 12.3)
+%%
+%% Sub-list: a list of several values from a list (not supported
+%% for statistics). The type of sub-list SHALL also be
+%% specified The type shall be chosen from the types
+%% specified in this section (with the exception of
+%% sub-list). For example, Type: sub-list of enumeration.
+%% The encoding of sub-lists is specified in Annex A
+%% and B.3.
+%%
+%% Optional: Yes/No
+%%
+%% Describes if the parameter may be omitted from the signal or
+%% event.
+%%
+%% Possible values:
+%%
+%% A package MUST specify either a specific set of values or a
+%% description of how values are determined. A package MUST
+%% also specify a default value or the default behavior when the
+%% value is omitted from its descriptor. For example, a package
+%% may specify that procedures related to the parameter are
+%% suspended when its value is omitted.
+%%
+%% Default:
+%%
+%% A default value (but not procedures) may be specified as
+%% provisionable.
+%%
+%%
+%% 12.3 Lists
+%%
+%% Possible values for parameters include enumerations. Enumerations may be
+%% defined in a list. It is recommended that the list be IANA registered so
+%% that packages that extend the list can be defined without concern for
+%% conflicting names.
+%%
+%%
+%% 12.4 Identifiers
+%%
+%% Identifiers in text encoding shall be strings of up to 64 characters,
+%% containing no spaces, starting with an alphabetic character and consisting
+%% of alphanumeric characters and/or digits, and possibly including the
+%% special character underscore ("_").
+%%
+%% Identifiers in binary encoding are 2 octets long.
+%%
+%% Both text and binary values shall be specified for each identifier,
+%% including identifiers used as values in enumerated types.
+%%
+%%
+%% 12.5 Package registration
+%%
+%% A package can be registered with IANA for interoperability reasons. See
+%% clause 14 for IANA considerations.
+%%
+%%----------------------------------------------------------------------
+
+capabilities() ->
+ [{P, capabilities(P)} || P <- packages()].
+
+%% -record(property, {name, type, values, defined_in, characteristics}).
+
+%%----------------------------------------------------------------------
+%% List all known packages
+%% 'native' and 'all' are not real packages
+%%----------------------------------------------------------------------
+
+packages() ->
+ [
+ "g", % Generic
+ "root", % Base Root Package
+ "tonegen", % Tone Generator Package
+ "tonedet", % Tone Detection Package
+ "dg", % Basic DTMF Generator Package
+ "dd", % DTMF detection Package
+ "cg", % Call Progress Tones Generator Package
+ "cd", % Call Progress Tones Detection Package
+ "al", % Analog Line Supervision Package
+ "ct", % Basic Continuity Package
+ "nt", % Network Package
+ "rtp", % RTP Package
+ "swb", % SwitchBoard Package
+ "tdmc", % TDM Circuit Package
+ "" % Native pseudo package
+ ].
+
+%%----------------------------------------------------------------------
+%% List all matching capabilities
+%%----------------------------------------------------------------------
+
+capabilities(Package) ->
+ case Package of
+ "g" -> capabilities_g();
+ "root" -> capabilities_root();
+ "tonegen" -> capabilities_tonegen();
+ "tonedet" -> capabilities_tonedet();
+ "dg" -> capabilities_dg();
+ "dd" -> capabilities_dd();
+ "cg" -> capabilities_cg();
+ "cd" -> capabilities_cd();
+ "al" -> capabilities_al();
+ "ct" -> capabilities_ct();
+ "nt" -> capabilities_nt();
+ "rtp" -> capabilities_rtp();
+ "swb" -> capabilities_swb();
+ "tdmc" -> capabilities_tdmc();
+ "" -> capabilities_native()
+ end.
+
+%%----------------------------------------------------------------------
+%% Decode package name to internal form
+%% Scope ::= property | event | signal | statistics
+%%----------------------------------------------------------------------
+
+decode(mid, Package) ->
+ decode_mid(Package);
+decode(package, Package) ->
+ decode_package(Package);
+decode(profile, Package) ->
+ decode_profile(Package);
+decode(dialplan, Dialplan) ->
+ decode_dialplan(Dialplan);
+decode(Scope, [A, B | Item]) when is_atom(Scope) ->
+ ?d("decode(~p) -> entry with"
+ "~n A: ~p"
+ "~n B: ~p"
+ "~n Item: ~p", [Scope, A, B, Item]),
+ case decode_package([A, B]) of
+ "" ->
+ ?d("decode -> \"no\" package",[]),
+ decode_item(Scope, [A, B], Item);
+ Package ->
+ ?d("decode -> Package: ~p", [Package]),
+ Package ++ "/" ++ decode_item(Scope, [A, B], Item)
+ end;
+decode({Scope, [A, B | Item]}, SubItem) when is_atom(Scope) ->
+ ?d("decode(~p) -> entry with"
+ "~n A: ~p"
+ "~n B: ~p"
+ "~n Item: ~p"
+ "~n SubItem: ~p", [Scope, A, B, Item, SubItem]),
+ decode_item({Scope, Item}, [A, B], SubItem).
+
+decode_item(Scope, [A, B], Item) ->
+ ?d("decode_item -> entry",[]),
+ case A of
+ 16#00 ->
+ case B of
+ 16#01 -> decode_g(Scope, Item);
+ 16#02 -> decode_root(Scope, Item);
+ 16#03 -> decode_tonegen(Scope, Item);
+ 16#04 -> decode_tonedet(Scope, Item);
+ 16#05 -> decode_dg(Scope, Item);
+ 16#06 -> decode_dd(Scope, Item);
+ 16#07 -> decode_cg(Scope, Item);
+ 16#08 -> decode_cd(Scope, Item);
+ 16#09 -> decode_al(Scope, Item);
+ 16#0a -> decode_ct(Scope, Item);
+ 16#0b -> decode_nt(Scope, Item);
+ 16#0c -> decode_rtp(Scope, Item);
+ 16#0d -> decode_tdmc(Scope, Item);
+ 16#00 -> decode_native(Scope, Item)
+ end;
+ 16#fe ->
+ case B of
+ %% Proprietary extension
+ 16#fe -> decode_swb(Scope, Item)
+ end;
+ 16#ff ->
+ case B of
+ 16#ff when Item =:= [16#ff, 16#ff] -> "*"
+ end
+ end.
+
+decode_package(Package) ->
+ ?d("decode_package -> entry with"
+ "~n Package: ~p", [Package]),
+ [A, B] = Package,
+ case A of
+ 16#00 ->
+ case B of
+ 16#01 -> "g";
+ 16#02 -> "root";
+ 16#03 -> "tonegen";
+ 16#04 -> "tonedet";
+ 16#05 -> "dg";
+ 16#06 -> "dd";
+ 16#07 -> "cg";
+ 16#08 -> "cd";
+ 16#09 -> "al";
+ 16#0a -> "ct";
+ 16#0b -> "nt";
+ 16#0c -> "rtp";
+ 16#0d -> "tdmc";
+ 16#00 -> ""
+ end;
+ 16#fe ->
+ case B of
+ 16#fe -> "swb"
+ end;
+ 16#ff ->
+ case B of
+ 16#ff -> "*"
+ end
+ end.
+
+decode_profile([A, B]) ->
+ case A of
+ 16#00 ->
+ case B of
+ 16#fe -> "resgw";
+ _ -> "profile" ++ [A + $0, B + $0]
+ end;
+ _ ->
+ "profile" ++ [A + $0, B + $0]
+ end.
+
+decode_dialplan([A, B]) ->
+ "dialplan" ++ [A + $0, B + $0].
+
+decode_mid(Mid) ->
+ case Mid of
+ {domainName, DN} ->
+ Lower = to_lower(DN#'DomainName'.name),
+ {domainName, DN#'DomainName'{name = Lower}};
+ {deviceName, PathName} ->
+ Lower = to_lower(PathName),
+ {deviceName, Lower};
+ Other ->
+ Other
+ end.
+
+to_lower(Chars) ->
+ [?LOWER(Char) || Char <- Chars].
+
+%%----------------------------------------------------------------------
+%% Encode package name from internal form
+%% Scope ::= property | event | signal | statistics
+%%----------------------------------------------------------------------
+
+encode(mid, Package) ->
+ encode_mid(Package);
+encode(package, Package) ->
+ encode_package(Package);
+encode(profile, Profile) ->
+ encode_profile(Profile);
+encode(dialplan, Dialplan) ->
+ encode_dialplan(Dialplan);
+encode(Scope, PackageItem) when is_atom(Scope) ->
+ ?d("encode(~p) -> entry with"
+ "~n PackageItem: ~p", [Scope, PackageItem]),
+ case string:tokens(PackageItem, [$/]) of
+ [Package, Item] ->
+ ?d("encode -> "
+ "~n Package: ~p"
+ "~n Item: ~p", [Package, Item]),
+ encode_package(Package) ++ encode_item(Scope, Package, Item);
+ [Item] ->
+ ?d("encode -> Item: ~p", [Item]),
+ [16#00, 16#00 | encode_native(Scope, Item)]
+ end;
+encode({Scope, PackageItem}, SubItem) when is_atom(Scope) ->
+ ?d("encode(~p) -> entry with"
+ "~n PackageItem: ~p"
+ "~n SubItem: ~p", [Scope, PackageItem, SubItem]),
+ case string:tokens(PackageItem, [$/]) of
+ [Package, Item] ->
+ ?d("encode -> "
+ "~n Package: ~p"
+ "~n Item: ~p", [Package, Item]),
+ encode_item({Scope, Item}, Package, SubItem);
+ [_Item] ->
+ ?d("encode -> _Item: ~p", [_Item]),
+ encode_native(Scope, SubItem)
+ end.
+
+encode_item(_Scope, _Package, "*") ->
+ [16#ff, 16#ff];
+encode_item(Scope, Package, Item) ->
+ ?d("encode_item(~s) -> entry", [Package]),
+ case Package of
+ "g" -> encode_g(Scope, Item);
+ "root" -> encode_root(Scope, Item);
+ "tonegen" -> encode_tonegen(Scope, Item);
+ "tonedet" -> encode_tonedet(Scope, Item);
+ "dg" -> encode_dg(Scope, Item);
+ "dd" -> encode_dd(Scope, Item);
+ "cg" -> encode_cg(Scope, Item);
+ "cd" -> encode_cd(Scope, Item);
+ "al" -> encode_al(Scope, Item);
+ "ct" -> encode_ct(Scope, Item);
+ "nt" -> encode_nt(Scope, Item);
+ "rtp" -> encode_rtp(Scope, Item);
+ "tdmc" -> encode_tdmc(Scope, Item);
+ "swb" -> encode_swb(Scope, Item)
+ end.
+
+encode_package(Package) ->
+ case Package of
+ "g" -> [16#00, 16#01];
+ "root" -> [16#00, 16#02];
+ "tonegen" -> [16#00, 16#03];
+ "tonedet" -> [16#00, 16#04];
+ "dg" -> [16#00, 16#05];
+ "dd" -> [16#00, 16#06];
+ "cg" -> [16#00, 16#07];
+ "cd" -> [16#00, 16#08];
+ "al" -> [16#00, 16#09];
+ "ct" -> [16#00, 16#0a];
+ "nt" -> [16#00, 16#0b];
+ "rtp" -> [16#00, 16#0c];
+ "tdmc" -> [16#00, 16#0d];
+ "" -> [16#00, 16#00];
+ "*" -> [16#ff, 16#ff];
+ "swb" -> [16#fe, 16#fe]
+ end.
+
+encode_profile(Profile) ->
+ case Profile of
+ "resgw" ->
+ [16#00, 16#fe];
+ [$p, $r, $o, $f, $i, $l, $e | Name] ->
+ case Name of
+ [A, B] -> [A - $0, B - $0];
+ [B] -> [0, B - $0];
+ [] -> [0, 0]
+ end
+ end.
+
+encode_dialplan(Dialplan) ->
+ case Dialplan of
+ [$d, $i, $a, $l, $p, $l, $a, $n | Name] ->
+ case Name of
+ [A, B] -> [A - $0, B - $0];
+ [B] -> [0, B - $0];
+ [] -> [0, 0]
+ end
+ end.
+
+encode_mid(Mid) ->
+ Mid.
+
+
+%%----------------------------------------------------------------------
+%% Name: g - Generic
+%% Version: 1
+%% Extends: None
+%% Purpose: Generic package for commonly encountered items
+%%----------------------------------------------------------------------
+
+capabilities_g() ->
+ [
+ {event, "cause"},
+ {event, "sc"}
+ ].
+
+encode_g(event, Item) ->
+ case Item of
+ "cause" -> [16#00, 16#01];
+ "sc" -> [16#00, 16#02]
+ end;
+
+encode_g({event_parameter, Item}, SubItem) ->
+ case Item of
+ "cause" ->
+ case SubItem of
+ "Generalcause" -> [16#00, 16#01];
+ "Failurecause" -> [16#00, 16#02]
+ end;
+ "sc" ->
+ case SubItem of
+ "SigID" -> [16#00, 16#01];
+ "Meth" -> [16#00, 16#02];
+ "SLID" -> [16#00, 16#03];
+ "RID" -> [16#00, 16#04]
+ end
+ end.
+
+decode_g(event, Item) ->
+ case Item of
+ [16#00, 16#01] -> "cause";
+ [16#00, 16#02] -> "sc"
+ end;
+
+decode_g({event_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#01] -> % Event: cause
+ case SubItem of
+ [16#00, 16#01] -> "Generalcause";
+ [16#00, 16#02] -> "Failurecause"
+ end;
+
+ [16#00, 16#02] -> % Event: sc
+ case SubItem of
+ [16#00, 16#01] -> "SigID";
+ [16#00, 16#02] -> "Meth";
+ [16#00, 16#03] -> "SLID";
+ [16#00, 16#04] -> "RID"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: root - Base Root Package
+%% Version: 2
+%% Extends: None
+%% Purpose: This package defines Gateway wide properties.
+%%----------------------------------------------------------------------
+
+capabilities_root() ->
+ [
+ {property, "maxNumberOfContexts"},
+ {property, "maxTerminationsPerContext"},
+ {property, "normalMGExecutionTime"},
+ {property, "normalMGCExecutionTime"},
+ {property, "MGProvisionalResponseTimerValue"},
+ {property, "MGCProvisionalResponseTimerValue"},
+ {property, "MGCOriginatedPendingLimit"},
+ {property, "MGOriginatedPendingLimit"},
+ {property, "MGSegmentationTimerValue"},
+ {property, "MGCSegmentationTimerValue"},
+ {property, "MGMaxPDUSize"},
+ {property, "MGCMaxPDUSize"}
+ ].
+
+encode_root(Scope, Item) ->
+ case Scope of
+ property ->
+ case Item of
+ "maxNumberOfContexts" -> [16#00, 16#01];
+ "maxTerminationsPerContext" -> [16#00, 16#02];
+ "normalMGExecutionTime" -> [16#00, 16#03];
+ "normalMGCExecutionTime" -> [16#00, 16#04];
+ "MGProvisionalResponseTimerValue" -> [16#00, 16#05];
+ "MGCProvisionalResponseTimerValue" -> [16#00, 16#06];
+ "MGCOriginatedPendingLimit" -> [16#00, 16#07];
+ "MGOriginatedPendingLimit" -> [16#00, 16#08];
+ "MGSegmentationTimerValue" -> [16#00, 16#09];
+ "MGCSegmentationTimerValue" -> [16#00, 16#0a];
+ "MGMaxPDUSize" -> [16#00, 16#0b];
+ "MGCMaxPDUSize" -> [16#00, 16#0c]
+ end
+ end.
+
+decode_root(Scope, Item) ->
+ case Scope of
+ property ->
+ case Item of
+ [16#00, 16#01] -> "maxNumberOfContexts";
+ [16#00, 16#02] -> "maxTerminationsPerContext";
+ [16#00, 16#03] -> "normalMGExecutionTime";
+ [16#00, 16#04] -> "normalMGCExecutionTime";
+ [16#00, 16#05] -> "MGProvisionalResponseTimerValue";
+ [16#00, 16#06] -> "MGCProvisionalResponseTimerValue";
+ [16#00, 16#07] -> "MGCOriginatedPendingLimit";
+ [16#00, 16#08] -> "MGOriginatedPendingLimit";
+ [16#00, 16#09] -> "MGSegmentationTimerValue";
+ [16#00, 16#0a] -> "MGCSegmentationTimerValue";
+ [16#00, 16#0b] -> "MGMaxPDUSize";
+ [16#00, 16#0c] -> "MGCMaxPDUSize"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: tonegen - Tone Generator Package
+%% Version: 2
+%% Extends: None
+%% Purpose: This package defines signals to generate audio tones.
+%% This package does not specify parameter values. It is
+%% intended to be extendable. Generally, tones are defined
+%% as an individual signal with a parameter, ind,
+%% representing "interdigit" time delay, and a tone id to
+%% be used with playtones. A tone id should be kept
+%% consistent with any tone generation for the same tone.
+%% MGs are expected to be provisioned with the characteristics
+%% of appropriate tones for the country in which the MG is located.
+%%----------------------------------------------------------------------
+
+capabilities_tonegen() ->
+ [
+ {signal, "pt"}
+ ].
+
+encode_tonegen(signal, Item) ->
+ case Item of
+ "pt" -> [16#00, 16#01]
+ end;
+
+encode_tonegen({signal_parameter, Item}, SubItem) ->
+ case Item of
+ "pt" ->
+ case SubItem of
+ "tl" -> [16#00, 16#01];
+ "ind" -> [16#00, 16#02];
+ "btd" -> [16#00, 16#03]
+ end
+ end.
+
+decode_tonegen(signal, Item) ->
+ case Item of
+ [16#00, 16#01] -> "pt"
+ end;
+
+decode_tonegen({signal_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#01] -> % Event: pt
+ case SubItem of
+ [16#00, 16#01] -> "tl";
+ [16#00, 16#02] -> "ind";
+ [16#00, 16#03] -> "btd"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: tonedet - Tone Detection Package
+%% Version: 1
+%% Extends: None
+%% Purpose: This Package defines events for audio tone detection.
+%% Tones are selected by name (tone id). MGs are expected
+%% to be provisioned with the characteristics of appropriate
+%% tones for the country in which the MG is located.
+%%
+%% This package does not specify parameter values.
+%% It is intended to be extendable.
+%%----------------------------------------------------------------------
+
+capabilities_tonedet() ->
+ [
+ {event, "std"},
+ {event, "etd"},
+ {event, "ltd"}
+ ].
+
+encode_tonedet(event, Item) ->
+ case Item of
+ "std" -> [16#00, 16#01];
+ "etd" -> [16#00, 16#02];
+ "ltd" -> [16#00, 16#03]
+ end;
+
+encode_tonedet({event_parameter, Item}, SubItem) ->
+ case Item of
+ "std" ->
+ case SubItem of
+ "tl" -> [16#00, 16#01];
+ "tid" -> [16#00, 16#03]
+ end;
+ "etd" ->
+ case SubItem of
+ "tl" -> [16#00, 16#01];
+ "tid" -> [16#00, 16#03];
+ "dur" -> [16#00, 16#02]
+ end;
+ "ltd" ->
+ case SubItem of
+ "tl" -> [16#00, 16#01];
+ "dur" -> [16#00, 16#02];
+ "tid" -> [16#00, 16#03]
+ end
+ end.
+
+decode_tonedet(event, Item) ->
+ case Item of
+ [16#00, 16#01] -> "std";
+ [16#00, 16#02] -> "etd";
+ [16#00, 16#03] -> "ltd"
+ end;
+
+decode_tonedet({event_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#01] -> % Event std
+ case SubItem of
+ [16#00, 16#01] -> "tl";
+ [16#00, 16#03] -> "tid"
+ end;
+ [16#00, 16#02] -> % Event etd
+ case SubItem of
+ [16#00, 16#01] -> "tl";
+ [16#00, 16#03] -> "tid";
+ [16#00, 16#02] -> "dur"
+ end;
+ [16#00, 16#03] -> % Event ltd
+ case SubItem of
+ [16#00, 16#01] -> "tl";
+ [16#00, 16#02] -> "dur";
+ [16#00, 16#03] -> "tid"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: dg - Basic DTMF Generator Package
+%% Version: 1
+%% Extends: tonegen version 1
+%% Purpose: This package defines the basic DTMF tones as signals and
+%% extends the allowed values of parameter tl of playtone
+%% in tonegen.
+%%----------------------------------------------------------------------
+
+capabilities_dg() ->
+ [
+ {signal, "d0"},
+ {signal, "d1"},
+ {signal, "d2"},
+ {signal, "d3"},
+ {signal, "d4"},
+ {signal, "d5"},
+ {signal, "d6"},
+ {signal, "d7"},
+ {signal, "d8"},
+ {signal, "d9"},
+ {signal, "ds"},
+ {signal, "do"},
+ {signal, "da"},
+ {signal, "db"},
+ {signal, "dc"},
+ {signal, "dd"}
+ ].
+
+encode_dg(signal, Item) ->
+ case Item of
+ "d0" -> [16#00, 16#10];
+ "d1" -> [16#00, 16#11];
+ "d2" -> [16#00, 16#12];
+ "d3" -> [16#00, 16#13];
+ "d4" -> [16#00, 16#14];
+ "d5" -> [16#00, 16#15];
+ "d6" -> [16#00, 16#16];
+ "d7" -> [16#00, 16#17];
+ "d8" -> [16#00, 16#18];
+ "d9" -> [16#00, 16#19];
+ "ds" -> [16#00, 16#20];
+ "do" -> [16#00, 16#21];
+ "da" -> [16#00, 16#1a];
+ "db" -> [16#00, 16#1b];
+ "dc" -> [16#00, 16#1c];
+ "dd" -> [16#00, 16#1d]
+ end;
+
+encode_dg({signal_parameter, Item}, SubItem) ->
+ case Item of
+ "d0" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d1" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d2" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d3" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d4" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d5" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d6" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d7" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d8" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d9" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "ds" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "do" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "da" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "db" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "dc" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "dd" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end
+ end.
+
+decode_dg(signal, Item) ->
+ case Item of
+ [16#00, 16#10] -> "d0";
+ [16#00, 16#11] -> "d1";
+ [16#00, 16#12] -> "d2";
+ [16#00, 16#13] -> "d3";
+ [16#00, 16#14] -> "d4";
+ [16#00, 16#15] -> "d5";
+ [16#00, 16#16] -> "d6";
+ [16#00, 16#17] -> "d7";
+ [16#00, 16#18] -> "d8";
+ [16#00, 16#19] -> "d9";
+ [16#00, 16#20] -> "ds";
+ [16#00, 16#21] -> "do";
+ [16#00, 16#1a] -> "da";
+ [16#00, 16#1b] -> "db";
+ [16#00, 16#1c] -> "dc";
+ [16#00, 16#1d] -> "dd"
+ end;
+
+decode_dg({signal_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#10] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#11] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#12] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#13] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#14] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#15] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#16] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#17] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#18] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#19] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#20] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#21] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#1a] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#1b] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#1c] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#1d] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: dd - DTMF detection Package
+%% Version: 1
+%% Extends: tonedet version 1
+%% Purpose: This package defines the basic DTMF tones detection.
+%% Tones are selected by name (tone id). MGs are expected
+%% to be provisioned with the characteristics of appropriate
+%% tones for the country in which the MG is located.
+%%
+%% This package does not specify parameter values.
+%% It is intended to be extendable.
+%%
+%% Additional tone id values are all tone ids described in package dg
+%% (basic DTMF generator package).
+%%
+%% The following table maps DTMF events to digit map symbols as described
+%% in section 7.1.14.
+%%
+%% _________________________________
+%% | DTMF Event | Symbol |
+%% | d0 | "0" |
+%% | d1 | "1" |
+%% | d2 | "2" |
+%% | d3 | "3" |
+%% | d4 | "4" |
+%% | d5 | "5" |
+%% | d6 | "6" |
+%% | d7 | "7" |
+%% | d8 | "8" |
+%% | d9 | "9" |
+%% | da | "A" or "a"|
+%% | db | "B" or "b"|
+%% | dc | "C" or "c"|
+%% | dd | "D" or "d"|
+%% | ds | "E" or "e"|
+%% | do | "F" or "f"|
+%% |___________________|____________|
+%%
+%%----------------------------------------------------------------------
+
+capabilities_dd() ->
+ [
+ {event, "ce"},
+ {event, "d0"},
+ {event, "d1"},
+ {event, "d2"},
+ {event, "d3"},
+ {event, "d4"},
+ {event, "d5"},
+ {event, "d6"},
+ {event, "d7"},
+ {event, "d8"},
+ {event, "d9"},
+ {event, "ds"},
+ {event, "do"},
+ {event, "da"},
+ {event, "db"},
+ {event, "dc"},
+ {event, "dd"}
+ ].
+
+encode_dd(event, Item) ->
+ case Item of
+ "ce" -> [16#00, 16#04];
+ "d0" -> [16#00, 16#10];
+ "d1" -> [16#00, 16#11];
+ "d2" -> [16#00, 16#12];
+ "d3" -> [16#00, 16#13];
+ "d4" -> [16#00, 16#14];
+ "d5" -> [16#00, 16#15];
+ "d6" -> [16#00, 16#16];
+ "d7" -> [16#00, 16#17];
+ "d8" -> [16#00, 16#18];
+ "d9" -> [16#00, 16#19];
+ "ds" -> [16#00, 16#20];
+ "do" -> [16#00, 16#21];
+ "da" -> [16#00, 16#1a];
+ "db" -> [16#00, 16#1b];
+ "dc" -> [16#00, 16#1c];
+ "dd" -> [16#00, 16#1d]
+ end;
+
+encode_dd({event_parameter, Item}, SubItem) ->
+ case Item of
+ "ce" ->
+ case SubItem of
+ "ds" -> [16#00, 16#01];
+ "Meth" -> [16#00, 16#03]
+ end;
+ "d0" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d1" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d2" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d3" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d4" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d5" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d6" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d7" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d8" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d9" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "ds" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "do" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "da" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "db" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "dc" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "dd" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end
+ end.
+
+decode_dd(event, Item) ->
+ case Item of
+ [16#00, 16#04] -> "ce";
+ [16#00, 16#10] -> "d0";
+ [16#00, 16#11] -> "d1";
+ [16#00, 16#12] -> "d2";
+ [16#00, 16#13] -> "d3";
+ [16#00, 16#14] -> "d4";
+ [16#00, 16#15] -> "d5";
+ [16#00, 16#16] -> "d6";
+ [16#00, 16#17] -> "d7";
+ [16#00, 16#18] -> "d8";
+ [16#00, 16#19] -> "d9";
+ [16#00, 16#20] -> "ds";
+ [16#00, 16#21] -> "do";
+ [16#00, 16#1a] -> "da";
+ [16#00, 16#1b] -> "db";
+ [16#00, 16#1c] -> "dc";
+ [16#00, 16#1d] -> "dd"
+ end;
+
+decode_dd({event_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#04] -> % Event ce
+ case SubItem of
+ [16#00, 16#01] -> "ds";
+ [16#00, 16#03] -> "Meth"
+ end;
+ [16#00, 16#10] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#11] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#12] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#13] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#14] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#15] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#16] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#17] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#18] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#19] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#20] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#21] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#1a] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#1b] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#1c] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#1d] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end
+ end.
+
+%%----------------------------------------------------------------------
+%% Name: cg - Call Progress Tones Generator Package
+%% Version: 1
+%% Extends: tonegen version 1
+%% Purpose: This package defines the basic call progress tones as signals
+%% and extends the allowed values of the tl parameter of
+%% playtone in tonegen.
+%%----------------------------------------------------------------------
+
+capabilities_cg() ->
+ [
+ {signal, "dt"},
+ {signal, "rt"},
+ {signal, "bt"},
+ {signal, "ct"},
+ {signal, "sit"},
+ {signal, "wt"},
+ {signal, "prt"},
+ {signal, "cw"},
+ {signal, "cr"}
+ ].
+
+
+encode_cg(Scope, Item) ->
+ case Scope of
+ signal ->
+ case Item of
+ "dt" -> [16#00, 16#30];
+ "rt" -> [16#00, 16#31];
+ "bt" -> [16#00, 16#32];
+ "ct" -> [16#00, 16#33];
+ "sit" -> [16#00, 16#34];
+ "wt" -> [16#00, 16#35];
+ "prt" -> [16#00, 16#36];
+ "cw" -> [16#00, 16#37];
+ "cr" -> [16#00, 16#38]
+ end
+ end.
+
+decode_cg(Scope, Item) ->
+ case Scope of
+ signal ->
+ case Item of
+ [16#00, 16#30] -> "dt";
+ [16#00, 16#31] -> "rt";
+ [16#00, 16#32] -> "bt";
+ [16#00, 16#33] -> "ct";
+ [16#00, 16#34] -> "sit";
+ [16#00, 16#35] -> "wt";
+ [16#00, 16#36] -> "prt";
+ [16#00, 16#37] -> "cw";
+ [16#00, 16#38] -> "cr"
+ end
+ end.
+
+%%----------------------------------------------------------------------
+%% Name: cd - Call Progress Tones Detection Package
+%% Version: 1
+%% Extends: tonedet version 1
+%% Purpose: This package defines the basic call progress detection tones.
+%% This Package extends the possible values of tone id
+%% in the "start tone detected", "end tone detected" and
+%% "long tone detected" events.
+%% Additional values
+%% tone id values are defined for start tone detected,
+%% end tone detected and long tone detected with
+%% the same values as those in package cg (call
+%% progress tones generation package).
+%%
+%% The required set of tone ids corresponds to Recommendation E.180/Q.35
+%% [ITU-T Recommendation E.180/Q.35 (1998)]. See Recommendation E.180/Q.35
+%% for definition of the meanings of these tones.
+%%----------------------------------------------------------------------
+
+capabilities_cd() ->
+ [
+ {event, "dt"},
+ {event, "rt"},
+ {event, "bt"},
+ {event, "ct"},
+ {event, "sit"},
+ {event, "wt"},
+ {event, "prt"},
+ {event, "cw"},
+ {event, "cr"}
+ ].
+
+
+encode_cd(Scope, Item) ->
+ case Scope of
+ event ->
+ case Item of
+ "dt" -> [16#00, 16#30];
+ "rt" -> [16#00, 16#31];
+ "bt" -> [16#00, 16#32];
+ "ct" -> [16#00, 16#33];
+ "sit"-> [16#00, 16#34];
+ "wt" -> [16#00, 16#35];
+ "prt"-> [16#00, 16#36];
+ "cw" -> [16#00, 16#37];
+ "cr" -> [16#00, 16#38]
+ end
+ end.
+
+decode_cd(Scope, Item) ->
+ case Scope of
+ event ->
+ case Item of
+ [16#00, 16#30] -> "dt";
+ [16#00, 16#31] -> "rt";
+ [16#00, 16#32] -> "bt";
+ [16#00, 16#33] -> "ct";
+ [16#00, 16#34] -> "sit";
+ [16#00, 16#35] -> "wt";
+ [16#00, 16#36] -> "prt";
+ [16#00, 16#37] -> "cw";
+ [16#00, 16#38] -> "cr"
+ end
+ end.
+
+%%----------------------------------------------------------------------
+%% Name: al - Analog Line Supervision Package
+%% Version: 1
+%% Extends: None
+%% Purpose: This package defines events and signals for an analog line.
+%%----------------------------------------------------------------------
+
+capabilities_al() ->
+ [
+ {event, "on"},
+ {event, "of"},
+ {event, "fl"},
+ {signal, "ri"}
+ ].
+
+encode_al(event, Item) ->
+ ?d("encode_al(event) -> entry with"
+ "~n Item: ~p", [Item]),
+ case Item of
+ "on" -> [16#00, 16#04];
+ "of" -> [16#00, 16#05];
+ "fl" -> [16#00, 16#06]
+ end;
+
+encode_al({event_parameter, Item}, SubItem) ->
+ ?d("encode_al({event_parameter,~p}) -> entry with"
+ "~n SubItem: ~p", [Item, SubItem]),
+ case Item of
+ "on" ->
+ case SubItem of
+ "strict" -> [16#00, 16#01];
+ "init" -> [16#00, 16#02]
+ end;
+ "of" ->
+ case SubItem of
+ "strict" -> [16#00, 16#01];
+ "init" -> [16#00, 16#02]
+ end;
+ "fl" ->
+ case SubItem of
+ "mindur" -> [16#00, 16#04];
+ "maxdur" -> [16#00, 16#05]
+ end
+ end;
+
+encode_al(signal, Item) ->
+ ?d("encode_al(signal) -> entry with"
+ "~n Item: ~p", [Item]),
+ case Item of
+ "ri" -> [16#00, 16#02]
+ end;
+
+encode_al({signal_parameter, Item}, SubItem) ->
+ ?d("encode_al({signal_parameter,~p}) -> entry with"
+ "~n SubItem: ~p", [Item, SubItem]),
+ case Item of
+ "ri" ->
+ case SubItem of
+ "cad" -> [16#00, 16#06];
+ "freq" -> [16#00, 16#07]
+ end
+ end.
+
+decode_al(event, SubItem) ->
+ ?d("decode_al(event) -> entry with"
+ "~n SubItem: ~p", [SubItem]),
+ case SubItem of
+ [16#00, 16#04] -> "on";
+ [16#00, 16#05] -> "of";
+ [16#00, 16#06] -> "fl"
+ end;
+
+decode_al({event_parameter, Item}, SubItem) ->
+ ?d("decode_al({event_parameter,~p}) -> entry with"
+ "~n SubItem: ~p", [Item, SubItem]),
+ case Item of
+ [16#00,16#04] -> %% Event: on
+ case SubItem of
+ [16#00, 16#01] -> "strict";
+ [16#00, 16#02] -> "init"
+ end;
+ [16#00,16#05] -> %% Event: of
+ case SubItem of
+ [16#00, 16#01] -> "strict";
+ [16#00, 16#02] -> "init"
+ end;
+ [16#00,16#06] -> %% Event: fl
+ case SubItem of
+ [16#00, 16#04] -> "mindur";
+ [16#00, 16#05] -> "maxdur"
+ end
+ end;
+
+decode_al(signal, SubItem) ->
+ ?d("decode_al(signal) -> entry with"
+ "~n SubItem: ~p", [SubItem]),
+ case SubItem of
+ [16#00, 16#02] -> "ri"
+ end;
+
+decode_al({signal_parameter, Item}, SubItem) ->
+ ?d("decode_al({signal_parameter,~p}) -> entry with"
+ "~n SubItem: ~p", [Item, SubItem]),
+ case Item of
+ [16#00,16#02] -> %% Event: ri
+ case SubItem of
+ [16#00, 16#06] -> "cad";
+ [16#00, 16#07] -> "freq"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: ct - Basic Continuity Package
+%% Version: 1
+%% Extends: None
+%% Purpose: This package defines events and signals for continuity test.
+%% The continuity test includes provision of either a loopback
+%% or transceiver functionality.
+%%----------------------------------------------------------------------
+
+capabilities_ct() ->
+ [
+ {event, "cmp"},
+ {signal, "ct"},
+ {signal, "rsp"}
+ ].
+
+encode_ct(event, Item) ->
+ case Item of
+ "cmp" -> [16#00, 16#05]
+ end;
+encode_ct({event_parameter, Item}, SubItem) ->
+ case Item of
+ "cmp" ->
+ case SubItem of
+ "res" -> [16#00, 16#08]
+ end
+ end;
+encode_ct(signal, Item) ->
+ case Item of
+ "ct" -> [16#00, 16#03];
+ "rsp" -> [16#00, 16#04]
+ end.
+
+decode_ct(event, Item) ->
+ case Item of
+ [16#00, 16#05] -> "cmp"
+ end;
+decode_ct({event_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#05] -> % Event cmp
+ case SubItem of
+ [16#00, 16#08] -> "res"
+ end
+ end;
+decode_ct(signal, Item) ->
+ case Item of
+ [16#00, 16#03] -> "ct";
+ [16#00, 16#04] -> "rsp"
+ end.
+
+%%----------------------------------------------------------------------
+%% Name: nt - Network Package
+%% Version: 1
+%% Extends: None
+%% Purpose: This package defines properties of network terminations
+%% independent of network type.
+%%----------------------------------------------------------------------
+
+capabilities_nt() ->
+ [
+ {property, "jit"},
+ {event, "netfail"},
+ {event, "qualert"},
+ {statistics, "dur"},
+ {statistics, "os"},
+ {statistics, "or"}
+ ].
+
+encode_nt(property, Item) ->
+ case Item of
+ "jit" -> [16#00, 16#07]
+ end;
+encode_nt(event, Item) ->
+ case Item of
+ "netfail" -> [16#00, 16#05];
+ "qualert" -> [16#00, 16#06]
+ end;
+encode_nt({event_parameter, Item}, SubItem) ->
+ case Item of
+ "netfail" ->
+ case SubItem of
+ "cs" -> [16#00, 16#01]
+ end;
+ "qualert" ->
+ case SubItem of
+ "th" -> [16#00, 16#01]
+ end
+ end;
+encode_nt(statistics, Item) ->
+ case Item of
+ "dur" -> [16#00, 16#01];
+ "os" -> [16#00, 16#02];
+ "or" -> [16#00, 16#03]
+ end.
+
+decode_nt(property, Item) ->
+ case Item of
+ [16#00, 16#07] -> "jit"
+ end;
+decode_nt(event, Item) ->
+ case Item of
+ [16#00, 16#05] -> "netfail";
+ [16#00, 16#06] -> "qualert"
+ end;
+decode_nt({event_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#05] -> % Event netfail
+ case SubItem of
+ [16#00, 16#01] -> "cs"
+ end;
+ [16#00, 16#06] -> % Event qualert
+ case Item of
+ [16#00, 16#01] -> "th"
+ end
+ end;
+decode_nt(statistics, Item) ->
+ case Item of
+ [16#00, 16#01] -> "dur";
+ [16#00, 16#02] -> "os";
+ [16#00, 16#03] -> "or"
+ end.
+
+%%----------------------------------------------------------------------
+%% Name: rtp - RTP Package
+%% Version: 1
+%% Extends: nt version 1
+%% Purpose: This package is used to support packet based multimedia
+%% data transfer by means of the Real-time Transport Protocol
+%% (RTP) [RFC 1889].
+%%----------------------------------------------------------------------
+
+capabilities_rtp() ->
+ [
+ {event, "pltrans"},
+ {statistics, "ps"},
+ {statistics, "pr"},
+ {statistics, "pl"},
+ {statistics, "jit"},
+ {statistics, "delay"}
+ ].
+
+encode_rtp(event, Item) ->
+ case Item of
+ "pltrans" -> [16#00, 16#01]
+ end;
+encode_rtp({event_parameter, Item}, SubItem) ->
+ case Item of
+ "pltrans" ->
+ case SubItem of
+ "rtppltype" -> [16#00, 16#01]
+ end
+ end;
+encode_rtp(statistics, Item) ->
+ case Item of
+ "ps" -> [16#00, 16#04];
+ "pr" -> [16#00, 16#05];
+ "pl" -> [16#00, 16#06];
+ "jit" -> [16#00, 16#07];
+ "delay" -> [16#00, 16#08]
+ end.
+
+decode_rtp(event, Item) ->
+ case Item of
+ [16#00, 16#01] -> "pltrans"
+ end;
+decode_rtp({event_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#01] -> % Event pltrans
+ case SubItem of
+ [16#00, 16#01] -> "rtppltype"
+ end
+ end;
+decode_rtp(statistics, Item) ->
+ case Item of
+ [16#00, 16#04] -> "ps";
+ [16#00, 16#05] -> "pr";
+ [16#00, 16#06] -> "pl";
+ [16#00, 16#07] -> "jit";
+ [16#00, 16#08] -> "delay"
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: tdmc - TDM Circuit Package
+%% Version: 1
+%% Extends: nt version 1
+%% Purpose: This package is used to support TDM circuit terminations.
+%%----------------------------------------------------------------------
+
+capabilities_tdmc() ->
+ [
+ {property, "ec"},
+ {property, "gain"}
+ ].
+
+encode_tdmc(Scope, Item) ->
+ case Scope of
+ property ->
+ case Item of
+ "ec" -> [16#00, 16#08];
+ "gain" -> [16#00, 16#0a]
+ end
+ end.
+
+decode_tdmc(Scope, Item) ->
+ case Scope of
+ property ->
+ case Item of
+ [16#00, 16#08] -> "ec";
+ [16#00, 16#0a] -> "gain"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: swb - SwitchBoard Package
+%% Version: 1
+%% Extends: none
+%% Purpose: This package is used to support SwitchBoard specials
+%%----------------------------------------------------------------------
+
+capabilities_swb() ->
+ [
+ {statistics, "fs"}, % Free slots
+ {statistics, "as"} % Allocated slots
+ ].
+
+encode_swb(Scope, Item) ->
+ case Scope of
+ statistics ->
+ case Item of
+ "fs" -> [16#00, 16#00];
+ "as" -> [16#00, 16#01]
+ end
+ end.
+
+decode_swb(Scope, Item) ->
+ case Scope of
+ statistics ->
+ case Item of
+ [16#00, 16#00] -> "fs";
+ [16#00, 16#01] -> "as"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: native - Pseudo package
+%% Version: 1
+%% Extends: None
+%% Purpose: Native tags for media stream properties
+%%
+%% Parameters for Local descriptors and Remote descriptors are
+%% specified as tag-value pairs if binary encoding is used for the
+%% protocol. This annex contains the property names (PropertyID), the
+%% tags (Property Tag), type of the property (Type) and the values
+%% (Value).Values presented in the Value field when the field contains
+%% references shall be regarded as "information". The reference
+%% contains the normative values. If a value field does not contain a
+%% reference then the values in that field can be considered as
+%% "normative".
+%%
+%% Tags are given as hexadecimal numbers in this annex. When setting
+%% the value of a property, a MGC may underspecify the value according
+%% to one of the mechanisms specified in section 7.1.1.
+%%
+%% For type "enumeration" the value is represented by the value in brack-
+%% ets, e.g., Send(0), Receive(1).
+%%----------------------------------------------------------------------
+%%
+%% C.6. IP
+%%
+%% ________________________________________________________________
+%% | PropertyID| Tag | Type | Value |
+%% | IPv4 | 6001 | 32 BITS | Ipv4Address |
+%% | IPv6 | 6002 | 128 BITS | IPv6 Address |
+%% | Port | 6003 | Unsigned Int| Port |
+%% | Porttype | 6004 | Enumerated | TCP(0),UDP(1),SCTP(2)|
+%% |___________|____________|______________|_______________________|
+%%
+%%
+%% C.11. SDP Equivalents
+%%
+%% ______________________________________________________________
+%% | PropertyID| Tag | Type | Value |
+%% | SDP_V | B001| STRING| Protocol Version |
+%% | SDP_O | B002| STRING| Owner-creator and session ID |
+%% | SDP_S | B003| STRING| Sesson name |
+%% | SDP_I | B004| STRING| Session identifier |
+%% | SDP_U | B005| STRING| URI of descriptor |
+%% | SDC_E | B006| STRING| email address |
+%% | SDP_P | B007| STRING| phone number |
+%% | SDP_C | B008| STRING| Connection information |
+%% | SDP_B | B009| STRING| Bandwidth Information |
+%% | SDP_Z | B00A| STRING| time zone adjustment |
+%% | SDP_K | B00B| STRING| Encryption Key |
+%% | SDP_A | B00C| STRING| Zero or more session attributes|
+%% | SDP_T | B00D| STRING| Active Session Time |
+%% | SDP_R | B00E| STRING| Zero or more repeat times |
+%% | SDP_M | B00F| STRING| Media name and transport addr |
+%% | | | | Reference: IETF RFC 2327 |
+%% |___________|______|________|_________________________________|
+%%
+%%----------------------------------------------------------------------
+
+capabilities_native() ->
+ [
+ %% C.6. IP
+ {property, "IPv4"},
+ {property, "IPv6"},
+ {property, "Port"},
+ {property, "Porttype"},
+
+ %% C.11. SDP Equivalents
+ {property, "v"},
+ {property, "o"},
+ {property, "s"},
+ {property, "i"},
+ {property, "u"},
+ {property, "e"},
+ {property, "p"},
+ {property, "c"},
+ {property, "b"},
+ {property, "z"},
+ {property, "k"},
+ {property, "a"},
+ {property, "t"},
+ {property, "r"},
+ {property, "m"}
+ ].
+
+encode_native(Scope, Item) ->
+ case Scope of
+ property ->
+ case Item of
+ %% IP
+ "IPv4" -> [16#60, 16#01];
+ "IPv6" -> [16#60, 16#02];
+ "Port" -> [16#60, 16#03];
+ "Porttype" -> [16#60, 16#04];
+
+ %% SDP
+ "v" -> [16#b0, 16#01];
+ "o" -> [16#b0, 16#02];
+ "s" -> [16#b0, 16#03];
+ "i" -> [16#b0, 16#04];
+ "u" -> [16#b0, 16#05];
+ "e" -> [16#b0, 16#06];
+ "p" -> [16#b0, 16#07];
+ "c" -> [16#b0, 16#08];
+ "b" -> [16#b0, 16#09];
+ "z" -> [16#b0, 16#0a];
+ "k" -> [16#b0, 16#0b];
+ "a" -> [16#b0, 16#0c];
+ "t" -> [16#b0, 16#0d];
+ "r" -> [16#b0, 16#0e];
+ "m" -> [16#b0, 16#0f]
+ end
+ end.
+
+decode_native(Scope, [Type, Item]) ->
+ case Scope of
+ property ->
+ case Type of
+ 16#60 ->
+ case Item of
+ 16#01 -> "IPv4";
+ 16#02 -> "IPv6";
+ 16#03 -> "Port";
+ 16#04 -> "Porttype"
+ end;
+
+ 16#b0 ->
+ case Item of
+ 16#01 -> "v";
+ 16#02 -> "o";
+ 16#03 -> "s";
+ 16#04 -> "i";
+ 16#05 -> "u";
+ 16#06 -> "e";
+ 16#07 -> "p";
+ 16#08 -> "c";
+ 16#09 -> "b";
+ 16#0a -> "z";
+ 16#0b -> "k";
+ 16#0c -> "a";
+ 16#0d -> "t";
+ 16#0e -> "r";
+ 16#0f -> "m"
+ end
+ end
+ end.
+
+%% -------------------------------------------------------------------
+
+% error(Reason) ->
+% erlang:error(Reason).
+
diff --git a/lib/megaco/src/binary/megaco_binary_term_id.erl b/lib/megaco/src/binary/megaco_binary_term_id.erl
new file mode 100644
index 0000000000..f975c1ab53
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_binary_term_id.erl
@@ -0,0 +1,187 @@
+%%
+%% %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 : Handle ASN.1 BER encoding of Megaco/H.248
+%%----------------------------------------------------------------------
+
+-module(megaco_binary_term_id).
+
+
+%%----------------------------------------------------------------------
+%% Include files
+%%----------------------------------------------------------------------
+
+-include_lib("megaco/include/megaco.hrl").
+-include_lib("megaco/src/engine/megaco_message_internal.hrl").
+
+
+%%----------------------------------------------------------------------
+%% External exports
+%%----------------------------------------------------------------------
+
+-export([encode/2, decode/2]).
+
+
+%%----------------------------------------------------------------------
+%% Internal exports
+%%----------------------------------------------------------------------
+
+
+%%----------------------------------------------------------------------
+%% Macros
+%%----------------------------------------------------------------------
+
+-define(default_config, [8,8,8]).
+
+-define(asn_root_termination_id,
+ #'TerminationID'{wildcard = [],
+ id = [16#FF, 16#FF, 16#FF, 16#FF,
+ 16#FF, 16#FF, 16#FF, 16#FF]}).
+
+-define(megaco_all_wildcard_termination_id,
+ #megaco_term_id{contains_wildcards = true,
+ id = [[?megaco_all]]}).
+-define(megaco_choose_wildcard_termination_id,
+ #megaco_term_id{contains_wildcards = true,
+ id = [[?megaco_choose]]}).
+
+
+%%----------------------------------------------------------------------
+%% Convert a 'TerminationId' record into a ASN.1 termination id
+%% Return {ok, TermId} | {error, Reason}
+%%----------------------------------------------------------------------
+
+encode(_Config, TermId) when TermId =:= ?megaco_root_termination_id ->
+ {ok, ?asn_root_termination_id};
+encode(Config, TermId) when (TermId =:= ?megaco_all_wildcard_termination_id) andalso
+ (Config =:= ?default_config) ->
+ {ok, asn_all_tid()};
+encode(Config, TermId) when (TermId =:= ?megaco_choose_wildcard_termination_id) andalso
+ (Config =:= ?default_config) ->
+ {ok, asn_choose_tid()};
+encode(Config, #megaco_term_id{contains_wildcards = false, id = IDs}) ->
+ case (catch encode1(IDs,Config)) of
+ {'EXIT',Reason} ->
+ {error,Reason};
+ EncodedTid ->
+ {ok, EncodedTid}
+ end;
+encode(Config, #megaco_term_id{contains_wildcards = true, id = IDs}) ->
+ case (catch encode2(IDs,Config)) of
+ {'EXIT',Reason} ->
+ {error,Reason};
+ EncodedTid ->
+ {ok, EncodedTid}
+ end;
+encode(_Config, TermId) ->
+ {error, {bad_type, TermId}}.
+
+
+first_bit() ->
+ lists:sum(?default_config) - 1.
+asn_all_tid() ->
+ #'TerminationID'{wildcard = [[(2#11000000 + first_bit())]],
+ id = [0, 0, 0]}.
+asn_choose_tid() ->
+ #'TerminationID'{wildcard = [[(2#01000000 + first_bit())]],
+ id = [0, 0, 0]}.
+
+
+%%----------------------------------------------------------------------
+%% Encode without wildcards
+%%----------------------------------------------------------------------
+encode1(IDs,LevelConfig) when is_list(LevelConfig) ->
+ megaco_binary_term_id_gen:encode_without_wildcards(IDs, LevelConfig);
+
+
+%% This is only temporary. Eventually a proper encoder for this case
+%% should be implemented
+encode1(IDs,LevelConfig) when is_integer(LevelConfig) ->
+ %% megaco_binary_term_id_8lev:encode_without_wildcards(IDs, LevelConfig).
+ encode1(IDs,lists:duplicate(LevelConfig,8)).
+
+
+%%----------------------------------------------------------------------
+%% Encode with wildcards
+%%----------------------------------------------------------------------
+encode2(IDs,LevelConfig) when is_list(LevelConfig) ->
+ megaco_binary_term_id_gen:encode_with_wildcards(IDs, LevelConfig);
+
+
+%% This is only temporary. Eventually a proper encoder for this case
+%% should be implemented
+encode2(IDs,LevelConfig) when is_integer(LevelConfig) ->
+ %% megaco_binary_term_id_8lev:encode_with_wildcards(IDs, LevelConfig).
+ encode2(IDs,lists:duplicate(LevelConfig,8)).
+
+
+%%----------------------------------------------------------------------
+%% Convert a ASN.1 termination id into a 'TerminationId' record
+%% Return {ok, TerminationId} | {error, Reason}
+%%----------------------------------------------------------------------
+
+decode(_Config, TermId) when (TermId =:= ?asn_root_termination_id) ->
+ {ok, ?megaco_root_termination_id};
+decode(Config, #'TerminationID'{wildcard = [], id = IDs}) ->
+ case (catch decode1(IDs,Config)) of
+ {'EXIT',Reason} ->
+ {error,Reason};
+ MegacoTid ->
+ {ok,MegacoTid}
+ end;
+decode(Config, #'TerminationID'{wildcard = Wildcards, id = IDs}) ->
+ case (catch decode2(Wildcards,IDs,Config)) of
+ {'EXIT',Reason} ->
+ {error,Reason};
+ MegacoTid ->
+ {ok,MegacoTid}
+ end;
+decode(_Config, TermId) ->
+ {error, {bad_type, TermId}}.
+
+
+%%----------------------------------------------------------------------
+%% Decode without wildcards
+%%----------------------------------------------------------------------
+decode1(IDs, Lc) when is_list(Lc) ->
+ megaco_binary_term_id_gen:decode_without_wildcards(IDs, Lc);
+
+%% This is only temporary. Eventually a proper encoder for this case
+%% should be implemented
+decode1(IDs, Lc) when is_integer(Lc) ->
+ %% megaco_binary_term_id_8lev:decode_without_wildcards(IDs, Lc).
+ decode1(IDs,lists:duplicate(Lc,8)).
+
+
+%%----------------------------------------------------------------------
+%% Decode with wildcards
+%%----------------------------------------------------------------------
+decode2(Wildcards, IDs, Lc) when is_list(Lc) ->
+ megaco_binary_term_id_gen:decode_with_wildcards(Wildcards, IDs, Lc);
+
+%% This is only temporary. Eventually a proper encoder for this case
+%% should be implemented
+decode2(Wildcards, IDs, Lc) when is_integer(Lc) ->
+ %% megaco_binary_term_id_8lev:decode_with_wildcards(Wildcards, IDs, Lc);
+ decode2(Wildcards, IDs, lists:duplicate(Lc,8)).
+
+
+
diff --git a/lib/megaco/src/binary/megaco_binary_term_id_gen.erl b/lib/megaco/src/binary/megaco_binary_term_id_gen.erl
new file mode 100644
index 0000000000..c8192c79b6
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_binary_term_id_gen.erl
@@ -0,0 +1,436 @@
+%%
+%% %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%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose : Handle ASN.1 BER encoding of Megaco/H.248
+%%----------------------------------------------------------------------
+
+-module(megaco_binary_term_id_gen).
+
+
+%%----------------------------------------------------------------------
+%% Include files
+%%----------------------------------------------------------------------
+
+-include_lib("megaco/include/megaco.hrl").
+-include_lib("megaco/src/engine/megaco_message_internal.hrl").
+
+
+%%----------------------------------------------------------------------
+%% External exports
+%%----------------------------------------------------------------------
+
+-export([encode_without_wildcards/2, encode_with_wildcards/2,
+ decode_without_wildcards/2, decode_with_wildcards/3]).
+
+
+%%----------------------------------------------------------------------
+%% Internal exports
+%%----------------------------------------------------------------------
+
+
+%%----------------------------------------------------------------------
+%% Macros
+%%----------------------------------------------------------------------
+
+-define(asn_choose, ?megaco_choose).
+-define(asn_all, ?megaco_all).
+
+
+%%----------------------------------------------------------------------
+%% Encode without wildcards
+%%----------------------------------------------------------------------
+encode_without_wildcards(IDs,LevelConfig) when is_list(LevelConfig) ->
+ EncodedIDs = encode_ids(false,IDs,LevelConfig),
+ #'TerminationID'{wildcard = [], id = EncodedIDs}.
+
+%%----------------------------------------------------------------------
+%% Encode with wildcards
+%%----------------------------------------------------------------------
+encode_with_wildcards(IDs,LevelConfig) when is_list(LevelConfig) ->
+ Wildcards = encode_wildcards(IDs,LevelConfig),
+ EncodedIDs = encode_ids(true,IDs,LevelConfig),
+ #'TerminationID'{wildcard = Wildcards, id = EncodedIDs}.
+
+
+%%----------------------------------------------------------------------
+%% Decode without wildcards
+%%----------------------------------------------------------------------
+decode_without_wildcards(IDs,Lc) ->
+ DecodedIDs = decode_ids(IDs,Lc),
+ #megaco_term_id{contains_wildcards = false,
+ id = DecodedIDs}.
+
+
+%%----------------------------------------------------------------------
+%% Decode with wildcards
+%%----------------------------------------------------------------------
+decode_with_wildcards(Wildcards,IDs,Lc) ->
+ DecodedIDs = decode_ids(Wildcards,IDs,Lc),
+ #megaco_term_id{contains_wildcards = true,
+ id = DecodedIDs}.
+
+
+%%----------------------------------------------------------------------
+%% Convert an internal TermId to an external
+%%----------------------------------------------------------------------
+
+encode_wildcards(IDs,LevelConfig) ->
+ case (catch encode_wildcards1(IDs,LevelConfig)) of
+ {'EXIT',id_config_mismatch} ->
+ exit({id_config_mismatch,IDs,LevelConfig});
+ {'EXIT',Reason} ->
+ exit(Reason);
+ Wildcards ->
+ encode_wildcards2(Wildcards)
+ end.
+
+encode_wildcards1(IDs,LevelConfig) ->
+ encode_wildcards3(IDs,LevelConfig).
+
+encode_wildcards2(Ws) ->
+ F = fun(no_wildcard) -> false; (_) -> true end,
+ lists:filter(F,Ws).
+
+
+
+encode_wildcards3(IDs,LevelConfig) ->
+ encode_wildcards3(IDs,LevelConfig,1,lists:sum(LevelConfig)).
+
+encode_wildcards3([],[],_,_) ->
+ [];
+encode_wildcards3([Level|Levels],[BitsInLevel|BitsRest],LevelNo,TotSize) ->
+ case (catch encode_wildcard(Level,BitsInLevel,TotSize-BitsInLevel,
+ length(Levels))) of
+ {'EXIT',{Reason,Info}} ->
+ exit({Reason,{LevelNo,Info}});
+
+ no_wildcard ->
+ encode_wildcards3(Levels,BitsRest,LevelNo+1,TotSize-BitsInLevel);
+
+ {level,Wl} ->
+ [Wl|
+ encode_wildcards3(Levels,BitsRest,LevelNo+1,TotSize-BitsInLevel)];
+
+ {recursive,Wr} ->
+ [Wr];
+
+ Else ->
+ exit({wildcard_decode_error,Else})
+ end;
+encode_wildcards3(Levels,[],LevelNo,TotSize) ->
+ exit({id_config_mismatch,{Levels,LevelNo,TotSize}});
+encode_wildcards3(L,B,N,S) ->
+ exit({wildcard_encode_error,{L,B,N,S}}).
+
+
+encode_wildcard([],0,_TotBits,_RemainingIdLevels) ->
+ no_wildcard;
+encode_wildcard([],More,_TotBits,_RemainingIdLevels) ->
+ exit({to_few_bits_in_level,More});
+encode_wildcard(More,0,_TotBits,_RemainingIdLevels) ->
+ exit({to_many_bits_in_level,More});
+encode_wildcard([$0|R],Pos,TotBits,RemainingIdLevels) ->
+ encode_wildcard(R,Pos-1,TotBits,RemainingIdLevels);
+encode_wildcard([$1|R],Pos,TotBits,RemainingIdLevels) ->
+ encode_wildcard(R,Pos-1,TotBits,RemainingIdLevels);
+encode_wildcard([?asn_choose],Pos,TotBits,RemainingIdLevels) ->
+ encode_choose(Pos-1,TotBits,RemainingIdLevels);
+encode_wildcard([?asn_all],Pos,TotBits,RemainingIdLevels) ->
+ encode_all(Pos-1,TotBits,RemainingIdLevels);
+encode_wildcard([Val|_Rest],Pos,_TotBits,_RemainingIdLevels) ->
+ exit({invalid_level_content,{Pos-1,Val}}).
+
+%% This is the last level specified in the id list.
+%% Therefor it is a 'recursive' wildcard, i.e. the 'choose'
+%% apply to this level and all remaining levels.
+encode_choose(BitPosInLevel,BitsInRemainingConfigLevels,0)
+ when BitsInRemainingConfigLevels > 0 ->
+ {recursive,[16#40 + BitPosInLevel + BitsInRemainingConfigLevels]};
+
+%% The fact that there is no more bits in the level config
+%% means that this is actually the last level.
+%% It should not be a 'recursive' case but a 'level' case.
+%% Although it is (propably) correct with both.
+encode_choose(BitPosInLevel,0,0) ->
+ {recursive,[16#00 + BitPosInLevel]};
+
+%% There are more levels specified in the id list.
+%% Therefor it is a 'level' wildcard, i.e. the 'choose'
+%% apply to this level only.
+encode_choose(BitPosInLevel,BitsInRemainingConfigLevels,RemainingIdLevels)
+ when RemainingIdLevels > 0 ->
+ {level,[16#00 + BitPosInLevel + BitsInRemainingConfigLevels]}.
+
+%% This is the last level specified in the id list.
+%% Therefor it is a 'recursive' wildcard, i.e. the 'all'
+%% apply to this level and all remaining levels.
+encode_all(BitPosInLevel,BitsInRemainingConfigLevels,0)
+ when BitsInRemainingConfigLevels > 0 ->
+ {recursive,[16#c0 + BitPosInLevel + BitsInRemainingConfigLevels]};
+
+%% The fact that there is no more bits in the level config
+%% means that this is actually the last level.
+%% It should not be a 'recursive' case but a 'level' case.
+%% Although it is (propably) correct with both.
+encode_all(BitPosInLevel,0,0) ->
+ {recursive,[16#80 + BitPosInLevel]};
+
+%% There are more levels specified in the id list.
+%% Therefor it is a 'level' wildcard, i.e. the 'all'
+%% apply to this level only.
+encode_all(BitPosInLevel,BitsInRemainingConfigLevels,RemainingIdLevels)
+ when RemainingIdLevels > 0 ->
+ {level,[16#80 + BitPosInLevel + BitsInRemainingConfigLevels]}.
+
+
+encode_ids(W,IDs,Config) ->
+ encode_ids(W,IDs,Config,8,[0],false).
+
+encode_ids(_,[],[],8,[0|EncodedIDs],_) ->
+ lists:reverse(EncodedIDs);
+encode_ids(W,IDs,Config,0,EncodedIDs,Wf) ->
+ encode_ids(W,IDs,Config,8,[0|EncodedIDs],Wf);
+encode_ids(W,[L|Ls],[C|Cs],R,E,_) ->
+ case (catch encode_id_level(W,L,C,R,E)) of
+ {'EXIT',Reason} ->
+ exit(Reason);
+ {true,R1,E1} when (length(Ls) =:= 0) ->
+ encode_ids2(Cs,encode_ids1(R1,E1));
+ {WildcardFound1,R1,E1} ->
+ encode_ids(W,Ls,Cs,R1,E1,WildcardFound1);
+ {true,E2} when (length(Ls) =:= 0) ->
+ encode_ids2(Cs,E2);
+ {WildcardFound2,E2} ->
+ encode_ids(W,Ls,Cs,8,[0|E2],WildcardFound2)
+ end;
+encode_ids(W,[[]],C,R,E,Wf) when length(C) > 0 ->
+ exit({empty_last_level,{W,C,R,E,Wf}});
+encode_ids(W,[],C,R,E,false) when length(C) > 0 ->
+ exit({unexpected_eof_data,{W,C,R,E}}).
+
+encode_ids1(_R,[0|Es]) ->
+ [0|Es];
+encode_ids1(R,[E|Es]) ->
+ [(E bsl R)|Es].
+
+encode_ids2([],Es) ->
+ lists:reverse(Es);
+encode_ids2(Cs,Es) ->
+ Fill = lists:duplicate(lists:sum(Cs) div 8,0),
+ lists:reverse(Fill ++ Es).
+
+
+encode_id_level(W,L,C,R,[E|Es]) ->
+ case encode_id_level1(W,L,C,R,E) of
+ %% End Of Byte (more bits in level)
+ {eob,_WildcardFound,L1,C1,E1} ->
+ encode_id_level(W,L1,C1,8,[0,E1|Es]);
+
+ %% End Of Level (more room in byte)
+ {eol,WildcardFound,R1,E1} ->
+ {WildcardFound,R1,[E1|Es]};
+
+ %% Done; Level used up all of the byte
+ {done,WildcardFound,E1} ->
+ {WildcardFound,[E1|Es]}
+ end.
+
+
+encode_id_level1(_W,[],0,0,E) ->
+ {done,false,E};
+encode_id_level1(_W,[],0,R,E) ->
+ {eol,false,R,E};
+encode_id_level1(_W,L,C,0,E) ->
+ {eob,false,L,C,E};
+encode_id_level1(W,[$0|L],C,R,E) ->
+ encode_id_level1(W,L,C-1,R-1,E bsl 1);
+encode_id_level1(W,[$1|L],C,R,E) ->
+ encode_id_level1(W,L,C-1,R-1,(E bsl 1) + 1);
+encode_id_level1(true,[$$],C,R,E) ->
+ encode_id_level2(C,R,E,$$);
+encode_id_level1(true,[$*],C,R,E) ->
+ encode_id_level2(C,R,E,$*);
+encode_id_level1(false,[$$],C,R,_E) ->
+ exit({wildcard_error,{$$,C,R}});
+encode_id_level1(false,[$*],C,R,_E) ->
+ exit({wildcard_error,{$*,C,R}});
+encode_id_level1(_W,[L|_Ls],C,R,_E) ->
+ exit({invalid_level_content,{C,R,L}}).
+
+encode_id_level2(C,C,E,_W) ->
+ {done,true,E bsl C};
+encode_id_level2(C,R,E,W) when C > R ->
+ {eob,true,[W],C-R,E bsl R};
+encode_id_level2(C,R,E,_W) ->
+ {eol,true,R-C,E bsl C}.
+
+
+%%----------------------------------------------------------------------
+%% Convert an external TermId to an internal
+%%----------------------------------------------------------------------
+
+%% Decode ID with wildcards
+decode_ids(Ws,IDs,Config) when is_list(Config) ->
+ IDs1 = decode_ids(IDs,Config),
+ Ws1 = decode_wildcards(Ws,(length(IDs)*8) - 1),
+ decode_ids1(Ws1,IDs1);
+
+%% This is only temporary. Eventually a proper encoder for this case
+%% should be implemented.
+%% This is the case when each level is 8 bits = 1 byte and the config
+%% simply indicates the number of (1 byte) levels
+decode_ids(Ws,IDs,Config) when is_integer(Config) ->
+ decode_ids(Ws,IDs,lists:duplicate(Config,8)).
+
+
+%% Decode ID without wildcards
+decode_ids(E,Config) when is_list(Config) ->
+ decode_ids(0,E,Config,[]);
+
+%% This is only temporary. Eventually a proper encoder for this case
+%% should be implemented.
+%% This is the case when each level is 8 bits = 1 byte and the config
+%% simply indicates the number of (1 byte) levels
+decode_ids(E,Config) when is_integer(Config) ->
+ decode_ids(E,lists:duplicate(Config,8)).
+
+
+%% The [0] is the result of all the bits of the byte has been shifted out.
+decode_ids(_B,[0],[],Acc) ->
+ lists:reverse(Acc);
+decode_ids(_B,[E],[],Acc) ->
+ exit({id_config_mismatch,{two_much_data,E,Acc}});
+decode_ids(_B,E,[],Acc) ->
+ exit({id_config_mismatch,{two_much_data,E,Acc}});
+decode_ids(B,E,[L|Ls],Acc) ->
+ case (catch decode_id_level(B,E,L,[])) of
+ {Level,E1,B1} ->
+ decode_ids(B1,E1,Ls,[Level|Acc]);
+ {'EXIT',{id_config_mismatch,{Bx,Ex,Lx,Accx}}} ->
+ exit({id_level_mismatch,{B,Bx,E,Ex,L,Ls,Lx,Acc,Accx}})
+ end.
+
+
+decode_wildcards(Ws,NofBits) ->
+ lists:keysort(3,[decode_wildcard(W,NofBits) || W <- Ws]).
+
+
+%% ----------------------------------------------------------------------
+%% A decoded wildcard is a three tuple:
+%% {wildcard_type(), wildcard_level(), wildcard_offset()}
+%% wildcard_type() -> $ | *
+%% wildcard_level() -> level | recursive
+%% wildcard_offset() -> integer()
+%%
+%% The "raw" wildcard offset is measured from the end of the id bytes:
+%%
+%% 0 1 2 3 4 5 6 7
+%% -----------------
+%% | | | | | | | | |
+%% -----------------
+%%
+%% |<--------|
+%% 5
+%%
+%% The decoded wildcard offset in contrast is measured from the start
+%% of the id field:
+%%
+%% 0 1 2 3 4 5 6 7
+%% -----------------
+%% | | | | | | | | |
+%% -----------------
+%%
+%% |---->|
+%% 3
+%%
+
+decode_wildcard([W],NofBits) ->
+ {decode_wildcard_t(W band 16#80),
+ decode_wildcard_l(W band 16#40),
+ NofBits - (W band 16#3F)}.
+
+decode_wildcard_t(16#80) -> ?asn_all;
+decode_wildcard_t(16#00) -> ?asn_choose.
+
+decode_wildcard_l(16#00) -> level;
+decode_wildcard_l(16#40) -> recursive.
+
+
+decode_ids1(W,IDs) ->
+ lists:reverse(decode_ids1(W,IDs,0,[])).
+
+decode_ids1([],IDs,_,Acc) ->
+ lists:reverse(IDs) ++ Acc;
+decode_ids1([{Type,recursive,Offset}],IDs,Bp,Acc) ->
+ decode_ids2(Type,Offset,IDs,Bp,Acc);
+decode_ids1([{Type,level,Offset}|Ws],IDs,Bp,Acc) ->
+ {IDs1,IDs2,Bp1} = decode_ids3(Type,Offset,IDs,Bp,[]),
+ decode_ids1(Ws,IDs2,Bp1,IDs1++Acc);
+decode_ids1(Ws,_,_,_) ->
+ exit({invalid_wildcards,Ws}).
+
+
+%% Called when recursive wildcard found
+decode_ids2(Type,Offset,[ID|IDs],Bp,Acc) ->
+ LevelSz = length(ID),
+ Bp1 = Offset-Bp,
+ case Bp1 >= LevelSz of
+ true ->
+ decode_ids2(Type,Offset,IDs,Bp+LevelSz,[ID|Acc]);
+ false ->
+ [decode_ids4(Type,Bp1,ID)|Acc]
+ end.
+
+
+decode_ids3(Type,Offset,[ID|IDs],Bp,Acc) ->
+ LevelSz = length(ID),
+ Bp1 = Offset-Bp,
+ case Bp1 > LevelSz of
+ true ->
+ decode_ids3(Type,Offset,IDs,Bp+LevelSz,[ID|Acc]);
+ false ->
+ A1 = decode_ids4(Type,Bp1,ID),
+ {[A1|Acc],IDs,Bp+LevelSz}
+ end.
+
+
+decode_ids4(Type,0,_ID) ->
+ [Type];
+decode_ids4(Type,O,[H|T]) ->
+ [H|decode_ids4(Type,O-1,T)].
+
+
+%% E: Encoded bits -> [byte()]
+%% L: Number of nits in level
+decode_id_level(B,E,0,Acc) ->
+ {lists:reverse(Acc),E,B};
+decode_id_level(8,[_H|T],L,Acc) ->
+ decode_id_level(0,T,L,Acc);
+decode_id_level(B,[H|T],L,Acc) ->
+ Acc1 = [decode_id_level1(H band 16#80) | Acc],
+ decode_id_level(B+1,[((H bsl 1) band 16#FF) |T],L-1,Acc1);
+decode_id_level(B,E,L,Acc) ->
+ exit({id_config_mismatch,{B,E,L,Acc}}).
+
+decode_id_level1(16#80) -> $1;
+decode_id_level1(16#00) -> $0.
+
+
diff --git a/lib/megaco/src/binary/megaco_binary_transformer_prev3a.erl b/lib/megaco/src/binary/megaco_binary_transformer_prev3a.erl
new file mode 100644
index 0000000000..609947c933
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_binary_transformer_prev3a.erl
@@ -0,0 +1,1629 @@
+%%
+%% %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: Transform internal form of Megaco/H.248 messages
+%%----------------------------------------------------------------------
+
+-module(megaco_binary_transformer_prev3a).
+
+-include_lib("megaco/include/megaco.hrl").
+%% -include_lib("megaco/include/megaco_message.hrl").
+-include_lib("megaco/include/megaco_message_prev3a.hrl").
+-include_lib("megaco/src/app/megaco_internal.hrl").
+
+-export([tr_message/3, tr_transaction/3]).
+
+-define(DEFAULT_NAME_RESOLVER, megaco_binary_name_resolver_prev3a).
+
+-record(state, {mode, % verify | encode | decode
+ resolver_module, %
+ resolver_options}).
+
+resolve(Type, Item, State, Constraint) ->
+ case State#state.mode of
+ verify ->
+ Item;
+ encode ->
+ ?d("resolve(encode) -> encode: ~p",[Item]),
+ Mod = State#state.resolver_module,
+ Opt = State#state.resolver_options,
+ EncodedItem = Mod:encode_name(Opt, Type, Item),
+ ?d("resolve -> verify contraint for ~p",[EncodedItem]),
+ verify_constraint(EncodedItem, Constraint);
+ decode ->
+ ?d("resolve(decode) -> verify contraint for ~p",[Item]),
+ DecodedItem = verify_constraint(Item, Constraint),
+ Mod = State#state.resolver_module,
+ Opt = State#state.resolver_options,
+ ?d("resolve(decode) -> decode: ~p",[DecodedItem]),
+ Mod:decode_name(Opt, Type, DecodedItem)
+ end.
+
+verify_constraint(Item, valid) ->
+ Item;
+verify_constraint(Item, Constraint) when is_function(Constraint) ->
+ Constraint(Item).
+
+tr_message(MegaMsg, Mode, Config) ->
+ case Config of
+ [native] ->
+ MegaMsg;
+ [verify] ->
+ State = #state{mode = verify},
+ tr_MegacoMessage(MegaMsg, State);
+ [] ->
+ State = #state{mode = Mode,
+ resolver_module = ?DEFAULT_NAME_RESOLVER,
+ resolver_options = [8, 8, 8]},
+ tr_MegacoMessage(MegaMsg, State);
+ [{binary_name_resolver, {Module, Options}}] when is_atom(Module) ->
+ State = #state{mode = Mode,
+ resolver_module = Module,
+ resolver_options = Options},
+ tr_MegacoMessage(MegaMsg, State)
+ end.
+
+tr_transaction(Trans, Mode, Config) ->
+ case Config of
+ [native] ->
+ Trans;
+ [verify] ->
+ State = #state{mode = verify},
+ tr_Transaction(Trans, State);
+ [] ->
+ State = #state{mode = Mode,
+ resolver_module = ?DEFAULT_NAME_RESOLVER,
+ resolver_options = [8, 8, 8]},
+ tr_Transaction(Trans, State);
+ [{binary_name_resolver, {Module, Options}}] when is_atom(Module) ->
+ State = #state{mode = Mode,
+ resolver_module = Module,
+ resolver_options = Options},
+ tr_Transaction(Trans, State)
+ end.
+
+tr_MegacoMessage(#'MegacoMessage'{authHeader = Auth,
+ mess = Mess},
+ State) ->
+ ?d("tr_MegacoMessage -> entry with"
+ "~n Auth: ~p"
+ "~n Mess: ~p"
+ "~n State: ~p", [Auth, Mess, State]),
+ #'MegacoMessage'{authHeader = tr_opt_AuthenticationHeader(Auth, State),
+ mess = tr_Message(Mess, State)}.
+
+tr_opt_AuthenticationHeader(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_AuthenticationHeader(#'AuthenticationHeader'{secParmIndex = SPI,
+ seqNum = SN,
+ ad = AuthData},
+ State) ->
+ #'AuthenticationHeader'{secParmIndex = tr_SecurityParmIndex(SPI, State),
+ seqNum = tr_SequenceNum(SN, State),
+ ad = tr_AuthData(AuthData, State)}.
+
+tr_SecurityParmIndex(SPI, State) ->
+ tr_HEXDIG(SPI, State, 4, 4). % BUGBUG: Mismatch between ASN.1 and ABNF
+
+tr_SequenceNum(SN, State) ->
+ tr_HEXDIG(SN, State, 4, 4). % BUGBUG: Mismatch between ASN.1 and ABNF
+
+tr_AuthData(AuthData, State) ->
+ tr_HEXDIG(AuthData, State, 12, 32). % BUGBUG: Mismatch between ASN.1 and ABNF
+
+tr_Message(#'Message'{version = Version,
+ mId = MID,
+ messageBody = Body},
+ State) ->
+ #'Message'{version = tr_version(Version, State),
+ mId = tr_MId(MID, State),
+ messageBody = tr_Message_messageBody(Body, State)}.
+
+tr_version(Version, State) ->
+ tr_DIGIT(Version, State, 0, 99).
+
+tr_Message_messageBody({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ messageError -> tr_ErrorDescriptor(Val, State);
+ transactions when is_list(Val) -> [tr_Transaction(T, State) || T <- Val]
+ end,
+ {Tag, Val2}.
+
+tr_MId({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ ip4Address -> tr_IP4Address(Val, State);
+ ip6Address -> tr_IP6Address(Val, State);
+ domainName -> tr_DomainName(Val, State);
+ deviceName -> tr_PathName(Val, State);
+ mtpAddress -> tr_mtpAddress(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_mtpAddress(MtpAddr, State) ->
+ tr_OCTET_STRING(MtpAddr, State, 2, 4). % BUGBUG: Mismatch between ASN.1 and ABNF
+
+tr_DomainName(#'DomainName'{name = Name,
+ portNumber = Port},
+ State) ->
+ Domain = #'DomainName'{name = tr_STRING(Name, State), % BUGBUG: Mismatch between ASN.1 and ABNF
+ portNumber = tr_opt_portNumber(Port, State)},
+ {domainName, Domain2} = resolve(mid, {domainName, Domain}, State, valid),
+ Domain2.
+
+tr_IP4Address(#'IP4Address'{address = [A1, A2, A3, A4],
+ portNumber = Port},
+ State) ->
+ #'IP4Address'{address = [tr_V4hex(A1, State),
+ tr_V4hex(A2, State),
+ tr_V4hex(A3, State),
+ tr_V4hex(A4, State)],
+ portNumber = tr_opt_portNumber(Port, State)}.
+
+tr_V4hex(Val, State) ->
+ tr_DIGIT(Val, State, 0, 255).
+
+tr_IP6Address(_Val, _State) ->
+ error(ipv6_not_supported). %% BUGBUG: nyi
+
+tr_PathName(Path, State) ->
+ %% BUGBUG: ["*"] NAME *("/" / "*"/ ALPHA / DIGIT /"_" / "$" )
+ %% BUGBUG: ["@" pathDomainName ]
+ Constraint = fun({deviceName, Item}) -> tr_STRING(Item, State, 1, 64) end,
+ resolve(mid, {deviceName, Path}, State, Constraint).
+
+tr_Transaction({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ transactionRequest -> tr_TransactionRequest(Val, State);
+ transactionPending -> tr_TransactionPending(Val, State);
+ transactionReply -> tr_TransactionReply(Val, State);
+ transactionResponseAck -> [tr_TransactionAck(T, State) || T <- Val]
+ end,
+ {Tag, Val2}.
+
+tr_TransactionAck(#'TransactionAck'{firstAck = First,
+ lastAck = Last},
+ State) ->
+ #'TransactionAck'{firstAck = tr_TransactionId(First, State),
+ lastAck = tr_opt_TransactionId(Last, State)}.
+
+tr_opt_TransactionId(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_TransactionId(Id, State) ->
+ tr_TransactionId(Id, State).
+
+tr_TransactionId(Id, State) ->
+ tr_UINT32(Id, State).
+
+tr_TransactionRequest(#'TransactionRequest'{transactionId = Id,
+ actions = Actions},
+ State) when is_list(Actions) ->
+
+ #'TransactionRequest'{transactionId = tr_TransactionId(Id, State),
+ actions = [tr_ActionRequest(ActReq, State) || ActReq <- Actions]}.
+
+tr_TransactionPending(#'TransactionPending'{transactionId = Id},
+ State) ->
+ #'TransactionPending'{transactionId = tr_TransactionId(Id, State)}.
+
+tr_TransactionReply(#'TransactionReply'{transactionId = Id,
+ immAckRequired = ImmAck,
+ transactionResult = TransRes,
+ %% 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) ->
+ #'TransactionReply'{transactionId = tr_TransactionId(Id, State),
+ immAckRequired = tr_opt_null(ImmAck, State),
+ transactionResult = tr_TransactionReply_transactionResult(TransRes, State),
+ segmentNumber = asn1_NOVALUE,
+ segmentationComplete = asn1_NOVALUE};
+tr_TransactionReply(TR, _State) ->
+ error({unsupported_TransactionReply, TR}).
+
+tr_opt_null(asn1_NOVALUE, _State) -> asn1_NOVALUE;
+tr_opt_null('NULL', _State) -> 'NULL'.
+
+tr_TransactionReply_transactionResult({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ transactionError ->
+ tr_ErrorDescriptor(Val, State);
+ actionReplies when is_list(Val) andalso (Val =/= []) ->
+ [tr_ActionReply(ActRep, State) || ActRep <- Val]
+ end,
+ {Tag, Val2}.
+
+tr_opt_ErrorDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_ErrorDescriptor(ErrDesc, State) ->
+ tr_ErrorDescriptor(ErrDesc, State).
+
+tr_ErrorDescriptor(#'ErrorDescriptor'{errorCode = Code,
+ errorText = Text},
+ State) ->
+ #'ErrorDescriptor'{errorCode = tr_ErrorCode(Code, State),
+ errorText = tr_opt_ErrorText(Text, State)}.
+
+tr_ErrorCode(Code, State) ->
+ tr_DIGIT(Code, State, 0, 999).
+
+tr_opt_ErrorText(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_ErrorText(Text, State) ->
+ tr_QUOTED_STRING(Text, State).
+
+tr_ContextID(CtxId, State) ->
+ case CtxId of
+ ?megaco_all_context_id -> ?megaco_all_context_id;
+ ?megaco_null_context_id -> ?megaco_null_context_id;
+ ?megaco_choose_context_id -> ?megaco_choose_context_id;
+ Int when is_integer(Int) -> tr_UINT32(Int, State)
+ end.
+
+tr_ActionRequest(#'ActionRequest'{contextId = CtxId,
+ contextRequest = CtxReq,
+ contextAttrAuditReq = CtxAuditReq,
+ commandRequests = CmdReqList},
+ State) ->
+ #'ActionRequest'{contextId = tr_ContextID(CtxId, State),
+ contextRequest = tr_opt_ContextRequest(CtxReq, State),
+ contextAttrAuditReq = tr_opt_ContextAttrAuditRequest(CtxAuditReq, State),
+ commandRequests = [tr_CommandRequest(CmdReq, State) || CmdReq <- CmdReqList]}.
+
+tr_ActionReply(#'ActionReply'{contextId = CtxId,
+ errorDescriptor = ErrDesc,
+ contextReply = CtxRep,
+ commandReply = CmdRepList},
+ State) ->
+ CmdRepList2 = [tr_CommandReply(CmdRep, State) || CmdRep <- CmdRepList],
+ #'ActionReply'{contextId = tr_ContextID(CtxId, State),
+ errorDescriptor = tr_opt_ErrorDescriptor(ErrDesc, State),
+ contextReply = tr_opt_ContextRequest(CtxRep, State),
+ commandReply = CmdRepList2}.
+
+tr_opt_ContextRequest(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_ContextRequest(CR, State) ->
+ tr_ContextRequest(CR, State).
+
+tr_ContextRequest(#'ContextRequest'{priority = Prio,
+ emergency = Em,
+ topologyReq = TopReqList,
+ iepsCallind = Ind,
+ contextProp = Props},
+ State) ->
+ Prio2 =
+ case Prio of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> tr_integer(Prio, State, 0, 15)
+ end,
+ Em2 =
+ case Em of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ false -> false;
+ true -> true
+ end,
+ TopReqList2 =
+ case TopReqList of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> [tr_TopologyRequest(TopReq, State) ||
+ TopReq <- TopReqList]
+ end,
+ Ind2 =
+ case Ind of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ false -> false;
+ true -> true
+ end,
+ Props2 =
+ case Props of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> [tr_PropertyParm(Prop, State) || Prop <- Props]
+ end,
+ #'ContextRequest'{priority = Prio2,
+ emergency = Em2,
+ topologyReq = TopReqList2,
+ iepsCallind = Ind2,
+ contextProp = Props2}.
+
+tr_opt_ContextAttrAuditRequest(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_ContextAttrAuditRequest(CAAR, State) ->
+ tr_ContextAttrAuditRequest(CAAR, State).
+
+tr_ContextAttrAuditRequest(#'ContextAttrAuditRequest'{topology = Top,
+ emergency = Em,
+ priority = Prio,
+ iepsCallind = Ind,
+ contextPropAud = Props},
+ State) ->
+ Top2 = tr_opt_null(Top, State),
+ Em2 = tr_opt_null(Em, State),
+ Prio2 = tr_opt_null(Prio, State),
+ Ind2 = tr_opt_null(Ind, State),
+ Props2 =
+ case Props of
+ asn1_NOVALUE ->
+ asn1_NOVALUE;
+ _ ->
+ [tr_indAudPropertyParm(Prop, State) || Prop <- Props]
+ end,
+ #'ContextAttrAuditRequest'{topology = Top2,
+ emergency = Em2,
+ priority = Prio2,
+ iepsCallind = Ind2,
+ contextPropAud = Props2}.
+
+tr_CommandRequest(#'CommandRequest'{command = Cmd,
+ optional = Opt,
+ wildcardReturn = Wild},
+ State) ->
+ #'CommandRequest'{optional = tr_opt_null(Opt, State),
+ wildcardReturn = tr_opt_null(Wild, State),
+ command = tr_Command(Cmd, State)}.
+
+tr_Command({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ addReq -> tr_AmmRequest(Val, State);
+ moveReq -> tr_AmmRequest(Val, State);
+ modReq -> tr_AmmRequest(Val, State);
+ subtractReq -> tr_SubtractRequest(Val, State);
+ auditCapRequest -> tr_AuditRequest(Val, State);
+ auditValueRequest -> tr_AuditRequest(Val, State);
+ notifyReq -> tr_NotifyRequest(Val, State);
+ serviceChangeReq -> tr_ServiceChangeRequest(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_CommandReply({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ addReply -> tr_AmmsReply(Val, State);
+ moveReply -> tr_AmmsReply(Val, State);
+ modReply -> tr_AmmsReply(Val, State);
+ subtractReply -> tr_AmmsReply(Val, State);
+ auditCapReply -> tr_AuditReply(Val, State);
+ auditValueReply -> tr_AuditReply(Val, State);
+ notifyReply -> tr_NotifyReply(Val, State);
+ serviceChangeReply -> tr_ServiceChangeReply(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_TopologyRequest(#'TopologyRequest'{terminationFrom = From,
+ terminationTo = To,
+ topologyDirection = Dir},
+ State) ->
+ Dir2 =
+ case Dir of
+ bothway -> bothway;
+ isolate -> isolate;
+ oneway -> oneway
+ end,
+ #'TopologyRequest'{terminationFrom = tr_TerminationID(From, State),
+ terminationTo = tr_TerminationID(To, State),
+ topologyDirection = Dir2}.
+
+tr_AmmRequest(#'AmmRequest'{terminationID = IdList,
+ descriptors = DescList},
+ State) ->
+ #'AmmRequest'{terminationID = [tr_TerminationID(Id, State) ||
+ Id <- IdList],
+ descriptors = tr_ammDescriptors(DescList, [], State)}.
+
+tr_ammDescriptors([], Acc, _State) ->
+ lists:reverse(Acc);
+tr_ammDescriptors([Desc|Descs], Acc, State) ->
+ case tr_ammDescriptor(Desc, State) of
+ {_, deprecated} when State#state.mode =:= encode ->
+ error({deprecated, Desc});
+ {_, deprecated} when State#state.mode =:= decode ->
+ %% SKIP
+ tr_ammDescriptors(Descs, Acc, State);
+ {_, deprecated} ->
+ %% SKIP
+ tr_ammDescriptors(Descs, Acc, State);
+ NewDesc ->
+ tr_ammDescriptors(Descs, [NewDesc|Acc], State)
+ end.
+
+tr_ammDescriptor({Tag, Desc}, State) ->
+ Desc2 =
+ case Tag of
+ mediaDescriptor -> tr_MediaDescriptor(Desc, State);
+ modemDescriptor -> tr_ModemDescriptor(Desc, State);
+ muxDescriptor -> tr_MuxDescriptor(Desc, State);
+ eventsDescriptor -> tr_EventsDescriptor(Desc, State);
+ eventBufferDescriptor -> tr_EventBufferDescriptor(Desc, State);
+ signalsDescriptor -> tr_SignalsDescriptor(Desc, State);
+ digitMapDescriptor -> tr_DigitMapDescriptor(Desc, State);
+ auditDescriptor -> tr_AuditDescriptor(Desc, State);
+ statisticsDescriptor -> tr_StatisticsDescriptor(Desc, State)
+ end,
+ {Tag, Desc2}.
+
+tr_AmmsReply(#'AmmsReply'{terminationID = IdList,
+ terminationAudit = TermAudit},
+ State) ->
+ TermAudit2 =
+ case TermAudit of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> tr_TerminationAudit(TermAudit, State)
+ end,
+ #'AmmsReply'{terminationID = [tr_TerminationID(Id, State) ||
+ Id <- IdList],
+ terminationAudit = TermAudit2}.
+
+tr_SubtractRequest(#'SubtractRequest'{terminationID = IdList,
+ auditDescriptor = Desc},
+ State) ->
+ #'SubtractRequest'{terminationID = [tr_TerminationID(Id, State) ||
+ Id <- IdList],
+ auditDescriptor = tr_opt_AuditDescriptor(Desc, State)}.
+
+tr_AuditRequest(#'AuditRequest'{terminationID = Id,
+ auditDescriptor = Desc},
+ State) ->
+ #'AuditRequest'{terminationID = tr_TerminationID(Id, State),
+ auditDescriptor = tr_AuditDescriptor(Desc, State)}.
+
+%% auditReply = (AuditValueToken / AuditCapToken )
+%% ( contextTerminationAudit / auditOther)
+%% auditOther = EQUAL TerminationID LBRKT
+%% terminationAudit RBRKT
+%% terminationAudit = auditReturnParameter *(COMMA auditReturnParameter)
+%%
+%% contextTerminationAudit = EQUAL CtxToken ( terminationIDList /
+%% LBRKT errorDescriptor RBRKT )
+
+tr_AuditReply({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ contextAuditResult ->
+ [tr_TerminationID(Id, State) || Id <- Val];
+ error ->
+ tr_ErrorDescriptor(Val, State);
+ auditResult ->
+ tr_AuditResult(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_AuditResult(#'AuditResult'{terminationID = Id,
+ terminationAuditResult = AuditRes},
+ State) ->
+ #'AuditResult'{terminationID = tr_TerminationID(Id, State),
+ terminationAuditResult = tr_TerminationAudit(AuditRes, State)}.
+
+tr_opt_AuditDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_AuditDescriptor(Desc, State) ->
+ tr_AuditDescriptor(Desc, State).
+
+%% BUGBUG BUGBUG BUGBUG
+%% With this construction it is possible to have both auditToken
+%% and auditPropertyToken, but it is actually valid?
+tr_AuditDescriptor(#'AuditDescriptor'{auditToken = Tokens,
+ auditPropertyToken = APTs},
+ State) ->
+ Tokens2 =
+ case Tokens of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> [tr_auditItem(Token, State) || Token <- Tokens]
+ end,
+ %% v2
+ APTs2 =
+ case APTs of
+ asn1_NOVALUE ->
+ asn1_NOVALUE;
+ _ ->
+ [tr_indAuditParameter(APT, State) || APT <- APTs]
+ end,
+ #'AuditDescriptor'{auditToken = Tokens2,
+ auditPropertyToken = APTs2}.
+
+tr_auditItem(Token, _State) ->
+ case Token of
+ muxToken -> muxToken;
+ modemToken -> modemToken;
+ mediaToken -> mediaToken;
+ eventsToken -> eventsToken;
+ signalsToken -> signalsToken;
+ digitMapToken -> digitMapToken;
+ statsToken -> statsToken;
+ observedEventsToken -> observedEventsToken;
+ packagesToken -> packagesToken;
+ eventBufferToken -> eventBufferToken
+ end.
+
+%% --- v2 begin ---
+
+tr_indAuditParameter({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ indAudMediaDescriptor ->
+ tr_indAudMediaDescriptor(Val, State);
+ indAudEventsDescriptor ->
+ tr_indAudEventsDescriptor(Val, State);
+ indAudSignalsDescriptor ->
+ tr_indAudSignalsDescriptor(Val, State);
+ indAudDigitMapDescriptor ->
+ tr_indAudDigitMapDescriptor(Val, State);
+ indAudEventBufferDescriptor ->
+ tr_indAudEventBufferDescriptor(Val, State);
+ indAudStatisticsDescriptor ->
+ tr_indAudStatisticsDescriptor(Val, State);
+ indAudPackagesDescriptor ->
+ tr_indAudPackagesDescriptor(Val, State)
+ end,
+ {Tag, Val2}.
+
+
+%% -
+
+tr_indAudMediaDescriptor(#'IndAudMediaDescriptor'{termStateDescr = TSD,
+ streams = S},
+ State) ->
+ TSD2 =
+ case TSD of
+ asn1_NOVALUE ->
+ asn1_NOVALUE;
+ _ ->
+ tr_indAudTerminationStateDescriptor(TSD, State)
+ end,
+ S2 =
+ case S of
+ asn1_NOVALUE ->
+ asn1_NOVALUE;
+ {oneStream, OS} ->
+ {oneStream, tr_indAudStreamParms(OS, State)};
+ {multiStream, MS} ->
+ MS2 = [tr_indAudStreamDescriptor(MS1, State) || MS1 <- MS],
+ {multiStream, MS2}
+ end,
+ #'IndAudMediaDescriptor'{termStateDescr = TSD2,
+ streams = S2}.
+
+tr_indAudTerminationStateDescriptor(Val, State)
+ when is_record(Val, 'IndAudTerminationStateDescriptor') ->
+ #'IndAudTerminationStateDescriptor'{propertyParms = Parms,
+ eventBufferControl = EBC,
+ serviceState = SS} = Val,
+ Parms2 = [tr_indAudPropertyParm(Parm, State) || Parm <- Parms],
+ EBC2 = tr_opt_null(EBC, State),
+ SS2 = tr_opt_null(SS, State),
+ #'IndAudTerminationStateDescriptor'{propertyParms = Parms2,
+ eventBufferControl = EBC2,
+ serviceState = SS2}.
+
+
+tr_indAudStreamParms(#'IndAudStreamParms'{localControlDescriptor = LCD,
+ localDescriptor = LD,
+ remoteDescriptor = RD,
+ statisticsDescriptor = SD},
+ State) ->
+ LCD2 =
+ case LCD of
+ asn1_NOVALUE ->
+ asn1_NOVALUE;
+ _ ->
+ tr_indAudLocalControlDescriptor(LCD, State)
+ end,
+ LD2 =
+ case LD of
+ asn1_NOVALUE ->
+ asn1_NOVALUE;
+ _ ->
+ tr_indAudLocalRemoteDescriptor(LD, State)
+ end,
+ RD2 =
+ case RD of
+ asn1_NOVALUE ->
+ asn1_NOVALUE;
+ _ ->
+ tr_indAudLocalRemoteDescriptor(RD, State)
+ end,
+ SD2 =
+ case SD of
+ asn1_NOVALUE ->
+ asn1_NOVALUE;
+ _ ->
+ tr_indAudStatisticsDescriptor(SD, State)
+ end,
+ #'IndAudStreamParms'{localControlDescriptor = LCD2,
+ localDescriptor = LD2,
+ remoteDescriptor = RD2,
+ statisticsDescriptor = SD2}.
+
+tr_indAudLocalControlDescriptor(Val, State)
+ when is_record(Val, 'IndAudLocalControlDescriptor') ->
+ #'IndAudLocalControlDescriptor'{streamMode = M,
+ reserveValue = V,
+ reserveGroup = G,
+ propertyParms = P} = Val,
+ M2 = tr_opt_null(M, State),
+ V2 = tr_opt_null(V, State),
+ G2 = tr_opt_null(G, State),
+ P2 = tr_indAudLocalControlDescriptor_propertyParms(P, State),
+ #'IndAudLocalControlDescriptor'{streamMode = M2,
+ reserveValue = V2,
+ reserveGroup = G2,
+ propertyParms = P2}.
+
+tr_indAudLocalControlDescriptor_propertyParms(Parms, State)
+ when is_list(Parms) andalso (length(Parms) > 0) ->
+ [tr_indAudPropertyParm(Parm, State) || Parm <- Parms];
+tr_indAudLocalControlDescriptor_propertyParms(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE.
+
+tr_indAudLocalRemoteDescriptor(#'IndAudLocalRemoteDescriptor'{propGroupID = ID,
+ propGrps = Grps},
+ State) ->
+ #'IndAudLocalRemoteDescriptor'{propGroupID = tr_opt_UINT16(ID, State),
+ propGrps = tr_indAudPropertyGroup(Grps,
+ State)}.
+
+tr_indAudPropertyGroup(Grps, State) when is_list(Grps) ->
+ [tr_indAudPropertyParm(Parm, State) || Parm <- Grps].
+
+tr_indAudPropertyParm(#'IndAudPropertyParm'{name = Name0}, State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ Name = resolve(property, Name0, State, Constraint),
+ #'IndAudPropertyParm'{name = Name}.
+
+
+tr_indAudStreamDescriptor(#'IndAudStreamDescriptor'{streamID = ID,
+ streamParms = Parms},
+ State) ->
+ #'IndAudStreamDescriptor'{streamID = tr_StreamID(ID, State),
+ streamParms = tr_indAudStreamParms(Parms,
+ State)}.
+
+
+%% -
+
+tr_indAudEventsDescriptor(#'IndAudEventsDescriptor'{requestID = RID,
+ pkgdName = Name0,
+ streamID = SID},
+ State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ Name = resolve(event, Name0, State, Constraint),
+ #'IndAudEventsDescriptor'{requestID = tr_opt_RequestID(RID, State),
+ pkgdName = Name,
+ streamID = tr_opt_StreamID(SID, State)}.
+
+
+%% -
+
+tr_indAudSignalsDescriptor({Tag, Val}, State) ->
+ case Tag of
+ signal ->
+ {signal, tr_indAudSignal(Val, State)};
+ seqSigList ->
+ {seqSigList, tr_indAudSeqSigList(Val, State)}
+ end.
+
+tr_opt_indAudSignal(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_indAudSignal(Val, State) ->
+ tr_indAudSignal(Val, State).
+
+tr_indAudSignal(#'IndAudSignal'{signalName = Name0,
+ streamID = SID}, State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ Name = resolve(signal, Name0, State, Constraint),
+ #'IndAudSignal'{signalName = Name,
+ streamID = tr_opt_StreamID(SID, State)}.
+
+tr_indAudSeqSigList(#'IndAudSeqSigList'{id = ID,
+ signalList = SigList}, State) ->
+ #'IndAudSeqSigList'{id = tr_integer(ID, State, 0, 65535),
+ signalList = tr_opt_indAudSignal(SigList, State)}.
+
+%% -
+
+tr_indAudDigitMapDescriptor(#'IndAudDigitMapDescriptor'{digitMapName = Name},
+ State) ->
+ #'IndAudDigitMapDescriptor'{digitMapName =
+ tr_opt_DigitMapName(Name, State)}.
+
+
+%% -
+
+tr_indAudEventBufferDescriptor(#'IndAudEventBufferDescriptor'{eventName = N,
+ streamID = SID},
+ State) ->
+ ?d("tr_indAudEventBufferDescriptor -> entry with"
+ "~n N: ~p"
+ "~n SID: ~p", [N, SID]),
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ Name = resolve(event, N, State, Constraint),
+ ?d("tr_indAudEventBufferDescriptor -> entry with"
+ "~n Name: ~p", [Name]),
+ #'IndAudEventBufferDescriptor'{eventName = Name,
+ streamID = tr_opt_StreamID(SID, State)}.
+
+%% -
+
+tr_indAudStatisticsDescriptor(#'IndAudStatisticsDescriptor'{statName = N},
+ State) ->
+ ?d("tr_indAudEventBufferDescriptor -> entry with"
+ "~n N: ~p", [N]),
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ Name = resolve(statistics, N, State, Constraint),
+ #'IndAudStatisticsDescriptor'{statName = Name}.
+
+
+%% -
+
+tr_indAudPackagesDescriptor(#'IndAudPackagesDescriptor'{packageName = N,
+ packageVersion = V},
+ State) ->
+ ?d("tr_indAudPackagesDescriptor -> entry with"
+ "~n N: ~p"
+ "~n V: ~p", [N, V]),
+ Constraint = fun(Item) -> tr_Name(Item, State) end,
+ Name = resolve(package, N, State, Constraint),
+ ?d("tr_indAudPackagesDescriptor -> entry with"
+ "~n Name: ~p", [Name]),
+ #'IndAudPackagesDescriptor'{packageName = Name,
+ packageVersion = tr_integer(V, State, 0, 99)}.
+
+%% -- v2 end --
+
+
+tr_TerminationAudit(ParmList, State) when is_list(ParmList) ->
+ do_tr_TerminationAudit(ParmList, [], State).
+
+do_tr_TerminationAudit([], Acc, _State) ->
+ lists:reverse(Acc);
+do_tr_TerminationAudit([Parm|ParmList], Acc, State) ->
+ case tr_AuditReturnParameter(Parm, State) of
+ {_, deprecated} when State#state.mode =:= encode ->
+ error({deprecated, Parm});
+ {_, deprecated} when State#state.mode =:= decode ->
+ %% SKIP
+ do_tr_TerminationAudit(ParmList, Acc, State);
+ {_, deprecated} ->
+ %% SKIP
+ do_tr_TerminationAudit(ParmList, Acc, State);
+ NewParm ->
+ do_tr_TerminationAudit(ParmList, [NewParm|Acc], State)
+ end.
+
+tr_AuditReturnParameter({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ errorDescriptor ->
+ tr_ErrorDescriptor(Val, State);
+ mediaDescriptor ->
+ tr_MediaDescriptor(Val, State);
+ modemDescriptor ->
+ tr_ModemDescriptor(Val, State);
+ muxDescriptor ->
+ tr_MuxDescriptor(Val, State);
+ eventsDescriptor ->
+ tr_EventsDescriptor(Val, State);
+ eventBufferDescriptor ->
+ tr_EventBufferDescriptor(Val, State);
+ signalsDescriptor ->
+ tr_SignalsDescriptor(Val, State);
+ digitMapDescriptor ->
+ tr_DigitMapDescriptor(Val, State);
+ observedEventsDescriptor ->
+ tr_ObservedEventsDescriptor(Val, State);
+ statisticsDescriptor ->
+ tr_StatisticsDescriptor(Val, State);
+ packagesDescriptor ->
+ tr_PackagesDescriptor(Val, State);
+ emptyDescriptors ->
+ tr_EmptyDescriptors(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_EmptyDescriptors(#'AuditDescriptor'{auditToken = Tokens},
+ State) ->
+ case Tokens of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> [tr_auditItem(Token, State) || Token <- Tokens]
+ end.
+
+tr_NotifyRequest(#'NotifyRequest'{terminationID = IdList,
+ observedEventsDescriptor = ObsDesc,
+ errorDescriptor = ErrDesc},
+ State) ->
+ %% BUGBUG: Mismatch between ASN.1 and ABNF
+ %% BUGBUG: The following ought to be a 'choice'
+ #'NotifyRequest'{terminationID = [tr_TerminationID(Id, State) ||
+ Id <- IdList],
+ observedEventsDescriptor = tr_ObservedEventsDescriptor(ObsDesc, State),
+ errorDescriptor = tr_opt_ErrorDescriptor(ErrDesc, State)}.
+
+tr_NotifyReply(#'NotifyReply'{terminationID = IdList,
+ errorDescriptor = ErrDesc},
+ State) ->
+ #'NotifyReply'{terminationID = [tr_TerminationID(Id, State) || Id <- IdList],
+ errorDescriptor = tr_opt_ErrorDescriptor(ErrDesc, State)}.
+
+tr_ObservedEventsDescriptor(#'ObservedEventsDescriptor'{requestId = Id,
+ observedEventLst = Events},
+ State) when is_list(Events) ->
+ #'ObservedEventsDescriptor'{requestId = tr_RequestID(Id, State),
+ observedEventLst = [tr_ObservedEvent(E, State) || E <- Events]}.
+
+%% ;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
+
+tr_ObservedEvent(#'ObservedEvent'{eventName = Name,
+ streamID = Id,
+ eventParList = Parms,
+ timeNotation = Time},
+ State) ->
+ #'ObservedEvent'{eventName = tr_EventName(Name, State),
+ streamID = tr_opt_StreamID(Id, State),
+ eventParList = [tr_EventParameter(P, Name, State) || P <- Parms],
+ timeNotation = tr_opt_TimeNotation(Time, State)}.
+
+tr_EventName(Name, State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ resolve(event, Name, State, Constraint).
+
+tr_EventParameter(#'EventParameter'{eventParameterName = ParName,
+ value = Value,
+ extraInfo = Extra},
+ EventName,
+ State) ->
+ %% BUGBUG: event parameter name
+ Constraint = fun(Item) -> tr_Name(Item, State) end,
+ N = resolve({event_parameter, EventName}, ParName, State, Constraint),
+ #'EventParameter'{eventParameterName = N,
+ value = tr_Value(Value, State),
+ extraInfo = tr_opt_extraInfo(Extra, State)}.
+
+tr_ServiceChangeRequest(#'ServiceChangeRequest'{terminationID = IdList,
+ serviceChangeParms = Parms},
+ State) ->
+ #'ServiceChangeRequest'{terminationID = [tr_TerminationID(Id, State) || Id <- IdList],
+ serviceChangeParms = tr_ServiceChangeParm(Parms, 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 )
+tr_ServiceChangeReply(#'ServiceChangeReply'{terminationID = IdList,
+ serviceChangeResult = Res},
+ State) ->
+ #'ServiceChangeReply'{terminationID = [tr_TerminationID(Id, State) || Id <- IdList],
+ serviceChangeResult = tr_ServiceChangeResult(Res, State)}.
+
+tr_ServiceChangeResult({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ errorDescriptor -> tr_ErrorDescriptor(Val, State);
+ serviceChangeResParms -> tr_ServiceChangeResParm(Val, State)
+ end,
+ {Tag, Val2}.
+
+%% TerminationID = "ROOT" / pathNAME / "$" / "*"
+%% ; Total length of pathNAME must not exceed 64 chars.
+%% pathNAME = ["*"] NAME *("/" / "*"/ ALPHA / DIGIT /"_" / "$" )
+%% ["@" pathDomainName ]
+
+tr_TerminationID(TermId, State) when State#state.mode =/= verify ->
+ resolve(term_id, TermId, State, valid);
+tr_TerminationID(#'TerminationID'{wildcard = Wild,
+ id = Id},
+ _State) ->
+ #'TerminationID'{wildcard = Wild,
+ id = Id};
+tr_TerminationID(#megaco_term_id{contains_wildcards = IsWild,
+ id = Id},
+ State) ->
+ #megaco_term_id{contains_wildcards = tr_bool(IsWild, State),
+ id = [tr_term_id_component(Sub, State) || Sub <- Id]}.
+
+tr_opt_bool(asn1_NOVALUE, _State) -> asn1_NOVALUE;
+tr_opt_bool(Bool, State) -> tr_bool(Bool, State).
+
+tr_bool(true, _State) -> true;
+tr_bool(false, _State) -> false.
+
+tr_term_id_component(Sub, _State) ->
+ case Sub of
+ all -> all;
+ choose -> 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
+tr_MediaDescriptor(#'MediaDescriptor'{termStateDescr = TermState,
+ streams = Streams},
+ State) ->
+ #'MediaDescriptor'{termStateDescr = tr_opt_TerminationStateDescriptor(TermState, State),
+ streams = tr_opt_streams(Streams, State)}.
+
+tr_opt_streams(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_streams({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ oneStream -> tr_StreamParms(Val, State);
+ multiStream -> [tr_StreamDescriptor(SD, State) || SD <- Val]
+ end,
+ {Tag, Val2}.
+
+tr_StreamParms(#'StreamParms'{localControlDescriptor = LCD,
+ localDescriptor = LD,
+ remoteDescriptor = RD,
+ statisticsDescriptor = SD},
+ State) ->
+ LCD2 = tr_opt_LocalControlDescriptor(LCD, State),
+ LD2 = tr_opt_LocalRemoteDescriptor(LD, State),
+ RD2 = tr_opt_LocalRemoteDescriptor(RD, State),
+ SD2 = tr_opt_StatisticsDescriptor(SD, State),
+ #'StreamParms'{localControlDescriptor = LCD2,
+ localDescriptor = LD2,
+ remoteDescriptor = RD2,
+ statisticsDescriptor = SD2}.
+
+tr_StreamDescriptor(#'StreamDescriptor'{streamID = Id,
+ streamParms = Parms},
+ State) ->
+ #'StreamDescriptor'{streamID = tr_StreamID(Id, State),
+ streamParms = tr_StreamParms(Parms, 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
+tr_opt_LocalControlDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_LocalControlDescriptor(#'LocalControlDescriptor'{streamMode = Mode,
+ reserveGroup = Group,
+ reserveValue = Value,
+ propertyParms = Props},
+ State) ->
+ #'LocalControlDescriptor'{streamMode = tr_opt_StreamMode(Mode, State),
+ reserveGroup = tr_opt_bool(Group, State),
+ reserveValue = tr_opt_bool(Value, State),
+ propertyParms = [tr_PropertyParm(P, State) || P <- Props]}.
+
+tr_opt_StreamMode(Mode, _State) ->
+ case Mode of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ sendOnly -> sendOnly;
+ recvOnly -> recvOnly;
+ sendRecv -> sendRecv;
+ inactive -> inactive;
+ loopBack -> loopBack
+ end.
+
+tr_Name(Name, State) ->
+ %% BUGBUG: transform
+ %% BUGBUG: NAME = ALPHA *63(ALPHA / DIGIT / "_" )
+ tr_STRING(Name, State, 2, 2).
+
+tr_PkgdName(Name, State) ->
+ %% BUGBUG: transform
+ %% BUGBUG: pkgdName = (NAME / "*") SLASH (ItemID / "*" )
+ tr_OCTET_STRING(Name, State, 4, 4).
+
+%% 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.
+tr_opt_LocalRemoteDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_LocalRemoteDescriptor(#'LocalRemoteDescriptor'{propGrps = Groups},
+ State) ->
+ #'LocalRemoteDescriptor'{propGrps = [tr_PropertyGroup(G, State) || G <- Groups]}.
+
+tr_PropertyGroup(Props, State) ->
+ [tr_PropertyGroupParm(P, State) || P <- Props].
+
+tr_PropertyGroupParm(#'PropertyParm'{name = Name,
+ value = Value},
+ State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ #'PropertyParm'{name = resolve(property, Name, State, Constraint),
+ value = tr_OCTET_STRING(Value, State, 0, infinity)}.
+
+tr_PropertyParm(#'PropertyParm'{name = Name,
+ value = Value,
+ extraInfo = Extra},
+ State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ #'PropertyParm'{name = resolve(property, Name, State, Constraint),
+ value = tr_Value(Value, State),
+ extraInfo = tr_opt_extraInfo(Extra, State)}.
+
+tr_opt_extraInfo(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_extraInfo({relation, Rel}, _State) ->
+ Rel2 =
+ case Rel of
+ greaterThan -> greaterThan;
+ smallerThan -> smallerThan;
+ unequalTo -> unequalTo
+ end,
+ {relation, Rel2};
+tr_opt_extraInfo({range, Range}, State) ->
+ Range2 = tr_bool(Range, State),
+ {range, Range2};
+tr_opt_extraInfo({sublist, Sub}, State) ->
+ Sub2 = tr_bool(Sub, State),
+ {sublist, Sub2}.
+
+tr_opt_TerminationStateDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_TerminationStateDescriptor(#'TerminationStateDescriptor'{propertyParms = Props,
+ eventBufferControl = Control,
+ serviceState = Service},
+ State) ->
+ #'TerminationStateDescriptor'{propertyParms = [tr_PropertyParm(P, State) || P <- Props],
+ eventBufferControl = tr_opt_EventBufferControl(Control, State),
+ serviceState = tr_opt_ServiceState(Service, State)}.
+
+tr_opt_EventBufferControl(Control, _State) ->
+ case Control of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ off -> off;
+ lockStep -> lockStep
+ end.
+
+tr_opt_ServiceState(Service, _State) ->
+ case Service of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ test -> test;
+ outOfSvc -> outOfSvc;
+ inSvc -> inSvc
+ end.
+
+tr_MuxDescriptor(#'MuxDescriptor'{muxType = Type,
+ termList = IdList},
+ State) ->
+ #'MuxDescriptor'{muxType = tr_MuxType(Type, State),
+ termList = [tr_TerminationID(Id, State) || Id <- IdList]}.
+
+tr_MuxType(Type, _State) ->
+ case Type of
+ h221 -> h221;
+ h223 -> h223;
+ h226 -> h226;
+ v76 -> v76
+ end.
+
+tr_opt_StreamID(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_StreamID(Id, State) ->
+ tr_StreamID(Id, State).
+
+tr_StreamID(Id, State) ->
+ tr_UINT16(Id, State).
+
+tr_EventsDescriptor(#'EventsDescriptor'{requestID = Id,
+ eventList = Events},
+ State) ->
+ #'EventsDescriptor'{requestID = tr_opt_RequestID(Id, State),
+ eventList = [tr_RequestedEvent(E, State) || E <- Events]}.
+
+tr_RequestedEvent(#'RequestedEvent'{pkgdName = Name,
+ streamID = Id,
+ evParList = Parms,
+ eventAction = Actions},
+ State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ #'RequestedEvent'{pkgdName = resolve(event, Name, State, Constraint),
+ streamID = tr_opt_StreamID(Id, State),
+ eventAction = tr_opt_RequestedActions(Actions, State),
+ evParList = [tr_EventParameter(P, Name, State) || P <- Parms]}.
+
+tr_opt_RequestedActions(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_RequestedActions(#'RequestedActions'{keepActive = Keep,
+ eventDM = DM,
+ secondEvent = Event,
+ signalsDescriptor = SigDesc},
+ State) ->
+ #'RequestedActions'{keepActive = tr_opt_keepActive(Keep, State),
+ eventDM = tr_opt_EventDM(DM, State),
+ secondEvent = tr_opt_SecondEventsDescriptor(Event, State),
+ signalsDescriptor = tr_opt_SignalsDescriptor(SigDesc, State)}.
+
+tr_opt_keepActive(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_keepActive(Keep, State) ->
+ tr_bool(Keep, State).
+
+tr_opt_EventDM(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_EventDM({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ digitMapName -> tr_DigitMapName(Val, State);
+ digitMapValue -> tr_DigitMapValue(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_opt_SecondEventsDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_SecondEventsDescriptor(#'SecondEventsDescriptor'{requestID = Id,
+ eventList = Events},
+ State) ->
+ #'SecondEventsDescriptor'{requestID = tr_RequestID(Id, State), %% IG v6 6.8 withdrawn
+ eventList = [tr_SecondRequestedEvent(E, State) || E <- Events]}.
+
+tr_SecondRequestedEvent(#'SecondRequestedEvent'{pkgdName = Name,
+ streamID = Id,
+ evParList = Parms,
+ eventAction = Actions},
+ State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ #'SecondRequestedEvent'{pkgdName = resolve(event, Name, State, Constraint),
+ streamID = tr_opt_StreamID(Id, State),
+ eventAction = tr_opt_SecondRequestedActions(Actions, State),
+ evParList = [tr_EventParameter(P, Name, State) || P <- Parms]}.
+
+
+tr_opt_SecondRequestedActions(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_SecondRequestedActions(#'SecondRequestedActions'{keepActive = Keep,
+ eventDM = DM,
+ signalsDescriptor = SigDesc},
+ State) ->
+ #'SecondRequestedActions'{keepActive = tr_opt_keepActive(Keep, State),
+ eventDM = tr_opt_EventDM(DM, State),
+ signalsDescriptor = tr_opt_SignalsDescriptor(SigDesc, State)}.
+
+tr_EventBufferDescriptor(EventSpecs, State) ->
+ [tr_EventSpec(ES, State) || ES <- EventSpecs].
+
+tr_EventSpec(#'EventSpec'{eventName = Name,
+ streamID = Id,
+ eventParList = Parms},
+ State) ->
+ #'EventSpec'{eventName = tr_EventName(Name, State),
+ streamID = tr_opt_StreamID(Id, State),
+ eventParList = [tr_EventParameter(P, Name, State) || P <- Parms]}.
+
+tr_opt_SignalsDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_SignalsDescriptor(SigDesc, State) ->
+ tr_SignalsDescriptor(SigDesc, State).
+
+tr_SignalsDescriptor(SigDesc, State) when is_list(SigDesc) ->
+ [tr_SignalRequest(SigReq, State) || SigReq <- SigDesc].
+
+tr_SignalRequest({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ signal -> tr_Signal(Val, State);
+ seqSigList -> tr_SeqSigList(Val, State)
+ end,
+ {Tag, Val2}.
+
+
+tr_SeqSigList(#'SeqSigList'{id = Id,
+ signalList = SigList},
+ State) when is_list(SigList) ->
+ #'SeqSigList'{id = tr_UINT16(Id, State),
+ signalList = [tr_Signal(Sig, State) || Sig <- SigList]}.
+
+tr_Signal(#'Signal'{signalName = Name,
+ streamID = SID,
+ sigType = Type,
+ duration = Dur,
+ notifyCompletion = Compl,
+ keepActive = Keep,
+ sigParList = Parms,
+ direction = Dir,
+ requestID = RID},
+ State) ->
+ Name2 = tr_SignalName(Name, State),
+ SID2 = tr_opt_StreamID(SID, State),
+ Type2 = tr_opt_SignalType(Type, State),
+ Dur2 = tr_opt_duration(Dur, State),
+ Compl2 = tr_opt_NotifyCompletion(Compl, State),
+ Keep2 = tr_opt_keepActive(Keep, State),
+ Parms2 = [tr_SigParameter(P, Name, State) || P <- Parms],
+ Dir2 = tr_opt_SignalDirection(Dir, State),
+ RID2 = tr_opt_RequestID(RID, State),
+ #'Signal'{signalName = Name2,
+ streamID = SID2,
+ sigType = Type2,
+ duration = Dur2,
+ notifyCompletion = Compl2,
+ keepActive = Keep2,
+ sigParList = Parms2,
+ direction = Dir2,
+ requestID = RID2}.
+
+tr_opt_duration(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_duration(Dur, State) ->
+ tr_UINT16(Dur, State).
+
+tr_opt_NotifyCompletion(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_NotifyCompletion(Items, State) when is_list(Items) ->
+ [tr_notifyCompletionItem(I, State) || I <- Items].
+
+tr_notifyCompletionItem(Item, _State) ->
+ case Item of
+ onTimeOut -> onTimeOut;
+ onInterruptByEvent -> onInterruptByEvent;
+ onInterruptByNewSignalDescr -> onInterruptByNewSignalDescr;
+ otherReason -> otherReason
+ end.
+
+tr_opt_SignalType(asn1_NOVALUE = Type, _State) ->
+ Type;
+tr_opt_SignalType(Type, _State) ->
+ case Type of
+ brief -> brief;
+ onOff -> onOff;
+ timeOut -> timeOut
+ end.
+
+tr_opt_SignalDirection(asn1_NOVALUE = SD, _State) ->
+ SD;
+tr_opt_SignalDirection(SD, _State) ->
+ case SD of
+ internal -> internal;
+ external -> external;
+ both -> both
+ end.
+
+tr_SignalName(Name, State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ resolve(signal, Name, State, Constraint).
+
+tr_SigParameter(#'SigParameter'{sigParameterName = ParName,
+ value = Value,
+ extraInfo = Extra},
+ SigName,
+ State) ->
+ Constraint = fun(Item) -> tr_Name(Item, State) end,
+ N = resolve({signal_parameter, SigName}, ParName, State, Constraint),
+ #'SigParameter'{sigParameterName = N,
+ value = tr_Value(Value, State),
+ extraInfo = tr_opt_extraInfo(Extra, State)}.
+
+tr_opt_RequestID(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_RequestID(Id, State) ->
+ tr_RequestID(Id, State).
+
+tr_RequestID(Id, _State) when Id =:= ?megaco_all_request_id ->
+ ?megaco_all_request_id;
+tr_RequestID(Id, State) ->
+ tr_UINT32(Id, State).
+
+tr_ModemDescriptor(_MD, _State) ->
+ deprecated.
+
+tr_DigitMapDescriptor(#'DigitMapDescriptor'{digitMapName = Name,
+ digitMapValue = Value},
+ State) ->
+ #'DigitMapDescriptor'{digitMapName = tr_opt_DigitMapName(Name, State),
+ digitMapValue = tr_opt_DigitMapValue(Value, State)}.
+
+tr_opt_DigitMapName(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_DigitMapName(Name, State) ->
+ tr_DigitMapName(Name, State).
+
+tr_DigitMapName(Name, State) ->
+ Constraint = fun(Item) -> tr_Name(Item, State) end,
+ resolve(dialplan, Name, State, Constraint).
+
+tr_opt_DigitMapValue(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_DigitMapValue(Value, State) ->
+ tr_DigitMapValue(Value, State).
+
+tr_DigitMapValue(#'DigitMapValue'{digitMapBody = Body,
+ startTimer = Start,
+ shortTimer = Short,
+ longTimer = Long},
+ State) ->
+ #'DigitMapValue'{startTimer = tr_opt_timer(Start, State),
+ shortTimer = tr_opt_timer(Short, State),
+ longTimer = tr_opt_timer(Long, State),
+ digitMapBody = tr_STRING(Body, State)}. %% BUGBUG: digitMapBody not handled at all
+
+tr_opt_timer(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_timer(Timer, State) ->
+ tr_DIGIT(Timer, State, 0, 99).
+
+tr_ServiceChangeParm(
+ #'ServiceChangeParm'{serviceChangeMethod = Method,
+ serviceChangeAddress = Addr,
+ serviceChangeVersion = Version,
+ serviceChangeProfile = Profile,
+ serviceChangeReason = Reason,
+ serviceChangeDelay = Delay,
+ serviceChangeMgcId = MgcId,
+ timeStamp = Time,
+ serviceChangeInfo = Info,
+ serviceChangeIncompleteFlag = Incomplete},
+ State) ->
+ Method2 = tr_ServiceChangeMethod(Method, State),
+ Addr2 = tr_opt_ServiceChangeAddress(Addr, State),
+ Version2 = tr_opt_serviceChangeVersion(Version, State),
+ Profile2 = tr_opt_ServiceChangeProfile(Profile, State),
+ Reason2 = tr_serviceChangeReason(Reason, State),
+ Delay2 = tr_opt_serviceChangeDelay(Delay, State),
+ MgcId2 = tr_opt_serviceChangeMgcId(MgcId, State),
+ Time2 = tr_opt_TimeNotation(Time, State),
+ Info2 = tr_opt_AuditDescriptor(Info, State),
+ Incomplete2 = tr_opt_null(Incomplete, State),
+ #'ServiceChangeParm'{serviceChangeMethod = Method2,
+ serviceChangeAddress = Addr2,
+ serviceChangeVersion = Version2,
+ serviceChangeProfile = Profile2,
+ serviceChangeReason = Reason2,
+ serviceChangeDelay = Delay2,
+ serviceChangeMgcId = MgcId2,
+ timeStamp = Time2,
+ serviceChangeInfo = Info2,
+ serviceChangeIncompleteFlag = Incomplete2}.
+
+tr_ServiceChangeMethod(Method, _State) ->
+ case Method of
+ failover -> failover;
+ forced -> forced;
+ graceful -> graceful;
+ restart -> restart;
+ disconnected -> disconnected;
+ handOff -> handOff
+ end. %% BUGBUG: extension
+
+tr_opt_ServiceChangeAddress(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_ServiceChangeAddress({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ portNumber -> tr_portNumber(Val, State);
+ ip4Address -> tr_IP4Address(Val, State);
+ ip6Address -> tr_IP6Address(Val, State);
+ domainName -> tr_DomainName(Val, State);
+ deviceName -> tr_PathName(Val, State);
+ mtpAddress -> tr_mtpAddress(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_opt_serviceChangeVersion(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_serviceChangeVersion(Version, State) ->
+ tr_version(Version, State).
+
+tr_opt_ServiceChangeProfile(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+%% Decode
+tr_opt_ServiceChangeProfile({'ServiceChangeProfile', ProfileName}, State) ->
+ case string:tokens(ProfileName, "/") of
+ [Name0, Version0] ->
+ Name = tr_STRING(Name0, State, 1, 64),
+ Version = tr_version(list_to_integer(Version0), State),
+ #'ServiceChangeProfile'{profileName = Name,
+ version = Version}
+ end;
+%% Encode
+tr_opt_ServiceChangeProfile(#'ServiceChangeProfile'{profileName = Name0,
+ version = Version0},
+ State) ->
+ Name = tr_STRING(Name0, State, 1, 64),
+ Version = tr_version(Version0, State),
+ ProfileName = lists:flatten(io_lib:format("~s/~w", [Name, Version])),
+ {'ServiceChangeProfile', ProfileName}.
+
+tr_serviceChangeReason([_] = Reason, State) ->
+ tr_Value(Reason, State).
+
+tr_opt_serviceChangeDelay(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_serviceChangeDelay(Delay, State) ->
+ tr_UINT32(Delay, State).
+
+tr_opt_serviceChangeMgcId(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_serviceChangeMgcId(MgcId, State) ->
+ tr_MId(MgcId, State).
+
+tr_opt_portNumber(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_portNumber(Port, State) ->
+ tr_portNumber(Port, State).
+
+tr_portNumber(Port, State) when is_integer(Port) andalso (Port >= 0) ->
+ tr_UINT16(Port, State).
+
+tr_ServiceChangeResParm(#'ServiceChangeResParm'{serviceChangeMgcId = MgcId,
+ serviceChangeAddress = Addr,
+ serviceChangeVersion = Version,
+ serviceChangeProfile = Profile,
+ timeStamp = Time},
+ State) ->
+ #'ServiceChangeResParm'{serviceChangeMgcId = tr_opt_serviceChangeMgcId(MgcId, State),
+ serviceChangeAddress = tr_opt_ServiceChangeAddress(Addr, State),
+ serviceChangeVersion = tr_opt_serviceChangeVersion(Version, State),
+ serviceChangeProfile = tr_opt_ServiceChangeProfile(Profile, State),
+ timeStamp = tr_opt_TimeNotation(Time, State)}.
+
+tr_PackagesDescriptor(Items, State) when is_list(Items) ->
+ [tr_PackagesItem(I, State) || I <- Items].
+
+tr_PackagesItem(#'PackagesItem'{packageName = Name,
+ packageVersion = Version},
+ State) ->
+ Constraint = fun(Item) -> tr_Name(Item, State) end,
+ #'PackagesItem'{packageName = resolve(package, Name, State, Constraint),
+ packageVersion = tr_UINT16(Version, State)}.
+
+tr_opt_StatisticsDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_StatisticsDescriptor(Parms, State) ->
+ tr_StatisticsDescriptor(Parms, State).
+
+tr_StatisticsDescriptor(Parms, State) when is_list(Parms) ->
+ [tr_StatisticsParameter(P, State) || P <- Parms].
+
+tr_StatisticsParameter(#'StatisticsParameter'{statName = Name,
+ statValue = Value},
+ State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ #'StatisticsParameter'{statName = resolve(statistics, Name, State, Constraint),
+ statValue = tr_opt_Value(Value, State)}.
+
+tr_opt_TimeNotation(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_TimeNotation(#'TimeNotation'{date = Date,
+ time = Time},
+ State) ->
+ #'TimeNotation'{date = tr_STRING(Date, State, 8, 8), % "yyyymmdd"
+ time = tr_STRING(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.
+
+tr_opt_Value(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_Value(Value, State) ->
+ tr_Value(Value, State).
+
+tr_Value(Strings, _State) when is_list(Strings) ->
+ [[Char || Char <- String] || String <- Strings].
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Encode an octet string, escape } by \ if necessary
+tr_OCTET_STRING(String, _State, Min, Max) when is_list(String) ->
+ verify_count(length(String), Min, Max),
+ String.
+
+tr_QUOTED_STRING(String, _State) when is_list(String) ->
+ verify_count(length(String), 1, infinity),
+ String.
+
+%% 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
+tr_HEXDIG(Octets, _State, Min, Max) when is_list(Octets) ->
+ verify_count(length(Octets), Min, Max),
+ Octets.
+
+tr_DIGIT(Val, State, Min, Max) ->
+ tr_integer(Val, State, Min, Max).
+
+tr_STRING(String, _State) when is_list(String) ->
+ String.
+
+tr_STRING(String, _State, Min, Max) when is_list(String) ->
+ verify_count(length(String), Min, Max),
+ String.
+
+tr_opt_UINT16(Val, State) ->
+ tr_opt_integer(Val, State, 0, 65535).
+
+tr_UINT16(Val, State) ->
+ tr_integer(Val, State, 0, 65535).
+
+tr_UINT32(Val, State) ->
+ tr_integer(Val, State, 0, 4294967295).
+
+tr_opt_integer(asn1_NOVALUE, _State, _Min, _Max) ->
+ asn1_NOVALUE;
+tr_opt_integer(Int, State, Min, Max) ->
+ tr_integer(Int, State, Min, Max).
+
+tr_integer(Int, _State, Min, Max) ->
+ verify_count(Int, Min, Max),
+ Int.
+
+%% 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).
+
+
diff --git a/lib/megaco/src/binary/megaco_binary_transformer_prev3b.erl b/lib/megaco/src/binary/megaco_binary_transformer_prev3b.erl
new file mode 100644
index 0000000000..baca84bbfe
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_binary_transformer_prev3b.erl
@@ -0,0 +1,1629 @@
+%%
+%% %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: Transform internal form of Megaco/H.248 messages
+%%----------------------------------------------------------------------
+
+-module(megaco_binary_transformer_prev3b).
+
+-include_lib("megaco/include/megaco.hrl").
+%% -include_lib("megaco/include/megaco_message.hrl").
+-include_lib("megaco/include/megaco_message_prev3b.hrl").
+-include_lib("megaco/src/app/megaco_internal.hrl").
+
+-export([tr_message/3, tr_transaction/3]).
+
+-define(DEFAULT_NAME_RESOLVER, megaco_binary_name_resolver_prev3b).
+
+-record(state, {mode, % verify | encode | decode
+ resolver_module, %
+ resolver_options}).
+
+resolve(Type, Item, State, Constraint) ->
+ case State#state.mode of
+ verify ->
+ Item;
+ encode ->
+ ?d("resolve(encode) -> encode: ~p",[Item]),
+ Mod = State#state.resolver_module,
+ Opt = State#state.resolver_options,
+ EncodedItem = Mod:encode_name(Opt, Type, Item),
+ ?d("resolve -> verify contraint for ~p",[EncodedItem]),
+ verify_constraint(EncodedItem, Constraint);
+ decode ->
+ ?d("resolve(decode) -> verify contraint for ~p",[Item]),
+ DecodedItem = verify_constraint(Item, Constraint),
+ Mod = State#state.resolver_module,
+ Opt = State#state.resolver_options,
+ ?d("resolve(decode) -> decode: ~p",[DecodedItem]),
+ Mod:decode_name(Opt, Type, DecodedItem)
+ end.
+
+verify_constraint(Item, valid) ->
+ Item;
+verify_constraint(Item, Constraint) when is_function(Constraint) ->
+ Constraint(Item).
+
+tr_message(MegaMsg, Mode, Config) ->
+ case Config of
+ [native] ->
+ MegaMsg;
+ [verify] ->
+ State = #state{mode = verify},
+ tr_MegacoMessage(MegaMsg, State);
+ [] ->
+ State = #state{mode = Mode,
+ resolver_module = ?DEFAULT_NAME_RESOLVER,
+ resolver_options = [8, 8, 8]},
+ tr_MegacoMessage(MegaMsg, State);
+ [{binary_name_resolver, {Module, Options}}] when is_atom(Module) ->
+ State = #state{mode = Mode,
+ resolver_module = Module,
+ resolver_options = Options},
+ tr_MegacoMessage(MegaMsg, State)
+ end.
+
+tr_transaction(Trans, Mode, Config) ->
+ case Config of
+ [native] ->
+ Trans;
+ [verify] ->
+ State = #state{mode = verify},
+ tr_Transaction(Trans, State);
+ [] ->
+ State = #state{mode = Mode,
+ resolver_module = ?DEFAULT_NAME_RESOLVER,
+ resolver_options = [8, 8, 8]},
+ tr_Transaction(Trans, State);
+ [{binary_name_resolver, {Module, Options}}] when is_atom(Module) ->
+ State = #state{mode = Mode,
+ resolver_module = Module,
+ resolver_options = Options},
+ tr_Transaction(Trans, State)
+ end.
+
+tr_MegacoMessage(#'MegacoMessage'{authHeader = Auth,
+ mess = Mess},
+ State) ->
+ ?d("tr_MegacoMessage -> entry with"
+ "~n Auth: ~p"
+ "~n Mess: ~p"
+ "~n State: ~p", [Auth, Mess, State]),
+ #'MegacoMessage'{authHeader = tr_opt_AuthenticationHeader(Auth, State),
+ mess = tr_Message(Mess, State)}.
+
+tr_opt_AuthenticationHeader(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_AuthenticationHeader(#'AuthenticationHeader'{secParmIndex = SPI,
+ seqNum = SN,
+ ad = AuthData},
+ State) ->
+ #'AuthenticationHeader'{secParmIndex = tr_SecurityParmIndex(SPI, State),
+ seqNum = tr_SequenceNum(SN, State),
+ ad = tr_AuthData(AuthData, State)}.
+
+tr_SecurityParmIndex(SPI, State) ->
+ tr_HEXDIG(SPI, State, 4, 4). % BUGBUG: Mismatch between ASN.1 and ABNF
+
+tr_SequenceNum(SN, State) ->
+ tr_HEXDIG(SN, State, 4, 4). % BUGBUG: Mismatch between ASN.1 and ABNF
+
+tr_AuthData(AuthData, State) ->
+ tr_HEXDIG(AuthData, State, 12, 32). % BUGBUG: Mismatch between ASN.1 and ABNF
+
+tr_Message(#'Message'{version = Version,
+ mId = MID,
+ messageBody = Body},
+ State) ->
+ #'Message'{version = tr_version(Version, State),
+ mId = tr_MId(MID, State),
+ messageBody = tr_Message_messageBody(Body, State)}.
+
+tr_version(Version, State) ->
+ tr_DIGIT(Version, State, 0, 99).
+
+tr_Message_messageBody({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ messageError -> tr_ErrorDescriptor(Val, State);
+ transactions when is_list(Val) -> [tr_Transaction(T, State) || T <- Val]
+ end,
+ {Tag, Val2}.
+
+tr_MId({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ ip4Address -> tr_IP4Address(Val, State);
+ ip6Address -> tr_IP6Address(Val, State);
+ domainName -> tr_DomainName(Val, State);
+ deviceName -> tr_PathName(Val, State);
+ mtpAddress -> tr_mtpAddress(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_mtpAddress(MtpAddr, State) ->
+ tr_OCTET_STRING(MtpAddr, State, 2, 4). % BUGBUG: Mismatch between ASN.1 and ABNF
+
+tr_DomainName(#'DomainName'{name = Name,
+ portNumber = Port},
+ State) ->
+ Domain = #'DomainName'{name = tr_STRING(Name, State), % BUGBUG: Mismatch between ASN.1 and ABNF
+ portNumber = tr_opt_portNumber(Port, State)},
+ {domainName, Domain2} = resolve(mid, {domainName, Domain}, State, valid),
+ Domain2.
+
+tr_IP4Address(#'IP4Address'{address = [A1, A2, A3, A4],
+ portNumber = Port},
+ State) ->
+ #'IP4Address'{address = [tr_V4hex(A1, State),
+ tr_V4hex(A2, State),
+ tr_V4hex(A3, State),
+ tr_V4hex(A4, State)],
+ portNumber = tr_opt_portNumber(Port, State)}.
+
+tr_V4hex(Val, State) ->
+ tr_DIGIT(Val, State, 0, 255).
+
+tr_IP6Address(_Val, _State) ->
+ error(ipv6_not_supported). %% BUGBUG: nyi
+
+tr_PathName(Path, State) ->
+ %% BUGBUG: ["*"] NAME *("/" / "*"/ ALPHA / DIGIT /"_" / "$" )
+ %% BUGBUG: ["@" pathDomainName ]
+ Constraint = fun({deviceName, Item}) -> tr_STRING(Item, State, 1, 64) end,
+ resolve(mid, {deviceName, Path}, State, Constraint).
+
+tr_Transaction({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ transactionRequest -> tr_TransactionRequest(Val, State);
+ transactionPending -> tr_TransactionPending(Val, State);
+ transactionReply -> tr_TransactionReply(Val, State);
+ transactionResponseAck -> [tr_TransactionAck(T, State) || T <- Val]
+ end,
+ {Tag, Val2}.
+
+tr_TransactionAck(#'TransactionAck'{firstAck = First,
+ lastAck = Last},
+ State) ->
+ #'TransactionAck'{firstAck = tr_TransactionId(First, State),
+ lastAck = tr_opt_TransactionId(Last, State)}.
+
+tr_opt_TransactionId(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_TransactionId(Id, State) ->
+ tr_TransactionId(Id, State).
+
+tr_TransactionId(Id, State) ->
+ tr_UINT32(Id, State).
+
+tr_TransactionRequest(#'TransactionRequest'{transactionId = Id,
+ actions = Actions},
+ State) when is_list(Actions) ->
+
+ #'TransactionRequest'{transactionId = tr_TransactionId(Id, State),
+ actions = [tr_ActionRequest(ActReq, State) || ActReq <- Actions]}.
+
+tr_TransactionPending(#'TransactionPending'{transactionId = Id},
+ State) ->
+ #'TransactionPending'{transactionId = tr_TransactionId(Id, State)}.
+
+tr_TransactionReply(#'TransactionReply'{transactionId = Id,
+ immAckRequired = ImmAck,
+ transactionResult = TransRes,
+ %% 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) ->
+ #'TransactionReply'{transactionId = tr_TransactionId(Id, State),
+ immAckRequired = tr_opt_null(ImmAck, State),
+ transactionResult = tr_TransactionReply_transactionResult(TransRes, State),
+ segmentNumber = asn1_NOVALUE,
+ segmentationComplete = asn1_NOVALUE};
+tr_TransactionReply(TR, _State) ->
+ error({unsupported_TransactionReply, TR}).
+
+tr_opt_null(asn1_NOVALUE, _State) -> asn1_NOVALUE;
+tr_opt_null('NULL', _State) -> 'NULL'.
+
+tr_TransactionReply_transactionResult({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ transactionError ->
+ tr_ErrorDescriptor(Val, State);
+ actionReplies when is_list(Val) andalso (Val =/= []) ->
+ [tr_ActionReply(ActRep, State) || ActRep <- Val]
+ end,
+ {Tag, Val2}.
+
+tr_opt_ErrorDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_ErrorDescriptor(ErrDesc, State) ->
+ tr_ErrorDescriptor(ErrDesc, State).
+
+tr_ErrorDescriptor(#'ErrorDescriptor'{errorCode = Code,
+ errorText = Text},
+ State) ->
+ #'ErrorDescriptor'{errorCode = tr_ErrorCode(Code, State),
+ errorText = tr_opt_ErrorText(Text, State)}.
+
+tr_ErrorCode(Code, State) ->
+ tr_DIGIT(Code, State, 0, 999).
+
+tr_opt_ErrorText(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_ErrorText(Text, State) ->
+ tr_QUOTED_STRING(Text, State).
+
+tr_ContextID(CtxId, State) ->
+ case CtxId of
+ ?megaco_all_context_id -> ?megaco_all_context_id;
+ ?megaco_null_context_id -> ?megaco_null_context_id;
+ ?megaco_choose_context_id -> ?megaco_choose_context_id;
+ Int when is_integer(Int) -> tr_UINT32(Int, State)
+ end.
+
+tr_ActionRequest(#'ActionRequest'{contextId = CtxId,
+ contextRequest = CtxReq,
+ contextAttrAuditReq = CtxAuditReq,
+ commandRequests = CmdReqList},
+ State) ->
+ #'ActionRequest'{contextId = tr_ContextID(CtxId, State),
+ contextRequest = tr_opt_ContextRequest(CtxReq, State),
+ contextAttrAuditReq = tr_opt_ContextAttrAuditRequest(CtxAuditReq, State),
+ commandRequests = [tr_CommandRequest(CmdReq, State) || CmdReq <- CmdReqList]}.
+
+tr_ActionReply(#'ActionReply'{contextId = CtxId,
+ errorDescriptor = ErrDesc,
+ contextReply = CtxRep,
+ commandReply = CmdRepList},
+ State) ->
+ CmdRepList2 = [tr_CommandReply(CmdRep, State) || CmdRep <- CmdRepList],
+ #'ActionReply'{contextId = tr_ContextID(CtxId, State),
+ errorDescriptor = tr_opt_ErrorDescriptor(ErrDesc, State),
+ contextReply = tr_opt_ContextRequest(CtxRep, State),
+ commandReply = CmdRepList2}.
+
+tr_opt_ContextRequest(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_ContextRequest(CR, State) ->
+ tr_ContextRequest(CR, State).
+
+tr_ContextRequest(#'ContextRequest'{priority = Prio,
+ emergency = Em,
+ topologyReq = TopReqList,
+ iepscallind = Ind,
+ contextProp = Props},
+ State) ->
+ Prio2 =
+ case Prio of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> tr_integer(Prio, State, 0, 15)
+ end,
+ Em2 =
+ case Em of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ false -> false;
+ true -> true
+ end,
+ TopReqList2 =
+ case TopReqList of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> [tr_TopologyRequest(TopReq, State) ||
+ TopReq <- TopReqList]
+ end,
+ Ind2 =
+ case Ind of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ false -> false;
+ true -> true
+ end,
+ Props2 =
+ case Props of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> [tr_PropertyParm(Prop, State) || Prop <- Props]
+ end,
+ #'ContextRequest'{priority = Prio2,
+ emergency = Em2,
+ topologyReq = TopReqList2,
+ iepscallind = Ind2,
+ contextProp = Props2}.
+
+tr_opt_ContextAttrAuditRequest(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_ContextAttrAuditRequest(CAAR, State) ->
+ tr_ContextAttrAuditRequest(CAAR, State).
+
+tr_ContextAttrAuditRequest(#'ContextAttrAuditRequest'{topology = Top,
+ emergency = Em,
+ priority = Prio,
+ iepscallind = Ind,
+ contextPropAud = Props},
+ State) ->
+ Top2 = tr_opt_null(Top, State),
+ Em2 = tr_opt_null(Em, State),
+ Prio2 = tr_opt_null(Prio, State),
+ Ind2 = tr_opt_null(Ind, State),
+ Props2 =
+ case Props of
+ asn1_NOVALUE ->
+ asn1_NOVALUE;
+ _ ->
+ [tr_indAudPropertyParm(Prop, State) || Prop <- Props]
+ end,
+ #'ContextAttrAuditRequest'{topology = Top2,
+ emergency = Em2,
+ priority = Prio2,
+ iepscallind = Ind2,
+ contextPropAud = Props2}.
+
+tr_CommandRequest(#'CommandRequest'{command = Cmd,
+ optional = Opt,
+ wildcardReturn = Wild},
+ State) ->
+ #'CommandRequest'{optional = tr_opt_null(Opt, State),
+ wildcardReturn = tr_opt_null(Wild, State),
+ command = tr_Command(Cmd, State)}.
+
+tr_Command({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ addReq -> tr_AmmRequest(Val, State);
+ moveReq -> tr_AmmRequest(Val, State);
+ modReq -> tr_AmmRequest(Val, State);
+ subtractReq -> tr_SubtractRequest(Val, State);
+ auditCapRequest -> tr_AuditRequest(Val, State);
+ auditValueRequest -> tr_AuditRequest(Val, State);
+ notifyReq -> tr_NotifyRequest(Val, State);
+ serviceChangeReq -> tr_ServiceChangeRequest(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_CommandReply({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ addReply -> tr_AmmsReply(Val, State);
+ moveReply -> tr_AmmsReply(Val, State);
+ modReply -> tr_AmmsReply(Val, State);
+ subtractReply -> tr_AmmsReply(Val, State);
+ auditCapReply -> tr_AuditReply(Val, State);
+ auditValueReply -> tr_AuditReply(Val, State);
+ notifyReply -> tr_NotifyReply(Val, State);
+ serviceChangeReply -> tr_ServiceChangeReply(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_TopologyRequest(#'TopologyRequest'{terminationFrom = From,
+ terminationTo = To,
+ topologyDirection = Dir},
+ State) ->
+ Dir2 =
+ case Dir of
+ bothway -> bothway;
+ isolate -> isolate;
+ oneway -> oneway
+ end,
+ #'TopologyRequest'{terminationFrom = tr_TerminationID(From, State),
+ terminationTo = tr_TerminationID(To, State),
+ topologyDirection = Dir2}.
+
+tr_AmmRequest(#'AmmRequest'{terminationID = IdList,
+ descriptors = DescList},
+ State) ->
+ #'AmmRequest'{terminationID = [tr_TerminationID(Id, State) ||
+ Id <- IdList],
+ descriptors = tr_ammDescriptors(DescList, [], State)}.
+
+tr_ammDescriptors([], Acc, _State) ->
+ lists:reverse(Acc);
+tr_ammDescriptors([Desc|Descs], Acc, State) ->
+ case tr_ammDescriptor(Desc, State) of
+ {_, deprecated} when State#state.mode =:= encode ->
+ error({deprecated, Desc});
+ {_, deprecated} when State#state.mode =:= decode ->
+ %% SKIP
+ tr_ammDescriptors(Descs, Acc, State);
+ {_, deprecated} ->
+ %% SKIP
+ tr_ammDescriptors(Descs, Acc, State);
+ NewDesc ->
+ tr_ammDescriptors(Descs, [NewDesc|Acc], State)
+ end.
+
+tr_ammDescriptor({Tag, Desc}, State) ->
+ Desc2 =
+ case Tag of
+ mediaDescriptor -> tr_MediaDescriptor(Desc, State);
+ modemDescriptor -> tr_ModemDescriptor(Desc, State);
+ muxDescriptor -> tr_MuxDescriptor(Desc, State);
+ eventsDescriptor -> tr_EventsDescriptor(Desc, State);
+ eventBufferDescriptor -> tr_EventBufferDescriptor(Desc, State);
+ signalsDescriptor -> tr_SignalsDescriptor(Desc, State);
+ digitMapDescriptor -> tr_DigitMapDescriptor(Desc, State);
+ auditDescriptor -> tr_AuditDescriptor(Desc, State);
+ statisticsDescriptor -> tr_StatisticsDescriptor(Desc, State)
+ end,
+ {Tag, Desc2}.
+
+tr_AmmsReply(#'AmmsReply'{terminationID = IdList,
+ terminationAudit = TermAudit},
+ State) ->
+ TermAudit2 =
+ case TermAudit of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> tr_TerminationAudit(TermAudit, State)
+ end,
+ #'AmmsReply'{terminationID = [tr_TerminationID(Id, State) ||
+ Id <- IdList],
+ terminationAudit = TermAudit2}.
+
+tr_SubtractRequest(#'SubtractRequest'{terminationID = IdList,
+ auditDescriptor = Desc},
+ State) ->
+ #'SubtractRequest'{terminationID = [tr_TerminationID(Id, State) ||
+ Id <- IdList],
+ auditDescriptor = tr_opt_AuditDescriptor(Desc, State)}.
+
+tr_AuditRequest(#'AuditRequest'{terminationID = Id,
+ auditDescriptor = Desc},
+ State) ->
+ #'AuditRequest'{terminationID = tr_TerminationID(Id, State),
+ auditDescriptor = tr_AuditDescriptor(Desc, State)}.
+
+%% auditReply = (AuditValueToken / AuditCapToken )
+%% ( contextTerminationAudit / auditOther)
+%% auditOther = EQUAL TerminationID LBRKT
+%% terminationAudit RBRKT
+%% terminationAudit = auditReturnParameter *(COMMA auditReturnParameter)
+%%
+%% contextTerminationAudit = EQUAL CtxToken ( terminationIDList /
+%% LBRKT errorDescriptor RBRKT )
+
+tr_AuditReply({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ contextAuditResult ->
+ [tr_TerminationID(Id, State) || Id <- Val];
+ error ->
+ tr_ErrorDescriptor(Val, State);
+ auditResult ->
+ tr_AuditResult(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_AuditResult(#'AuditResult'{terminationID = Id,
+ terminationAuditResult = AuditRes},
+ State) ->
+ #'AuditResult'{terminationID = tr_TerminationID(Id, State),
+ terminationAuditResult = tr_TerminationAudit(AuditRes, State)}.
+
+tr_opt_AuditDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_AuditDescriptor(Desc, State) ->
+ tr_AuditDescriptor(Desc, State).
+
+%% BUGBUG BUGBUG BUGBUG
+%% With this construction it is possible to have both auditToken
+%% and auditPropertyToken, but it is actually valid?
+tr_AuditDescriptor(#'AuditDescriptor'{auditToken = Tokens,
+ auditPropertyToken = APTs},
+ State) ->
+ Tokens2 =
+ case Tokens of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> [tr_auditItem(Token, State) || Token <- Tokens]
+ end,
+ %% v2
+ APTs2 =
+ case APTs of
+ asn1_NOVALUE ->
+ asn1_NOVALUE;
+ _ ->
+ [tr_indAuditParameter(APT, State) || APT <- APTs]
+ end,
+ #'AuditDescriptor'{auditToken = Tokens2,
+ auditPropertyToken = APTs2}.
+
+tr_auditItem(Token, _State) ->
+ case Token of
+ muxToken -> muxToken;
+ modemToken -> modemToken;
+ mediaToken -> mediaToken;
+ eventsToken -> eventsToken;
+ signalsToken -> signalsToken;
+ digitMapToken -> digitMapToken;
+ statsToken -> statsToken;
+ observedEventsToken -> observedEventsToken;
+ packagesToken -> packagesToken;
+ eventBufferToken -> eventBufferToken
+ end.
+
+%% --- v2 begin ---
+
+tr_indAuditParameter({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ indAudMediaDescriptor ->
+ tr_indAudMediaDescriptor(Val, State);
+ indAudEventsDescriptor ->
+ tr_indAudEventsDescriptor(Val, State);
+ indAudSignalsDescriptor ->
+ tr_indAudSignalsDescriptor(Val, State);
+ indAudDigitMapDescriptor ->
+ tr_indAudDigitMapDescriptor(Val, State);
+ indAudEventBufferDescriptor ->
+ tr_indAudEventBufferDescriptor(Val, State);
+ indAudStatisticsDescriptor ->
+ tr_indAudStatisticsDescriptor(Val, State);
+ indAudPackagesDescriptor ->
+ tr_indAudPackagesDescriptor(Val, State)
+ end,
+ {Tag, Val2}.
+
+
+%% -
+
+tr_indAudMediaDescriptor(#'IndAudMediaDescriptor'{termStateDescr = TSD,
+ streams = S},
+ State) ->
+ TSD2 =
+ case TSD of
+ asn1_NOVALUE ->
+ asn1_NOVALUE;
+ _ ->
+ tr_indAudTerminationStateDescriptor(TSD, State)
+ end,
+ S2 =
+ case S of
+ asn1_NOVALUE ->
+ asn1_NOVALUE;
+ {oneStream, OS} ->
+ {oneStream, tr_indAudStreamParms(OS, State)};
+ {multiStream, MS} ->
+ MS2 = [tr_indAudStreamDescriptor(MS1, State) || MS1 <- MS],
+ {multiStream, MS2}
+ end,
+ #'IndAudMediaDescriptor'{termStateDescr = TSD2,
+ streams = S2}.
+
+tr_indAudTerminationStateDescriptor(Val, State)
+ when is_record(Val, 'IndAudTerminationStateDescriptor') ->
+ #'IndAudTerminationStateDescriptor'{propertyParms = Parms,
+ eventBufferControl = EBC,
+ serviceState = SS} = Val,
+ Parms2 = [tr_indAudPropertyParm(Parm, State) || Parm <- Parms],
+ EBC2 = tr_opt_null(EBC, State),
+ SS2 = tr_opt_null(SS, State),
+ #'IndAudTerminationStateDescriptor'{propertyParms = Parms2,
+ eventBufferControl = EBC2,
+ serviceState = SS2}.
+
+
+tr_indAudStreamParms(#'IndAudStreamParms'{localControlDescriptor = LCD,
+ localDescriptor = LD,
+ remoteDescriptor = RD,
+ statisticsDescriptor = SD},
+ State) ->
+ LCD2 =
+ case LCD of
+ asn1_NOVALUE ->
+ asn1_NOVALUE;
+ _ ->
+ tr_indAudLocalControlDescriptor(LCD, State)
+ end,
+ LD2 =
+ case LD of
+ asn1_NOVALUE ->
+ asn1_NOVALUE;
+ _ ->
+ tr_indAudLocalRemoteDescriptor(LD, State)
+ end,
+ RD2 =
+ case RD of
+ asn1_NOVALUE ->
+ asn1_NOVALUE;
+ _ ->
+ tr_indAudLocalRemoteDescriptor(RD, State)
+ end,
+ SD2 =
+ case SD of
+ asn1_NOVALUE ->
+ asn1_NOVALUE;
+ _ ->
+ tr_indAudStatisticsDescriptor(SD, State)
+ end,
+ #'IndAudStreamParms'{localControlDescriptor = LCD2,
+ localDescriptor = LD2,
+ remoteDescriptor = RD2,
+ statisticsDescriptor = SD2}.
+
+tr_indAudLocalControlDescriptor(Val, State)
+ when is_record(Val, 'IndAudLocalControlDescriptor') ->
+ #'IndAudLocalControlDescriptor'{streamMode = M,
+ reserveValue = V,
+ reserveGroup = G,
+ propertyParms = P} = Val,
+ M2 = tr_opt_null(M, State),
+ V2 = tr_opt_null(V, State),
+ G2 = tr_opt_null(G, State),
+ P2 = tr_indAudLocalControlDescriptor_propertyParms(P, State),
+ #'IndAudLocalControlDescriptor'{streamMode = M2,
+ reserveValue = V2,
+ reserveGroup = G2,
+ propertyParms = P2}.
+
+tr_indAudLocalControlDescriptor_propertyParms(Parms, State)
+ when is_list(Parms) andalso (length(Parms) > 0) ->
+ [tr_indAudPropertyParm(Parm, State) || Parm <- Parms];
+tr_indAudLocalControlDescriptor_propertyParms(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE.
+
+tr_indAudLocalRemoteDescriptor(#'IndAudLocalRemoteDescriptor'{propGroupID = ID,
+ propGrps = Grps},
+ State) ->
+ #'IndAudLocalRemoteDescriptor'{propGroupID = tr_opt_UINT16(ID, State),
+ propGrps = tr_indAudPropertyGroup(Grps,
+ State)}.
+
+tr_indAudPropertyGroup(Grps, State) when is_list(Grps) ->
+ [tr_indAudPropertyParm(Parm, State) || Parm <- Grps].
+
+tr_indAudPropertyParm(#'IndAudPropertyParm'{name = Name0}, State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ Name = resolve(property, Name0, State, Constraint),
+ #'IndAudPropertyParm'{name = Name}.
+
+
+tr_indAudStreamDescriptor(#'IndAudStreamDescriptor'{streamID = ID,
+ streamParms = Parms},
+ State) ->
+ #'IndAudStreamDescriptor'{streamID = tr_StreamID(ID, State),
+ streamParms = tr_indAudStreamParms(Parms,
+ State)}.
+
+
+%% -
+
+tr_indAudEventsDescriptor(#'IndAudEventsDescriptor'{requestID = RID,
+ pkgdName = Name0,
+ streamID = SID},
+ State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ Name = resolve(event, Name0, State, Constraint),
+ #'IndAudEventsDescriptor'{requestID = tr_opt_RequestID(RID, State),
+ pkgdName = Name,
+ streamID = tr_opt_StreamID(SID, State)}.
+
+
+%% -
+
+tr_indAudSignalsDescriptor({Tag, Val}, State) ->
+ case Tag of
+ signal ->
+ {signal, tr_indAudSignal(Val, State)};
+ seqSigList ->
+ {seqSigList, tr_indAudSeqSigList(Val, State)}
+ end.
+
+tr_opt_indAudSignal(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_indAudSignal(Val, State) ->
+ tr_indAudSignal(Val, State).
+
+tr_indAudSignal(#'IndAudSignal'{signalName = Name0,
+ streamID = SID}, State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ Name = resolve(signal, Name0, State, Constraint),
+ #'IndAudSignal'{signalName = Name,
+ streamID = tr_opt_StreamID(SID, State)}.
+
+tr_indAudSeqSigList(#'IndAudSeqSigList'{id = ID,
+ signalList = SigList}, State) ->
+ #'IndAudSeqSigList'{id = tr_integer(ID, State, 0, 65535),
+ signalList = tr_opt_indAudSignal(SigList, State)}.
+
+%% -
+
+tr_indAudDigitMapDescriptor(#'IndAudDigitMapDescriptor'{digitMapName = Name},
+ State) ->
+ #'IndAudDigitMapDescriptor'{digitMapName =
+ tr_opt_DigitMapName(Name, State)}.
+
+
+%% -
+
+tr_indAudEventBufferDescriptor(#'IndAudEventBufferDescriptor'{eventName = N,
+ streamID = SID},
+ State) ->
+ ?d("tr_indAudEventBufferDescriptor -> entry with"
+ "~n N: ~p"
+ "~n SID: ~p", [N, SID]),
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ Name = resolve(event, N, State, Constraint),
+ ?d("tr_indAudEventBufferDescriptor -> entry with"
+ "~n Name: ~p", [Name]),
+ #'IndAudEventBufferDescriptor'{eventName = Name,
+ streamID = tr_opt_StreamID(SID, State)}.
+
+%% -
+
+tr_indAudStatisticsDescriptor(#'IndAudStatisticsDescriptor'{statName = N},
+ State) ->
+ ?d("tr_indAudEventBufferDescriptor -> entry with"
+ "~n N: ~p", [N]),
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ Name = resolve(statistics, N, State, Constraint),
+ #'IndAudStatisticsDescriptor'{statName = Name}.
+
+
+%% -
+
+tr_indAudPackagesDescriptor(#'IndAudPackagesDescriptor'{packageName = N,
+ packageVersion = V},
+ State) ->
+ ?d("tr_indAudPackagesDescriptor -> entry with"
+ "~n N: ~p"
+ "~n V: ~p", [N, V]),
+ Constraint = fun(Item) -> tr_Name(Item, State) end,
+ Name = resolve(package, N, State, Constraint),
+ ?d("tr_indAudPackagesDescriptor -> entry with"
+ "~n Name: ~p", [Name]),
+ #'IndAudPackagesDescriptor'{packageName = Name,
+ packageVersion = tr_integer(V, State, 0, 99)}.
+
+%% -- v2 end --
+
+
+tr_TerminationAudit(ParmList, State) when is_list(ParmList) ->
+ do_tr_TerminationAudit(ParmList, [], State).
+
+do_tr_TerminationAudit([], Acc, _State) ->
+ lists:reverse(Acc);
+do_tr_TerminationAudit([Parm|ParmList], Acc, State) ->
+ case tr_AuditReturnParameter(Parm, State) of
+ {_, deprecated} when State#state.mode =:= encode ->
+ error({deprecated, Parm});
+ {_, deprecated} when State#state.mode =:= decode ->
+ %% SKIP
+ do_tr_TerminationAudit(ParmList, Acc, State);
+ {_, deprecated} ->
+ %% SKIP
+ do_tr_TerminationAudit(ParmList, Acc, State);
+ NewParm ->
+ do_tr_TerminationAudit(ParmList, [NewParm|Acc], State)
+ end.
+
+tr_AuditReturnParameter({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ errorDescriptor ->
+ tr_ErrorDescriptor(Val, State);
+ mediaDescriptor ->
+ tr_MediaDescriptor(Val, State);
+ modemDescriptor ->
+ tr_ModemDescriptor(Val, State);
+ muxDescriptor ->
+ tr_MuxDescriptor(Val, State);
+ eventsDescriptor ->
+ tr_EventsDescriptor(Val, State);
+ eventBufferDescriptor ->
+ tr_EventBufferDescriptor(Val, State);
+ signalsDescriptor ->
+ tr_SignalsDescriptor(Val, State);
+ digitMapDescriptor ->
+ tr_DigitMapDescriptor(Val, State);
+ observedEventsDescriptor ->
+ tr_ObservedEventsDescriptor(Val, State);
+ statisticsDescriptor ->
+ tr_StatisticsDescriptor(Val, State);
+ packagesDescriptor ->
+ tr_PackagesDescriptor(Val, State);
+ emptyDescriptors ->
+ tr_EmptyDescriptors(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_EmptyDescriptors(#'AuditDescriptor'{auditToken = Tokens},
+ State) ->
+ case Tokens of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> [tr_auditItem(Token, State) || Token <- Tokens]
+ end.
+
+tr_NotifyRequest(#'NotifyRequest'{terminationID = IdList,
+ observedEventsDescriptor = ObsDesc,
+ errorDescriptor = ErrDesc},
+ State) ->
+ %% BUGBUG: Mismatch between ASN.1 and ABNF
+ %% BUGBUG: The following ought to be a 'choice'
+ #'NotifyRequest'{terminationID = [tr_TerminationID(Id, State) ||
+ Id <- IdList],
+ observedEventsDescriptor = tr_ObservedEventsDescriptor(ObsDesc, State),
+ errorDescriptor = tr_opt_ErrorDescriptor(ErrDesc, State)}.
+
+tr_NotifyReply(#'NotifyReply'{terminationID = IdList,
+ errorDescriptor = ErrDesc},
+ State) ->
+ #'NotifyReply'{terminationID = [tr_TerminationID(Id, State) || Id <- IdList],
+ errorDescriptor = tr_opt_ErrorDescriptor(ErrDesc, State)}.
+
+tr_ObservedEventsDescriptor(#'ObservedEventsDescriptor'{requestId = Id,
+ observedEventLst = Events},
+ State) when is_list(Events) ->
+ #'ObservedEventsDescriptor'{requestId = tr_RequestID(Id, State),
+ observedEventLst = [tr_ObservedEvent(E, State) || E <- Events]}.
+
+%% ;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
+
+tr_ObservedEvent(#'ObservedEvent'{eventName = Name,
+ streamID = Id,
+ eventParList = Parms,
+ timeNotation = Time},
+ State) ->
+ #'ObservedEvent'{eventName = tr_EventName(Name, State),
+ streamID = tr_opt_StreamID(Id, State),
+ eventParList = [tr_EventParameter(P, Name, State) || P <- Parms],
+ timeNotation = tr_opt_TimeNotation(Time, State)}.
+
+tr_EventName(Name, State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ resolve(event, Name, State, Constraint).
+
+tr_EventParameter(#'EventParameter'{eventParameterName = ParName,
+ value = Value,
+ extraInfo = Extra},
+ EventName,
+ State) ->
+ %% BUGBUG: event parameter name
+ Constraint = fun(Item) -> tr_Name(Item, State) end,
+ N = resolve({event_parameter, EventName}, ParName, State, Constraint),
+ #'EventParameter'{eventParameterName = N,
+ value = tr_Value(Value, State),
+ extraInfo = tr_opt_extraInfo(Extra, State)}.
+
+tr_ServiceChangeRequest(#'ServiceChangeRequest'{terminationID = IdList,
+ serviceChangeParms = Parms},
+ State) ->
+ #'ServiceChangeRequest'{terminationID = [tr_TerminationID(Id, State) || Id <- IdList],
+ serviceChangeParms = tr_ServiceChangeParm(Parms, 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 )
+tr_ServiceChangeReply(#'ServiceChangeReply'{terminationID = IdList,
+ serviceChangeResult = Res},
+ State) ->
+ #'ServiceChangeReply'{terminationID = [tr_TerminationID(Id, State) || Id <- IdList],
+ serviceChangeResult = tr_ServiceChangeResult(Res, State)}.
+
+tr_ServiceChangeResult({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ errorDescriptor -> tr_ErrorDescriptor(Val, State);
+ serviceChangeResParms -> tr_ServiceChangeResParm(Val, State)
+ end,
+ {Tag, Val2}.
+
+%% TerminationID = "ROOT" / pathNAME / "$" / "*"
+%% ; Total length of pathNAME must not exceed 64 chars.
+%% pathNAME = ["*"] NAME *("/" / "*"/ ALPHA / DIGIT /"_" / "$" )
+%% ["@" pathDomainName ]
+
+tr_TerminationID(TermId, State) when State#state.mode =/= verify ->
+ resolve(term_id, TermId, State, valid);
+tr_TerminationID(#'TerminationID'{wildcard = Wild,
+ id = Id},
+ _State) ->
+ #'TerminationID'{wildcard = Wild,
+ id = Id};
+tr_TerminationID(#megaco_term_id{contains_wildcards = IsWild,
+ id = Id},
+ State) ->
+ #megaco_term_id{contains_wildcards = tr_bool(IsWild, State),
+ id = [tr_term_id_component(Sub, State) || Sub <- Id]}.
+
+tr_opt_bool(asn1_NOVALUE, _State) -> asn1_NOVALUE;
+tr_opt_bool(Bool, State) -> tr_bool(Bool, State).
+
+tr_bool(true, _State) -> true;
+tr_bool(false, _State) -> false.
+
+tr_term_id_component(Sub, _State) ->
+ case Sub of
+ all -> all;
+ choose -> 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
+tr_MediaDescriptor(#'MediaDescriptor'{termStateDescr = TermState,
+ streams = Streams},
+ State) ->
+ #'MediaDescriptor'{termStateDescr = tr_opt_TerminationStateDescriptor(TermState, State),
+ streams = tr_opt_streams(Streams, State)}.
+
+tr_opt_streams(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_streams({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ oneStream -> tr_StreamParms(Val, State);
+ multiStream -> [tr_StreamDescriptor(SD, State) || SD <- Val]
+ end,
+ {Tag, Val2}.
+
+tr_StreamParms(#'StreamParms'{localControlDescriptor = LCD,
+ localDescriptor = LD,
+ remoteDescriptor = RD,
+ statisticsDescriptor = SD},
+ State) ->
+ LCD2 = tr_opt_LocalControlDescriptor(LCD, State),
+ LD2 = tr_opt_LocalRemoteDescriptor(LD, State),
+ RD2 = tr_opt_LocalRemoteDescriptor(RD, State),
+ SD2 = tr_opt_StatisticsDescriptor(SD, State),
+ #'StreamParms'{localControlDescriptor = LCD2,
+ localDescriptor = LD2,
+ remoteDescriptor = RD2,
+ statisticsDescriptor = SD2}.
+
+tr_StreamDescriptor(#'StreamDescriptor'{streamID = Id,
+ streamParms = Parms},
+ State) ->
+ #'StreamDescriptor'{streamID = tr_StreamID(Id, State),
+ streamParms = tr_StreamParms(Parms, 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
+tr_opt_LocalControlDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_LocalControlDescriptor(#'LocalControlDescriptor'{streamMode = Mode,
+ reserveGroup = Group,
+ reserveValue = Value,
+ propertyParms = Props},
+ State) ->
+ #'LocalControlDescriptor'{streamMode = tr_opt_StreamMode(Mode, State),
+ reserveGroup = tr_opt_bool(Group, State),
+ reserveValue = tr_opt_bool(Value, State),
+ propertyParms = [tr_PropertyParm(P, State) || P <- Props]}.
+
+tr_opt_StreamMode(Mode, _State) ->
+ case Mode of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ sendOnly -> sendOnly;
+ recvOnly -> recvOnly;
+ sendRecv -> sendRecv;
+ inactive -> inactive;
+ loopBack -> loopBack
+ end.
+
+tr_Name(Name, State) ->
+ %% BUGBUG: transform
+ %% BUGBUG: NAME = ALPHA *63(ALPHA / DIGIT / "_" )
+ tr_STRING(Name, State, 2, 2).
+
+tr_PkgdName(Name, State) ->
+ %% BUGBUG: transform
+ %% BUGBUG: pkgdName = (NAME / "*") SLASH (ItemID / "*" )
+ tr_OCTET_STRING(Name, State, 4, 4).
+
+%% 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.
+tr_opt_LocalRemoteDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_LocalRemoteDescriptor(#'LocalRemoteDescriptor'{propGrps = Groups},
+ State) ->
+ #'LocalRemoteDescriptor'{propGrps = [tr_PropertyGroup(G, State) || G <- Groups]}.
+
+tr_PropertyGroup(Props, State) ->
+ [tr_PropertyGroupParm(P, State) || P <- Props].
+
+tr_PropertyGroupParm(#'PropertyParm'{name = Name,
+ value = Value},
+ State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ #'PropertyParm'{name = resolve(property, Name, State, Constraint),
+ value = tr_OCTET_STRING(Value, State, 0, infinity)}.
+
+tr_PropertyParm(#'PropertyParm'{name = Name,
+ value = Value,
+ extraInfo = Extra},
+ State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ #'PropertyParm'{name = resolve(property, Name, State, Constraint),
+ value = tr_Value(Value, State),
+ extraInfo = tr_opt_extraInfo(Extra, State)}.
+
+tr_opt_extraInfo(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_extraInfo({relation, Rel}, _State) ->
+ Rel2 =
+ case Rel of
+ greaterThan -> greaterThan;
+ smallerThan -> smallerThan;
+ unequalTo -> unequalTo
+ end,
+ {relation, Rel2};
+tr_opt_extraInfo({range, Range}, State) ->
+ Range2 = tr_bool(Range, State),
+ {range, Range2};
+tr_opt_extraInfo({sublist, Sub}, State) ->
+ Sub2 = tr_bool(Sub, State),
+ {sublist, Sub2}.
+
+tr_opt_TerminationStateDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_TerminationStateDescriptor(#'TerminationStateDescriptor'{propertyParms = Props,
+ eventBufferControl = Control,
+ serviceState = Service},
+ State) ->
+ #'TerminationStateDescriptor'{propertyParms = [tr_PropertyParm(P, State) || P <- Props],
+ eventBufferControl = tr_opt_EventBufferControl(Control, State),
+ serviceState = tr_opt_ServiceState(Service, State)}.
+
+tr_opt_EventBufferControl(Control, _State) ->
+ case Control of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ off -> off;
+ lockStep -> lockStep
+ end.
+
+tr_opt_ServiceState(Service, _State) ->
+ case Service of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ test -> test;
+ outOfSvc -> outOfSvc;
+ inSvc -> inSvc
+ end.
+
+tr_MuxDescriptor(#'MuxDescriptor'{muxType = Type,
+ termList = IdList},
+ State) ->
+ #'MuxDescriptor'{muxType = tr_MuxType(Type, State),
+ termList = [tr_TerminationID(Id, State) || Id <- IdList]}.
+
+tr_MuxType(Type, _State) ->
+ case Type of
+ h221 -> h221;
+ h223 -> h223;
+ h226 -> h226;
+ v76 -> v76
+ end.
+
+tr_opt_StreamID(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_StreamID(Id, State) ->
+ tr_StreamID(Id, State).
+
+tr_StreamID(Id, State) ->
+ tr_UINT16(Id, State).
+
+tr_EventsDescriptor(#'EventsDescriptor'{requestID = Id,
+ eventList = Events},
+ State) ->
+ #'EventsDescriptor'{requestID = tr_opt_RequestID(Id, State),
+ eventList = [tr_RequestedEvent(E, State) || E <- Events]}.
+
+tr_RequestedEvent(#'RequestedEvent'{pkgdName = Name,
+ streamID = Id,
+ evParList = Parms,
+ eventAction = Actions},
+ State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ #'RequestedEvent'{pkgdName = resolve(event, Name, State, Constraint),
+ streamID = tr_opt_StreamID(Id, State),
+ eventAction = tr_opt_RequestedActions(Actions, State),
+ evParList = [tr_EventParameter(P, Name, State) || P <- Parms]}.
+
+tr_opt_RequestedActions(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_RequestedActions(#'RequestedActions'{keepActive = Keep,
+ eventDM = DM,
+ secondEvent = Event,
+ signalsDescriptor = SigDesc},
+ State) ->
+ #'RequestedActions'{keepActive = tr_opt_keepActive(Keep, State),
+ eventDM = tr_opt_EventDM(DM, State),
+ secondEvent = tr_opt_SecondEventsDescriptor(Event, State),
+ signalsDescriptor = tr_opt_SignalsDescriptor(SigDesc, State)}.
+
+tr_opt_keepActive(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_keepActive(Keep, State) ->
+ tr_bool(Keep, State).
+
+tr_opt_EventDM(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_EventDM({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ digitMapName -> tr_DigitMapName(Val, State);
+ digitMapValue -> tr_DigitMapValue(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_opt_SecondEventsDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_SecondEventsDescriptor(#'SecondEventsDescriptor'{requestID = Id,
+ eventList = Events},
+ State) ->
+ #'SecondEventsDescriptor'{requestID = tr_RequestID(Id, State), %% IG v6 6.8 withdrawn
+ eventList = [tr_SecondRequestedEvent(E, State) || E <- Events]}.
+
+tr_SecondRequestedEvent(#'SecondRequestedEvent'{pkgdName = Name,
+ streamID = Id,
+ evParList = Parms,
+ eventAction = Actions},
+ State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ #'SecondRequestedEvent'{pkgdName = resolve(event, Name, State, Constraint),
+ streamID = tr_opt_StreamID(Id, State),
+ eventAction = tr_opt_SecondRequestedActions(Actions, State),
+ evParList = [tr_EventParameter(P, Name, State) || P <- Parms]}.
+
+
+tr_opt_SecondRequestedActions(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_SecondRequestedActions(#'SecondRequestedActions'{keepActive = Keep,
+ eventDM = DM,
+ signalsDescriptor = SigDesc},
+ State) ->
+ #'SecondRequestedActions'{keepActive = tr_opt_keepActive(Keep, State),
+ eventDM = tr_opt_EventDM(DM, State),
+ signalsDescriptor = tr_opt_SignalsDescriptor(SigDesc, State)}.
+
+tr_EventBufferDescriptor(EventSpecs, State) ->
+ [tr_EventSpec(ES, State) || ES <- EventSpecs].
+
+tr_EventSpec(#'EventSpec'{eventName = Name,
+ streamID = Id,
+ eventParList = Parms},
+ State) ->
+ #'EventSpec'{eventName = tr_EventName(Name, State),
+ streamID = tr_opt_StreamID(Id, State),
+ eventParList = [tr_EventParameter(P, Name, State) || P <- Parms]}.
+
+tr_opt_SignalsDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_SignalsDescriptor(SigDesc, State) ->
+ tr_SignalsDescriptor(SigDesc, State).
+
+tr_SignalsDescriptor(SigDesc, State) when is_list(SigDesc) ->
+ [tr_SignalRequest(SigReq, State) || SigReq <- SigDesc].
+
+tr_SignalRequest({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ signal -> tr_Signal(Val, State);
+ seqSigList -> tr_SeqSigList(Val, State)
+ end,
+ {Tag, Val2}.
+
+
+tr_SeqSigList(#'SeqSigList'{id = Id,
+ signalList = SigList},
+ State) when is_list(SigList) ->
+ #'SeqSigList'{id = tr_UINT16(Id, State),
+ signalList = [tr_Signal(Sig, State) || Sig <- SigList]}.
+
+tr_Signal(#'Signal'{signalName = Name,
+ streamID = SID,
+ sigType = Type,
+ duration = Dur,
+ notifyCompletion = Compl,
+ keepActive = Keep,
+ sigParList = Parms,
+ direction = Dir,
+ requestID = RID},
+ State) ->
+ Name2 = tr_SignalName(Name, State),
+ SID2 = tr_opt_StreamID(SID, State),
+ Type2 = tr_opt_SignalType(Type, State),
+ Dur2 = tr_opt_duration(Dur, State),
+ Compl2 = tr_opt_NotifyCompletion(Compl, State),
+ Keep2 = tr_opt_keepActive(Keep, State),
+ Parms2 = [tr_SigParameter(P, Name, State) || P <- Parms],
+ Dir2 = tr_opt_SignalDirection(Dir, State),
+ RID2 = tr_opt_RequestID(RID, State),
+ #'Signal'{signalName = Name2,
+ streamID = SID2,
+ sigType = Type2,
+ duration = Dur2,
+ notifyCompletion = Compl2,
+ keepActive = Keep2,
+ sigParList = Parms2,
+ direction = Dir2,
+ requestID = RID2}.
+
+tr_opt_duration(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_duration(Dur, State) ->
+ tr_UINT16(Dur, State).
+
+tr_opt_NotifyCompletion(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_NotifyCompletion(Items, State) when is_list(Items) ->
+ [tr_notifyCompletionItem(I, State) || I <- Items].
+
+tr_notifyCompletionItem(Item, _State) ->
+ case Item of
+ onTimeOut -> onTimeOut;
+ onInterruptByEvent -> onInterruptByEvent;
+ onInterruptByNewSignalDescr -> onInterruptByNewSignalDescr;
+ otherReason -> otherReason
+ end.
+
+tr_opt_SignalType(asn1_NOVALUE = Type, _State) ->
+ Type;
+tr_opt_SignalType(Type, _State) ->
+ case Type of
+ brief -> brief;
+ onOff -> onOff;
+ timeOut -> timeOut
+ end.
+
+tr_opt_SignalDirection(asn1_NOVALUE = SD, _State) ->
+ SD;
+tr_opt_SignalDirection(SD, _State) ->
+ case SD of
+ internal -> internal;
+ external -> external;
+ both -> both
+ end.
+
+tr_SignalName(Name, State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ resolve(signal, Name, State, Constraint).
+
+tr_SigParameter(#'SigParameter'{sigParameterName = ParName,
+ value = Value,
+ extraInfo = Extra},
+ SigName,
+ State) ->
+ Constraint = fun(Item) -> tr_Name(Item, State) end,
+ N = resolve({signal_parameter, SigName}, ParName, State, Constraint),
+ #'SigParameter'{sigParameterName = N,
+ value = tr_Value(Value, State),
+ extraInfo = tr_opt_extraInfo(Extra, State)}.
+
+tr_opt_RequestID(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_RequestID(Id, State) ->
+ tr_RequestID(Id, State).
+
+tr_RequestID(Id, _State) when Id =:= ?megaco_all_request_id ->
+ ?megaco_all_request_id;
+tr_RequestID(Id, State) ->
+ tr_UINT32(Id, State).
+
+tr_ModemDescriptor(_MD, _State) ->
+ deprecated.
+
+tr_DigitMapDescriptor(#'DigitMapDescriptor'{digitMapName = Name,
+ digitMapValue = Value},
+ State) ->
+ #'DigitMapDescriptor'{digitMapName = tr_opt_DigitMapName(Name, State),
+ digitMapValue = tr_opt_DigitMapValue(Value, State)}.
+
+tr_opt_DigitMapName(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_DigitMapName(Name, State) ->
+ tr_DigitMapName(Name, State).
+
+tr_DigitMapName(Name, State) ->
+ Constraint = fun(Item) -> tr_Name(Item, State) end,
+ resolve(dialplan, Name, State, Constraint).
+
+tr_opt_DigitMapValue(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_DigitMapValue(Value, State) ->
+ tr_DigitMapValue(Value, State).
+
+tr_DigitMapValue(#'DigitMapValue'{digitMapBody = Body,
+ startTimer = Start,
+ shortTimer = Short,
+ longTimer = Long},
+ State) ->
+ #'DigitMapValue'{startTimer = tr_opt_timer(Start, State),
+ shortTimer = tr_opt_timer(Short, State),
+ longTimer = tr_opt_timer(Long, State),
+ digitMapBody = tr_STRING(Body, State)}. %% BUGBUG: digitMapBody not handled at all
+
+tr_opt_timer(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_timer(Timer, State) ->
+ tr_DIGIT(Timer, State, 0, 99).
+
+tr_ServiceChangeParm(
+ #'ServiceChangeParm'{serviceChangeMethod = Method,
+ serviceChangeAddress = Addr,
+ serviceChangeVersion = Version,
+ serviceChangeProfile = Profile,
+ serviceChangeReason = Reason,
+ serviceChangeDelay = Delay,
+ serviceChangeMgcId = MgcId,
+ timeStamp = Time,
+ serviceChangeInfo = Info,
+ serviceChangeIncompleteFlag = Incomplete},
+ State) ->
+ Method2 = tr_ServiceChangeMethod(Method, State),
+ Addr2 = tr_opt_ServiceChangeAddress(Addr, State),
+ Version2 = tr_opt_serviceChangeVersion(Version, State),
+ Profile2 = tr_opt_ServiceChangeProfile(Profile, State),
+ Reason2 = tr_serviceChangeReason(Reason, State),
+ Delay2 = tr_opt_serviceChangeDelay(Delay, State),
+ MgcId2 = tr_opt_serviceChangeMgcId(MgcId, State),
+ Time2 = tr_opt_TimeNotation(Time, State),
+ Info2 = tr_opt_AuditDescriptor(Info, State),
+ Incomplete2 = tr_opt_null(Incomplete, State),
+ #'ServiceChangeParm'{serviceChangeMethod = Method2,
+ serviceChangeAddress = Addr2,
+ serviceChangeVersion = Version2,
+ serviceChangeProfile = Profile2,
+ serviceChangeReason = Reason2,
+ serviceChangeDelay = Delay2,
+ serviceChangeMgcId = MgcId2,
+ timeStamp = Time2,
+ serviceChangeInfo = Info2,
+ serviceChangeIncompleteFlag = Incomplete2}.
+
+tr_ServiceChangeMethod(Method, _State) ->
+ case Method of
+ failover -> failover;
+ forced -> forced;
+ graceful -> graceful;
+ restart -> restart;
+ disconnected -> disconnected;
+ handOff -> handOff
+ end. %% BUGBUG: extension
+
+tr_opt_ServiceChangeAddress(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_ServiceChangeAddress({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ portNumber -> tr_portNumber(Val, State);
+ ip4Address -> tr_IP4Address(Val, State);
+ ip6Address -> tr_IP6Address(Val, State);
+ domainName -> tr_DomainName(Val, State);
+ deviceName -> tr_PathName(Val, State);
+ mtpAddress -> tr_mtpAddress(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_opt_serviceChangeVersion(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_serviceChangeVersion(Version, State) ->
+ tr_version(Version, State).
+
+tr_opt_ServiceChangeProfile(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+%% Decode
+tr_opt_ServiceChangeProfile({'ServiceChangeProfile', ProfileName}, State) ->
+ case string:tokens(ProfileName, "/") of
+ [Name0, Version0] ->
+ Name = tr_STRING(Name0, State, 1, 64),
+ Version = tr_version(list_to_integer(Version0), State),
+ #'ServiceChangeProfile'{profileName = Name,
+ version = Version}
+ end;
+%% Encode
+tr_opt_ServiceChangeProfile(#'ServiceChangeProfile'{profileName = Name0,
+ version = Version0},
+ State) ->
+ Name = tr_STRING(Name0, State, 1, 64),
+ Version = tr_version(Version0, State),
+ ProfileName = lists:flatten(io_lib:format("~s/~w", [Name, Version])),
+ {'ServiceChangeProfile', ProfileName}.
+
+tr_serviceChangeReason([_] = Reason, State) ->
+ tr_Value(Reason, State).
+
+tr_opt_serviceChangeDelay(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_serviceChangeDelay(Delay, State) ->
+ tr_UINT32(Delay, State).
+
+tr_opt_serviceChangeMgcId(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_serviceChangeMgcId(MgcId, State) ->
+ tr_MId(MgcId, State).
+
+tr_opt_portNumber(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_portNumber(Port, State) ->
+ tr_portNumber(Port, State).
+
+tr_portNumber(Port, State) when is_integer(Port) andalso (Port >= 0) ->
+ tr_UINT16(Port, State).
+
+tr_ServiceChangeResParm(#'ServiceChangeResParm'{serviceChangeMgcId = MgcId,
+ serviceChangeAddress = Addr,
+ serviceChangeVersion = Version,
+ serviceChangeProfile = Profile,
+ timeStamp = Time},
+ State) ->
+ #'ServiceChangeResParm'{serviceChangeMgcId = tr_opt_serviceChangeMgcId(MgcId, State),
+ serviceChangeAddress = tr_opt_ServiceChangeAddress(Addr, State),
+ serviceChangeVersion = tr_opt_serviceChangeVersion(Version, State),
+ serviceChangeProfile = tr_opt_ServiceChangeProfile(Profile, State),
+ timeStamp = tr_opt_TimeNotation(Time, State)}.
+
+tr_PackagesDescriptor(Items, State) when is_list(Items) ->
+ [tr_PackagesItem(I, State) || I <- Items].
+
+tr_PackagesItem(#'PackagesItem'{packageName = Name,
+ packageVersion = Version},
+ State) ->
+ Constraint = fun(Item) -> tr_Name(Item, State) end,
+ #'PackagesItem'{packageName = resolve(package, Name, State, Constraint),
+ packageVersion = tr_UINT16(Version, State)}.
+
+tr_opt_StatisticsDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_StatisticsDescriptor(Parms, State) ->
+ tr_StatisticsDescriptor(Parms, State).
+
+tr_StatisticsDescriptor(Parms, State) when is_list(Parms) ->
+ [tr_StatisticsParameter(P, State) || P <- Parms].
+
+tr_StatisticsParameter(#'StatisticsParameter'{statName = Name,
+ statValue = Value},
+ State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ #'StatisticsParameter'{statName = resolve(statistics, Name, State, Constraint),
+ statValue = tr_opt_Value(Value, State)}.
+
+tr_opt_TimeNotation(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_TimeNotation(#'TimeNotation'{date = Date,
+ time = Time},
+ State) ->
+ #'TimeNotation'{date = tr_STRING(Date, State, 8, 8), % "yyyymmdd"
+ time = tr_STRING(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.
+
+tr_opt_Value(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_Value(Value, State) ->
+ tr_Value(Value, State).
+
+tr_Value(Strings, _State) when is_list(Strings) ->
+ [[Char || Char <- String] || String <- Strings].
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Encode an octet string, escape } by \ if necessary
+tr_OCTET_STRING(String, _State, Min, Max) when is_list(String) ->
+ verify_count(length(String), Min, Max),
+ String.
+
+tr_QUOTED_STRING(String, _State) when is_list(String) ->
+ verify_count(length(String), 1, infinity),
+ String.
+
+%% 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
+tr_HEXDIG(Octets, _State, Min, Max) when is_list(Octets) ->
+ verify_count(length(Octets), Min, Max),
+ Octets.
+
+tr_DIGIT(Val, State, Min, Max) ->
+ tr_integer(Val, State, Min, Max).
+
+tr_STRING(String, _State) when is_list(String) ->
+ String.
+
+tr_STRING(String, _State, Min, Max) when is_list(String) ->
+ verify_count(length(String), Min, Max),
+ String.
+
+tr_opt_UINT16(Val, State) ->
+ tr_opt_integer(Val, State, 0, 65535).
+
+tr_UINT16(Val, State) ->
+ tr_integer(Val, State, 0, 65535).
+
+tr_UINT32(Val, State) ->
+ tr_integer(Val, State, 0, 4294967295).
+
+tr_opt_integer(asn1_NOVALUE, _State, _Min, _Max) ->
+ asn1_NOVALUE;
+tr_opt_integer(Int, State, Min, Max) ->
+ tr_integer(Int, State, Min, Max).
+
+tr_integer(Int, _State, Min, Max) ->
+ verify_count(Int, Min, Max),
+ Int.
+
+%% 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).
+
+
diff --git a/lib/megaco/src/binary/megaco_binary_transformer_prev3c.erl b/lib/megaco/src/binary/megaco_binary_transformer_prev3c.erl
new file mode 100644
index 0000000000..8d2f9eea38
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_binary_transformer_prev3c.erl
@@ -0,0 +1,1756 @@
+%%
+%% %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: Transform internal form of Megaco/H.248 messages
+%%----------------------------------------------------------------------
+
+-module(megaco_binary_transformer_prev3c).
+
+-include_lib("megaco/include/megaco.hrl").
+%% -include_lib("megaco/include/megaco_message.hrl").
+-include_lib("megaco/include/megaco_message_prev3c.hrl").
+-include_lib("megaco/src/app/megaco_internal.hrl").
+
+-export([tr_message/3, tr_transaction/3]).
+
+-define(DEFAULT_NAME_RESOLVER, megaco_binary_name_resolver_prev3c).
+
+-record(state, {mode, % verify | encode | decode
+ resolver_module, %
+ resolver_options}).
+
+resolve(Type, Item, State, Constraint) ->
+ case State#state.mode of
+ verify ->
+ Item;
+ encode ->
+ ?d("resolve(encode) -> encode: ~p",[Item]),
+ Mod = State#state.resolver_module,
+ Opt = State#state.resolver_options,
+ EncodedItem = Mod:encode_name(Opt, Type, Item),
+ ?d("resolve -> verify contraint for ~p",[EncodedItem]),
+ verify_constraint(EncodedItem, Constraint);
+ decode ->
+ ?d("resolve(decode) -> verify contraint for ~p",[Item]),
+ DecodedItem = verify_constraint(Item, Constraint),
+ Mod = State#state.resolver_module,
+ Opt = State#state.resolver_options,
+ ?d("resolve(decode) -> decode: ~p",[DecodedItem]),
+ Mod:decode_name(Opt, Type, DecodedItem)
+ end.
+
+verify_constraint(Item, valid) ->
+ Item;
+verify_constraint(Item, Constraint) when is_function(Constraint) ->
+ Constraint(Item).
+
+tr_message(MegaMsg, Mode, Config) ->
+ case Config of
+ [native] ->
+ MegaMsg;
+ [verify] ->
+ State = #state{mode = verify},
+ tr_MegacoMessage(MegaMsg, State);
+ [] ->
+ State = #state{mode = Mode,
+ resolver_module = ?DEFAULT_NAME_RESOLVER,
+ resolver_options = [8, 8, 8]},
+ tr_MegacoMessage(MegaMsg, State);
+ [{binary_name_resolver, {Module, Options}}] when is_atom(Module) ->
+ State = #state{mode = Mode,
+ resolver_module = Module,
+ resolver_options = Options},
+ tr_MegacoMessage(MegaMsg, State)
+ end.
+
+tr_transaction(Trans, Mode, Config) ->
+ case Config of
+ [native] ->
+ Trans;
+ [verify] ->
+ State = #state{mode = verify},
+ tr_Transaction(Trans, State);
+ [] ->
+ State = #state{mode = Mode,
+ resolver_module = ?DEFAULT_NAME_RESOLVER,
+ resolver_options = [8, 8, 8]},
+ tr_Transaction(Trans, State);
+ [{binary_name_resolver, {Module, Options}}] when is_atom(Module) ->
+ State = #state{mode = Mode,
+ resolver_module = Module,
+ resolver_options = Options},
+ tr_Transaction(Trans, State)
+ end.
+
+tr_MegacoMessage(#'MegacoMessage'{authHeader = Auth,
+ mess = Mess},
+ State) ->
+ ?d("tr_MegacoMessage -> entry with"
+ "~n Auth: ~p"
+ "~n Mess: ~p"
+ "~n State: ~p", [Auth, Mess, State]),
+ #'MegacoMessage'{authHeader = tr_opt_AuthenticationHeader(Auth, State),
+ mess = tr_Message(Mess, State)}.
+
+tr_opt_AuthenticationHeader(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_AuthenticationHeader(#'AuthenticationHeader'{secParmIndex = SPI,
+ seqNum = SN,
+ ad = AuthData},
+ State) ->
+ #'AuthenticationHeader'{secParmIndex = tr_SecurityParmIndex(SPI, State),
+ seqNum = tr_SequenceNum(SN, State),
+ ad = tr_AuthData(AuthData, State)}.
+
+tr_SecurityParmIndex(SPI, State) ->
+ tr_HEXDIG(SPI, State, 4, 4). % BUGBUG: Mismatch between ASN.1 and ABNF
+
+tr_SequenceNum(SN, State) ->
+ tr_HEXDIG(SN, State, 4, 4). % BUGBUG: Mismatch between ASN.1 and ABNF
+
+tr_AuthData(AuthData, State) ->
+ tr_HEXDIG(AuthData, State, 12, 32). % BUGBUG: Mismatch between ASN.1 and ABNF
+
+tr_Message(#'Message'{version = Version,
+ mId = MID,
+ messageBody = Body},
+ State) ->
+ #'Message'{version = tr_version(Version, State),
+ mId = tr_MId(MID, State),
+ messageBody = tr_Message_messageBody(Body, State)}.
+
+tr_version(Version, State) ->
+ tr_DIGIT(Version, State, 0, 99).
+
+tr_Message_messageBody({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ messageError -> tr_ErrorDescriptor(Val, State);
+ transactions when is_list(Val) -> [tr_Transaction(T, State) || T <- Val]
+ end,
+ {Tag, Val2}.
+
+tr_MId({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ ip4Address -> tr_IP4Address(Val, State);
+ ip6Address -> tr_IP6Address(Val, State);
+ domainName -> tr_DomainName(Val, State);
+ deviceName -> tr_PathName(Val, State);
+ mtpAddress -> tr_mtpAddress(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_mtpAddress(MtpAddr, State) ->
+ tr_OCTET_STRING(MtpAddr, State, 2, 4). % BUGBUG: Mismatch between ASN.1 and ABNF
+
+tr_DomainName(#'DomainName'{name = Name,
+ portNumber = Port},
+ State) ->
+ Domain = #'DomainName'{name = tr_STRING(Name, State), % BUGBUG: Mismatch between ASN.1 and ABNF
+ portNumber = tr_opt_portNumber(Port, State)},
+ {domainName, Domain2} = resolve(mid, {domainName, Domain}, State, valid),
+ Domain2.
+
+tr_IP4Address(#'IP4Address'{address = [A1, A2, A3, A4],
+ portNumber = Port},
+ State) ->
+ #'IP4Address'{address = [tr_V4hex(A1, State),
+ tr_V4hex(A2, State),
+ tr_V4hex(A3, State),
+ tr_V4hex(A4, State)],
+ portNumber = tr_opt_portNumber(Port, State)}.
+
+tr_V4hex(Val, State) ->
+ tr_DIGIT(Val, State, 0, 255).
+
+tr_IP6Address(_Val, _State) ->
+ error(ipv6_not_supported). %% BUGBUG: nyi
+
+tr_PathName(Path, State) ->
+ %% BUGBUG: ["*"] NAME *("/" / "*"/ ALPHA / DIGIT /"_" / "$" )
+ %% BUGBUG: ["@" pathDomainName ]
+ Constraint = fun({deviceName, Item}) -> tr_STRING(Item, State, 1, 64) end,
+ resolve(mid, {deviceName, Path}, State, Constraint).
+
+tr_Transaction({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ transactionRequest -> tr_TransactionRequest(Val, State);
+ transactionPending -> tr_TransactionPending(Val, State);
+ transactionReply -> tr_TransactionReply(Val, State);
+ transactionResponseAck -> [tr_TransactionAck(T, State) || T <- Val]
+ end,
+ {Tag, Val2}.
+
+tr_TransactionAck(#'TransactionAck'{firstAck = First,
+ lastAck = Last},
+ State) ->
+ #'TransactionAck'{firstAck = tr_TransactionId(First, State),
+ lastAck = tr_opt_TransactionId(Last, State)}.
+
+tr_opt_TransactionId(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_TransactionId(Id, State) ->
+ tr_TransactionId(Id, State).
+
+tr_TransactionId(Id, State) ->
+ tr_UINT32(Id, State).
+
+tr_TransactionRequest(#'TransactionRequest'{transactionId = Id,
+ actions = Actions},
+ State) when is_list(Actions) ->
+
+ #'TransactionRequest'{transactionId = tr_TransactionId(Id, State),
+ actions = [tr_ActionRequest(ActReq, State) || ActReq <- Actions]}.
+
+tr_TransactionPending(#'TransactionPending'{transactionId = Id},
+ State) ->
+ #'TransactionPending'{transactionId = tr_TransactionId(Id, State)}.
+
+tr_TransactionReply(#'TransactionReply'{transactionId = Id,
+ immAckRequired = ImmAck,
+ transactionResult = TransRes,
+ %% 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) ->
+ #'TransactionReply'{transactionId = tr_TransactionId(Id, State),
+ immAckRequired = tr_opt_null(ImmAck, State),
+ transactionResult = tr_TransactionReply_transactionResult(TransRes, State),
+ segmentNumber = asn1_NOVALUE,
+ segmentationComplete = asn1_NOVALUE};
+tr_TransactionReply(TR, _State) ->
+ error({unsupported_TransactionReply, TR}).
+
+tr_opt_null(asn1_NOVALUE, _State) -> asn1_NOVALUE;
+tr_opt_null('NULL', _State) -> 'NULL'.
+
+tr_TransactionReply_transactionResult({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ transactionError ->
+ tr_ErrorDescriptor(Val, State);
+ actionReplies when is_list(Val) andalso (Val =/= []) ->
+ [tr_ActionReply(ActRep, State) || ActRep <- Val]
+ end,
+ {Tag, Val2}.
+
+tr_opt_ErrorDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_ErrorDescriptor(ErrDesc, State) ->
+ tr_ErrorDescriptor(ErrDesc, State).
+
+tr_ErrorDescriptor(#'ErrorDescriptor'{errorCode = Code,
+ errorText = Text},
+ State) ->
+ #'ErrorDescriptor'{errorCode = tr_ErrorCode(Code, State),
+ errorText = tr_opt_ErrorText(Text, State)}.
+
+tr_ErrorCode(Code, State) ->
+ tr_DIGIT(Code, State, 0, 999).
+
+tr_opt_ErrorText(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_ErrorText(Text, State) ->
+ tr_QUOTED_STRING(Text, State).
+
+tr_ContextID(CtxId, State) ->
+ case CtxId of
+ ?megaco_all_context_id -> ?megaco_all_context_id;
+ ?megaco_null_context_id -> ?megaco_null_context_id;
+ ?megaco_choose_context_id -> ?megaco_choose_context_id;
+ Int when is_integer(Int) -> tr_UINT32(Int, State)
+ end.
+
+tr_ActionRequest(#'ActionRequest'{contextId = CtxId,
+ contextRequest = CtxReq,
+ contextAttrAuditReq = CtxAuditReq,
+ commandRequests = CmdReqList},
+ State) ->
+ #'ActionRequest'{contextId = tr_ContextID(CtxId, State),
+ contextRequest = tr_opt_ContextRequest(CtxReq, State),
+ contextAttrAuditReq = tr_opt_ContextAttrAuditRequest(CtxAuditReq, State),
+ commandRequests = [tr_CommandRequest(CmdReq, State) || CmdReq <- CmdReqList]}.
+
+tr_ActionReply(#'ActionReply'{contextId = CtxId,
+ errorDescriptor = ErrDesc,
+ contextReply = CtxRep,
+ commandReply = CmdRepList},
+ State) ->
+ CmdRepList2 = [tr_CommandReply(CmdRep, State) || CmdRep <- CmdRepList],
+ #'ActionReply'{contextId = tr_ContextID(CtxId, State),
+ errorDescriptor = tr_opt_ErrorDescriptor(ErrDesc, State),
+ contextReply = tr_opt_ContextRequest(CtxRep, State),
+ commandReply = CmdRepList2}.
+
+tr_opt_ContextRequest(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_ContextRequest(CR, State) ->
+ tr_ContextRequest(CR, State).
+
+tr_ContextRequest(#'ContextRequest'{priority = Prio,
+ emergency = Em,
+ topologyReq = TopReqList,
+ iepscallind = Ind,
+ contextProp = CtxProps,
+ contextList = CtxList},
+ State) ->
+ Prio2 =
+ case Prio of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> tr_integer(Prio, State, 0, 15)
+ end,
+ Em2 =
+ case Em of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ false -> false;
+ true -> true
+ end,
+ TopReqList2 =
+ case TopReqList of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> [tr_TopologyRequest(TopReq, State) ||
+ TopReq <- TopReqList]
+ end,
+ Ind2 =
+ case Ind of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ false -> false;
+ true -> true
+ end,
+ CtxProps2 =
+ case CtxProps of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> [tr_PropertyParm(Prop, State) || Prop <- CtxProps]
+ end,
+ CtxList2 =
+ case CtxList of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> [tr_ContextID(Id, State) || Id <- CtxList]
+ end,
+ #'ContextRequest'{priority = Prio2,
+ emergency = Em2,
+ topologyReq = TopReqList2,
+ iepscallind = Ind2,
+ contextProp = CtxProps2,
+ contextList = CtxList2}.
+
+tr_opt_ContextAttrAuditRequest(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_ContextAttrAuditRequest(CAAR, State) ->
+ tr_ContextAttrAuditRequest(CAAR, State).
+
+tr_ContextAttrAuditRequest(#'ContextAttrAuditRequest'{topology = Top,
+ emergency = Em,
+ priority = Prio,
+ iepscallind = Ind,
+ contextPropAud = Props,
+ selectpriority = SPrio,
+ selectemergency = SEm,
+ selectiepscallind = SInd,
+ selectLogic = SLog},
+ State) ->
+ Top2 = tr_opt_null(Top, State),
+ Em2 = tr_opt_null(Em, State),
+ Prio2 = tr_opt_null(Prio, State),
+ Ind2 = tr_opt_null(Ind, State),
+ Props2 =
+ case Props of
+ asn1_NOVALUE ->
+ asn1_NOVALUE;
+ _ ->
+ [tr_indAudPropertyParm(Prop, State) || Prop <- Props]
+ end,
+ SPrio2 =
+ case SPrio of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> tr_integer(SPrio, State, 0, 15)
+ end,
+ SEm2 =
+ case SEm of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ false -> false;
+ true -> true
+ end,
+ SInd2 =
+ case SInd of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ false -> false;
+ true -> true
+ end,
+ SLog2 =
+ case SLog of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> tr_SelectLogic(SLog, State)
+ end,
+ #'ContextAttrAuditRequest'{topology = Top2,
+ emergency = Em2,
+ priority = Prio2,
+ iepscallind = Ind2,
+ contextPropAud = Props2,
+ selectpriority = SPrio2,
+ selectemergency = SEm2,
+ selectiepscallind = SInd2,
+ selectLogic = SLog2}.
+
+tr_SelectLogic({andAUDITSelect, 'NULL'} = Val, _State) ->
+ Val;
+tr_SelectLogic({orAUDITSelect, 'NULL'} = Val, _State) ->
+ Val.
+
+tr_CommandRequest(#'CommandRequest'{command = Cmd,
+ optional = Opt,
+ wildcardReturn = Wild},
+ State) ->
+ #'CommandRequest'{optional = tr_opt_null(Opt, State),
+ wildcardReturn = tr_opt_null(Wild, State),
+ command = tr_Command(Cmd, State)}.
+
+tr_Command({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ addReq -> tr_AmmRequest(Val, State);
+ moveReq -> tr_AmmRequest(Val, State);
+ modReq -> tr_AmmRequest(Val, State);
+ subtractReq -> tr_SubtractRequest(Val, State);
+ auditCapRequest -> tr_AuditRequest(Val, State);
+ auditValueRequest -> tr_AuditRequest(Val, State);
+ notifyReq -> tr_NotifyRequest(Val, State);
+ serviceChangeReq -> tr_ServiceChangeRequest(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_CommandReply({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ addReply -> tr_AmmsReply(Val, State);
+ moveReply -> tr_AmmsReply(Val, State);
+ modReply -> tr_AmmsReply(Val, State);
+ subtractReply -> tr_AmmsReply(Val, State);
+ auditCapReply -> tr_AuditReply(Val, State);
+ auditValueReply -> tr_AuditReply(Val, State);
+ notifyReply -> tr_NotifyReply(Val, State);
+ serviceChangeReply -> tr_ServiceChangeReply(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_TopologyRequest(#'TopologyRequest'{terminationFrom = From,
+ terminationTo = To,
+ topologyDirection = Dir,
+ streamID = SID,
+ topologyDirectionExtension = TDE},
+ State) ->
+ Dir2 =
+ case Dir of
+ bothway -> bothway;
+ isolate -> isolate;
+ oneway -> oneway
+ end,
+ TDE2 =
+ case TDE of
+ onewayexternal -> onewayexternal;
+ onewayboth -> onewayboth;
+ asn1_NOVALUE -> asn1_NOVALUE
+ end,
+ #'TopologyRequest'{terminationFrom = tr_TerminationID(From, State),
+ terminationTo = tr_TerminationID(To, State),
+ topologyDirection = Dir2,
+ streamID = tr_opt_StreamID(SID, State),
+ topologyDirectionExtension = TDE2}.
+
+tr_AmmRequest(#'AmmRequest'{terminationID = IdList,
+ descriptors = DescList},
+ State) ->
+ #'AmmRequest'{terminationID = [tr_TerminationID(Id, State) ||
+ Id <- IdList],
+ descriptors = tr_ammDescriptors(DescList, [], State)}.
+
+tr_ammDescriptors([], Acc, _State) ->
+ lists:reverse(Acc);
+tr_ammDescriptors([Desc|Descs], Acc, State) ->
+ case tr_ammDescriptor(Desc, State) of
+ {_, deprecated} when State#state.mode =:= encode ->
+ error({deprecated, Desc});
+ {_, deprecated} when State#state.mode =:= decode ->
+ %% SKIP
+ tr_ammDescriptors(Descs, Acc, State);
+ {_, deprecated} ->
+ %% SKIP
+ tr_ammDescriptors(Descs, Acc, State);
+ NewDesc ->
+ tr_ammDescriptors(Descs, [NewDesc|Acc], State)
+ end.
+
+tr_ammDescriptor({Tag, Desc}, State) ->
+ Desc2 =
+ case Tag of
+ mediaDescriptor -> tr_MediaDescriptor(Desc, State);
+ modemDescriptor -> tr_ModemDescriptor(Desc, State);
+ muxDescriptor -> tr_MuxDescriptor(Desc, State);
+ eventsDescriptor -> tr_EventsDescriptor(Desc, State);
+ eventBufferDescriptor -> tr_EventBufferDescriptor(Desc, State);
+ signalsDescriptor -> tr_SignalsDescriptor(Desc, State);
+ digitMapDescriptor -> tr_DigitMapDescriptor(Desc, State);
+ auditDescriptor -> tr_AuditDescriptor(Desc, State);
+ statisticsDescriptor -> tr_StatisticsDescriptor(Desc, State)
+ end,
+ {Tag, Desc2}.
+
+tr_AmmsReply(#'AmmsReply'{terminationID = IdList,
+ terminationAudit = TermAudit},
+ State) ->
+ TermAudit2 =
+ case TermAudit of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> tr_TerminationAudit(TermAudit, State)
+ end,
+ #'AmmsReply'{terminationID = [tr_TerminationID(Id, State) ||
+ Id <- IdList],
+ terminationAudit = TermAudit2}.
+
+tr_SubtractRequest(#'SubtractRequest'{terminationID = IdList,
+ auditDescriptor = Desc},
+ State) ->
+ #'SubtractRequest'{terminationID = [tr_TerminationID(Id, State) ||
+ Id <- IdList],
+ auditDescriptor = tr_opt_AuditDescriptor(Desc, State)}.
+
+tr_AuditRequest(#'AuditRequest'{terminationID = Id,
+ auditDescriptor = Desc,
+ terminationIDList = TIDList},
+ State) ->
+ TIDList2 =
+ case TIDList of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> [tr_TerminationID(TID, State) || TID <- TIDList]
+ end,
+ #'AuditRequest'{terminationID = tr_TerminationID(Id, State),
+ auditDescriptor = tr_AuditDescriptor(Desc, State),
+ terminationIDList = TIDList2}.
+
+%% auditReply = (AuditValueToken / AuditCapToken )
+%% ( contextTerminationAudit / auditOther)
+%% auditOther = EQUAL TerminationID LBRKT
+%% terminationAudit RBRKT
+%% terminationAudit = auditReturnParameter *(COMMA auditReturnParameter)
+%%
+%% contextTerminationAudit = EQUAL CtxToken ( terminationIDList /
+%% LBRKT errorDescriptor RBRKT )
+
+tr_AuditReply({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ contextAuditResult ->
+ [tr_TerminationID(Id, State) || Id <- Val];
+ error ->
+ tr_ErrorDescriptor(Val, State);
+ auditResult ->
+ tr_AuditResult(Val, State);
+ auditResultTermList ->
+ tr_TermListAuditResult(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_AuditResult(#'AuditResult'{terminationID = Id,
+ terminationAuditResult = AuditRes},
+ State) ->
+ #'AuditResult'{terminationID = tr_TerminationID(Id, State),
+ terminationAuditResult = tr_TerminationAudit(AuditRes, State)}.
+
+tr_TermListAuditResult(
+ #'TermListAuditResult'{terminationIDList = TIDList,
+ terminationAuditResult = TAR},
+ State) ->
+ TIDList2 = [tr_TerminationID(TID, State) || TID <- TIDList],
+ TAR2 = tr_TerminationAudit(TAR, State),
+ #'TermListAuditResult'{terminationIDList = TIDList2,
+ terminationAuditResult = TAR2}.
+
+
+tr_opt_AuditDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_AuditDescriptor(Desc, State) ->
+ tr_AuditDescriptor(Desc, State).
+
+%% BUGBUG BUGBUG BUGBUG
+%% With this construction it is possible to have both auditToken
+%% and auditPropertyToken, but it is actually valid?
+tr_AuditDescriptor(#'AuditDescriptor'{auditToken = Tokens,
+ auditPropertyToken = APTs},
+ State) ->
+ Tokens2 =
+ case Tokens of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> [tr_auditItem(Token, State) || Token <- Tokens]
+ end,
+ %% v2
+ APTs2 =
+ case APTs of
+ asn1_NOVALUE ->
+ asn1_NOVALUE;
+ _ ->
+ [tr_indAuditParameter(APT, State) || APT <- APTs]
+ end,
+ #'AuditDescriptor'{auditToken = Tokens2,
+ auditPropertyToken = APTs2}.
+
+tr_auditItem(Token, _State) ->
+ case Token of
+ muxToken -> muxToken;
+ modemToken -> modemToken;
+ mediaToken -> mediaToken;
+ eventsToken -> eventsToken;
+ signalsToken -> signalsToken;
+ digitMapToken -> digitMapToken;
+ statsToken -> statsToken;
+ observedEventsToken -> observedEventsToken;
+ packagesToken -> packagesToken;
+ eventBufferToken -> eventBufferToken
+ end.
+
+%% --- v2 begin ---
+
+tr_indAuditParameter({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ indAudMediaDescriptor ->
+ tr_indAudMediaDescriptor(Val, State);
+ indAudEventsDescriptor ->
+ tr_indAudEventsDescriptor(Val, State);
+ indAudSignalsDescriptor ->
+ tr_indAudSignalsDescriptor(Val, State);
+ indAudDigitMapDescriptor ->
+ tr_indAudDigitMapDescriptor(Val, State);
+ indAudEventBufferDescriptor ->
+ tr_indAudEventBufferDescriptor(Val, State);
+ indAudStatisticsDescriptor ->
+ tr_indAudStatisticsDescriptor(Val, State);
+ indAudPackagesDescriptor ->
+ tr_indAudPackagesDescriptor(Val, State)
+ end,
+ {Tag, Val2}.
+
+
+%% -
+
+tr_indAudMediaDescriptor(#'IndAudMediaDescriptor'{termStateDescr = TSD,
+ streams = S},
+ State) ->
+ TSD2 =
+ case TSD of
+ asn1_NOVALUE ->
+ asn1_NOVALUE;
+ _ ->
+ tr_indAudTerminationStateDescriptor(TSD, State)
+ end,
+ S2 =
+ case S of
+ asn1_NOVALUE ->
+ asn1_NOVALUE;
+ {oneStream, OS} ->
+ {oneStream, tr_indAudStreamParms(OS, State)};
+ {multiStream, MS} ->
+ MS2 = [tr_indAudStreamDescriptor(MS1, State) || MS1 <- MS],
+ {multiStream, MS2}
+ end,
+ #'IndAudMediaDescriptor'{termStateDescr = TSD2,
+ streams = S2}.
+
+tr_indAudTerminationStateDescriptor(Val, State)
+ when is_record(Val, 'IndAudTerminationStateDescriptor') ->
+ #'IndAudTerminationStateDescriptor'{propertyParms = Parms,
+ eventBufferControl = EBC,
+ serviceState = SS,
+ serviceStateSel = SSS} = Val,
+ Parms2 = [tr_indAudPropertyParm(Parm, State) || Parm <- Parms],
+ EBC2 = tr_opt_null(EBC, State),
+ SS2 = tr_opt_null(SS, State),
+ SSS2 = tr_opt_ServiceState(SSS, State),
+ #'IndAudTerminationStateDescriptor'{propertyParms = Parms2,
+ eventBufferControl = EBC2,
+ serviceState = SS2,
+ serviceStateSel = SSS2}.
+
+
+tr_indAudStreamParms(#'IndAudStreamParms'{localControlDescriptor = LCD,
+ localDescriptor = LD,
+ remoteDescriptor = RD,
+ statisticsDescriptor = SD},
+ State) ->
+ LCD2 =
+ case LCD of
+ asn1_NOVALUE ->
+ asn1_NOVALUE;
+ _ ->
+ tr_indAudLocalControlDescriptor(LCD, State)
+ end,
+ LD2 =
+ case LD of
+ asn1_NOVALUE ->
+ asn1_NOVALUE;
+ _ ->
+ tr_indAudLocalRemoteDescriptor(LD, State)
+ end,
+ RD2 =
+ case RD of
+ asn1_NOVALUE ->
+ asn1_NOVALUE;
+ _ ->
+ tr_indAudLocalRemoteDescriptor(RD, State)
+ end,
+ SD2 =
+ case SD of
+ asn1_NOVALUE ->
+ asn1_NOVALUE;
+ _ ->
+ tr_indAudStatisticsDescriptor(SD, State)
+ end,
+ #'IndAudStreamParms'{localControlDescriptor = LCD2,
+ localDescriptor = LD2,
+ remoteDescriptor = RD2,
+ statisticsDescriptor = SD2}.
+
+tr_indAudLocalControlDescriptor(Val, State)
+ when is_record(Val, 'IndAudLocalControlDescriptor') ->
+ #'IndAudLocalControlDescriptor'{streamMode = M,
+ reserveValue = V,
+ reserveGroup = G,
+ propertyParms = P,
+ streamModeSel = SMS} = Val,
+ M2 = tr_opt_null(M, State),
+ V2 = tr_opt_null(V, State),
+ G2 = tr_opt_null(G, State),
+ P2 = tr_indAudLocalControlDescriptor_propertyParms(P, State),
+ SMS2 = tr_opt_StreamMode(SMS, State),
+ #'IndAudLocalControlDescriptor'{streamMode = M2,
+ reserveValue = V2,
+ reserveGroup = G2,
+ propertyParms = P2,
+ streamModeSel = SMS2}.
+
+tr_indAudLocalControlDescriptor_propertyParms(Parms, State)
+ when is_list(Parms) andalso (length(Parms) > 0) ->
+ [tr_indAudPropertyParm(Parm, State) || Parm <- Parms];
+tr_indAudLocalControlDescriptor_propertyParms(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE.
+
+tr_indAudLocalRemoteDescriptor(#'IndAudLocalRemoteDescriptor'{propGroupID = ID,
+ propGrps = Grps},
+ State) ->
+ #'IndAudLocalRemoteDescriptor'{propGroupID = tr_opt_UINT16(ID, State),
+ propGrps = tr_indAudPropertyGroup(Grps,
+ State)}.
+
+tr_indAudPropertyGroup(Grps, State) when is_list(Grps) ->
+ [tr_indAudPropertyParm(Parm, State) || Parm <- Grps].
+
+tr_indAudPropertyParm(#'IndAudPropertyParm'{name = Name0,
+ propertyParms = Prop0}, State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ Name = resolve(property, Name0, State, Constraint),
+ Prop =
+ case Prop0 of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> tr_PropertyParm(Prop0, State)
+ end,
+ #'IndAudPropertyParm'{name = Name,
+ propertyParms = Prop}.
+
+
+tr_indAudStreamDescriptor(#'IndAudStreamDescriptor'{streamID = ID,
+ streamParms = Parms},
+ State) ->
+ #'IndAudStreamDescriptor'{streamID = tr_StreamID(ID, State),
+ streamParms = tr_indAudStreamParms(Parms,
+ State)}.
+
+
+%% -
+
+tr_indAudEventsDescriptor(#'IndAudEventsDescriptor'{requestID = RID,
+ pkgdName = Name0,
+ streamID = SID},
+ State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ Name = resolve(event, Name0, State, Constraint),
+ #'IndAudEventsDescriptor'{requestID = tr_opt_RequestID(RID, State),
+ pkgdName = Name,
+ streamID = tr_opt_StreamID(SID, State)}.
+
+
+%% -
+
+tr_indAudSignalsDescriptor({Tag, Val}, State) ->
+ case Tag of
+ signal ->
+ {signal, tr_indAudSignal(Val, State)};
+ seqSigList ->
+ {seqSigList, tr_indAudSeqSigList(Val, State)}
+ end.
+
+tr_opt_indAudSignal(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_indAudSignal(Val, State) ->
+ tr_indAudSignal(Val, State).
+
+tr_indAudSignal(#'IndAudSignal'{signalName = Name0,
+ streamID = SID,
+ signalRequestID = RID}, State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ Name = resolve(signal, Name0, State, Constraint),
+ #'IndAudSignal'{signalName = Name,
+ streamID = tr_opt_StreamID(SID, State),
+ signalRequestID = tr_opt_RequestID(RID, State)}.
+
+tr_indAudSeqSigList(#'IndAudSeqSigList'{id = ID,
+ signalList = SigList}, State) ->
+ #'IndAudSeqSigList'{id = tr_integer(ID, State, 0, 65535),
+ signalList = tr_opt_indAudSignal(SigList, State)}.
+
+%% -
+
+tr_indAudDigitMapDescriptor(#'IndAudDigitMapDescriptor'{digitMapName = Name},
+ State) ->
+ #'IndAudDigitMapDescriptor'{digitMapName =
+ tr_opt_DigitMapName(Name, State)}.
+
+
+%% -
+
+tr_indAudEventBufferDescriptor(#'IndAudEventBufferDescriptor'{eventName = N,
+ streamID = SID},
+ State) ->
+ ?d("tr_indAudEventBufferDescriptor -> entry with"
+ "~n N: ~p"
+ "~n SID: ~p", [N, SID]),
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ Name = resolve(event, N, State, Constraint),
+ ?d("tr_indAudEventBufferDescriptor -> entry with"
+ "~n Name: ~p", [Name]),
+ #'IndAudEventBufferDescriptor'{eventName = Name,
+ streamID = tr_opt_StreamID(SID, State)}.
+
+%% -
+
+tr_indAudStatisticsDescriptor(#'IndAudStatisticsDescriptor'{statName = N},
+ State) ->
+ ?d("tr_indAudEventBufferDescriptor -> entry with"
+ "~n N: ~p", [N]),
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ Name = resolve(statistics, N, State, Constraint),
+ #'IndAudStatisticsDescriptor'{statName = Name}.
+
+
+%% -
+
+tr_indAudPackagesDescriptor(#'IndAudPackagesDescriptor'{packageName = N,
+ packageVersion = V},
+ State) ->
+ ?d("tr_indAudPackagesDescriptor -> entry with"
+ "~n N: ~p"
+ "~n V: ~p", [N, V]),
+ Constraint = fun(Item) -> tr_Name(Item, State) end,
+ Name = resolve(package, N, State, Constraint),
+ ?d("tr_indAudPackagesDescriptor -> entry with"
+ "~n Name: ~p", [Name]),
+ #'IndAudPackagesDescriptor'{packageName = Name,
+ packageVersion = tr_integer(V, State, 0, 99)}.
+
+%% -- v2 end --
+
+
+tr_TerminationAudit(ParmList, State) when is_list(ParmList) ->
+ do_tr_TerminationAudit(ParmList, [], State).
+
+do_tr_TerminationAudit([], Acc, _State) ->
+ lists:reverse(Acc);
+do_tr_TerminationAudit([Parm|ParmList], Acc, State) ->
+ case tr_AuditReturnParameter(Parm, State) of
+ {_, deprecated} when State#state.mode =:= encode ->
+ error({deprecated, Parm});
+ {_, deprecated} when State#state.mode =:= decode ->
+ %% SKIP
+ do_tr_TerminationAudit(ParmList, Acc, State);
+ {_, deprecated} ->
+ %% SKIP
+ do_tr_TerminationAudit(ParmList, Acc, State);
+ NewParm ->
+ do_tr_TerminationAudit(ParmList, [NewParm|Acc], State)
+ end.
+
+tr_AuditReturnParameter({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ errorDescriptor ->
+ tr_ErrorDescriptor(Val, State);
+ mediaDescriptor ->
+ tr_MediaDescriptor(Val, State);
+ modemDescriptor ->
+ tr_ModemDescriptor(Val, State);
+ muxDescriptor ->
+ tr_MuxDescriptor(Val, State);
+ eventsDescriptor ->
+ tr_EventsDescriptor(Val, State);
+ eventBufferDescriptor ->
+ tr_EventBufferDescriptor(Val, State);
+ signalsDescriptor ->
+ tr_SignalsDescriptor(Val, State);
+ digitMapDescriptor ->
+ tr_DigitMapDescriptor(Val, State);
+ observedEventsDescriptor ->
+ tr_ObservedEventsDescriptor(Val, State);
+ statisticsDescriptor ->
+ tr_StatisticsDescriptor(Val, State);
+ packagesDescriptor ->
+ tr_PackagesDescriptor(Val, State);
+ emptyDescriptors ->
+ tr_EmptyDescriptors(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_EmptyDescriptors(#'AuditDescriptor'{auditToken = Tokens},
+ State) ->
+ Tokens2 =
+ case Tokens of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> [tr_auditItem(Token, State) || Token <- Tokens]
+ end,
+ #'AuditDescriptor'{auditToken = Tokens2}.
+
+tr_NotifyRequest(#'NotifyRequest'{terminationID = IdList,
+ observedEventsDescriptor = ObsDesc,
+ errorDescriptor = ErrDesc},
+ State) ->
+ %% BUGBUG: Mismatch between ASN.1 and ABNF
+ %% BUGBUG: The following ought to be a 'choice'
+ #'NotifyRequest'{terminationID = [tr_TerminationID(Id, State) ||
+ Id <- IdList],
+ observedEventsDescriptor = tr_ObservedEventsDescriptor(ObsDesc, State),
+ errorDescriptor = tr_opt_ErrorDescriptor(ErrDesc, State)}.
+
+tr_NotifyReply(#'NotifyReply'{terminationID = IdList,
+ errorDescriptor = ErrDesc},
+ State) ->
+ #'NotifyReply'{terminationID = [tr_TerminationID(Id, State) || Id <- IdList],
+ errorDescriptor = tr_opt_ErrorDescriptor(ErrDesc, State)}.
+
+tr_ObservedEventsDescriptor(#'ObservedEventsDescriptor'{requestId = Id,
+ observedEventLst = Events},
+ State) when is_list(Events) ->
+ #'ObservedEventsDescriptor'{requestId = tr_RequestID(Id, State),
+ observedEventLst = [tr_ObservedEvent(E, State) || E <- Events]}.
+
+%% ;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
+
+tr_ObservedEvent(#'ObservedEvent'{eventName = Name,
+ streamID = Id,
+ eventParList = Parms,
+ timeNotation = Time},
+ State) ->
+ #'ObservedEvent'{eventName = tr_EventName(Name, State),
+ streamID = tr_opt_StreamID(Id, State),
+ eventParList = [tr_EventParameter(P, Name, State) || P <- Parms],
+ timeNotation = tr_opt_TimeNotation(Time, State)}.
+
+tr_EventName(Name, State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ resolve(event, Name, State, Constraint).
+
+tr_EventParameter(#'EventParameter'{eventParameterName = ParName,
+ value = Value,
+ extraInfo = Extra},
+ EventName,
+ State) ->
+ %% BUGBUG: event parameter name
+ Constraint = fun(Item) -> tr_Name(Item, State) end,
+ N = resolve({event_parameter, EventName}, ParName, State, Constraint),
+ #'EventParameter'{eventParameterName = N,
+ value = tr_Value(Value, State),
+ extraInfo = tr_opt_extraInfo(Extra, State)}.
+
+tr_ServiceChangeRequest(#'ServiceChangeRequest'{terminationID = IdList,
+ serviceChangeParms = Parms},
+ State) ->
+ #'ServiceChangeRequest'{terminationID = [tr_TerminationID(Id, State) || Id <- IdList],
+ serviceChangeParms = tr_ServiceChangeParm(Parms, 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 )
+tr_ServiceChangeReply(#'ServiceChangeReply'{terminationID = IdList,
+ serviceChangeResult = Res},
+ State) ->
+ #'ServiceChangeReply'{terminationID = [tr_TerminationID(Id, State) || Id <- IdList],
+ serviceChangeResult = tr_ServiceChangeResult(Res, State)}.
+
+tr_ServiceChangeResult({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ errorDescriptor -> tr_ErrorDescriptor(Val, State);
+ serviceChangeResParms -> tr_ServiceChangeResParm(Val, State)
+ end,
+ {Tag, Val2}.
+
+%% TerminationID = "ROOT" / pathNAME / "$" / "*"
+%% ; Total length of pathNAME must not exceed 64 chars.
+%% pathNAME = ["*"] NAME *("/" / "*"/ ALPHA / DIGIT /"_" / "$" )
+%% ["@" pathDomainName ]
+
+tr_TerminationID(TermId, State) when State#state.mode =/= verify ->
+ resolve(term_id, TermId, State, valid);
+tr_TerminationID(#'TerminationID'{wildcard = Wild,
+ id = Id},
+ _State) ->
+ #'TerminationID'{wildcard = Wild,
+ id = Id};
+tr_TerminationID(#megaco_term_id{contains_wildcards = IsWild,
+ id = Id},
+ State) ->
+ #megaco_term_id{contains_wildcards = tr_bool(IsWild, State),
+ id = [tr_term_id_component(Sub, State) || Sub <- Id]}.
+
+tr_opt_bool(asn1_NOVALUE, _State) -> asn1_NOVALUE;
+tr_opt_bool(Bool, State) -> tr_bool(Bool, State).
+
+tr_bool(true, _State) -> true;
+tr_bool(false, _State) -> false.
+
+tr_term_id_component(Sub, _State) ->
+ case Sub of
+ all -> all;
+ choose -> 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
+tr_MediaDescriptor(#'MediaDescriptor'{termStateDescr = TermState,
+ streams = Streams},
+ State) ->
+ #'MediaDescriptor'{termStateDescr = tr_opt_TerminationStateDescriptor(TermState, State),
+ streams = tr_opt_streams(Streams, State)}.
+
+tr_opt_streams(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_streams({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ oneStream -> tr_StreamParms(Val, State);
+ multiStream -> [tr_StreamDescriptor(SD, State) || SD <- Val]
+ end,
+ {Tag, Val2}.
+
+tr_StreamParms(#'StreamParms'{localControlDescriptor = LCD,
+ localDescriptor = LD,
+ remoteDescriptor = RD,
+ statisticsDescriptor = SD},
+ State) ->
+ LCD2 = tr_opt_LocalControlDescriptor(LCD, State),
+ LD2 = tr_opt_LocalRemoteDescriptor(LD, State),
+ RD2 = tr_opt_LocalRemoteDescriptor(RD, State),
+ SD2 = tr_opt_StatisticsDescriptor(SD, State),
+ #'StreamParms'{localControlDescriptor = LCD2,
+ localDescriptor = LD2,
+ remoteDescriptor = RD2,
+ statisticsDescriptor = SD2}.
+
+tr_StreamDescriptor(#'StreamDescriptor'{streamID = Id,
+ streamParms = Parms},
+ State) ->
+ #'StreamDescriptor'{streamID = tr_StreamID(Id, State),
+ streamParms = tr_StreamParms(Parms, 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
+tr_opt_LocalControlDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_LocalControlDescriptor(#'LocalControlDescriptor'{streamMode = Mode,
+ reserveGroup = Group,
+ reserveValue = Value,
+ propertyParms = Props},
+ State) ->
+ #'LocalControlDescriptor'{streamMode = tr_opt_StreamMode(Mode, State),
+ reserveGroup = tr_opt_bool(Group, State),
+ reserveValue = tr_opt_bool(Value, State),
+ propertyParms = [tr_PropertyParm(P, State) || P <- Props]}.
+
+tr_opt_StreamMode(Mode, _State) ->
+ case Mode of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ sendOnly -> sendOnly;
+ recvOnly -> recvOnly;
+ sendRecv -> sendRecv;
+ inactive -> inactive;
+ loopBack -> loopBack
+ end.
+
+tr_Name(Name, State) ->
+ %% BUGBUG: transform
+ %% BUGBUG: NAME = ALPHA *63(ALPHA / DIGIT / "_" )
+ tr_STRING(Name, State, 2, 2).
+
+tr_PkgdName(Name, State) ->
+ %% BUGBUG: transform
+ %% BUGBUG: pkgdName = (NAME / "*") SLASH (ItemID / "*" )
+ tr_OCTET_STRING(Name, State, 4, 4).
+
+%% 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.
+tr_opt_LocalRemoteDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_LocalRemoteDescriptor(#'LocalRemoteDescriptor'{propGrps = Groups},
+ State) ->
+ #'LocalRemoteDescriptor'{propGrps = [tr_PropertyGroup(G, State) || G <- Groups]}.
+
+tr_PropertyGroup(Props, State) ->
+ [tr_PropertyGroupParm(P, State) || P <- Props].
+
+tr_PropertyGroupParm(#'PropertyParm'{name = Name,
+ value = Value},
+ State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ #'PropertyParm'{name = resolve(property, Name, State, Constraint),
+ value = tr_OCTET_STRING(Value, State, 0, infinity)}.
+
+tr_PropertyParm(#'PropertyParm'{name = Name,
+ value = Value,
+ extraInfo = Extra},
+ State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ #'PropertyParm'{name = resolve(property, Name, State, Constraint),
+ value = tr_Value(Value, State),
+ extraInfo = tr_opt_extraInfo(Extra, State)}.
+
+tr_opt_extraInfo(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_extraInfo({relation, Rel}, _State) ->
+ Rel2 =
+ case Rel of
+ greaterThan -> greaterThan;
+ smallerThan -> smallerThan;
+ unequalTo -> unequalTo
+ end,
+ {relation, Rel2};
+tr_opt_extraInfo({range, Range}, State) ->
+ Range2 = tr_bool(Range, State),
+ {range, Range2};
+tr_opt_extraInfo({sublist, Sub}, State) ->
+ Sub2 = tr_bool(Sub, State),
+ {sublist, Sub2}.
+
+tr_opt_TerminationStateDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_TerminationStateDescriptor(#'TerminationStateDescriptor'{propertyParms = Props,
+ eventBufferControl = Control,
+ serviceState = Service},
+ State) ->
+ #'TerminationStateDescriptor'{propertyParms = [tr_PropertyParm(P, State) || P <- Props],
+ eventBufferControl = tr_opt_EventBufferControl(Control, State),
+ serviceState = tr_opt_ServiceState(Service, State)}.
+
+tr_opt_EventBufferControl(Control, _State) ->
+ case Control of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ off -> off;
+ lockStep -> lockStep
+ end.
+
+tr_opt_ServiceState(Service, _State) ->
+ case Service of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ test -> test;
+ outOfSvc -> outOfSvc;
+ inSvc -> inSvc
+ end.
+
+tr_MuxDescriptor(#'MuxDescriptor'{muxType = Type,
+ termList = IdList},
+ State) ->
+ #'MuxDescriptor'{muxType = tr_MuxType(Type, State),
+ termList = [tr_TerminationID(Id, State) || Id <- IdList]}.
+
+tr_MuxType(Type, _State) ->
+ case Type of
+ h221 -> h221;
+ h223 -> h223;
+ h226 -> h226;
+ v76 -> v76
+ end.
+
+tr_opt_StreamID(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_StreamID(Id, State) ->
+ tr_StreamID(Id, State).
+
+tr_StreamID(Id, State) ->
+ tr_UINT16(Id, State).
+
+tr_EventsDescriptor(#'EventsDescriptor'{requestID = Id,
+ eventList = Events},
+ State) ->
+ #'EventsDescriptor'{requestID = tr_opt_RequestID(Id, State),
+ eventList = [tr_RequestedEvent(E, State) || E <- Events]}.
+
+tr_RequestedEvent(#'RequestedEvent'{pkgdName = Name,
+ streamID = Id,
+ evParList = Parms,
+ eventAction = Actions},
+ State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ #'RequestedEvent'{pkgdName = resolve(event, Name, State, Constraint),
+ streamID = tr_opt_StreamID(Id, State),
+ eventAction = tr_opt_RequestedActions(Actions, State),
+ evParList = [tr_EventParameter(P, Name, State) || P <- Parms]}.
+
+tr_RegulatedEmbeddedDescriptor(
+ #'RegulatedEmbeddedDescriptor'{secondEvent = SE,
+ signalsDescriptor = SD}, State) ->
+ SE2 = tr_opt_SecondEventsDescriptor(SE, State),
+ SD2 = tr_opt_SignalsDescriptor(SD, State),
+ #'RegulatedEmbeddedDescriptor'{secondEvent = SE2,
+ signalsDescriptor = SD2}.
+
+tr_opt_NotifyBehaviour(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_NotifyBehaviour(NB, State) ->
+ tr_NotifyBehaviour(NB, State).
+
+tr_NotifyBehaviour({notifyImmediate, 'NULL'} = NB, _State) ->
+ NB;
+tr_NotifyBehaviour({notifyRegulated = Tag, Val}, State) ->
+ {Tag, tr_RegulatedEmbeddedDescriptor(Val, State)};
+tr_NotifyBehaviour({neverNotify, 'NULL'} = NB, _State) ->
+ NB.
+
+tr_opt_RequestedActions(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_RequestedActions(#'RequestedActions'{keepActive = KA,
+ eventDM = DM,
+ secondEvent = SE,
+ signalsDescriptor = SD,
+ notifyBehaviour = NB,
+ resetEventsDescriptor = RSD},
+ State) ->
+ KA2 = tr_opt_keepActive(KA, State),
+ DM2 = tr_opt_EventDM(DM, State),
+ SE2 = tr_opt_SecondEventsDescriptor(SE, State),
+ SD2 = tr_opt_SignalsDescriptor(SD, State),
+ NB2 = tr_opt_NotifyBehaviour(NB, State),
+ RSD2 = tr_opt_null(RSD, State),
+ #'RequestedActions'{keepActive = KA2,
+ eventDM = DM2,
+ secondEvent = SE2,
+ signalsDescriptor = SD2,
+ notifyBehaviour = NB2,
+ resetEventsDescriptor = RSD2}.
+
+tr_opt_keepActive(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_keepActive(Keep, State) ->
+ tr_bool(Keep, State).
+
+tr_opt_EventDM(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_EventDM({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ digitMapName -> tr_DigitMapName(Val, State);
+ digitMapValue -> tr_DigitMapValue(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_opt_SecondEventsDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_SecondEventsDescriptor(#'SecondEventsDescriptor'{requestID = Id,
+ eventList = Events},
+ State) ->
+ #'SecondEventsDescriptor'{requestID = tr_RequestID(Id, State), %% IG v6 6.8 withdrawn
+ eventList = [tr_SecondRequestedEvent(E, State) || E <- Events]}.
+
+tr_SecondRequestedEvent(#'SecondRequestedEvent'{pkgdName = Name,
+ streamID = Id,
+ evParList = Parms,
+ eventAction = Actions},
+ State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ #'SecondRequestedEvent'{pkgdName = resolve(event, Name, State, Constraint),
+ streamID = tr_opt_StreamID(Id, State),
+ eventAction = tr_opt_SecondRequestedActions(Actions, State),
+ evParList = [tr_EventParameter(P, Name, State) || P <- Parms]}.
+
+
+tr_opt_SecondRequestedActions(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_SecondRequestedActions(
+ #'SecondRequestedActions'{keepActive = KA,
+ eventDM = DM,
+ signalsDescriptor = SD,
+ notifyBehaviour = NB,
+ resetEventsDescriptor = RSD},
+ State) ->
+ KA2 = tr_opt_keepActive(KA, State),
+ DM2 = tr_opt_EventDM(DM, State),
+ SD2 = tr_opt_SignalsDescriptor(SD, State),
+ NB2 = tr_opt_NotifyBehaviour(NB, State),
+ RSD2 = tr_opt_null(RSD, State),
+ #'SecondRequestedActions'{keepActive = KA2,
+ eventDM = DM2,
+ signalsDescriptor = SD2,
+ notifyBehaviour = NB2,
+ resetEventsDescriptor = RSD2}.
+
+tr_EventBufferDescriptor(EventSpecs, State) ->
+ [tr_EventSpec(ES, State) || ES <- EventSpecs].
+
+tr_EventSpec(#'EventSpec'{eventName = Name,
+ streamID = Id,
+ eventParList = Parms},
+ State) ->
+ #'EventSpec'{eventName = tr_EventName(Name, State),
+ streamID = tr_opt_StreamID(Id, State),
+ eventParList = [tr_EventParameter(P, Name, State) || P <- Parms]}.
+
+tr_opt_SignalsDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_SignalsDescriptor(SigDesc, State) ->
+ tr_SignalsDescriptor(SigDesc, State).
+
+tr_SignalsDescriptor(SigDesc, State) when is_list(SigDesc) ->
+ [tr_SignalRequest(SigReq, State) || SigReq <- SigDesc].
+
+tr_SignalRequest({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ signal -> tr_Signal(Val, State);
+ seqSigList -> tr_SeqSigList(Val, State)
+ end,
+ {Tag, Val2}.
+
+
+tr_SeqSigList(#'SeqSigList'{id = Id,
+ signalList = SigList},
+ State) when is_list(SigList) ->
+ #'SeqSigList'{id = tr_UINT16(Id, State),
+ signalList = [tr_Signal(Sig, State) || Sig <- SigList]}.
+
+tr_Signal(#'Signal'{signalName = Name,
+ streamID = SID,
+ sigType = Type,
+ duration = Dur,
+ notifyCompletion = Compl,
+ keepActive = Keep,
+ sigParList = Parms,
+ direction = Dir,
+ requestID = RID,
+ intersigDelay = ID},
+ State) ->
+ Name2 = tr_SignalName(Name, State),
+ SID2 = tr_opt_StreamID(SID, State),
+ Type2 = tr_opt_SignalType(Type, State),
+ Dur2 = tr_opt_UINT16(Dur, State),
+ Compl2 = tr_opt_NotifyCompletion(Compl, State),
+ Keep2 = tr_opt_keepActive(Keep, State),
+ Parms2 = [tr_SigParameter(P, Name, State) || P <- Parms],
+ Dir2 = tr_opt_SignalDirection(Dir, State),
+ RID2 = tr_opt_RequestID(RID, State),
+ ID2 = tr_opt_UINT16(ID, State),
+ #'Signal'{signalName = Name2,
+ streamID = SID2,
+ sigType = Type2,
+ duration = Dur2,
+ notifyCompletion = Compl2,
+ keepActive = Keep2,
+ sigParList = Parms2,
+ direction = Dir2,
+ requestID = RID2,
+ intersigDelay = ID2}.
+
+tr_opt_NotifyCompletion(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_NotifyCompletion(Items, State) when is_list(Items) ->
+ [tr_notifyCompletionItem(I, State) || I <- Items].
+
+tr_notifyCompletionItem(Item, _State) ->
+ case Item of
+ onTimeOut -> onTimeOut;
+ onInterruptByEvent -> onInterruptByEvent;
+ onInterruptByNewSignalDescr -> onInterruptByNewSignalDescr;
+ otherReason -> otherReason;
+ onIteration -> onIteration
+ end.
+
+tr_opt_SignalType(asn1_NOVALUE = Type, _State) ->
+ Type;
+tr_opt_SignalType(Type, _State) ->
+ case Type of
+ brief -> brief;
+ onOff -> onOff;
+ timeOut -> timeOut
+ end.
+
+tr_opt_SignalDirection(asn1_NOVALUE = SD, _State) ->
+ SD;
+tr_opt_SignalDirection(SD, _State) ->
+ case SD of
+ internal -> internal;
+ external -> external;
+ both -> both
+ end.
+
+tr_SignalName(Name, State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ resolve(signal, Name, State, Constraint).
+
+tr_SigParameter(#'SigParameter'{sigParameterName = ParName,
+ value = Value,
+ extraInfo = Extra},
+ SigName,
+ State) ->
+ Constraint = fun(Item) -> tr_Name(Item, State) end,
+ N = resolve({signal_parameter, SigName}, ParName, State, Constraint),
+ #'SigParameter'{sigParameterName = N,
+ value = tr_Value(Value, State),
+ extraInfo = tr_opt_extraInfo(Extra, State)}.
+
+tr_opt_RequestID(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_RequestID(Id, State) ->
+ tr_RequestID(Id, State).
+
+tr_RequestID(Id, _State) when Id =:= ?megaco_all_request_id ->
+ ?megaco_all_request_id;
+tr_RequestID(Id, State) ->
+ tr_UINT32(Id, State).
+
+tr_ModemDescriptor(_MD, _State) ->
+ deprecated.
+
+tr_DigitMapDescriptor(#'DigitMapDescriptor'{digitMapName = Name,
+ digitMapValue = Value},
+ State) ->
+ #'DigitMapDescriptor'{digitMapName = tr_opt_DigitMapName(Name, State),
+ digitMapValue = tr_opt_DigitMapValue(Value, State)}.
+
+tr_opt_DigitMapName(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_DigitMapName(Name, State) ->
+ tr_DigitMapName(Name, State).
+
+tr_DigitMapName(Name, State) ->
+ Constraint = fun(Item) -> tr_Name(Item, State) end,
+ resolve(dialplan, Name, State, Constraint).
+
+tr_opt_DigitMapValue(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_DigitMapValue(Value, State) ->
+ tr_DigitMapValue(Value, State).
+
+tr_DigitMapValue(#'DigitMapValue'{digitMapBody = Body,
+ startTimer = Start,
+ shortTimer = Short,
+ longTimer = Long},
+ State) ->
+ #'DigitMapValue'{startTimer = tr_opt_timer(Start, State),
+ shortTimer = tr_opt_timer(Short, State),
+ longTimer = tr_opt_timer(Long, State),
+ digitMapBody = tr_STRING(Body, State)}. %% BUGBUG: digitMapBody not handled at all
+
+tr_opt_timer(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_timer(Timer, State) ->
+ tr_DIGIT(Timer, State, 0, 99).
+
+tr_ServiceChangeParm(
+ #'ServiceChangeParm'{serviceChangeMethod = Method,
+ serviceChangeAddress = Addr,
+ serviceChangeVersion = Version,
+ serviceChangeProfile = Profile,
+ serviceChangeReason = Reason,
+ serviceChangeDelay = Delay,
+ serviceChangeMgcId = MgcId,
+ timeStamp = Time,
+ serviceChangeInfo = Info,
+ serviceChangeIncompleteFlag = Incomplete},
+ State) ->
+ Method2 = tr_ServiceChangeMethod(Method, State),
+ Addr2 = tr_opt_ServiceChangeAddress(Addr, State),
+ Version2 = tr_opt_serviceChangeVersion(Version, State),
+ Profile2 = tr_opt_ServiceChangeProfile(Profile, State),
+ Reason2 = tr_serviceChangeReason(Reason, State),
+ Delay2 = tr_opt_serviceChangeDelay(Delay, State),
+ MgcId2 = tr_opt_serviceChangeMgcId(MgcId, State),
+ Time2 = tr_opt_TimeNotation(Time, State),
+ Info2 = tr_opt_AuditDescriptor(Info, State),
+ Incomplete2 = tr_opt_null(Incomplete, State),
+ #'ServiceChangeParm'{serviceChangeMethod = Method2,
+ serviceChangeAddress = Addr2,
+ serviceChangeVersion = Version2,
+ serviceChangeProfile = Profile2,
+ serviceChangeReason = Reason2,
+ serviceChangeDelay = Delay2,
+ serviceChangeMgcId = MgcId2,
+ timeStamp = Time2,
+ serviceChangeInfo = Info2,
+ serviceChangeIncompleteFlag = Incomplete2}.
+
+tr_ServiceChangeMethod(Method, _State) ->
+ case Method of
+ failover -> failover;
+ forced -> forced;
+ graceful -> graceful;
+ restart -> restart;
+ disconnected -> disconnected;
+ handOff -> handOff
+ end. %% BUGBUG: extension
+
+tr_opt_ServiceChangeAddress(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_ServiceChangeAddress({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ portNumber -> tr_portNumber(Val, State);
+ ip4Address -> tr_IP4Address(Val, State);
+ ip6Address -> tr_IP6Address(Val, State);
+ domainName -> tr_DomainName(Val, State);
+ deviceName -> tr_PathName(Val, State);
+ mtpAddress -> tr_mtpAddress(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_opt_serviceChangeVersion(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_serviceChangeVersion(Version, State) ->
+ tr_version(Version, State).
+
+tr_opt_ServiceChangeProfile(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+%% Decode
+tr_opt_ServiceChangeProfile({'ServiceChangeProfile', ProfileName}, State) ->
+ case string:tokens(ProfileName, "/") of
+ [Name0, Version0] ->
+ Name = tr_STRING(Name0, State, 1, 64),
+ Version = tr_version(list_to_integer(Version0), State),
+ #'ServiceChangeProfile'{profileName = Name,
+ version = Version}
+ end;
+%% Encode
+tr_opt_ServiceChangeProfile(#'ServiceChangeProfile'{profileName = Name0,
+ version = Version0},
+ State) ->
+ Name = tr_STRING(Name0, State, 1, 64),
+ Version = tr_version(Version0, State),
+ ProfileName = lists:flatten(io_lib:format("~s/~w", [Name, Version])),
+ {'ServiceChangeProfile', ProfileName}.
+
+tr_serviceChangeReason([_] = Reason, State) ->
+ tr_Value(Reason, State).
+
+tr_opt_serviceChangeDelay(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_serviceChangeDelay(Delay, State) ->
+ tr_UINT32(Delay, State).
+
+tr_opt_serviceChangeMgcId(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_serviceChangeMgcId(MgcId, State) ->
+ tr_MId(MgcId, State).
+
+tr_opt_portNumber(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_portNumber(Port, State) ->
+ tr_portNumber(Port, State).
+
+tr_portNumber(Port, State) when is_integer(Port) andalso (Port >= 0) ->
+ tr_UINT16(Port, State).
+
+tr_ServiceChangeResParm(#'ServiceChangeResParm'{serviceChangeMgcId = MgcId,
+ serviceChangeAddress = Addr,
+ serviceChangeVersion = Version,
+ serviceChangeProfile = Profile,
+ timeStamp = Time},
+ State) ->
+ #'ServiceChangeResParm'{serviceChangeMgcId = tr_opt_serviceChangeMgcId(MgcId, State),
+ serviceChangeAddress = tr_opt_ServiceChangeAddress(Addr, State),
+ serviceChangeVersion = tr_opt_serviceChangeVersion(Version, State),
+ serviceChangeProfile = tr_opt_ServiceChangeProfile(Profile, State),
+ timeStamp = tr_opt_TimeNotation(Time, State)}.
+
+tr_PackagesDescriptor(Items, State) when is_list(Items) ->
+ [tr_PackagesItem(I, State) || I <- Items].
+
+tr_PackagesItem(#'PackagesItem'{packageName = Name,
+ packageVersion = Version},
+ State) ->
+ Constraint = fun(Item) -> tr_Name(Item, State) end,
+ #'PackagesItem'{packageName = resolve(package, Name, State, Constraint),
+ packageVersion = tr_UINT16(Version, State)}.
+
+tr_opt_StatisticsDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_StatisticsDescriptor(Parms, State) ->
+ tr_StatisticsDescriptor(Parms, State).
+
+tr_StatisticsDescriptor(Parms, State) when is_list(Parms) ->
+ [tr_StatisticsParameter(P, State) || P <- Parms].
+
+tr_StatisticsParameter(#'StatisticsParameter'{statName = Name,
+ statValue = Value},
+ State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ #'StatisticsParameter'{statName = resolve(statistics, Name, State, Constraint),
+ statValue = tr_opt_Value(Value, State)}.
+
+tr_opt_TimeNotation(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_TimeNotation(#'TimeNotation'{date = Date,
+ time = Time},
+ State) ->
+ #'TimeNotation'{date = tr_STRING(Date, State, 8, 8), % "yyyymmdd"
+ time = tr_STRING(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.
+
+tr_opt_Value(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_Value(Value, State) ->
+ tr_Value(Value, State).
+
+tr_Value(Strings, _State) when is_list(Strings) ->
+ [[Char || Char <- String] || String <- Strings].
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Encode an octet string, escape } by \ if necessary
+tr_OCTET_STRING(String, _State, Min, Max) when is_list(String) ->
+ verify_count(length(String), Min, Max),
+ String.
+
+tr_QUOTED_STRING(String, _State) when is_list(String) ->
+ verify_count(length(String), 1, infinity),
+ String.
+
+%% 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
+tr_HEXDIG(Octets, _State, Min, Max) when is_list(Octets) ->
+ verify_count(length(Octets), Min, Max),
+ Octets.
+
+tr_DIGIT(Val, State, Min, Max) ->
+ tr_integer(Val, State, Min, Max).
+
+tr_STRING(String, _State) when is_list(String) ->
+ String.
+
+tr_STRING(String, _State, Min, Max) when is_list(String) ->
+ verify_count(length(String), Min, Max),
+ String.
+
+tr_opt_UINT16(Val, State) ->
+ tr_opt_integer(Val, State, 0, 65535).
+
+tr_UINT16(Val, State) ->
+ tr_integer(Val, State, 0, 65535).
+
+tr_UINT32(Val, State) ->
+ tr_integer(Val, State, 0, 4294967295).
+
+tr_opt_integer(asn1_NOVALUE, _State, _Min, _Max) ->
+ asn1_NOVALUE;
+tr_opt_integer(Int, State, Min, Max) ->
+ tr_integer(Int, State, Min, Max).
+
+tr_integer(Int, _State, Min, Max) ->
+ verify_count(Int, Min, Max),
+ Int.
+
+%% 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).
+
+
diff --git a/lib/megaco/src/binary/megaco_binary_transformer_v1.erl b/lib/megaco/src/binary/megaco_binary_transformer_v1.erl
new file mode 100644
index 0000000000..7236c0a9e1
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_binary_transformer_v1.erl
@@ -0,0 +1,1261 @@
+%%
+%% %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%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Transform internal form of Megaco/H.248 messages
+%%----------------------------------------------------------------------
+
+-module(megaco_binary_transformer_v1).
+
+-include_lib("megaco/include/megaco.hrl").
+-include_lib("megaco/include/megaco_message_v1.hrl").
+
+-export([tr_message/3, tr_transaction/3]).
+
+-define(DEFAULT_NAME_RESOLVER,megaco_binary_name_resolver_v1).
+-define(error(R), erlang:error({error, R})).
+
+-record(state, {mode, % verify | encode | decode
+ resolver_module, %
+ resolver_options}).
+
+resolve(Type, Item, State, Constraint) ->
+ case State#state.mode of
+ verify ->
+ Item;
+ encode ->
+ %% i("resolve(encode) -> encode: ~p",[Item]),
+ Mod = State#state.resolver_module,
+ Opt = State#state.resolver_options,
+ EncodedItem = Mod:encode_name(Opt, Type, Item),
+ %% i("resolve -> verify contraint for ~p",[EncodedItem]),
+ verify_constraint(EncodedItem, Constraint);
+ decode ->
+ %% i("resolve(decode) -> verify contraint for ~p",[Item]),
+ DecodedItem = verify_constraint(Item, Constraint),
+ Mod = State#state.resolver_module,
+ Opt = State#state.resolver_options,
+ %% i("resolve(decode) -> decode: ~p",[DecodedItem]),
+ Mod:decode_name(Opt, Type, DecodedItem)
+ end.
+
+verify_constraint(Item, valid) ->
+ Item;
+verify_constraint(Item, Constraint) when is_function(Constraint) ->
+ Constraint(Item).
+
+tr_message(MegaMsg, Mode, Config) ->
+ case Config of
+ [native] ->
+ MegaMsg;
+ [verify] ->
+ State = #state{mode = verify},
+ tr_MegacoMessage(MegaMsg, State);
+ [] ->
+ State = #state{mode = Mode,
+ resolver_module = ?DEFAULT_NAME_RESOLVER,
+ resolver_options = [8, 8, 8]},
+ tr_MegacoMessage(MegaMsg, State);
+ [{binary_name_resolver, {Module, Options}}] when is_atom(Module) ->
+ State = #state{mode = Mode,
+ resolver_module = Module,
+ resolver_options = Options},
+ tr_MegacoMessage(MegaMsg, State)
+ end.
+
+tr_transaction(Trans, Mode, Config) ->
+ case Config of
+ [native] ->
+ Trans;
+ [verify] ->
+ State = #state{mode = verify},
+ tr_Transaction(Trans, State);
+ [] ->
+ State = #state{mode = Mode,
+ resolver_module = ?DEFAULT_NAME_RESOLVER,
+ resolver_options = [8, 8, 8]},
+ tr_Transaction(Trans, State);
+ [{binary_name_resolver, {Module, Options}}] when is_atom(Module) ->
+ State = #state{mode = Mode,
+ resolver_module = Module,
+ resolver_options = Options},
+ tr_Transaction(Trans, State)
+ end.
+
+tr_MegacoMessage(#'MegacoMessage'{authHeader = Auth,
+ mess = Mess},
+ State) ->
+ #'MegacoMessage'{authHeader = tr_opt_AuthenticationHeader(Auth, State),
+ mess = tr_Message(Mess, State)}.
+
+tr_opt_AuthenticationHeader(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_AuthenticationHeader(#'AuthenticationHeader'{secParmIndex = SPI,
+ seqNum = SN,
+ ad = AuthData},
+ State) ->
+ #'AuthenticationHeader'{secParmIndex = tr_SecurityParmIndex(SPI, State),
+ seqNum = tr_SequenceNum(SN, State),
+ ad = tr_AuthData(AuthData, State)}.
+
+tr_SecurityParmIndex(SPI, State) ->
+ tr_HEXDIG(SPI, State, 4, 4). % BUGBUG: Mismatch between ASN.1 and ABNF
+
+tr_SequenceNum(SN, State) ->
+ tr_HEXDIG(SN, State, 4, 4). % BUGBUG: Mismatch between ASN.1 and ABNF
+
+tr_AuthData(AuthData, State) ->
+ tr_HEXDIG(AuthData, State, 12, 32). % BUGBUG: Mismatch between ASN.1 and ABNF
+
+tr_Message(#'Message'{version = Version,
+ mId = MID,
+ messageBody = Body},
+ State) ->
+ #'Message'{version = tr_version(Version, State),
+ mId = tr_MId(MID, State),
+ messageBody = tr_Message_messageBody(Body, State)}.
+
+tr_version(Version, State) ->
+ tr_DIGIT(Version, State, 0, 99).
+
+tr_Message_messageBody({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ messageError -> tr_ErrorDescriptor(Val, State);
+ transactions when is_list(Val) -> [tr_Transaction(T, State) || T <- Val]
+ end,
+ {Tag, Val2}.
+
+tr_MId({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ ip4Address -> tr_IP4Address(Val, State);
+ ip6Address -> tr_IP6Address(Val, State);
+ domainName -> tr_DomainName(Val, State);
+ deviceName -> tr_PathName(Val, State);
+ mtpAddress -> tr_mtpAddress(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_mtpAddress(MtpAddr, State) ->
+ tr_OCTET_STRING(MtpAddr, State, 2, 4). % BUGBUG: Mismatch between ASN.1 and ABNF
+
+tr_DomainName(#'DomainName'{name = Name,
+ portNumber = Port},
+ State) ->
+ Domain = #'DomainName'{name = tr_STRING(Name, State), % BUGBUG: Mismatch between ASN.1 and ABNF
+ portNumber = tr_opt_portNumber(Port, State)},
+ {domainName, Domain2} = resolve(mid, {domainName, Domain}, State, valid),
+ Domain2.
+
+tr_IP4Address(#'IP4Address'{address = [A1, A2, A3, A4],
+ portNumber = Port},
+ State) ->
+ #'IP4Address'{address = [tr_V4hex(A1, State),
+ tr_V4hex(A2, State),
+ tr_V4hex(A3, State),
+ tr_V4hex(A4, State)],
+ portNumber = tr_opt_portNumber(Port, State)}.
+
+tr_V4hex(Val, State) ->
+ tr_DIGIT(Val, State, 0, 255).
+
+tr_IP6Address(_Val, _State) ->
+ ?error(ipv6_not_supported). %% BUGBUG: nyi
+
+tr_PathName(Path, State) ->
+ %% BUGBUG: ["*"] NAME *("/" / "*"/ ALPHA / DIGIT /"_" / "$" )
+ %% BUGBUG: ["@" pathDomainName ]
+ Constraint = fun({deviceName, Item}) -> tr_STRING(Item, State, 1, 64) end,
+ resolve(mid, {deviceName, Path}, State, Constraint).
+
+tr_Transaction({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ transactionRequest -> tr_TransactionRequest(Val, State);
+ transactionPending -> tr_TransactionPending(Val, State);
+ transactionReply -> tr_TransactionReply(Val, State);
+ transactionResponseAck -> [tr_TransactionAck(T, State) || T <- Val]
+ end,
+ {Tag, Val2}.
+
+tr_TransactionAck(#'TransactionAck'{firstAck = First,
+ lastAck = Last},
+ State) ->
+ #'TransactionAck'{firstAck = tr_TransactionId(First, State),
+ lastAck = tr_opt_TransactionId(Last, State)}.
+
+tr_opt_TransactionId(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_TransactionId(Id, State) ->
+ tr_TransactionId(Id, State).
+
+tr_TransactionId(Id, State) ->
+ tr_UINT32(Id, State).
+
+tr_TransactionRequest(#'TransactionRequest'{transactionId = Id,
+ actions = Actions},
+ State) when is_list(Actions) ->
+
+ #'TransactionRequest'{transactionId = tr_TransactionId(Id, State),
+ actions = [tr_ActionRequest(ActReq, State) || ActReq <- Actions]}.
+
+tr_TransactionPending(#'TransactionPending'{transactionId = Id},
+ State) ->
+ #'TransactionPending'{transactionId = tr_TransactionId(Id, State)}.
+
+tr_TransactionReply(#'TransactionReply'{transactionId = Id,
+ immAckRequired = ImmAck,
+ transactionResult = TransRes},
+ State) ->
+ #'TransactionReply'{transactionId = tr_TransactionId(Id, State),
+ immAckRequired = tr_opt_null(ImmAck, State),
+ transactionResult = tr_TransactionReply_transactionResult(TransRes, State)}.
+
+tr_opt_null(asn1_NOVALUE, _State) -> asn1_NOVALUE;
+tr_opt_null('NULL', _State) -> 'NULL'.
+
+tr_TransactionReply_transactionResult({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ transactionError ->
+ tr_ErrorDescriptor(Val, State);
+ actionReplies when is_list(Val) andalso (Val =/= []) ->
+ [tr_ActionReply(ActRep, State) || ActRep <- Val]
+ end,
+ {Tag, Val2}.
+
+tr_opt_ErrorDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_ErrorDescriptor(ErrDesc, State) ->
+ tr_ErrorDescriptor(ErrDesc, State).
+
+tr_ErrorDescriptor(#'ErrorDescriptor'{errorCode = Code,
+ errorText = Text},
+ State) ->
+ #'ErrorDescriptor'{errorCode = tr_ErrorCode(Code, State),
+ errorText = tr_opt_ErrorText(Text, State)}.
+
+tr_ErrorCode(Code, State) ->
+ tr_DIGIT(Code, State, 0, 999).
+
+tr_opt_ErrorText(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_ErrorText(Text, State) ->
+ tr_QUOTED_STRING(Text, State).
+
+tr_ContextID(CtxId, State) ->
+ case CtxId of
+ ?megaco_all_context_id -> ?megaco_all_context_id;
+ ?megaco_null_context_id -> ?megaco_null_context_id;
+ ?megaco_choose_context_id -> ?megaco_choose_context_id;
+ Int when is_integer(Int) -> tr_UINT32(Int, State)
+ end.
+
+tr_ActionRequest(#'ActionRequest'{contextId = CtxId,
+ contextRequest = CtxReq,
+ contextAttrAuditReq = CtxAuditReq,
+ commandRequests = CmdReqList},
+ State) ->
+ #'ActionRequest'{contextId = tr_ContextID(CtxId, State),
+ contextRequest = tr_opt_ContextRequest(CtxReq, State),
+ contextAttrAuditReq = tr_opt_ContextAttrAuditRequest(CtxAuditReq, State),
+ commandRequests = [tr_CommandRequest(CmdReq, State) || CmdReq <- CmdReqList]}.
+
+tr_ActionReply(#'ActionReply'{contextId = CtxId,
+ errorDescriptor = ErrDesc,
+ contextReply = CtxRep,
+ commandReply = CmdRepList},
+ State) ->
+ CmdRepList2 = [tr_CommandReply(CmdRep, State) || CmdRep <- CmdRepList],
+ #'ActionReply'{contextId = tr_ContextID(CtxId, State),
+ errorDescriptor = tr_opt_ErrorDescriptor(ErrDesc, State),
+ contextReply = tr_opt_ContextRequest(CtxRep, State),
+ commandReply = CmdRepList2}.
+
+tr_opt_ContextRequest(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_ContextRequest(#'ContextRequest'{priority = Prio,
+ emergency = Em,
+ topologyReq = TopReqList},
+ State) ->
+ Prio2 =
+ case Prio of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> tr_integer(Prio, State, 0, 15)
+ end,
+ Em2 =
+ case Em of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ false -> false;
+ true -> true
+ end,
+ TopReqList2 =
+ case TopReqList of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> [tr_TopologyRequest(TopReq, State) ||
+ TopReq <- TopReqList]
+ end,
+ #'ContextRequest'{priority = Prio2,
+ emergency = Em2,
+ topologyReq = TopReqList2}.
+
+tr_opt_ContextAttrAuditRequest(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_ContextAttrAuditRequest(#'ContextAttrAuditRequest'{topology = Top,
+ emergency = Em,
+ priority = Prio},
+ State) ->
+ #'ContextAttrAuditRequest'{topology = tr_opt_null(Top, State),
+ emergency = tr_opt_null(Em, State),
+ priority = tr_opt_null(Prio, State)}.
+
+tr_CommandRequest(#'CommandRequest'{command = Cmd,
+ optional = Opt,
+ wildcardReturn = Wild},
+ State) ->
+ #'CommandRequest'{optional = tr_opt_null(Opt, State),
+ wildcardReturn = tr_opt_null(Wild, State),
+ command = tr_Command(Cmd, State)}.
+
+tr_Command({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ addReq -> tr_AmmRequest(Val, State);
+ moveReq -> tr_AmmRequest(Val, State);
+ modReq -> tr_AmmRequest(Val, State);
+ subtractReq -> tr_SubtractRequest(Val, State);
+ auditCapRequest -> tr_AuditRequest(Val, State);
+ auditValueRequest -> tr_AuditRequest(Val, State);
+ notifyReq -> tr_NotifyRequest(Val, State);
+ serviceChangeReq -> tr_ServiceChangeRequest(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_CommandReply({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ addReply -> tr_AmmsReply(Val, State);
+ moveReply -> tr_AmmsReply(Val, State);
+ modReply -> tr_AmmsReply(Val, State);
+ subtractReply -> tr_AmmsReply(Val, State);
+ auditCapReply -> tr_AuditReply(Val, State);
+ auditValueReply -> tr_AuditReply(Val, State);
+ notifyReply -> tr_NotifyReply(Val, State);
+ serviceChangeReply -> tr_ServiceChangeReply(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_TopologyRequest(#'TopologyRequest'{terminationFrom = From,
+ terminationTo = To,
+ topologyDirection = Dir},
+ State) ->
+ Dir2 =
+ case Dir of
+ bothway -> bothway;
+ isolate -> isolate;
+ oneway -> oneway
+ end,
+ #'TopologyRequest'{terminationFrom = tr_TerminationID(From, State),
+ terminationTo = tr_TerminationID(To, State),
+ topologyDirection = Dir2}.
+
+tr_AmmRequest(#'AmmRequest'{terminationID = IdList,
+ descriptors = DescList},
+ State) ->
+ #'AmmRequest'{terminationID = [tr_TerminationID(Id, State) ||
+ Id <- IdList],
+ descriptors = [tr_ammDescriptor(Desc, State) ||
+ Desc <- DescList]}.
+
+tr_ammDescriptor({Tag, Desc}, State) ->
+ Desc2 =
+ case Tag of
+ mediaDescriptor -> tr_MediaDescriptor(Desc, State);
+ modemDescriptor -> tr_ModemDescriptor(Desc, State);
+ muxDescriptor -> tr_MuxDescriptor(Desc, State);
+ eventsDescriptor -> tr_EventsDescriptor(Desc, State);
+ eventBufferDescriptor -> tr_EventBufferDescriptor(Desc, State);
+ signalsDescriptor -> tr_SignalsDescriptor(Desc, State);
+ digitMapDescriptor -> tr_DigitMapDescriptor(Desc, State);
+ auditDescriptor -> tr_AuditDescriptor(Desc, State)
+ end,
+ {Tag, Desc2}.
+
+tr_AmmsReply(#'AmmsReply'{terminationID = IdList,
+ terminationAudit = TermAudit},
+ State) ->
+ TermAudit2 =
+ case TermAudit of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> tr_TerminationAudit(TermAudit, State)
+ end,
+ #'AmmsReply'{terminationID = [tr_TerminationID(Id, State) ||
+ Id <- IdList],
+ terminationAudit = TermAudit2}.
+
+tr_SubtractRequest(#'SubtractRequest'{terminationID = IdList,
+ auditDescriptor = Desc},
+ State) ->
+ #'SubtractRequest'{terminationID = [tr_TerminationID(Id, State) ||
+ Id <- IdList],
+ auditDescriptor = tr_opt_AuditDescriptor(Desc, State)}.
+
+tr_AuditRequest(#'AuditRequest'{terminationID = Id,
+ auditDescriptor = Desc},
+ State) ->
+ #'AuditRequest'{terminationID = tr_TerminationID(Id, State),
+ auditDescriptor = tr_AuditDescriptor(Desc, State)}.
+
+%% auditReply = (AuditValueToken / AuditCapToken )
+%% ( contextTerminationAudit / auditOther)
+%% auditOther = EQUAL TerminationID LBRKT
+%% terminationAudit RBRKT
+%% terminationAudit = auditReturnParameter *(COMMA auditReturnParameter)
+%%
+%% contextTerminationAudit = EQUAL CtxToken ( terminationIDList /
+%% LBRKT errorDescriptor RBRKT )
+
+tr_AuditReply({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ contextAuditResult ->
+ [tr_TerminationID(Id, State) || Id <- Val];
+ error ->
+ tr_ErrorDescriptor(Val, State);
+ auditResult ->
+ tr_AuditResult(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_AuditResult(#'AuditResult'{terminationID = Id,
+ terminationAuditResult = AuditRes},
+ State) ->
+ #'AuditResult'{terminationID = tr_TerminationID(Id, State),
+ terminationAuditResult = tr_TerminationAudit(AuditRes, State)}.
+
+tr_opt_AuditDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_AuditDescriptor(Desc, State) ->
+ tr_AuditDescriptor(Desc, State).
+
+tr_AuditDescriptor(#'AuditDescriptor'{auditToken = Tokens},
+ State) ->
+ Tokens2 =
+ case Tokens of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> [tr_auditItem(Token, State) || Token <- Tokens]
+ end,
+ #'AuditDescriptor'{auditToken = Tokens2}.
+
+tr_auditItem(Token, _State) ->
+ case Token of
+ muxToken -> muxToken;
+ modemToken -> modemToken;
+ mediaToken -> mediaToken;
+ eventsToken -> eventsToken;
+ signalsToken -> signalsToken;
+ digitMapToken -> digitMapToken;
+ statsToken -> statsToken;
+ observedEventsToken -> observedEventsToken;
+ packagesToken -> packagesToken;
+ eventBufferToken -> eventBufferToken
+ end.
+
+tr_TerminationAudit(ParmList, State) when is_list(ParmList) ->
+ [tr_AuditReturnParameter(Parm, State) || Parm <- ParmList].
+
+tr_AuditReturnParameter({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ errorDescriptor ->
+ tr_ErrorDescriptor(Val, State);
+ mediaDescriptor ->
+ tr_MediaDescriptor(Val, State);
+ modemDescriptor ->
+ tr_ModemDescriptor(Val, State);
+ muxDescriptor ->
+ tr_MuxDescriptor(Val, State);
+ eventsDescriptor ->
+ tr_EventsDescriptor(Val, State);
+ eventBufferDescriptor ->
+ tr_EventBufferDescriptor(Val, State);
+ signalsDescriptor ->
+ tr_SignalsDescriptor(Val, State);
+ digitMapDescriptor ->
+ tr_DigitMapDescriptor(Val, State);
+ observedEventsDescriptor ->
+ tr_ObservedEventsDescriptor(Val, State);
+ statisticsDescriptor ->
+ tr_StatisticsDescriptor(Val, State);
+ packagesDescriptor ->
+ tr_PackagesDescriptor(Val, State);
+ emptyDescriptors ->
+ tr_EmptyDescriptors(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_EmptyDescriptors(#'AuditDescriptor'{auditToken = Tokens},
+ State) ->
+ case Tokens of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> [tr_auditItem(Token, State) || Token <- Tokens]
+ end.
+
+tr_NotifyRequest(#'NotifyRequest'{terminationID = IdList,
+ observedEventsDescriptor = ObsDesc,
+ errorDescriptor = ErrDesc},
+ State) ->
+ %% BUGBUG: Mismatch between ASN.1 and ABNF
+ %% BUGBUG: The following ought to be a 'choice'
+ #'NotifyRequest'{terminationID = [tr_TerminationID(Id, State) ||
+ Id <- IdList],
+ observedEventsDescriptor = tr_ObservedEventsDescriptor(ObsDesc, State),
+ errorDescriptor = tr_opt_ErrorDescriptor(ErrDesc, State)}.
+
+tr_NotifyReply(#'NotifyReply'{terminationID = IdList,
+ errorDescriptor = ErrDesc},
+ State) ->
+ #'NotifyReply'{terminationID = [tr_TerminationID(Id, State) || Id <- IdList],
+ errorDescriptor = tr_opt_ErrorDescriptor(ErrDesc, State)}.
+
+tr_ObservedEventsDescriptor(#'ObservedEventsDescriptor'{requestId = Id,
+ observedEventLst = Events},
+ State) when is_list(Events) ->
+ #'ObservedEventsDescriptor'{requestId = tr_RequestID(Id, State),
+ observedEventLst = [tr_ObservedEvent(E, State) || E <- Events]}.
+
+%% ;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
+
+tr_ObservedEvent(#'ObservedEvent'{eventName = Name,
+ streamID = Id,
+ eventParList = Parms,
+ timeNotation = Time},
+ State) ->
+ #'ObservedEvent'{eventName = tr_EventName(Name, State),
+ streamID = tr_opt_StreamID(Id, State),
+ eventParList = [tr_EventParameter(P, Name, State) || P <- Parms],
+ timeNotation = tr_opt_TimeNotation(Time, State)}.
+
+tr_EventName(Name, State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ resolve(event, Name, State, Constraint).
+
+tr_EventParameter(#'EventParameter'{eventParameterName = ParName,
+ value = Value,
+ extraInfo = Extra},
+ EventName,
+ State) ->
+ %% BUGBUG: event parameter name
+ Constraint = fun(Item) -> tr_Name(Item, State) end,
+ N = resolve({event_parameter, EventName}, ParName, State, Constraint),
+ #'EventParameter'{eventParameterName = N,
+ value = tr_Value(Value, State),
+ extraInfo = tr_opt_extraInfo(Extra, State)}.
+
+tr_ServiceChangeRequest(#'ServiceChangeRequest'{terminationID = IdList,
+ serviceChangeParms = Parms},
+ State) ->
+ #'ServiceChangeRequest'{terminationID = [tr_TerminationID(Id, State) || Id <- IdList],
+ serviceChangeParms = tr_ServiceChangeParm(Parms, 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 )
+tr_ServiceChangeReply(#'ServiceChangeReply'{terminationID = IdList,
+ serviceChangeResult = Res},
+ State) ->
+ #'ServiceChangeReply'{terminationID = [tr_TerminationID(Id, State) || Id <- IdList],
+ serviceChangeResult = tr_ServiceChangeResult(Res, State)}.
+
+tr_ServiceChangeResult({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ errorDescriptor -> tr_ErrorDescriptor(Val, State);
+ serviceChangeResParms -> tr_ServiceChangeResParm(Val, State)
+ end,
+ {Tag, Val2}.
+
+%% TerminationID = "ROOT" / pathNAME / "$" / "*"
+%% ; Total length of pathNAME must not exceed 64 chars.
+%% pathNAME = ["*"] NAME *("/" / "*"/ ALPHA / DIGIT /"_" / "$" )
+%% ["@" pathDomainName ]
+
+tr_TerminationID(TermId, State) when State#state.mode =/= verify ->
+ resolve(term_id, TermId, State, valid);
+tr_TerminationID(#'TerminationID'{wildcard = Wild,
+ id = Id},
+ _State) ->
+ #'TerminationID'{wildcard = Wild,
+ id = Id};
+tr_TerminationID(#megaco_term_id{contains_wildcards = IsWild,
+ id = Id},
+ State) ->
+ #megaco_term_id{contains_wildcards = tr_bool(IsWild, State),
+ id = [tr_term_id_component(Sub, State) || Sub <- Id]}.
+
+tr_opt_bool(asn1_NOVALUE, _State) -> asn1_NOVALUE;
+tr_opt_bool(Bool, State) -> tr_bool(Bool, State).
+
+tr_bool(true, _State) -> true;
+tr_bool(false, _State) -> false.
+
+tr_term_id_component(Sub, _State) ->
+ case Sub of
+ all -> all;
+ choose -> 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
+tr_MediaDescriptor(#'MediaDescriptor'{termStateDescr = TermState,
+ streams = Streams},
+ State) ->
+ #'MediaDescriptor'{termStateDescr = tr_opt_TerminationStateDescriptor(TermState, State),
+ streams = tr_opt_streams(Streams, State)}.
+
+tr_opt_streams(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_streams({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ oneStream -> tr_StreamParms(Val, State);
+ multiStream -> [tr_StreamDescriptor(SD, State) || SD <- Val]
+ end,
+ {Tag, Val2}.
+
+tr_StreamParms(#'StreamParms'{localControlDescriptor = Control,
+ localDescriptor = Local,
+ remoteDescriptor = Remote},
+ State) ->
+ #'StreamParms'{localControlDescriptor = tr_opt_LocalControlDescriptor(Control, State),
+ localDescriptor = tr_opt_LocalRemoteDescriptor(Local, State),
+ remoteDescriptor = tr_opt_LocalRemoteDescriptor(Remote, State)}.
+
+tr_StreamDescriptor(#'StreamDescriptor'{streamID = Id,
+ streamParms = Parms},
+ State) ->
+ #'StreamDescriptor'{streamID = tr_StreamID(Id, State),
+ streamParms = tr_StreamParms(Parms, 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
+tr_opt_LocalControlDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_LocalControlDescriptor(#'LocalControlDescriptor'{streamMode = Mode,
+ reserveGroup = Group,
+ reserveValue = Value,
+ propertyParms = Props},
+ State) ->
+ #'LocalControlDescriptor'{streamMode = tr_opt_StreamMode(Mode, State),
+ reserveGroup = tr_opt_bool(Group, State),
+ reserveValue = tr_opt_bool(Value, State),
+ propertyParms = [tr_PropertyParm(P, State) || P <- Props]}.
+
+tr_opt_StreamMode(Mode, _State) ->
+ case Mode of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ sendOnly -> sendOnly;
+ recvOnly -> recvOnly;
+ sendRecv -> sendRecv;
+ inactive -> inactive;
+ loopBack -> loopBack
+ end.
+
+tr_Name(Name, State) ->
+ %% BUGBUG: transform
+ %% BUGBUG: NAME = ALPHA *63(ALPHA / DIGIT / "_" )
+ tr_STRING(Name, State, 2, 2).
+
+tr_PkgdName(Name, State) ->
+ %% BUGBUG: transform
+ %% BUGBUG: pkgdName = (NAME / "*") SLASH (ItemID / "*" )
+ tr_OCTET_STRING(Name, State, 4, 4).
+
+%% 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.
+tr_opt_LocalRemoteDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_LocalRemoteDescriptor(#'LocalRemoteDescriptor'{propGrps = Groups},
+ State) ->
+ #'LocalRemoteDescriptor'{propGrps = [tr_PropertyGroup(G, State) || G <- Groups]}.
+
+tr_PropertyGroup(Props, State) ->
+ [tr_PropertyGroupParm(P, State) || P <- Props].
+
+tr_PropertyGroupParm(#'PropertyParm'{name = Name,
+ value = Value},
+ State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ #'PropertyParm'{name = resolve(property, Name, State, Constraint),
+ value = tr_OCTET_STRING(Value, State, 0, infinity)}.
+
+tr_PropertyParm(#'PropertyParm'{name = Name,
+ value = Value,
+ extraInfo = Extra},
+ State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ #'PropertyParm'{name = resolve(property, Name, State, Constraint),
+ value = tr_Value(Value, State),
+ extraInfo = tr_opt_extraInfo(Extra, State)}.
+
+tr_opt_extraInfo(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_extraInfo({relation, Rel}, _State) ->
+ Rel2 =
+ case Rel of
+ greaterThan -> greaterThan;
+ smallerThan -> smallerThan;
+ unequalTo -> unequalTo
+ end,
+ {relation, Rel2};
+tr_opt_extraInfo({range, Range}, State) ->
+ Range2 = tr_bool(Range, State),
+ {range, Range2};
+tr_opt_extraInfo({sublist, Sub}, State) ->
+ Sub2 = tr_bool(Sub, State),
+ {sublist, Sub2}.
+
+tr_opt_TerminationStateDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_TerminationStateDescriptor(#'TerminationStateDescriptor'{propertyParms = Props,
+ eventBufferControl = Control,
+ serviceState = Service},
+ State) ->
+ #'TerminationStateDescriptor'{propertyParms = [tr_PropertyParm(P, State) || P <- Props],
+ eventBufferControl = tr_opt_EventBufferControl(Control, State),
+ serviceState = tr_opt_ServiceState(Service, State)}.
+
+tr_opt_EventBufferControl(Control, _State) ->
+ case Control of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ off -> off;
+ lockStep -> lockStep
+ end.
+
+tr_opt_ServiceState(Service, _State) ->
+ case Service of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ test -> test;
+ outOfSvc -> outOfSvc;
+ inSvc -> inSvc
+ end.
+
+tr_MuxDescriptor(#'MuxDescriptor'{muxType = Type,
+ termList = IdList},
+ State) ->
+ #'MuxDescriptor'{muxType = tr_MuxType(Type, State),
+ termList = [tr_TerminationID(Id, State) || Id <- IdList]}.
+
+tr_MuxType(Type, _State) ->
+ case Type of
+ h221 -> h221;
+ h223 -> h223;
+ h226 -> h226;
+ v76 -> v76
+ end.
+
+tr_opt_StreamID(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_StreamID(Id, State) ->
+ tr_StreamID(Id, State).
+
+tr_StreamID(Id, State) ->
+ tr_UINT16(Id, State).
+
+tr_EventsDescriptor(#'EventsDescriptor'{requestID = Id,
+ eventList = Events},
+ State) ->
+ #'EventsDescriptor'{requestID = tr_opt_RequestID(Id, State),
+ eventList = [tr_RequestedEvent(E, State) || E <- Events]}.
+
+tr_RequestedEvent(#'RequestedEvent'{pkgdName = Name,
+ streamID = Id,
+ evParList = Parms,
+ eventAction = Actions},
+ State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ #'RequestedEvent'{pkgdName = resolve(event, Name, State, Constraint),
+ streamID = tr_opt_StreamID(Id, State),
+ eventAction = tr_opt_RequestedActions(Actions, State),
+ evParList = [tr_EventParameter(P, Name, State) || P <- Parms]}.
+
+tr_opt_RequestedActions(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_RequestedActions(#'RequestedActions'{keepActive = Keep,
+ eventDM = DM,
+ secondEvent = Event,
+ signalsDescriptor = SigDesc},
+ State) ->
+ #'RequestedActions'{keepActive = tr_opt_keepActive(Keep, State),
+ eventDM = tr_opt_EventDM(DM, State),
+ secondEvent = tr_opt_SecondEventsDescriptor(Event, State),
+ signalsDescriptor = tr_opt_SignalsDescriptor(SigDesc, State)}.
+
+tr_opt_keepActive(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_keepActive(Keep, State) ->
+ tr_bool(Keep, State).
+
+tr_opt_EventDM(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_EventDM({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ digitMapName -> tr_DigitMapName(Val, State);
+ digitMapValue -> tr_DigitMapValue(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_opt_SecondEventsDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_SecondEventsDescriptor(#'SecondEventsDescriptor'{requestID = Id,
+ eventList = Events},
+ State) ->
+ #'SecondEventsDescriptor'{requestID = tr_RequestID(Id, State), %% IG v6 6.8 withdrawn
+ eventList = [tr_SecondRequestedEvent(E, State) || E <- Events]}.
+
+tr_SecondRequestedEvent(#'SecondRequestedEvent'{pkgdName = Name,
+ streamID = Id,
+ evParList = Parms,
+ eventAction = Actions},
+ State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ #'SecondRequestedEvent'{pkgdName = resolve(event, Name, State, Constraint),
+ streamID = tr_opt_StreamID(Id, State),
+ eventAction = tr_opt_SecondRequestedActions(Actions, State),
+ evParList = [tr_EventParameter(P, Name, State) || P <- Parms]}.
+
+
+tr_opt_SecondRequestedActions(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_SecondRequestedActions(#'SecondRequestedActions'{keepActive = Keep,
+ eventDM = DM,
+ signalsDescriptor = SigDesc},
+ State) ->
+ #'SecondRequestedActions'{keepActive = tr_opt_keepActive(Keep, State),
+ eventDM = tr_opt_EventDM(DM, State),
+ signalsDescriptor = tr_opt_SignalsDescriptor(SigDesc, State)}.
+
+tr_EventBufferDescriptor(EventSpecs, State) ->
+ [tr_EventSpec(ES, State) || ES <- EventSpecs].
+
+tr_EventSpec(#'EventSpec'{eventName = Name,
+ streamID = Id,
+ eventParList = Parms},
+ State) ->
+ #'EventSpec'{eventName = tr_EventName(Name, State),
+ streamID = tr_opt_StreamID(Id, State),
+ eventParList = [tr_EventParameter(P, Name, State) || P <- Parms]}.
+
+tr_opt_SignalsDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_SignalsDescriptor(SigDesc, State) ->
+ tr_SignalsDescriptor(SigDesc, State).
+
+tr_SignalsDescriptor(SigDesc, State) when is_list(SigDesc) ->
+ [tr_SignalRequest(SigReq, State) || SigReq <- SigDesc].
+
+tr_SignalRequest({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ signal -> tr_Signal(Val, State);
+ seqSigList -> tr_SeqSigList(Val, State)
+ end,
+ {Tag, Val2}.
+
+
+tr_SeqSigList(#'SeqSigList'{id = Id,
+ signalList = SigList},
+ State) when is_list(SigList) ->
+ #'SeqSigList'{id = tr_UINT16(Id, State),
+ signalList = [tr_Signal(Sig, State) || Sig <- SigList]}.
+
+tr_Signal(#'Signal'{signalName = Name,
+ streamID = Id,
+ sigType = Type,
+ duration = Dur,
+ notifyCompletion = Compl,
+ keepActive = Keep,
+ sigParList = Parms},
+ State) ->
+ #'Signal'{signalName = tr_SignalName(Name, State),
+ streamID = tr_opt_StreamID(Id, State),
+ sigType = tr_opt_SignalType(Type, State),
+ duration = tr_opt_duration(Dur, State),
+ notifyCompletion = tr_opt_NotifyCompletion(Compl, State),
+ keepActive = tr_opt_keepActive(Keep, State),
+ sigParList = [tr_SigParameter(P, Name, State) || P <- Parms]}.
+
+tr_opt_duration(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_duration(Dur, State) ->
+ tr_UINT16(Dur, State).
+
+tr_opt_NotifyCompletion(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_NotifyCompletion(Items, State) when is_list(Items) ->
+ [tr_notifyCompletionItem(I, State) || I <- Items].
+
+tr_notifyCompletionItem(Item, _State) ->
+ case Item of
+ onTimeOut -> onTimeOut;
+ onInterruptByEvent -> onInterruptByEvent;
+ onInterruptByNewSignalDescr -> onInterruptByNewSignalDescr;
+ otherReason -> otherReason
+ end.
+
+tr_opt_SignalType(Type, _State) ->
+ case Type of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ brief -> brief;
+ onOff -> onOff;
+ timeOut -> timeOut
+ end.
+
+tr_SignalName(Name, State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ resolve(signal, Name, State, Constraint).
+
+tr_SigParameter(#'SigParameter'{sigParameterName = ParName,
+ value = Value,
+ extraInfo = Extra},
+ SigName,
+ State) ->
+ Constraint = fun(Item) -> tr_Name(Item, State) end,
+ N = resolve({signal_parameter, SigName}, ParName, State, Constraint),
+ #'SigParameter'{sigParameterName = N,
+ value = tr_Value(Value, State),
+ extraInfo = tr_opt_extraInfo(Extra, State)}.
+
+tr_opt_RequestID(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_RequestID(Id, State) ->
+ tr_RequestID(Id, State).
+
+tr_RequestID(Id, _State) when Id =:= ?megaco_all_request_id ->
+ ?megaco_all_request_id;
+tr_RequestID(Id, State) ->
+ tr_UINT32(Id, State).
+
+tr_ModemDescriptor(#'ModemDescriptor'{mtl = Types,
+ mpl = Props},
+ State) when is_list(Types) andalso is_list(Props) ->
+ %% BUGBUG: Does not handle extensionParameter
+ #'ModemDescriptor'{mtl = [tr_ModemType(T, State) || T <- Types],
+ mpl = [tr_PropertyParm(P, State) || P <- Props]}.
+
+tr_ModemType(Type, _State) ->
+ %% BUGBUG: Does not handle extensionParameter
+ case Type of
+ v18 -> v18;
+ v22 -> v22;
+ v22bis -> v22bis;
+ v32 -> v32;
+ v32bis -> v32bis;
+ v34 -> v34;
+ v90 -> v90;
+ v91 -> v91;
+ synchISDN -> synchISDN
+ end.
+
+tr_DigitMapDescriptor(#'DigitMapDescriptor'{digitMapName = Name,
+ digitMapValue = Value},
+ State) ->
+ #'DigitMapDescriptor'{digitMapName = tr_opt_DigitMapName(Name, State),
+ digitMapValue = tr_opt_DigitMapValue(Value, State)}.
+
+tr_opt_DigitMapName(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_DigitMapName(Name, State) ->
+ tr_DigitMapName(Name, State).
+
+tr_DigitMapName(Name, State) ->
+ Constraint = fun(Item) -> tr_Name(Item, State) end,
+ resolve(dialplan, Name, State, Constraint).
+
+tr_opt_DigitMapValue(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_DigitMapValue(Value, State) ->
+ tr_DigitMapValue(Value, State).
+
+tr_DigitMapValue(#'DigitMapValue'{digitMapBody = Body,
+ startTimer = Start,
+ shortTimer = Short,
+ longTimer = Long},
+ State) ->
+ #'DigitMapValue'{startTimer = tr_opt_timer(Start, State),
+ shortTimer = tr_opt_timer(Short, State),
+ longTimer = tr_opt_timer(Long, State),
+ digitMapBody = tr_STRING(Body, State)}. %% BUGBUG: digitMapBody not handled at all
+
+tr_opt_timer(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_timer(Timer, State) ->
+ tr_DIGIT(Timer, State, 0, 99).
+
+tr_ServiceChangeParm(#'ServiceChangeParm'{serviceChangeMethod = Method,
+ serviceChangeAddress = Addr,
+ serviceChangeVersion = Version,
+ serviceChangeProfile = Profile,
+ serviceChangeReason = Reason,
+ serviceChangeDelay = Delay,
+ serviceChangeMgcId = MgcId,
+ timeStamp = Time},
+ State) ->
+ #'ServiceChangeParm'{serviceChangeMethod = tr_ServiceChangeMethod(Method, State),
+ serviceChangeAddress = tr_opt_ServiceChangeAddress(Addr, State),
+ serviceChangeVersion = tr_opt_serviceChangeVersion(Version, State),
+ serviceChangeProfile = tr_opt_ServiceChangeProfile(Profile, State),
+ serviceChangeReason = tr_serviceChangeReason(Reason, State),
+ serviceChangeDelay = tr_opt_serviceChangeDelay(Delay, State),
+ serviceChangeMgcId = tr_opt_serviceChangeMgcId(MgcId, State),
+ timeStamp = tr_opt_TimeNotation(Time, State)}.
+
+tr_ServiceChangeMethod(Method, _State) ->
+ case Method of
+ failover -> failover;
+ forced -> forced;
+ graceful -> graceful;
+ restart -> restart;
+ disconnected -> disconnected;
+ handOff -> handOff
+ end. %% BUGBUG: extension
+
+tr_opt_ServiceChangeAddress(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_ServiceChangeAddress({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ portNumber -> tr_portNumber(Val, State);
+ ip4Address -> tr_IP4Address(Val, State);
+ ip6Address -> tr_IP6Address(Val, State);
+ domainName -> tr_DomainName(Val, State);
+ deviceName -> tr_PathName(Val, State);
+ mtpAddress -> tr_mtpAddress(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_opt_serviceChangeVersion(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_serviceChangeVersion(Version, State) ->
+ tr_version(Version, State).
+
+tr_opt_ServiceChangeProfile(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+%% Decode
+tr_opt_ServiceChangeProfile({'ServiceChangeProfile', ProfileName}, State) ->
+ case string:tokens(ProfileName, "/") of
+ [Name0, Version0] ->
+ Name = tr_STRING(Name0, State, 1, 64),
+ Version = tr_version(list_to_integer(Version0), State),
+ #'ServiceChangeProfile'{profileName = Name,
+ version = Version}
+ end;
+%% Encode
+tr_opt_ServiceChangeProfile(#'ServiceChangeProfile'{profileName = Name0,
+ version = Version0},
+ State) ->
+ Name = tr_STRING(Name0, State, 1, 64),
+ Version = tr_version(Version0, State),
+ ProfileName = lists:flatten(io_lib:format("~s/~w", [Name, Version])),
+ {'ServiceChangeProfile', ProfileName}.
+
+tr_serviceChangeReason([_] = Reason, State) ->
+ tr_Value(Reason, State).
+
+tr_opt_serviceChangeDelay(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_serviceChangeDelay(Delay, State) ->
+ tr_UINT32(Delay, State).
+
+tr_opt_serviceChangeMgcId(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_serviceChangeMgcId(MgcId, State) ->
+ tr_MId(MgcId, State).
+
+tr_opt_portNumber(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_portNumber(Port, State) ->
+ tr_portNumber(Port, State).
+
+tr_portNumber(Port, State) when is_integer(Port) andalso (Port >= 0) ->
+ tr_UINT16(Port, State).
+
+tr_ServiceChangeResParm(#'ServiceChangeResParm'{serviceChangeMgcId = MgcId,
+ serviceChangeAddress = Addr,
+ serviceChangeVersion = Version,
+ serviceChangeProfile = Profile,
+ timeStamp = Time},
+ State) ->
+ #'ServiceChangeResParm'{serviceChangeMgcId = tr_opt_serviceChangeMgcId(MgcId, State),
+ serviceChangeAddress = tr_opt_ServiceChangeAddress(Addr, State),
+ serviceChangeVersion = tr_opt_serviceChangeVersion(Version, State),
+ serviceChangeProfile = tr_opt_ServiceChangeProfile(Profile, State),
+ timeStamp = tr_opt_TimeNotation(Time, State)}.
+
+tr_PackagesDescriptor(Items, State) when is_list(Items) ->
+ [tr_PackagesItem(I, State) || I <- Items].
+
+tr_PackagesItem(#'PackagesItem'{packageName = Name,
+ packageVersion = Version},
+ State) ->
+ Constraint = fun(Item) -> tr_Name(Item, State) end,
+ #'PackagesItem'{packageName = resolve(package, Name, State, Constraint),
+ packageVersion = tr_UINT16(Version, State)}.
+
+tr_StatisticsDescriptor(Parms, State) when is_list(Parms) ->
+ [tr_StatisticsParameter(P, State) || P <- Parms].
+
+tr_StatisticsParameter(#'StatisticsParameter'{statName = Name,
+ statValue = Value},
+ State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ #'StatisticsParameter'{statName = resolve(statistics, Name, State, Constraint),
+ statValue = tr_opt_Value(Value, State)}.
+
+tr_opt_TimeNotation(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_TimeNotation(#'TimeNotation'{date = Date,
+ time = Time},
+ State) ->
+ #'TimeNotation'{date = tr_STRING(Date, State, 8, 8), % "yyyymmdd"
+ time = tr_STRING(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.
+
+tr_opt_Value(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_Value(Value, State) ->
+ tr_Value(Value, State).
+
+tr_Value(Strings, _State) when is_list(Strings) ->
+ [[Char || Char <- String] || String <- Strings].
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Encode an octet string, escape } by \ if necessary
+tr_OCTET_STRING(String, _State, Min, Max) when is_list(String) ->
+ verify_count(length(String), Min, Max),
+ String.
+
+tr_QUOTED_STRING(String, _State) when is_list(String) ->
+ verify_count(length(String), 1, infinity),
+ String.
+
+%% 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
+tr_HEXDIG(Octets, _State, Min, Max) when is_list(Octets) ->
+ verify_count(length(Octets), Min, Max),
+ Octets.
+
+tr_DIGIT(Val, State, Min, Max) ->
+ tr_integer(Val, State, Min, Max).
+
+tr_STRING(String, _State) when is_list(String) ->
+ String.
+
+tr_STRING(String, _State, Min, Max) when is_list(String) ->
+ verify_count(length(String), Min, Max),
+ String.
+
+tr_UINT16(Val, State) ->
+ tr_integer(Val, State, 0, 65535).
+
+tr_UINT32(Val, State) ->
+ tr_integer(Val, State, 0, 4294967295).
+
+tr_integer(Int, _State, Min, Max) ->
+ verify_count(Int, Min, Max),
+ Int.
+
+%% 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.
+
+
+% i(F,A) ->
+% %% i(true,F,A).
+% i(get(dbg),F,A).
+
+% i(true,F,A) ->
+% S1 = io_lib:format("TRANSF-v1: " ++ F ++ "~n",A),
+% S2 = lists:flatten(S1),
+% io:format("~s",[S2]);
+% i(_,_F,_A) ->
+% ok.
diff --git a/lib/megaco/src/binary/megaco_binary_transformer_v2.erl b/lib/megaco/src/binary/megaco_binary_transformer_v2.erl
new file mode 100644
index 0000000000..686e384a29
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_binary_transformer_v2.erl
@@ -0,0 +1,1544 @@
+%%
+%% %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: Transform internal form of Megaco/H.248 messages
+%%----------------------------------------------------------------------
+
+-module(megaco_binary_transformer_v2).
+
+-include_lib("megaco/include/megaco.hrl").
+%% -include_lib("megaco/include/megaco_message.hrl").
+-include_lib("megaco/include/megaco_message_v2.hrl").
+
+-export([tr_message/3, tr_transaction/3]).
+
+-define(DEFAULT_NAME_RESOLVER,megaco_binary_name_resolver_v2).
+-define(error(R), erlang:error({error, R})).
+
+-record(state, {mode, % verify | encode | decode
+ resolver_module, %
+ resolver_options}).
+
+resolve(Type, Item, State, Constraint) ->
+ case State#state.mode of
+ verify ->
+ Item;
+ encode ->
+ %% i("resolve(encode) -> encode: ~p",[Item]),
+ Mod = State#state.resolver_module,
+ Opt = State#state.resolver_options,
+ EncodedItem = Mod:encode_name(Opt, Type, Item),
+ %% i("resolve -> verify contraint for ~p",[EncodedItem]),
+ verify_constraint(EncodedItem, Constraint);
+ decode ->
+ %% i("resolve(decode) -> verify contraint for ~p",[Item]),
+ DecodedItem = verify_constraint(Item, Constraint),
+ Mod = State#state.resolver_module,
+ Opt = State#state.resolver_options,
+ %% i("resolve(decode) -> decode: ~p",[DecodedItem]),
+ Mod:decode_name(Opt, Type, DecodedItem)
+ end.
+
+verify_constraint(Item, valid) ->
+ Item;
+verify_constraint(Item, Constraint) when is_function(Constraint) ->
+ Constraint(Item).
+
+tr_message(MegaMsg, Mode, Config) ->
+ case Config of
+ [native] ->
+ MegaMsg;
+ [verify] ->
+ State = #state{mode = verify},
+ tr_MegacoMessage(MegaMsg, State);
+ [] ->
+ State = #state{mode = Mode,
+ resolver_module = ?DEFAULT_NAME_RESOLVER,
+ resolver_options = [8, 8, 8]},
+ tr_MegacoMessage(MegaMsg, State);
+ [{binary_name_resolver, {Module, Options}}] when is_atom(Module) ->
+ State = #state{mode = Mode,
+ resolver_module = Module,
+ resolver_options = Options},
+ tr_MegacoMessage(MegaMsg, State)
+ end.
+
+tr_transaction(Trans, Mode, Config) ->
+ case Config of
+ [native] ->
+ Trans;
+ [verify] ->
+ State = #state{mode = verify},
+ tr_Transaction(Trans, State);
+ [] ->
+ State = #state{mode = Mode,
+ resolver_module = ?DEFAULT_NAME_RESOLVER,
+ resolver_options = [8, 8, 8]},
+ tr_Transaction(Trans, State);
+ [{binary_name_resolver, {Module, Options}}] when is_atom(Module) ->
+ State = #state{mode = Mode,
+ resolver_module = Module,
+ resolver_options = Options},
+ tr_Transaction(Trans, State)
+ end.
+
+tr_MegacoMessage(#'MegacoMessage'{authHeader = Auth,
+ mess = Mess},
+ State) ->
+% i("tr_MegacoMessage -> entry with"
+% "~n Auth: ~p"
+% "~n Mess: ~p"
+% "~n State: ~p", [Auth, Mess, State]),
+ #'MegacoMessage'{authHeader = tr_opt_AuthenticationHeader(Auth, State),
+ mess = tr_Message(Mess, State)}.
+
+tr_opt_AuthenticationHeader(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_AuthenticationHeader(#'AuthenticationHeader'{secParmIndex = SPI,
+ seqNum = SN,
+ ad = AuthData},
+ State) ->
+ #'AuthenticationHeader'{secParmIndex = tr_SecurityParmIndex(SPI, State),
+ seqNum = tr_SequenceNum(SN, State),
+ ad = tr_AuthData(AuthData, State)}.
+
+tr_SecurityParmIndex(SPI, State) ->
+ tr_HEXDIG(SPI, State, 4, 4). % BUGBUG: Mismatch between ASN.1 and ABNF
+
+tr_SequenceNum(SN, State) ->
+ tr_HEXDIG(SN, State, 4, 4). % BUGBUG: Mismatch between ASN.1 and ABNF
+
+tr_AuthData(AuthData, State) ->
+ tr_HEXDIG(AuthData, State, 12, 32). % BUGBUG: Mismatch between ASN.1 and ABNF
+
+tr_Message(#'Message'{version = Version,
+ mId = MID,
+ messageBody = Body},
+ State) ->
+ #'Message'{version = tr_version(Version, State),
+ mId = tr_MId(MID, State),
+ messageBody = tr_Message_messageBody(Body, State)}.
+
+tr_version(Version, State) ->
+ tr_DIGIT(Version, State, 0, 99).
+
+tr_Message_messageBody({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ messageError -> tr_ErrorDescriptor(Val, State);
+ transactions when is_list(Val) -> [tr_Transaction(T, State) || T <- Val]
+ end,
+ {Tag, Val2}.
+
+tr_MId({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ ip4Address -> tr_IP4Address(Val, State);
+ ip6Address -> tr_IP6Address(Val, State);
+ domainName -> tr_DomainName(Val, State);
+ deviceName -> tr_PathName(Val, State);
+ mtpAddress -> tr_mtpAddress(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_mtpAddress(MtpAddr, State) ->
+ tr_OCTET_STRING(MtpAddr, State, 2, 4). % BUGBUG: Mismatch between ASN.1 and ABNF
+
+tr_DomainName(#'DomainName'{name = Name,
+ portNumber = Port},
+ State) ->
+ Domain = #'DomainName'{name = tr_STRING(Name, State), % BUGBUG: Mismatch between ASN.1 and ABNF
+ portNumber = tr_opt_portNumber(Port, State)},
+ {domainName, Domain2} = resolve(mid, {domainName, Domain}, State, valid),
+ Domain2.
+
+tr_IP4Address(#'IP4Address'{address = [A1, A2, A3, A4],
+ portNumber = Port},
+ State) ->
+ #'IP4Address'{address = [tr_V4hex(A1, State),
+ tr_V4hex(A2, State),
+ tr_V4hex(A3, State),
+ tr_V4hex(A4, State)],
+ portNumber = tr_opt_portNumber(Port, State)}.
+
+tr_V4hex(Val, State) ->
+ tr_DIGIT(Val, State, 0, 255).
+
+tr_IP6Address(_Val, _State) ->
+ ?error(ipv6_not_supported). %% BUGBUG: nyi
+
+tr_PathName(Path, State) ->
+ %% BUGBUG: ["*"] NAME *("/" / "*"/ ALPHA / DIGIT /"_" / "$" )
+ %% BUGBUG: ["@" pathDomainName ]
+ Constraint = fun({deviceName, Item}) -> tr_STRING(Item, State, 1, 64) end,
+ resolve(mid, {deviceName, Path}, State, Constraint).
+
+tr_Transaction({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ transactionRequest -> tr_TransactionRequest(Val, State);
+ transactionPending -> tr_TransactionPending(Val, State);
+ transactionReply -> tr_TransactionReply(Val, State);
+ transactionResponseAck -> [tr_TransactionAck(T, State) || T <- Val]
+ end,
+ {Tag, Val2}.
+
+tr_TransactionAck(#'TransactionAck'{firstAck = First,
+ lastAck = Last},
+ State) ->
+ #'TransactionAck'{firstAck = tr_TransactionId(First, State),
+ lastAck = tr_opt_TransactionId(Last, State)}.
+
+tr_opt_TransactionId(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_TransactionId(Id, State) ->
+ tr_TransactionId(Id, State).
+
+tr_TransactionId(Id, State) ->
+ tr_UINT32(Id, State).
+
+tr_TransactionRequest(#'TransactionRequest'{transactionId = Id,
+ actions = Actions},
+ State) when is_list(Actions) ->
+
+ #'TransactionRequest'{transactionId = tr_TransactionId(Id, State),
+ actions = [tr_ActionRequest(ActReq, State) || ActReq <- Actions]}.
+
+tr_TransactionPending(#'TransactionPending'{transactionId = Id},
+ State) ->
+ #'TransactionPending'{transactionId = tr_TransactionId(Id, State)}.
+
+tr_TransactionReply(#'TransactionReply'{transactionId = Id,
+ immAckRequired = ImmAck,
+ transactionResult = TransRes},
+ State) ->
+ #'TransactionReply'{transactionId = tr_TransactionId(Id, State),
+ immAckRequired = tr_opt_null(ImmAck, State),
+ transactionResult = tr_TransactionReply_transactionResult(TransRes, State)}.
+
+tr_opt_null(asn1_NOVALUE, _State) -> asn1_NOVALUE;
+tr_opt_null('NULL', _State) -> 'NULL'.
+
+tr_TransactionReply_transactionResult({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ transactionError ->
+ tr_ErrorDescriptor(Val, State);
+ actionReplies when is_list(Val) andalso (Val =/= []) ->
+ [tr_ActionReply(ActRep, State) || ActRep <- Val]
+ end,
+ {Tag, Val2}.
+
+tr_opt_ErrorDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_ErrorDescriptor(ErrDesc, State) ->
+ tr_ErrorDescriptor(ErrDesc, State).
+
+tr_ErrorDescriptor(#'ErrorDescriptor'{errorCode = Code,
+ errorText = Text},
+ State) ->
+ #'ErrorDescriptor'{errorCode = tr_ErrorCode(Code, State),
+ errorText = tr_opt_ErrorText(Text, State)}.
+
+tr_ErrorCode(Code, State) ->
+ tr_DIGIT(Code, State, 0, 999).
+
+tr_opt_ErrorText(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_ErrorText(Text, State) ->
+ tr_QUOTED_STRING(Text, State).
+
+tr_ContextID(CtxId, State) ->
+ case CtxId of
+ ?megaco_all_context_id -> ?megaco_all_context_id;
+ ?megaco_null_context_id -> ?megaco_null_context_id;
+ ?megaco_choose_context_id -> ?megaco_choose_context_id;
+ Int when is_integer(Int) -> tr_UINT32(Int, State)
+ end.
+
+tr_ActionRequest(#'ActionRequest'{contextId = CtxId,
+ contextRequest = CtxReq,
+ contextAttrAuditReq = CtxAuditReq,
+ commandRequests = CmdReqList},
+ State) ->
+ #'ActionRequest'{contextId = tr_ContextID(CtxId, State),
+ contextRequest = tr_opt_ContextRequest(CtxReq, State),
+ contextAttrAuditReq = tr_opt_ContextAttrAuditRequest(CtxAuditReq, State),
+ commandRequests = [tr_CommandRequest(CmdReq, State) || CmdReq <- CmdReqList]}.
+
+tr_ActionReply(#'ActionReply'{contextId = CtxId,
+ errorDescriptor = ErrDesc,
+ contextReply = CtxRep,
+ commandReply = CmdRepList},
+ State) ->
+ CmdRepList2 = [tr_CommandReply(CmdRep, State) || CmdRep <- CmdRepList],
+ #'ActionReply'{contextId = tr_ContextID(CtxId, State),
+ errorDescriptor = tr_opt_ErrorDescriptor(ErrDesc, State),
+ contextReply = tr_opt_ContextRequest(CtxRep, State),
+ commandReply = CmdRepList2}.
+
+tr_opt_ContextRequest(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_ContextRequest(#'ContextRequest'{priority = Prio,
+ emergency = Em,
+ topologyReq = TopReqList},
+ State) ->
+ Prio2 =
+ case Prio of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> tr_integer(Prio, State, 0, 15)
+ end,
+ Em2 =
+ case Em of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ false -> false;
+ true -> true
+ end,
+ TopReqList2 =
+ case TopReqList of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> [tr_TopologyRequest(TopReq, State) ||
+ TopReq <- TopReqList]
+ end,
+ #'ContextRequest'{priority = Prio2,
+ emergency = Em2,
+ topologyReq = TopReqList2}.
+
+tr_opt_ContextAttrAuditRequest(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_ContextAttrAuditRequest(#'ContextAttrAuditRequest'{topology = Top,
+ emergency = Em,
+ priority = Prio},
+ State) ->
+ #'ContextAttrAuditRequest'{topology = tr_opt_null(Top, State),
+ emergency = tr_opt_null(Em, State),
+ priority = tr_opt_null(Prio, State)}.
+
+tr_CommandRequest(#'CommandRequest'{command = Cmd,
+ optional = Opt,
+ wildcardReturn = Wild},
+ State) ->
+ #'CommandRequest'{optional = tr_opt_null(Opt, State),
+ wildcardReturn = tr_opt_null(Wild, State),
+ command = tr_Command(Cmd, State)}.
+
+tr_Command({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ addReq -> tr_AmmRequest(Val, State);
+ moveReq -> tr_AmmRequest(Val, State);
+ modReq -> tr_AmmRequest(Val, State);
+ subtractReq -> tr_SubtractRequest(Val, State);
+ auditCapRequest -> tr_AuditRequest(Val, State);
+ auditValueRequest -> tr_AuditRequest(Val, State);
+ notifyReq -> tr_NotifyRequest(Val, State);
+ serviceChangeReq -> tr_ServiceChangeRequest(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_CommandReply({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ addReply -> tr_AmmsReply(Val, State);
+ moveReply -> tr_AmmsReply(Val, State);
+ modReply -> tr_AmmsReply(Val, State);
+ subtractReply -> tr_AmmsReply(Val, State);
+ auditCapReply -> tr_AuditReply(Val, State);
+ auditValueReply -> tr_AuditReply(Val, State);
+ notifyReply -> tr_NotifyReply(Val, State);
+ serviceChangeReply -> tr_ServiceChangeReply(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_TopologyRequest(#'TopologyRequest'{terminationFrom = From,
+ terminationTo = To,
+ topologyDirection = Dir},
+ State) ->
+ Dir2 =
+ case Dir of
+ bothway -> bothway;
+ isolate -> isolate;
+ oneway -> oneway
+ end,
+ #'TopologyRequest'{terminationFrom = tr_TerminationID(From, State),
+ terminationTo = tr_TerminationID(To, State),
+ topologyDirection = Dir2}.
+
+tr_AmmRequest(#'AmmRequest'{terminationID = IdList,
+ descriptors = DescList},
+ State) ->
+ #'AmmRequest'{terminationID = [tr_TerminationID(Id, State) ||
+ Id <- IdList],
+ descriptors = tr_ammDescriptors(DescList, [], State)}.
+
+tr_ammDescriptors([], Acc, _State) ->
+ lists:reverse(Acc);
+tr_ammDescriptors([Desc|Descs], Acc, State) ->
+ case tr_ammDescriptor(Desc, State) of
+ {_, deprecated} when State#state.mode =:= encode ->
+ ?error({deprecated, Desc});
+ {_, deprecated} when State#state.mode =:= decode ->
+ %% SKIP
+ tr_ammDescriptors(Descs, Acc, State);
+ {_, deprecated} ->
+ %% SKIP
+ tr_ammDescriptors(Descs, Acc, State);
+ NewDesc ->
+ tr_ammDescriptors(Descs, [NewDesc|Acc], State)
+ end.
+
+tr_ammDescriptor({Tag, Desc}, State) ->
+ Desc2 =
+ case Tag of
+ mediaDescriptor -> tr_MediaDescriptor(Desc, State);
+ modemDescriptor -> tr_ModemDescriptor(Desc, State);
+ muxDescriptor -> tr_MuxDescriptor(Desc, State);
+ eventsDescriptor -> tr_EventsDescriptor(Desc, State);
+ eventBufferDescriptor -> tr_EventBufferDescriptor(Desc, State);
+ signalsDescriptor -> tr_SignalsDescriptor(Desc, State);
+ digitMapDescriptor -> tr_DigitMapDescriptor(Desc, State);
+ auditDescriptor -> tr_AuditDescriptor(Desc, State)
+ end,
+ {Tag, Desc2}.
+
+tr_AmmsReply(#'AmmsReply'{terminationID = IdList,
+ terminationAudit = TermAudit},
+ State) ->
+ TermAudit2 =
+ case TermAudit of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> tr_TerminationAudit(TermAudit, State)
+ end,
+ #'AmmsReply'{terminationID = [tr_TerminationID(Id, State) ||
+ Id <- IdList],
+ terminationAudit = TermAudit2}.
+
+tr_SubtractRequest(#'SubtractRequest'{terminationID = IdList,
+ auditDescriptor = Desc},
+ State) ->
+ #'SubtractRequest'{terminationID = [tr_TerminationID(Id, State) ||
+ Id <- IdList],
+ auditDescriptor = tr_opt_AuditDescriptor(Desc, State)}.
+
+tr_AuditRequest(#'AuditRequest'{terminationID = Id,
+ auditDescriptor = Desc},
+ State) ->
+ #'AuditRequest'{terminationID = tr_TerminationID(Id, State),
+ auditDescriptor = tr_AuditDescriptor(Desc, State)}.
+
+%% auditReply = (AuditValueToken / AuditCapToken )
+%% ( contextTerminationAudit / auditOther)
+%% auditOther = EQUAL TerminationID LBRKT
+%% terminationAudit RBRKT
+%% terminationAudit = auditReturnParameter *(COMMA auditReturnParameter)
+%%
+%% contextTerminationAudit = EQUAL CtxToken ( terminationIDList /
+%% LBRKT errorDescriptor RBRKT )
+
+tr_AuditReply({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ contextAuditResult ->
+ [tr_TerminationID(Id, State) || Id <- Val];
+ error ->
+ tr_ErrorDescriptor(Val, State);
+ auditResult ->
+ tr_AuditResult(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_AuditResult(#'AuditResult'{terminationID = Id,
+ terminationAuditResult = AuditRes},
+ State) ->
+ #'AuditResult'{terminationID = tr_TerminationID(Id, State),
+ terminationAuditResult = tr_TerminationAudit(AuditRes, State)}.
+
+tr_opt_AuditDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_AuditDescriptor(Desc, State) ->
+ tr_AuditDescriptor(Desc, State).
+
+%% BUGBUG BUGBUG BUGBUG
+%% With this construction it is possible to have both auditToken
+%% and auditPropertyToken, but it is actually valid?
+tr_AuditDescriptor(#'AuditDescriptor'{auditToken = Tokens,
+ auditPropertyToken = APTs},
+ State) ->
+ Tokens2 =
+ case Tokens of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> [tr_auditItem(Token, State) || Token <- Tokens]
+ end,
+ %% v2
+ APTs2 =
+ case APTs of
+ asn1_NOVALUE ->
+ asn1_NOVALUE;
+ _ ->
+ [tr_indAuditParameter(APT, State) || APT <- APTs]
+ end,
+ #'AuditDescriptor'{auditToken = Tokens2,
+ auditPropertyToken = APTs2}.
+
+tr_auditItem(Token, _State) ->
+ case Token of
+ muxToken -> muxToken;
+ modemToken -> modemToken;
+ mediaToken -> mediaToken;
+ eventsToken -> eventsToken;
+ signalsToken -> signalsToken;
+ digitMapToken -> digitMapToken;
+ statsToken -> statsToken;
+ observedEventsToken -> observedEventsToken;
+ packagesToken -> packagesToken;
+ eventBufferToken -> eventBufferToken
+ end.
+
+%% --- v2 begin ---
+
+tr_indAuditParameter({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ indAudMediaDescriptor ->
+ tr_indAudMediaDescriptor(Val, State);
+ indAudEventsDescriptor ->
+ tr_indAudEventsDescriptor(Val, State);
+ indAudSignalsDescriptor ->
+ tr_indAudSignalsDescriptor(Val, State);
+ indAudDigitMapDescriptor ->
+ tr_indAudDigitMapDescriptor(Val, State);
+ indAudEventBufferDescriptor ->
+ tr_indAudEventBufferDescriptor(Val, State);
+ indAudStatisticsDescriptor ->
+ tr_indAudStatisticsDescriptor(Val, State);
+ indAudPackagesDescriptor ->
+ tr_indAudPackagesDescriptor(Val, State)
+ end,
+ {Tag, Val2}.
+
+
+%% -
+
+tr_indAudMediaDescriptor(#'IndAudMediaDescriptor'{termStateDescr = TSD,
+ streams = S},
+ State) ->
+ TSD2 =
+ case TSD of
+ asn1_NOVALUE ->
+ asn1_NOVALUE;
+ _ ->
+ tr_indAudTerminationStateDescriptor(TSD, State)
+ end,
+ S2 =
+ case S of
+ asn1_NOVALUE ->
+ asn1_NOVALUE;
+ {oneStream, OS} ->
+ {oneStream, tr_indAudStreamParms(OS, State)};
+ {multiStream, MS} ->
+ MS2 = [tr_indAudStreamDescriptor(MS1, State) || MS1 <- MS],
+ {multiStream, MS2}
+ end,
+ #'IndAudMediaDescriptor'{termStateDescr = TSD2,
+ streams = S2}.
+
+tr_indAudTerminationStateDescriptor(Val, State)
+ when is_record(Val, 'IndAudTerminationStateDescriptor') ->
+ #'IndAudTerminationStateDescriptor'{propertyParms = Parms,
+ eventBufferControl = EBC,
+ serviceState = SS} = Val,
+ Parms2 = [tr_indAudPropertyParm(Parm, State) || Parm <- Parms],
+ EBC2 = tr_opt_null(EBC, State),
+ SS2 = tr_opt_null(SS, State),
+ #'IndAudTerminationStateDescriptor'{propertyParms = Parms2,
+ eventBufferControl = EBC2,
+ serviceState = SS2}.
+
+
+tr_indAudStreamParms(#'IndAudStreamParms'{localControlDescriptor = LCD,
+ localDescriptor = LD,
+ remoteDescriptor = RD},
+ State) ->
+ LCD2 =
+ case LCD of
+ asn1_NOVALUE ->
+ asn1_NOVALUE;
+ _ ->
+ tr_indAudLocalControlDescriptor(LCD, State)
+ end,
+ LD2 =
+ case LD of
+ asn1_NOVALUE ->
+ asn1_NOVALUE;
+ _ ->
+ tr_indAudLocalRemoteDescriptor(LD, State)
+ end,
+ RD2 =
+ case RD of
+ asn1_NOVALUE ->
+ asn1_NOVALUE;
+ _ ->
+ tr_indAudLocalRemoteDescriptor(RD, State)
+ end,
+ #'IndAudStreamParms'{localControlDescriptor = LCD2,
+ localDescriptor = LD2,
+ remoteDescriptor = RD2}.
+
+tr_indAudLocalControlDescriptor(Val, State)
+ when is_record(Val, 'IndAudLocalControlDescriptor') ->
+ #'IndAudLocalControlDescriptor'{streamMode = M,
+ reserveValue = V,
+ reserveGroup = G,
+ propertyParms = P} = Val,
+ M2 = tr_opt_null(M, State),
+ V2 = tr_opt_null(V, State),
+ G2 = tr_opt_null(G, State),
+ P2 = tr_indAudLocalControlDescriptor_propertyParms(P, State),
+ #'IndAudLocalControlDescriptor'{streamMode = M2,
+ reserveValue = V2,
+ reserveGroup = G2,
+ propertyParms = P2}.
+
+tr_indAudLocalControlDescriptor_propertyParms(Parms, State)
+ when is_list(Parms) andalso (length(Parms) > 0) ->
+ [tr_indAudPropertyParm(Parm, State) || Parm <- Parms];
+tr_indAudLocalControlDescriptor_propertyParms(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE.
+
+tr_indAudLocalRemoteDescriptor(#'IndAudLocalRemoteDescriptor'{propGroupID = ID,
+ propGrps = Grps},
+ State) ->
+ #'IndAudLocalRemoteDescriptor'{propGroupID = tr_opt_UINT16(ID, State),
+ propGrps = tr_indAudPropertyGroup(Grps,
+ State)}.
+
+tr_indAudPropertyGroup(Grps, State) when is_list(Grps) ->
+ [tr_indAudPropertyParm(Parm, State) || Parm <- Grps].
+
+tr_indAudPropertyParm(#'IndAudPropertyParm'{name = Name0}, State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ Name = resolve(property, Name0, State, Constraint),
+ #'IndAudPropertyParm'{name = Name}.
+
+
+tr_indAudStreamDescriptor(#'IndAudStreamDescriptor'{streamID = ID,
+ streamParms = Parms},
+ State) ->
+ #'IndAudStreamDescriptor'{streamID = tr_StreamID(ID, State),
+ streamParms = tr_indAudStreamParms(Parms,
+ State)}.
+
+
+%% -
+
+tr_indAudEventsDescriptor(#'IndAudEventsDescriptor'{requestID = RID,
+ pkgdName = Name0,
+ streamID = SID},
+ State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ Name = resolve(event, Name0, State, Constraint),
+ #'IndAudEventsDescriptor'{requestID = tr_opt_RequestID(RID, State),
+ pkgdName = Name,
+ streamID = tr_opt_StreamID(SID, State)}.
+
+
+%% -
+
+tr_indAudSignalsDescriptor({Tag, Val}, State) ->
+ case Tag of
+ signal ->
+ {signal, tr_indAudSignal(Val, State)};
+ seqSigList ->
+ {seqSigList, tr_indAudSeqSigList(Val, State)}
+ end.
+
+tr_opt_indAudSignal(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_indAudSignal(Val, State) ->
+ tr_indAudSignal(Val, State).
+
+tr_indAudSignal(#'IndAudSignal'{signalName = Name0,
+ streamID = SID}, State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ Name = resolve(signal, Name0, State, Constraint),
+ #'IndAudSignal'{signalName = Name,
+ streamID = tr_opt_StreamID(SID, State)}.
+
+tr_indAudSeqSigList(#'IndAudSeqSigList'{id = ID,
+ signalList = SigList}, State) ->
+ #'IndAudSeqSigList'{id = tr_integer(ID, State, 0, 65535),
+ signalList = tr_opt_indAudSignal(SigList, State)}.
+
+%% -
+
+tr_indAudDigitMapDescriptor(#'IndAudDigitMapDescriptor'{digitMapName = Name},
+ State) ->
+ #'IndAudDigitMapDescriptor'{digitMapName =
+ tr_opt_DigitMapName(Name, State)}.
+
+
+%% -
+
+tr_indAudEventBufferDescriptor(#'IndAudEventBufferDescriptor'{eventName = N,
+ streamID = SID},
+ State) ->
+% i("tr_indAudEventBufferDescriptor -> entry with"
+% "~n N: ~p"
+% "~n SID: ~p", [N, SID]),
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ Name = resolve(event, N, State, Constraint),
+% i("tr_indAudEventBufferDescriptor -> entry with"
+% "~n Name: ~p", [Name]),
+ #'IndAudEventBufferDescriptor'{eventName = Name,
+ streamID = tr_opt_StreamID(SID, State)}.
+
+%% -
+
+tr_indAudStatisticsDescriptor(#'IndAudStatisticsDescriptor'{statName = N},
+ State) ->
+% i("tr_indAudEventBufferDescriptor -> entry with"
+% "~n N: ~p"
+% "~n SID: ~p", [N, SID]),
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ Name = resolve(statistics, N, State, Constraint),
+ #'IndAudStatisticsDescriptor'{statName = Name}.
+
+
+%% -
+
+tr_indAudPackagesDescriptor(#'IndAudPackagesDescriptor'{packageName = N,
+ packageVersion = V},
+ State) ->
+% i("tr_indAudPackagesDescriptor -> entry with"
+% "~n N: ~p"
+% "~n V: ~p", [N, V]),
+ Constraint = fun(Item) -> tr_Name(Item, State) end,
+ Name = resolve(package, N, State, Constraint),
+% i("tr_indAudPackagesDescriptor -> entry with"
+% "~n Name: ~p", [Name]),
+ #'IndAudPackagesDescriptor'{packageName = Name,
+ packageVersion = tr_integer(V, State, 0, 99)}.
+
+%% -- v2 end --
+
+
+tr_TerminationAudit(ParmList, State) when is_list(ParmList) ->
+ do_tr_TerminationAudit(ParmList, [], State).
+
+do_tr_TerminationAudit([], Acc, _State) ->
+ lists:reverse(Acc);
+do_tr_TerminationAudit([Parm|ParmList], Acc, State) ->
+ case tr_AuditReturnParameter(Parm, State) of
+ {_, deprecated} when State#state.mode =:= encode ->
+ ?error({deprecated, Parm});
+ {_, deprecated} when State#state.mode =:= decode ->
+ %% SKIP
+ do_tr_TerminationAudit(ParmList, Acc, State);
+ {_, deprecated} ->
+ %% SKIP
+ do_tr_TerminationAudit(ParmList, Acc, State);
+ NewParm ->
+ do_tr_TerminationAudit(ParmList, [NewParm|Acc], State)
+ end.
+
+tr_AuditReturnParameter({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ errorDescriptor ->
+ tr_ErrorDescriptor(Val, State);
+ mediaDescriptor ->
+ tr_MediaDescriptor(Val, State);
+ modemDescriptor ->
+ tr_ModemDescriptor(Val, State);
+ muxDescriptor ->
+ tr_MuxDescriptor(Val, State);
+ eventsDescriptor ->
+ tr_EventsDescriptor(Val, State);
+ eventBufferDescriptor ->
+ tr_EventBufferDescriptor(Val, State);
+ signalsDescriptor ->
+ tr_SignalsDescriptor(Val, State);
+ digitMapDescriptor ->
+ tr_DigitMapDescriptor(Val, State);
+ observedEventsDescriptor ->
+ tr_ObservedEventsDescriptor(Val, State);
+ statisticsDescriptor ->
+ tr_StatisticsDescriptor(Val, State);
+ packagesDescriptor ->
+ tr_PackagesDescriptor(Val, State);
+ emptyDescriptors ->
+ tr_EmptyDescriptors(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_EmptyDescriptors(#'AuditDescriptor'{auditToken = Tokens},
+ State) ->
+ case Tokens of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> [tr_auditItem(Token, State) || Token <- Tokens]
+ end.
+
+tr_NotifyRequest(#'NotifyRequest'{terminationID = IdList,
+ observedEventsDescriptor = ObsDesc,
+ errorDescriptor = ErrDesc},
+ State) ->
+ %% BUGBUG: Mismatch between ASN.1 and ABNF
+ %% BUGBUG: The following ought to be a 'choice'
+ #'NotifyRequest'{terminationID = [tr_TerminationID(Id, State) ||
+ Id <- IdList],
+ observedEventsDescriptor = tr_ObservedEventsDescriptor(ObsDesc, State),
+ errorDescriptor = tr_opt_ErrorDescriptor(ErrDesc, State)}.
+
+tr_NotifyReply(#'NotifyReply'{terminationID = IdList,
+ errorDescriptor = ErrDesc},
+ State) ->
+ #'NotifyReply'{terminationID = [tr_TerminationID(Id, State) || Id <- IdList],
+ errorDescriptor = tr_opt_ErrorDescriptor(ErrDesc, State)}.
+
+tr_ObservedEventsDescriptor(#'ObservedEventsDescriptor'{requestId = Id,
+ observedEventLst = Events},
+ State) when is_list(Events) ->
+ #'ObservedEventsDescriptor'{requestId = tr_RequestID(Id, State),
+ observedEventLst = [tr_ObservedEvent(E, State) || E <- Events]}.
+
+%% ;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
+
+tr_ObservedEvent(#'ObservedEvent'{eventName = Name,
+ streamID = Id,
+ eventParList = Parms,
+ timeNotation = Time},
+ State) ->
+ #'ObservedEvent'{eventName = tr_EventName(Name, State),
+ streamID = tr_opt_StreamID(Id, State),
+ eventParList = [tr_EventParameter(P, Name, State) || P <- Parms],
+ timeNotation = tr_opt_TimeNotation(Time, State)}.
+
+tr_EventName(Name, State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ resolve(event, Name, State, Constraint).
+
+tr_EventParameter(#'EventParameter'{eventParameterName = ParName,
+ value = Value,
+ extraInfo = Extra},
+ EventName,
+ State) ->
+ %% BUGBUG: event parameter name
+ Constraint = fun(Item) -> tr_Name(Item, State) end,
+ N = resolve({event_parameter, EventName}, ParName, State, Constraint),
+ #'EventParameter'{eventParameterName = N,
+ value = tr_Value(Value, State),
+ extraInfo = tr_opt_extraInfo(Extra, State)}.
+
+tr_ServiceChangeRequest(#'ServiceChangeRequest'{terminationID = IdList,
+ serviceChangeParms = Parms},
+ State) ->
+ #'ServiceChangeRequest'{terminationID = [tr_TerminationID(Id, State) || Id <- IdList],
+ serviceChangeParms = tr_ServiceChangeParm(Parms, 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 )
+tr_ServiceChangeReply(#'ServiceChangeReply'{terminationID = IdList,
+ serviceChangeResult = Res},
+ State) ->
+ #'ServiceChangeReply'{terminationID = [tr_TerminationID(Id, State) || Id <- IdList],
+ serviceChangeResult = tr_ServiceChangeResult(Res, State)}.
+
+tr_ServiceChangeResult({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ errorDescriptor -> tr_ErrorDescriptor(Val, State);
+ serviceChangeResParms -> tr_ServiceChangeResParm(Val, State)
+ end,
+ {Tag, Val2}.
+
+%% TerminationID = "ROOT" / pathNAME / "$" / "*"
+%% ; Total length of pathNAME must not exceed 64 chars.
+%% pathNAME = ["*"] NAME *("/" / "*"/ ALPHA / DIGIT /"_" / "$" )
+%% ["@" pathDomainName ]
+
+tr_TerminationID(TermId, State) when State#state.mode =/= verify ->
+ resolve(term_id, TermId, State, valid);
+tr_TerminationID(#'TerminationID'{wildcard = Wild,
+ id = Id},
+ _State) ->
+ #'TerminationID'{wildcard = Wild,
+ id = Id};
+tr_TerminationID(#megaco_term_id{contains_wildcards = IsWild,
+ id = Id},
+ State) ->
+ #megaco_term_id{contains_wildcards = tr_bool(IsWild, State),
+ id = [tr_term_id_component(Sub, State) || Sub <- Id]}.
+
+tr_opt_bool(asn1_NOVALUE, _State) -> asn1_NOVALUE;
+tr_opt_bool(Bool, State) -> tr_bool(Bool, State).
+
+tr_bool(true, _State) -> true;
+tr_bool(false, _State) -> false.
+
+tr_term_id_component(Sub, _State) ->
+ case Sub of
+ all -> all;
+ choose -> 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
+tr_MediaDescriptor(#'MediaDescriptor'{termStateDescr = TermState,
+ streams = Streams},
+ State) ->
+ #'MediaDescriptor'{termStateDescr = tr_opt_TerminationStateDescriptor(TermState, State),
+ streams = tr_opt_streams(Streams, State)}.
+
+tr_opt_streams(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_streams({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ oneStream -> tr_StreamParms(Val, State);
+ multiStream -> [tr_StreamDescriptor(SD, State) || SD <- Val]
+ end,
+ {Tag, Val2}.
+
+tr_StreamParms(#'StreamParms'{localControlDescriptor = Control,
+ localDescriptor = Local,
+ remoteDescriptor = Remote},
+ State) ->
+ #'StreamParms'{localControlDescriptor = tr_opt_LocalControlDescriptor(Control, State),
+ localDescriptor = tr_opt_LocalRemoteDescriptor(Local, State),
+ remoteDescriptor = tr_opt_LocalRemoteDescriptor(Remote, State)}.
+
+tr_StreamDescriptor(#'StreamDescriptor'{streamID = Id,
+ streamParms = Parms},
+ State) ->
+ #'StreamDescriptor'{streamID = tr_StreamID(Id, State),
+ streamParms = tr_StreamParms(Parms, 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
+tr_opt_LocalControlDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_LocalControlDescriptor(#'LocalControlDescriptor'{streamMode = Mode,
+ reserveGroup = Group,
+ reserveValue = Value,
+ propertyParms = Props},
+ State) ->
+ #'LocalControlDescriptor'{streamMode = tr_opt_StreamMode(Mode, State),
+ reserveGroup = tr_opt_bool(Group, State),
+ reserveValue = tr_opt_bool(Value, State),
+ propertyParms = [tr_PropertyParm(P, State) || P <- Props]}.
+
+tr_opt_StreamMode(Mode, _State) ->
+ case Mode of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ sendOnly -> sendOnly;
+ recvOnly -> recvOnly;
+ sendRecv -> sendRecv;
+ inactive -> inactive;
+ loopBack -> loopBack
+ end.
+
+tr_Name(Name, State) ->
+ %% BUGBUG: transform
+ %% BUGBUG: NAME = ALPHA *63(ALPHA / DIGIT / "_" )
+ tr_STRING(Name, State, 2, 2).
+
+tr_PkgdName(Name, State) ->
+ %% BUGBUG: transform
+ %% BUGBUG: pkgdName = (NAME / "*") SLASH (ItemID / "*" )
+ tr_OCTET_STRING(Name, State, 4, 4).
+
+%% 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.
+tr_opt_LocalRemoteDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_LocalRemoteDescriptor(#'LocalRemoteDescriptor'{propGrps = Groups},
+ State) ->
+ #'LocalRemoteDescriptor'{propGrps = [tr_PropertyGroup(G, State) || G <- Groups]}.
+
+tr_PropertyGroup(Props, State) ->
+ [tr_PropertyGroupParm(P, State) || P <- Props].
+
+tr_PropertyGroupParm(#'PropertyParm'{name = Name,
+ value = Value},
+ State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ #'PropertyParm'{name = resolve(property, Name, State, Constraint),
+ value = tr_OCTET_STRING(Value, State, 0, infinity)}.
+
+tr_PropertyParm(#'PropertyParm'{name = Name,
+ value = Value,
+ extraInfo = Extra},
+ State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ #'PropertyParm'{name = resolve(property, Name, State, Constraint),
+ value = tr_Value(Value, State),
+ extraInfo = tr_opt_extraInfo(Extra, State)}.
+
+tr_opt_extraInfo(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_extraInfo({relation, Rel}, _State) ->
+ Rel2 =
+ case Rel of
+ greaterThan -> greaterThan;
+ smallerThan -> smallerThan;
+ unequalTo -> unequalTo
+ end,
+ {relation, Rel2};
+tr_opt_extraInfo({range, Range}, State) ->
+ Range2 = tr_bool(Range, State),
+ {range, Range2};
+tr_opt_extraInfo({sublist, Sub}, State) ->
+ Sub2 = tr_bool(Sub, State),
+ {sublist, Sub2}.
+
+tr_opt_TerminationStateDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_TerminationStateDescriptor(#'TerminationStateDescriptor'{propertyParms = Props,
+ eventBufferControl = Control,
+ serviceState = Service},
+ State) ->
+ #'TerminationStateDescriptor'{propertyParms = [tr_PropertyParm(P, State) || P <- Props],
+ eventBufferControl = tr_opt_EventBufferControl(Control, State),
+ serviceState = tr_opt_ServiceState(Service, State)}.
+
+tr_opt_EventBufferControl(Control, _State) ->
+ case Control of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ off -> off;
+ lockStep -> lockStep
+ end.
+
+tr_opt_ServiceState(Service, _State) ->
+ case Service of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ test -> test;
+ outOfSvc -> outOfSvc;
+ inSvc -> inSvc
+ end.
+
+tr_MuxDescriptor(#'MuxDescriptor'{muxType = Type,
+ termList = IdList},
+ State) ->
+ #'MuxDescriptor'{muxType = tr_MuxType(Type, State),
+ termList = [tr_TerminationID(Id, State) || Id <- IdList]}.
+
+tr_MuxType(Type, _State) ->
+ case Type of
+ h221 -> h221;
+ h223 -> h223;
+ h226 -> h226;
+ v76 -> v76
+ end.
+
+tr_opt_StreamID(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_StreamID(Id, State) ->
+ tr_StreamID(Id, State).
+
+tr_StreamID(Id, State) ->
+ tr_UINT16(Id, State).
+
+tr_EventsDescriptor(#'EventsDescriptor'{requestID = Id,
+ eventList = Events},
+ State) ->
+ #'EventsDescriptor'{requestID = tr_opt_RequestID(Id, State),
+ eventList = [tr_RequestedEvent(E, State) || E <- Events]}.
+
+tr_RequestedEvent(#'RequestedEvent'{pkgdName = Name,
+ streamID = Id,
+ evParList = Parms,
+ eventAction = Actions},
+ State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ #'RequestedEvent'{pkgdName = resolve(event, Name, State, Constraint),
+ streamID = tr_opt_StreamID(Id, State),
+ eventAction = tr_opt_RequestedActions(Actions, State),
+ evParList = [tr_EventParameter(P, Name, State) || P <- Parms]}.
+
+tr_opt_RequestedActions(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_RequestedActions(#'RequestedActions'{keepActive = Keep,
+ eventDM = DM,
+ secondEvent = Event,
+ signalsDescriptor = SigDesc},
+ State) ->
+ #'RequestedActions'{keepActive = tr_opt_keepActive(Keep, State),
+ eventDM = tr_opt_EventDM(DM, State),
+ secondEvent = tr_opt_SecondEventsDescriptor(Event, State),
+ signalsDescriptor = tr_opt_SignalsDescriptor(SigDesc, State)}.
+
+tr_opt_keepActive(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_keepActive(Keep, State) ->
+ tr_bool(Keep, State).
+
+tr_opt_EventDM(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_EventDM({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ digitMapName -> tr_DigitMapName(Val, State);
+ digitMapValue -> tr_DigitMapValue(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_opt_SecondEventsDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_SecondEventsDescriptor(#'SecondEventsDescriptor'{requestID = Id,
+ eventList = Events},
+ State) ->
+ #'SecondEventsDescriptor'{requestID = tr_RequestID(Id, State), %% IG v6 6.8 withdrawn
+ eventList = [tr_SecondRequestedEvent(E, State) || E <- Events]}.
+
+tr_SecondRequestedEvent(#'SecondRequestedEvent'{pkgdName = Name,
+ streamID = Id,
+ evParList = Parms,
+ eventAction = Actions},
+ State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ #'SecondRequestedEvent'{pkgdName = resolve(event, Name, State, Constraint),
+ streamID = tr_opt_StreamID(Id, State),
+ eventAction = tr_opt_SecondRequestedActions(Actions, State),
+ evParList = [tr_EventParameter(P, Name, State) || P <- Parms]}.
+
+
+tr_opt_SecondRequestedActions(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_SecondRequestedActions(#'SecondRequestedActions'{keepActive = Keep,
+ eventDM = DM,
+ signalsDescriptor = SigDesc},
+ State) ->
+ #'SecondRequestedActions'{keepActive = tr_opt_keepActive(Keep, State),
+ eventDM = tr_opt_EventDM(DM, State),
+ signalsDescriptor = tr_opt_SignalsDescriptor(SigDesc, State)}.
+
+tr_EventBufferDescriptor(EventSpecs, State) ->
+ [tr_EventSpec(ES, State) || ES <- EventSpecs].
+
+tr_EventSpec(#'EventSpec'{eventName = Name,
+ streamID = Id,
+ eventParList = Parms},
+ State) ->
+ #'EventSpec'{eventName = tr_EventName(Name, State),
+ streamID = tr_opt_StreamID(Id, State),
+ eventParList = [tr_EventParameter(P, Name, State) || P <- Parms]}.
+
+tr_opt_SignalsDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_SignalsDescriptor(SigDesc, State) ->
+ tr_SignalsDescriptor(SigDesc, State).
+
+tr_SignalsDescriptor(SigDesc, State) when is_list(SigDesc) ->
+ [tr_SignalRequest(SigReq, State) || SigReq <- SigDesc].
+
+tr_SignalRequest({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ signal -> tr_Signal(Val, State);
+ seqSigList -> tr_SeqSigList(Val, State)
+ end,
+ {Tag, Val2}.
+
+
+tr_SeqSigList(#'SeqSigList'{id = Id,
+ signalList = SigList},
+ State) when is_list(SigList) ->
+ #'SeqSigList'{id = tr_UINT16(Id, State),
+ signalList = [tr_Signal(Sig, State) || Sig <- SigList]}.
+
+tr_Signal(#'Signal'{signalName = Name,
+ streamID = Id,
+ sigType = Type,
+ duration = Dur,
+ notifyCompletion = Compl,
+ keepActive = Keep,
+ sigParList = Parms},
+ State) ->
+ #'Signal'{signalName = tr_SignalName(Name, State),
+ streamID = tr_opt_StreamID(Id, State),
+ sigType = tr_opt_SignalType(Type, State),
+ duration = tr_opt_duration(Dur, State),
+ notifyCompletion = tr_opt_NotifyCompletion(Compl, State),
+ keepActive = tr_opt_keepActive(Keep, State),
+ sigParList = [tr_SigParameter(P, Name, State) || P <- Parms]}.
+
+tr_opt_duration(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_duration(Dur, State) ->
+ tr_UINT16(Dur, State).
+
+tr_opt_NotifyCompletion(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_NotifyCompletion(Items, State) when is_list(Items) ->
+ [tr_notifyCompletionItem(I, State) || I <- Items].
+
+tr_notifyCompletionItem(Item, _State) ->
+ case Item of
+ onTimeOut -> onTimeOut;
+ onInterruptByEvent -> onInterruptByEvent;
+ onInterruptByNewSignalDescr -> onInterruptByNewSignalDescr;
+ otherReason -> otherReason
+ end.
+
+tr_opt_SignalType(Type, _State) ->
+ case Type of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ brief -> brief;
+ onOff -> onOff;
+ timeOut -> timeOut
+ end.
+
+tr_SignalName(Name, State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ resolve(signal, Name, State, Constraint).
+
+tr_SigParameter(#'SigParameter'{sigParameterName = ParName,
+ value = Value,
+ extraInfo = Extra},
+ SigName,
+ State) ->
+ Constraint = fun(Item) -> tr_Name(Item, State) end,
+ N = resolve({signal_parameter, SigName}, ParName, State, Constraint),
+ #'SigParameter'{sigParameterName = N,
+ value = tr_Value(Value, State),
+ extraInfo = tr_opt_extraInfo(Extra, State)}.
+
+tr_opt_RequestID(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_RequestID(Id, State) ->
+ tr_RequestID(Id, State).
+
+tr_RequestID(Id, _State) when Id =:= ?megaco_all_request_id ->
+ ?megaco_all_request_id;
+tr_RequestID(Id, State) ->
+ tr_UINT32(Id, State).
+
+tr_ModemDescriptor(_MD, _State) ->
+ deprecated.
+% tr_ModemDescriptor(#'ModemDescriptor'{mtl = Types,
+% mpl = Props},
+% State) when list(Types), list(Props) ->
+% %% BUGBUG: Does not handle extensionParameter
+% #'ModemDescriptor'{mtl = [tr_ModemType(T, State) || T <- Types],
+% mpl = [tr_PropertyParm(P, State) || P <- Props]}.
+
+% tr_ModemType(Type, _State) ->
+% %% BUGBUG: Does not handle extensionParameter
+% case Type of
+% v18 -> v18;
+% v22 -> v22;
+% v22bis -> v22bis;
+% v32 -> v32;
+% v32bis -> v32bis;
+% v34 -> v34;
+% v90 -> v90;
+% v91 -> v91;
+% synchISDN -> synchISDN
+% end.
+
+tr_DigitMapDescriptor(#'DigitMapDescriptor'{digitMapName = Name,
+ digitMapValue = Value},
+ State) ->
+ #'DigitMapDescriptor'{digitMapName = tr_opt_DigitMapName(Name, State),
+ digitMapValue = tr_opt_DigitMapValue(Value, State)}.
+
+tr_opt_DigitMapName(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_DigitMapName(Name, State) ->
+ tr_DigitMapName(Name, State).
+
+tr_DigitMapName(Name, State) ->
+ Constraint = fun(Item) -> tr_Name(Item, State) end,
+ resolve(dialplan, Name, State, Constraint).
+
+tr_opt_DigitMapValue(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_DigitMapValue(Value, State) ->
+ tr_DigitMapValue(Value, State).
+
+tr_DigitMapValue(#'DigitMapValue'{digitMapBody = Body,
+ startTimer = Start,
+ shortTimer = Short,
+ longTimer = Long},
+ State) ->
+ #'DigitMapValue'{startTimer = tr_opt_timer(Start, State),
+ shortTimer = tr_opt_timer(Short, State),
+ longTimer = tr_opt_timer(Long, State),
+ digitMapBody = tr_STRING(Body, State)}. %% BUGBUG: digitMapBody not handled at all
+
+tr_opt_timer(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_timer(Timer, State) ->
+ tr_DIGIT(Timer, State, 0, 99).
+
+tr_ServiceChangeParm(#'ServiceChangeParm'{serviceChangeMethod = Method,
+ serviceChangeAddress = Addr,
+ serviceChangeVersion = Version,
+ serviceChangeProfile = Profile,
+ serviceChangeReason = Reason,
+ serviceChangeDelay = Delay,
+ serviceChangeMgcId = MgcId,
+ timeStamp = Time,
+ serviceChangeInfo = Info},
+ State) ->
+ #'ServiceChangeParm'{serviceChangeMethod = tr_ServiceChangeMethod(Method, State),
+ serviceChangeAddress = tr_opt_ServiceChangeAddress(Addr, State),
+ serviceChangeVersion = tr_opt_serviceChangeVersion(Version, State),
+ serviceChangeProfile = tr_opt_ServiceChangeProfile(Profile, State),
+ serviceChangeReason = tr_serviceChangeReason(Reason, State),
+ serviceChangeDelay = tr_opt_serviceChangeDelay(Delay, State),
+ serviceChangeMgcId = tr_opt_serviceChangeMgcId(MgcId, State),
+ timeStamp = tr_opt_TimeNotation(Time, State),
+ serviceChangeInfo = tr_opt_AuditDescriptor(Info, State)}.
+
+tr_ServiceChangeMethod(Method, _State) ->
+ case Method of
+ failover -> failover;
+ forced -> forced;
+ graceful -> graceful;
+ restart -> restart;
+ disconnected -> disconnected;
+ handOff -> handOff
+ end. %% BUGBUG: extension
+
+tr_opt_ServiceChangeAddress(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_ServiceChangeAddress({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ portNumber -> tr_portNumber(Val, State);
+ ip4Address -> tr_IP4Address(Val, State);
+ ip6Address -> tr_IP6Address(Val, State);
+ domainName -> tr_DomainName(Val, State);
+ deviceName -> tr_PathName(Val, State);
+ mtpAddress -> tr_mtpAddress(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_opt_serviceChangeVersion(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_serviceChangeVersion(Version, State) ->
+ tr_version(Version, State).
+
+tr_opt_ServiceChangeProfile(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+%% Decode
+tr_opt_ServiceChangeProfile({'ServiceChangeProfile', ProfileName}, State) ->
+ case string:tokens(ProfileName, "/") of
+ [Name0, Version0] ->
+ Name = tr_STRING(Name0, State, 1, 64),
+ Version = tr_version(list_to_integer(Version0), State),
+ #'ServiceChangeProfile'{profileName = Name,
+ version = Version}
+ end;
+%% Encode
+tr_opt_ServiceChangeProfile(#'ServiceChangeProfile'{profileName = Name0,
+ version = Version0},
+ State) ->
+ Name = tr_STRING(Name0, State, 1, 64),
+ Version = tr_version(Version0, State),
+ ProfileName = lists:flatten(io_lib:format("~s/~w", [Name, Version])),
+ {'ServiceChangeProfile', ProfileName}.
+
+tr_serviceChangeReason([_] = Reason, State) ->
+ tr_Value(Reason, State).
+
+tr_opt_serviceChangeDelay(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_serviceChangeDelay(Delay, State) ->
+ tr_UINT32(Delay, State).
+
+tr_opt_serviceChangeMgcId(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_serviceChangeMgcId(MgcId, State) ->
+ tr_MId(MgcId, State).
+
+tr_opt_portNumber(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_portNumber(Port, State) ->
+ tr_portNumber(Port, State).
+
+tr_portNumber(Port, State) when is_integer(Port) andalso (Port >= 0) ->
+ tr_UINT16(Port, State).
+
+tr_ServiceChangeResParm(#'ServiceChangeResParm'{serviceChangeMgcId = MgcId,
+ serviceChangeAddress = Addr,
+ serviceChangeVersion = Version,
+ serviceChangeProfile = Profile,
+ timeStamp = Time},
+ State) ->
+ #'ServiceChangeResParm'{serviceChangeMgcId = tr_opt_serviceChangeMgcId(MgcId, State),
+ serviceChangeAddress = tr_opt_ServiceChangeAddress(Addr, State),
+ serviceChangeVersion = tr_opt_serviceChangeVersion(Version, State),
+ serviceChangeProfile = tr_opt_ServiceChangeProfile(Profile, State),
+ timeStamp = tr_opt_TimeNotation(Time, State)}.
+
+tr_PackagesDescriptor(Items, State) when is_list(Items) ->
+ [tr_PackagesItem(I, State) || I <- Items].
+
+tr_PackagesItem(#'PackagesItem'{packageName = Name,
+ packageVersion = Version},
+ State) ->
+ Constraint = fun(Item) -> tr_Name(Item, State) end,
+ #'PackagesItem'{packageName = resolve(package, Name, State, Constraint),
+ packageVersion = tr_UINT16(Version, State)}.
+
+tr_StatisticsDescriptor(Parms, State) when is_list(Parms) ->
+ [tr_StatisticsParameter(P, State) || P <- Parms].
+
+tr_StatisticsParameter(#'StatisticsParameter'{statName = Name,
+ statValue = Value},
+ State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ #'StatisticsParameter'{statName = resolve(statistics, Name, State, Constraint),
+ statValue = tr_opt_Value(Value, State)}.
+
+tr_opt_TimeNotation(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_TimeNotation(#'TimeNotation'{date = Date,
+ time = Time},
+ State) ->
+ #'TimeNotation'{date = tr_STRING(Date, State, 8, 8), % "yyyymmdd"
+ time = tr_STRING(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.
+
+tr_opt_Value(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_Value(Value, State) ->
+ tr_Value(Value, State).
+
+tr_Value(Strings, _State) when is_list(Strings) ->
+ [[Char || Char <- String] || String <- Strings].
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Encode an octet string, escape } by \ if necessary
+tr_OCTET_STRING(String, _State, Min, Max) when is_list(String) ->
+ verify_count(length(String), Min, Max),
+ String.
+
+tr_QUOTED_STRING(String, _State) when is_list(String) ->
+ verify_count(length(String), 1, infinity),
+ String.
+
+%% 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
+tr_HEXDIG(Octets, _State, Min, Max) when is_list(Octets) ->
+ verify_count(length(Octets), Min, Max),
+ Octets.
+
+tr_DIGIT(Val, State, Min, Max) ->
+ tr_integer(Val, State, Min, Max).
+
+tr_STRING(String, _State) when is_list(String) ->
+ String.
+
+tr_STRING(String, _State, Min, Max) when is_list(String) ->
+ verify_count(length(String), Min, Max),
+ String.
+
+tr_opt_UINT16(Val, State) ->
+ tr_opt_integer(Val, State, 0, 65535).
+
+tr_UINT16(Val, State) ->
+ tr_integer(Val, State, 0, 65535).
+
+tr_UINT32(Val, State) ->
+ tr_integer(Val, State, 0, 4294967295).
+
+tr_opt_integer(asn1_NOVALUE, _State, _Min, _Max) ->
+ asn1_NOVALUE;
+tr_opt_integer(Int, State, Min, Max) ->
+ tr_integer(Int, State, Min, Max).
+
+tr_integer(Int, _State, Min, Max) ->
+ verify_count(Int, Min, Max),
+ Int.
+
+%% 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.
+
+
+% i(F,A) ->
+% S1 = io_lib:format("TRANSF-v2: " ++ F ++ "~n",A),
+% S2 = lists:flatten(S1),
+% io:format("~s",[S2]).
diff --git a/lib/megaco/src/binary/megaco_binary_transformer_v3.erl b/lib/megaco/src/binary/megaco_binary_transformer_v3.erl
new file mode 100644
index 0000000000..cef49b03fd
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_binary_transformer_v3.erl
@@ -0,0 +1,1763 @@
+%%
+%% %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: Transform internal form of Megaco/H.248 messages
+%%----------------------------------------------------------------------
+
+-module(megaco_binary_transformer_v3).
+
+-include_lib("megaco/include/megaco.hrl").
+%% -include_lib("megaco/include/megaco_message.hrl").
+-include_lib("megaco/include/megaco_message_v3.hrl").
+-include_lib("megaco/src/app/megaco_internal.hrl").
+
+-export([tr_message/3, tr_transaction/3]).
+
+-define(DEFAULT_NAME_RESOLVER, megaco_binary_name_resolver_v3).
+
+-record(state, {mode, % verify | encode | decode
+ resolver_module, %
+ resolver_options}).
+
+resolve(Type, Item, State, Constraint) ->
+ case State#state.mode of
+ verify ->
+ Item;
+ encode ->
+ ?d("resolve(encode) -> encode: ~p",[Item]),
+ Mod = State#state.resolver_module,
+ Opt = State#state.resolver_options,
+ EncodedItem = Mod:encode_name(Opt, Type, Item),
+ ?d("resolve -> verify contraint for ~p",[EncodedItem]),
+ verify_constraint(EncodedItem, Constraint);
+ decode ->
+ ?d("resolve(decode) -> verify contraint for ~p",[Item]),
+ DecodedItem = verify_constraint(Item, Constraint),
+ Mod = State#state.resolver_module,
+ Opt = State#state.resolver_options,
+ ?d("resolve(decode) -> decode: ~p",[DecodedItem]),
+ Mod:decode_name(Opt, Type, DecodedItem)
+ end.
+
+verify_constraint(Item, valid) ->
+ Item;
+verify_constraint(Item, Constraint) when is_function(Constraint) ->
+ Constraint(Item).
+
+tr_message(MegaMsg, Mode, Config) ->
+ case Config of
+ [native] ->
+ MegaMsg;
+ [verify] ->
+ State = #state{mode = verify},
+ tr_MegacoMessage(MegaMsg, State);
+ [] ->
+ State = #state{mode = Mode,
+ resolver_module = ?DEFAULT_NAME_RESOLVER,
+ resolver_options = [8, 8, 8]},
+ tr_MegacoMessage(MegaMsg, State);
+ [{binary_name_resolver, {Module, Options}}] when is_atom(Module) ->
+ State = #state{mode = Mode,
+ resolver_module = Module,
+ resolver_options = Options},
+ tr_MegacoMessage(MegaMsg, State)
+ end.
+
+tr_transaction(Trans, Mode, Config) ->
+ case Config of
+ [native] ->
+ Trans;
+ [verify] ->
+ State = #state{mode = verify},
+ tr_Transaction(Trans, State);
+ [] ->
+ State = #state{mode = Mode,
+ resolver_module = ?DEFAULT_NAME_RESOLVER,
+ resolver_options = [8, 8, 8]},
+ tr_Transaction(Trans, State);
+ [{binary_name_resolver, {Module, Options}}] when is_atom(Module) ->
+ State = #state{mode = Mode,
+ resolver_module = Module,
+ resolver_options = Options},
+ tr_Transaction(Trans, State)
+ end.
+
+tr_MegacoMessage(#'MegacoMessage'{authHeader = Auth,
+ mess = Mess},
+ State) ->
+ ?d("tr_MegacoMessage -> entry with"
+ "~n Auth: ~p"
+ "~n Mess: ~p"
+ "~n State: ~p", [Auth, Mess, State]),
+ #'MegacoMessage'{authHeader = tr_opt_AuthenticationHeader(Auth, State),
+ mess = tr_Message(Mess, State)}.
+
+tr_opt_AuthenticationHeader(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_AuthenticationHeader(#'AuthenticationHeader'{secParmIndex = SPI,
+ seqNum = SN,
+ ad = AuthData},
+ State) ->
+ #'AuthenticationHeader'{secParmIndex = tr_SecurityParmIndex(SPI, State),
+ seqNum = tr_SequenceNum(SN, State),
+ ad = tr_AuthData(AuthData, State)}.
+
+tr_SecurityParmIndex(SPI, State) ->
+ tr_HEXDIG(SPI, State, 4, 4). % BUGBUG: Mismatch between ASN.1 and ABNF
+
+tr_SequenceNum(SN, State) ->
+ tr_HEXDIG(SN, State, 4, 4). % BUGBUG: Mismatch between ASN.1 and ABNF
+
+tr_AuthData(AuthData, State) ->
+ tr_HEXDIG(AuthData, State, 12, 32). % BUGBUG: Mismatch between ASN.1 and ABNF
+
+tr_Message(#'Message'{version = Version,
+ mId = MID,
+ messageBody = Body},
+ State) ->
+ #'Message'{version = tr_version(Version, State),
+ mId = tr_MId(MID, State),
+ messageBody = tr_Message_messageBody(Body, State)}.
+
+tr_version(Version, State) ->
+ tr_DIGIT(Version, State, 0, 99).
+
+tr_Message_messageBody({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ messageError -> tr_ErrorDescriptor(Val, State);
+ transactions when is_list(Val) -> [tr_Transaction(T, State) || T <- Val]
+ end,
+ {Tag, Val2}.
+
+tr_MId({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ ip4Address -> tr_IP4Address(Val, State);
+ ip6Address -> tr_IP6Address(Val, State);
+ domainName -> tr_DomainName(Val, State);
+ deviceName -> tr_PathName(Val, State);
+ mtpAddress -> tr_mtpAddress(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_mtpAddress(MtpAddr, State) ->
+ tr_OCTET_STRING(MtpAddr, State, 2, 4). % BUGBUG: Mismatch between ASN.1 and ABNF
+
+tr_DomainName(#'DomainName'{name = Name,
+ portNumber = Port},
+ State) ->
+ Domain = #'DomainName'{name = tr_STRING(Name, State), % BUGBUG: Mismatch between ASN.1 and ABNF
+ portNumber = tr_opt_portNumber(Port, State)},
+ {domainName, Domain2} = resolve(mid, {domainName, Domain}, State, valid),
+ Domain2.
+
+tr_IP4Address(#'IP4Address'{address = [A1, A2, A3, A4],
+ portNumber = Port},
+ State) ->
+ #'IP4Address'{address = [tr_V4hex(A1, State),
+ tr_V4hex(A2, State),
+ tr_V4hex(A3, State),
+ tr_V4hex(A4, State)],
+ portNumber = tr_opt_portNumber(Port, State)}.
+
+tr_V4hex(Val, State) ->
+ tr_DIGIT(Val, State, 0, 255).
+
+tr_IP6Address(_Val, _State) ->
+ error(ipv6_not_supported). %% BUGBUG: nyi
+
+tr_PathName(Path, State) ->
+ %% BUGBUG: ["*"] NAME *("/" / "*"/ ALPHA / DIGIT /"_" / "$" )
+ %% BUGBUG: ["@" pathDomainName ]
+ Constraint = fun({deviceName, Item}) -> tr_STRING(Item, State, 1, 64) end,
+ resolve(mid, {deviceName, Path}, State, Constraint).
+
+tr_Transaction({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ transactionRequest -> tr_TransactionRequest(Val, State);
+ transactionPending -> tr_TransactionPending(Val, State);
+ transactionReply -> tr_TransactionReply(Val, State);
+ transactionResponseAck -> [tr_TransactionAck(T, State) || T <- Val];
+ segmentReply -> tr_SegmentReply(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_TransactionAck(#'TransactionAck'{firstAck = First,
+ lastAck = Last},
+ State) ->
+ #'TransactionAck'{firstAck = tr_TransactionId(First, State),
+ lastAck = tr_opt_TransactionId(Last, State)}.
+
+tr_opt_TransactionId(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_TransactionId(Id, State) ->
+ tr_TransactionId(Id, State).
+
+tr_TransactionId(Id, State) ->
+ tr_UINT32(Id, State).
+
+tr_TransactionRequest(#'TransactionRequest'{transactionId = Id,
+ actions = Actions},
+ State) when is_list(Actions) ->
+
+ #'TransactionRequest'{transactionId = tr_TransactionId(Id, State),
+ actions = [tr_ActionRequest(ActReq, State) || ActReq <- Actions]}.
+
+tr_TransactionPending(#'TransactionPending'{transactionId = Id},
+ State) ->
+ #'TransactionPending'{transactionId = tr_TransactionId(Id, State)}.
+
+tr_TransactionReply(#'TransactionReply'{transactionId = Id,
+ immAckRequired = ImmAck,
+ transactionResult = TransRes,
+ segmentNumber = SN,
+ segmentationComplete = SC},
+ State) ->
+ #'TransactionReply'{transactionId = tr_TransactionId(Id, State),
+ immAckRequired = tr_opt_null(ImmAck, State),
+ transactionResult = tr_TransactionReply_transactionResult(TransRes, State),
+ segmentNumber = tr_opt_SegmentNumber(SN, State),
+ segmentationComplete = tr_opt_null(SC, State)}.
+
+tr_opt_null(asn1_NOVALUE, _State) -> asn1_NOVALUE;
+tr_opt_null('NULL', _State) -> 'NULL'.
+
+tr_SegmentNumber(Num, State) ->
+ tr_UINT16(Num, State).
+
+tr_opt_SegmentNumber(Num, State) ->
+ tr_opt_UINT16(Num, State).
+
+tr_SegmentReply(#'SegmentReply'{transactionId = TID,
+ segmentNumber = SN,
+ segmentationComplete = SC}, State) ->
+ #'SegmentReply'{transactionId = tr_TransactionId(TID, State),
+ segmentNumber = tr_SegmentNumber(SN, State),
+ segmentationComplete = tr_opt_null(SC, State)}.
+
+tr_TransactionReply_transactionResult({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ transactionError ->
+ tr_ErrorDescriptor(Val, State);
+ actionReplies when is_list(Val) andalso (Val =/= []) ->
+ [tr_ActionReply(ActRep, State) || ActRep <- Val]
+ end,
+ {Tag, Val2}.
+
+tr_opt_ErrorDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_ErrorDescriptor(ErrDesc, State) ->
+ tr_ErrorDescriptor(ErrDesc, State).
+
+tr_ErrorDescriptor(#'ErrorDescriptor'{errorCode = Code,
+ errorText = Text},
+ State) ->
+ #'ErrorDescriptor'{errorCode = tr_ErrorCode(Code, State),
+ errorText = tr_opt_ErrorText(Text, State)}.
+
+tr_ErrorCode(Code, State) ->
+ tr_DIGIT(Code, State, 0, 999).
+
+tr_opt_ErrorText(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_ErrorText(Text, State) ->
+ tr_QUOTED_STRING(Text, State).
+
+tr_ContextID(CtxId, State) ->
+ case CtxId of
+ ?megaco_all_context_id -> ?megaco_all_context_id;
+ ?megaco_null_context_id -> ?megaco_null_context_id;
+ ?megaco_choose_context_id -> ?megaco_choose_context_id;
+ Int when is_integer(Int) -> tr_UINT32(Int, State)
+ end.
+
+tr_ActionRequest(#'ActionRequest'{contextId = CtxId,
+ contextRequest = CtxReq,
+ contextAttrAuditReq = CtxAuditReq,
+ commandRequests = CmdReqList},
+ State) ->
+ #'ActionRequest'{contextId = tr_ContextID(CtxId, State),
+ contextRequest = tr_opt_ContextRequest(CtxReq, State),
+ contextAttrAuditReq = tr_opt_ContextAttrAuditRequest(CtxAuditReq, State),
+ commandRequests = [tr_CommandRequest(CmdReq, State) || CmdReq <- CmdReqList]}.
+
+tr_ActionReply(#'ActionReply'{contextId = CtxId,
+ errorDescriptor = ErrDesc,
+ contextReply = CtxRep,
+ commandReply = CmdRepList},
+ State) ->
+ CmdRepList2 = [tr_CommandReply(CmdRep, State) || CmdRep <- CmdRepList],
+ #'ActionReply'{contextId = tr_ContextID(CtxId, State),
+ errorDescriptor = tr_opt_ErrorDescriptor(ErrDesc, State),
+ contextReply = tr_opt_ContextRequest(CtxRep, State),
+ commandReply = CmdRepList2}.
+
+tr_opt_ContextRequest(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_ContextRequest(CR, State) ->
+ tr_ContextRequest(CR, State).
+
+tr_ContextRequest(#'ContextRequest'{priority = Prio,
+ emergency = Em,
+ topologyReq = TopReqList,
+ iepscallind = Ind,
+ contextProp = CtxProps,
+ contextList = CtxList},
+ State) ->
+ Prio2 =
+ case Prio of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> tr_integer(Prio, State, 0, 15)
+ end,
+ Em2 =
+ case Em of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ false -> false;
+ true -> true
+ end,
+ TopReqList2 =
+ case TopReqList of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> [tr_TopologyRequest(TopReq, State) ||
+ TopReq <- TopReqList]
+ end,
+ Ind2 =
+ case Ind of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ false -> false;
+ true -> true
+ end,
+ CtxProps2 =
+ case CtxProps of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> [tr_PropertyParm(Prop, State) || Prop <- CtxProps]
+ end,
+ CtxList2 =
+ case CtxList of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> [tr_ContextID(Id, State) || Id <- CtxList]
+ end,
+ #'ContextRequest'{priority = Prio2,
+ emergency = Em2,
+ topologyReq = TopReqList2,
+ iepscallind = Ind2,
+ contextProp = CtxProps2,
+ contextList = CtxList2}.
+
+tr_opt_ContextAttrAuditRequest(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_ContextAttrAuditRequest(CAAR, State) ->
+ tr_ContextAttrAuditRequest(CAAR, State).
+
+tr_ContextAttrAuditRequest(#'ContextAttrAuditRequest'{topology = Top,
+ emergency = Em,
+ priority = Prio,
+ iepscallind = Ind,
+ contextPropAud = Props,
+ selectpriority = SPrio,
+ selectemergency = SEm,
+ selectiepscallind = SInd,
+ selectLogic = SLog},
+ State) ->
+ Top2 = tr_opt_null(Top, State),
+ Em2 = tr_opt_null(Em, State),
+ Prio2 = tr_opt_null(Prio, State),
+ Ind2 = tr_opt_null(Ind, State),
+ Props2 =
+ case Props of
+ asn1_NOVALUE ->
+ asn1_NOVALUE;
+ _ ->
+ [tr_indAudPropertyParm(Prop, State) || Prop <- Props]
+ end,
+ SPrio2 =
+ case SPrio of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> tr_integer(SPrio, State, 0, 15)
+ end,
+ SEm2 =
+ case SEm of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ false -> false;
+ true -> true
+ end,
+ SInd2 =
+ case SInd of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ false -> false;
+ true -> true
+ end,
+ SLog2 =
+ case SLog of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> tr_SelectLogic(SLog, State)
+ end,
+ #'ContextAttrAuditRequest'{topology = Top2,
+ emergency = Em2,
+ priority = Prio2,
+ iepscallind = Ind2,
+ contextPropAud = Props2,
+ selectpriority = SPrio2,
+ selectemergency = SEm2,
+ selectiepscallind = SInd2,
+ selectLogic = SLog2}.
+
+tr_SelectLogic({andAUDITSelect, 'NULL'} = Val, _State) ->
+ Val;
+tr_SelectLogic({orAUDITSelect, 'NULL'} = Val, _State) ->
+ Val.
+
+tr_CommandRequest(#'CommandRequest'{command = Cmd,
+ optional = Opt,
+ wildcardReturn = Wild},
+ State) ->
+ #'CommandRequest'{optional = tr_opt_null(Opt, State),
+ wildcardReturn = tr_opt_null(Wild, State),
+ command = tr_Command(Cmd, State)}.
+
+tr_Command({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ addReq -> tr_AmmRequest(Val, State);
+ moveReq -> tr_AmmRequest(Val, State);
+ modReq -> tr_AmmRequest(Val, State);
+ subtractReq -> tr_SubtractRequest(Val, State);
+ auditCapRequest -> tr_AuditRequest(Val, State);
+ auditValueRequest -> tr_AuditRequest(Val, State);
+ notifyReq -> tr_NotifyRequest(Val, State);
+ serviceChangeReq -> tr_ServiceChangeRequest(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_CommandReply({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ addReply -> tr_AmmsReply(Val, State);
+ moveReply -> tr_AmmsReply(Val, State);
+ modReply -> tr_AmmsReply(Val, State);
+ subtractReply -> tr_AmmsReply(Val, State);
+ auditCapReply -> tr_AuditReply(Val, State);
+ auditValueReply -> tr_AuditReply(Val, State);
+ notifyReply -> tr_NotifyReply(Val, State);
+ serviceChangeReply -> tr_ServiceChangeReply(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_TopologyRequest(#'TopologyRequest'{terminationFrom = From,
+ terminationTo = To,
+ topologyDirection = Dir,
+ streamID = SID,
+ topologyDirectionExtension = TDE},
+ State) ->
+ Dir2 =
+ case Dir of
+ bothway -> bothway;
+ isolate -> isolate;
+ oneway -> oneway
+ end,
+ TDE2 =
+ case TDE of
+ onewayexternal -> onewayexternal;
+ onewayboth -> onewayboth;
+ asn1_NOVALUE -> asn1_NOVALUE
+ end,
+ #'TopologyRequest'{terminationFrom = tr_TerminationID(From, State),
+ terminationTo = tr_TerminationID(To, State),
+ topologyDirection = Dir2,
+ streamID = tr_opt_StreamID(SID, State),
+ topologyDirectionExtension = TDE2}.
+
+tr_AmmRequest(#'AmmRequest'{terminationID = IdList,
+ descriptors = DescList},
+ State) ->
+ #'AmmRequest'{terminationID = [tr_TerminationID(Id, State) ||
+ Id <- IdList],
+ descriptors = tr_ammDescriptors(DescList, [], State)}.
+
+tr_ammDescriptors([], Acc, _State) ->
+ lists:reverse(Acc);
+tr_ammDescriptors([Desc|Descs], Acc, State) ->
+ case tr_ammDescriptor(Desc, State) of
+ {_, deprecated} when State#state.mode =:= encode ->
+ error({deprecated, Desc});
+ {_, deprecated} when State#state.mode =:= decode ->
+ %% SKIP
+ tr_ammDescriptors(Descs, Acc, State);
+ {_, deprecated} ->
+ %% SKIP
+ tr_ammDescriptors(Descs, Acc, State);
+ NewDesc ->
+ tr_ammDescriptors(Descs, [NewDesc|Acc], State)
+ end.
+
+tr_ammDescriptor({Tag, Desc}, State) ->
+ Desc2 =
+ case Tag of
+ mediaDescriptor -> tr_MediaDescriptor(Desc, State);
+ modemDescriptor -> tr_ModemDescriptor(Desc, State);
+ muxDescriptor -> tr_MuxDescriptor(Desc, State);
+ eventsDescriptor -> tr_EventsDescriptor(Desc, State);
+ eventBufferDescriptor -> tr_EventBufferDescriptor(Desc, State);
+ signalsDescriptor -> tr_SignalsDescriptor(Desc, State);
+ digitMapDescriptor -> tr_DigitMapDescriptor(Desc, State);
+ auditDescriptor -> tr_AuditDescriptor(Desc, State);
+ statisticsDescriptor -> tr_StatisticsDescriptor(Desc, State)
+ end,
+ {Tag, Desc2}.
+
+tr_AmmsReply(#'AmmsReply'{terminationID = IdList,
+ terminationAudit = TermAudit},
+ State) ->
+ TermAudit2 =
+ case TermAudit of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> tr_TerminationAudit(TermAudit, State)
+ end,
+ #'AmmsReply'{terminationID = [tr_TerminationID(Id, State) ||
+ Id <- IdList],
+ terminationAudit = TermAudit2}.
+
+tr_SubtractRequest(#'SubtractRequest'{terminationID = IdList,
+ auditDescriptor = Desc},
+ State) ->
+ #'SubtractRequest'{terminationID = [tr_TerminationID(Id, State) ||
+ Id <- IdList],
+ auditDescriptor = tr_opt_AuditDescriptor(Desc, State)}.
+
+tr_AuditRequest(#'AuditRequest'{terminationID = Id,
+ auditDescriptor = Desc,
+ terminationIDList = TIDList},
+ State) ->
+ TIDList2 =
+ case TIDList of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> [tr_TerminationID(TID, State) || TID <- TIDList]
+ end,
+ #'AuditRequest'{terminationID = tr_TerminationID(Id, State),
+ auditDescriptor = tr_AuditDescriptor(Desc, State),
+ terminationIDList = TIDList2}.
+
+%% auditReply = (AuditValueToken / AuditCapToken )
+%% ( contextTerminationAudit / auditOther)
+%% auditOther = EQUAL TerminationID LBRKT
+%% terminationAudit RBRKT
+%% terminationAudit = auditReturnParameter *(COMMA auditReturnParameter)
+%%
+%% contextTerminationAudit = EQUAL CtxToken ( terminationIDList /
+%% LBRKT errorDescriptor RBRKT )
+
+tr_AuditReply({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ contextAuditResult ->
+ [tr_TerminationID(Id, State) || Id <- Val];
+ error ->
+ tr_ErrorDescriptor(Val, State);
+ auditResult ->
+ tr_AuditResult(Val, State);
+ auditResultTermList ->
+ tr_TermListAuditResult(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_AuditResult(#'AuditResult'{terminationID = Id,
+ terminationAuditResult = AuditRes},
+ State) ->
+ #'AuditResult'{terminationID = tr_TerminationID(Id, State),
+ terminationAuditResult = tr_TerminationAudit(AuditRes, State)}.
+
+tr_TermListAuditResult(
+ #'TermListAuditResult'{terminationIDList = TIDList,
+ terminationAuditResult = TAR},
+ State) ->
+ TIDList2 = [tr_TerminationID(TID, State) || TID <- TIDList],
+ TAR2 = tr_TerminationAudit(TAR, State),
+ #'TermListAuditResult'{terminationIDList = TIDList2,
+ terminationAuditResult = TAR2}.
+
+
+tr_opt_AuditDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_AuditDescriptor(Desc, State) ->
+ tr_AuditDescriptor(Desc, State).
+
+%% BUGBUG BUGBUG BUGBUG
+%% With this construction it is possible to have both auditToken
+%% and auditPropertyToken, but it is actually valid?
+tr_AuditDescriptor(#'AuditDescriptor'{auditToken = Tokens,
+ auditPropertyToken = APTs},
+ State) ->
+ Tokens2 =
+ case Tokens of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> [tr_auditItem(Token, State) || Token <- Tokens]
+ end,
+ %% v2
+ APTs2 =
+ case APTs of
+ asn1_NOVALUE ->
+ asn1_NOVALUE;
+ _ ->
+ [tr_indAuditParameter(APT, State) || APT <- APTs]
+ end,
+ #'AuditDescriptor'{auditToken = Tokens2,
+ auditPropertyToken = APTs2}.
+
+tr_auditItem(Token, _State) ->
+ case Token of
+ muxToken -> muxToken;
+ modemToken -> modemToken;
+ mediaToken -> mediaToken;
+ eventsToken -> eventsToken;
+ signalsToken -> signalsToken;
+ digitMapToken -> digitMapToken;
+ statsToken -> statsToken;
+ observedEventsToken -> observedEventsToken;
+ packagesToken -> packagesToken;
+ eventBufferToken -> eventBufferToken
+ end.
+
+%% --- v2 begin ---
+
+tr_indAuditParameter({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ indAudMediaDescriptor ->
+ tr_indAudMediaDescriptor(Val, State);
+ indAudEventsDescriptor ->
+ tr_indAudEventsDescriptor(Val, State);
+ indAudSignalsDescriptor ->
+ tr_indAudSignalsDescriptor(Val, State);
+ indAudDigitMapDescriptor ->
+ tr_indAudDigitMapDescriptor(Val, State);
+ indAudEventBufferDescriptor ->
+ tr_indAudEventBufferDescriptor(Val, State);
+ indAudStatisticsDescriptor ->
+ tr_indAudStatisticsDescriptor(Val, State);
+ indAudPackagesDescriptor ->
+ tr_indAudPackagesDescriptor(Val, State)
+ end,
+ {Tag, Val2}.
+
+
+%% -
+
+tr_indAudMediaDescriptor(#'IndAudMediaDescriptor'{termStateDescr = TSD,
+ streams = S},
+ State) ->
+ TSD2 =
+ case TSD of
+ asn1_NOVALUE ->
+ asn1_NOVALUE;
+ _ ->
+ tr_indAudTerminationStateDescriptor(TSD, State)
+ end,
+ S2 =
+ case S of
+ asn1_NOVALUE ->
+ asn1_NOVALUE;
+ {oneStream, OS} ->
+ {oneStream, tr_indAudStreamParms(OS, State)};
+ {multiStream, MS} ->
+ MS2 = [tr_indAudStreamDescriptor(MS1, State) || MS1 <- MS],
+ {multiStream, MS2}
+ end,
+ #'IndAudMediaDescriptor'{termStateDescr = TSD2,
+ streams = S2}.
+
+tr_indAudTerminationStateDescriptor(Val, State)
+ when is_record(Val, 'IndAudTerminationStateDescriptor') ->
+ #'IndAudTerminationStateDescriptor'{propertyParms = Parms,
+ eventBufferControl = EBC,
+ serviceState = SS,
+ serviceStateSel = SSS} = Val,
+ Parms2 = [tr_indAudPropertyParm(Parm, State) || Parm <- Parms],
+ EBC2 = tr_opt_null(EBC, State),
+ SS2 = tr_opt_null(SS, State),
+ SSS2 = tr_opt_ServiceState(SSS, State),
+ #'IndAudTerminationStateDescriptor'{propertyParms = Parms2,
+ eventBufferControl = EBC2,
+ serviceState = SS2,
+ serviceStateSel = SSS2}.
+
+
+tr_indAudStreamParms(#'IndAudStreamParms'{localControlDescriptor = LCD,
+ localDescriptor = LD,
+ remoteDescriptor = RD,
+ statisticsDescriptor = SD},
+ State) ->
+ LCD2 =
+ case LCD of
+ asn1_NOVALUE ->
+ asn1_NOVALUE;
+ _ ->
+ tr_indAudLocalControlDescriptor(LCD, State)
+ end,
+ LD2 =
+ case LD of
+ asn1_NOVALUE ->
+ asn1_NOVALUE;
+ _ ->
+ tr_indAudLocalRemoteDescriptor(LD, State)
+ end,
+ RD2 =
+ case RD of
+ asn1_NOVALUE ->
+ asn1_NOVALUE;
+ _ ->
+ tr_indAudLocalRemoteDescriptor(RD, State)
+ end,
+ SD2 =
+ case SD of
+ asn1_NOVALUE ->
+ asn1_NOVALUE;
+ _ ->
+ tr_indAudStatisticsDescriptor(SD, State)
+ end,
+ #'IndAudStreamParms'{localControlDescriptor = LCD2,
+ localDescriptor = LD2,
+ remoteDescriptor = RD2,
+ statisticsDescriptor = SD2}.
+
+tr_indAudLocalControlDescriptor(Val, State)
+ when is_record(Val, 'IndAudLocalControlDescriptor') ->
+ #'IndAudLocalControlDescriptor'{streamMode = M,
+ reserveValue = V,
+ reserveGroup = G,
+ propertyParms = P,
+ streamModeSel = SMS} = Val,
+ M2 = tr_opt_null(M, State),
+ V2 = tr_opt_null(V, State),
+ G2 = tr_opt_null(G, State),
+ P2 = tr_indAudLocalControlDescriptor_propertyParms(P, State),
+ SMS2 = tr_opt_StreamMode(SMS, State),
+ #'IndAudLocalControlDescriptor'{streamMode = M2,
+ reserveValue = V2,
+ reserveGroup = G2,
+ propertyParms = P2,
+ streamModeSel = SMS2}.
+
+tr_indAudLocalControlDescriptor_propertyParms(Parms, State)
+ when is_list(Parms) andalso (length(Parms) > 0) ->
+ [tr_indAudPropertyParm(Parm, State) || Parm <- Parms];
+tr_indAudLocalControlDescriptor_propertyParms(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE.
+
+tr_indAudLocalRemoteDescriptor(#'IndAudLocalRemoteDescriptor'{propGroupID = ID,
+ propGrps = Grps},
+ State) ->
+ #'IndAudLocalRemoteDescriptor'{propGroupID = tr_opt_UINT16(ID, State),
+ propGrps = tr_indAudPropertyGroup(Grps,
+ State)}.
+
+tr_indAudPropertyGroup(Grps, State) when is_list(Grps) ->
+ [tr_indAudPropertyParm(Parm, State) || Parm <- Grps].
+
+tr_indAudPropertyParm(#'IndAudPropertyParm'{name = Name0,
+ propertyParms = Prop0}, State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ Name = resolve(property, Name0, State, Constraint),
+ Prop =
+ case Prop0 of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> tr_PropertyParm(Prop0, State)
+ end,
+ #'IndAudPropertyParm'{name = Name,
+ propertyParms = Prop}.
+
+
+tr_indAudStreamDescriptor(#'IndAudStreamDescriptor'{streamID = ID,
+ streamParms = Parms},
+ State) ->
+ #'IndAudStreamDescriptor'{streamID = tr_StreamID(ID, State),
+ streamParms = tr_indAudStreamParms(Parms,
+ State)}.
+
+
+%% -
+
+tr_indAudEventsDescriptor(#'IndAudEventsDescriptor'{requestID = RID,
+ pkgdName = Name0,
+ streamID = SID},
+ State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ Name = resolve(event, Name0, State, Constraint),
+ #'IndAudEventsDescriptor'{requestID = tr_opt_RequestID(RID, State),
+ pkgdName = Name,
+ streamID = tr_opt_StreamID(SID, State)}.
+
+
+%% -
+
+tr_indAudSignalsDescriptor({Tag, Val}, State) ->
+ case Tag of
+ signal ->
+ {signal, tr_indAudSignal(Val, State)};
+ seqSigList ->
+ {seqSigList, tr_indAudSeqSigList(Val, State)}
+ end.
+
+tr_opt_indAudSignal(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_indAudSignal(Val, State) ->
+ tr_indAudSignal(Val, State).
+
+tr_indAudSignal(#'IndAudSignal'{signalName = Name0,
+ streamID = SID,
+ signalRequestID = RID}, State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ Name = resolve(signal, Name0, State, Constraint),
+ #'IndAudSignal'{signalName = Name,
+ streamID = tr_opt_StreamID(SID, State),
+ signalRequestID = tr_opt_RequestID(RID, State)}.
+
+tr_indAudSeqSigList(#'IndAudSeqSigList'{id = ID,
+ signalList = SigList}, State) ->
+ #'IndAudSeqSigList'{id = tr_integer(ID, State, 0, 65535),
+ signalList = tr_opt_indAudSignal(SigList, State)}.
+
+%% -
+
+tr_indAudDigitMapDescriptor(#'IndAudDigitMapDescriptor'{digitMapName = Name},
+ State) ->
+ #'IndAudDigitMapDescriptor'{digitMapName =
+ tr_opt_DigitMapName(Name, State)}.
+
+
+%% -
+
+tr_indAudEventBufferDescriptor(#'IndAudEventBufferDescriptor'{eventName = N,
+ streamID = SID},
+ State) ->
+ ?d("tr_indAudEventBufferDescriptor -> entry with"
+ "~n N: ~p"
+ "~n SID: ~p", [N, SID]),
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ Name = resolve(event, N, State, Constraint),
+ ?d("tr_indAudEventBufferDescriptor -> entry with"
+ "~n Name: ~p", [Name]),
+ #'IndAudEventBufferDescriptor'{eventName = Name,
+ streamID = tr_opt_StreamID(SID, State)}.
+
+%% -
+
+tr_indAudStatisticsDescriptor(#'IndAudStatisticsDescriptor'{statName = N},
+ State) ->
+ ?d("tr_indAudEventBufferDescriptor -> entry with"
+ "~n N: ~p", [N]),
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ Name = resolve(statistics, N, State, Constraint),
+ #'IndAudStatisticsDescriptor'{statName = Name}.
+
+
+%% -
+
+tr_indAudPackagesDescriptor(#'IndAudPackagesDescriptor'{packageName = N,
+ packageVersion = V},
+ State) ->
+ ?d("tr_indAudPackagesDescriptor -> entry with"
+ "~n N: ~p"
+ "~n V: ~p", [N, V]),
+ Constraint = fun(Item) -> tr_Name(Item, State) end,
+ Name = resolve(package, N, State, Constraint),
+ ?d("tr_indAudPackagesDescriptor -> entry with"
+ "~n Name: ~p", [Name]),
+ #'IndAudPackagesDescriptor'{packageName = Name,
+ packageVersion = tr_integer(V, State, 0, 99)}.
+
+%% -- v2 end --
+
+
+tr_TerminationAudit(ParmList, State) when is_list(ParmList) ->
+ do_tr_TerminationAudit(ParmList, [], State).
+
+do_tr_TerminationAudit([], Acc, _State) ->
+ lists:reverse(Acc);
+do_tr_TerminationAudit([Parm|ParmList], Acc, State) ->
+ case tr_AuditReturnParameter(Parm, State) of
+ {_, deprecated} when State#state.mode =:= encode ->
+ error({deprecated, Parm});
+ {_, deprecated} when State#state.mode =:= decode ->
+ %% SKIP
+ do_tr_TerminationAudit(ParmList, Acc, State);
+ {_, deprecated} ->
+ %% SKIP
+ do_tr_TerminationAudit(ParmList, Acc, State);
+ NewParm ->
+ do_tr_TerminationAudit(ParmList, [NewParm|Acc], State)
+ end.
+
+tr_AuditReturnParameter({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ errorDescriptor ->
+ tr_ErrorDescriptor(Val, State);
+ mediaDescriptor ->
+ tr_MediaDescriptor(Val, State);
+ modemDescriptor ->
+ tr_ModemDescriptor(Val, State);
+ muxDescriptor ->
+ tr_MuxDescriptor(Val, State);
+ eventsDescriptor ->
+ tr_EventsDescriptor(Val, State);
+ eventBufferDescriptor ->
+ tr_EventBufferDescriptor(Val, State);
+ signalsDescriptor ->
+ tr_SignalsDescriptor(Val, State);
+ digitMapDescriptor ->
+ tr_DigitMapDescriptor(Val, State);
+ observedEventsDescriptor ->
+ tr_ObservedEventsDescriptor(Val, State);
+ statisticsDescriptor ->
+ tr_StatisticsDescriptor(Val, State);
+ packagesDescriptor ->
+ tr_PackagesDescriptor(Val, State);
+ emptyDescriptors ->
+ tr_EmptyDescriptors(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_EmptyDescriptors(#'AuditDescriptor'{auditToken = Tokens},
+ State) ->
+ Tokens2 =
+ case Tokens of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> [tr_auditItem(Token, State) || Token <- Tokens]
+ end,
+ #'AuditDescriptor'{auditToken = Tokens2}.
+
+tr_NotifyRequest(#'NotifyRequest'{terminationID = IdList,
+ observedEventsDescriptor = ObsDesc,
+ errorDescriptor = ErrDesc},
+ State) ->
+ %% BUGBUG: Mismatch between ASN.1 and ABNF
+ %% BUGBUG: The following ought to be a 'choice'
+ #'NotifyRequest'{terminationID = [tr_TerminationID(Id, State) ||
+ Id <- IdList],
+ observedEventsDescriptor = tr_ObservedEventsDescriptor(ObsDesc, State),
+ errorDescriptor = tr_opt_ErrorDescriptor(ErrDesc, State)}.
+
+tr_NotifyReply(#'NotifyReply'{terminationID = IdList,
+ errorDescriptor = ErrDesc},
+ State) ->
+ #'NotifyReply'{terminationID = [tr_TerminationID(Id, State) || Id <- IdList],
+ errorDescriptor = tr_opt_ErrorDescriptor(ErrDesc, State)}.
+
+tr_ObservedEventsDescriptor(#'ObservedEventsDescriptor'{requestId = Id,
+ observedEventLst = Events},
+ State) when is_list (Events) ->
+ #'ObservedEventsDescriptor'{requestId = tr_RequestID(Id, State),
+ observedEventLst = [tr_ObservedEvent(E, State) || E <- Events]}.
+
+%% ;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
+
+tr_ObservedEvent(#'ObservedEvent'{eventName = Name,
+ streamID = Id,
+ eventParList = Parms,
+ timeNotation = Time},
+ State) ->
+ #'ObservedEvent'{eventName = tr_EventName(Name, State),
+ streamID = tr_opt_StreamID(Id, State),
+ eventParList = [tr_EventParameter(P, Name, State) || P <- Parms],
+ timeNotation = tr_opt_TimeNotation(Time, State)}.
+
+tr_EventName(Name, State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ resolve(event, Name, State, Constraint).
+
+tr_EventParameter(#'EventParameter'{eventParameterName = ParName,
+ value = Value,
+ extraInfo = Extra},
+ EventName,
+ State) ->
+ %% BUGBUG: event parameter name
+ Constraint = fun(Item) -> tr_Name(Item, State) end,
+ N = resolve({event_parameter, EventName}, ParName, State, Constraint),
+ #'EventParameter'{eventParameterName = N,
+ value = tr_Value(Value, State),
+ extraInfo = tr_opt_extraInfo(Extra, State)}.
+
+tr_ServiceChangeRequest(#'ServiceChangeRequest'{terminationID = IdList,
+ serviceChangeParms = Parms},
+ State) ->
+ #'ServiceChangeRequest'{terminationID = [tr_TerminationID(Id, State) || Id <- IdList],
+ serviceChangeParms = tr_ServiceChangeParm(Parms, 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 )
+tr_ServiceChangeReply(#'ServiceChangeReply'{terminationID = IdList,
+ serviceChangeResult = Res},
+ State) ->
+ #'ServiceChangeReply'{terminationID = [tr_TerminationID(Id, State) || Id <- IdList],
+ serviceChangeResult = tr_ServiceChangeResult(Res, State)}.
+
+tr_ServiceChangeResult({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ errorDescriptor -> tr_ErrorDescriptor(Val, State);
+ serviceChangeResParms -> tr_ServiceChangeResParm(Val, State)
+ end,
+ {Tag, Val2}.
+
+%% TerminationID = "ROOT" / pathNAME / "$" / "*"
+%% ; Total length of pathNAME must not exceed 64 chars.
+%% pathNAME = ["*"] NAME *("/" / "*"/ ALPHA / DIGIT /"_" / "$" )
+%% ["@" pathDomainName ]
+
+tr_TerminationID(TermId, State) when State#state.mode =/= verify ->
+ resolve(term_id, TermId, State, valid);
+tr_TerminationID(#'TerminationID'{wildcard = Wild,
+ id = Id},
+ _State) ->
+ #'TerminationID'{wildcard = Wild,
+ id = Id};
+tr_TerminationID(#megaco_term_id{contains_wildcards = IsWild,
+ id = Id},
+ State) ->
+ #megaco_term_id{contains_wildcards = tr_bool(IsWild, State),
+ id = [tr_term_id_component(Sub, State) || Sub <- Id]}.
+
+tr_opt_bool(asn1_NOVALUE, _State) -> asn1_NOVALUE;
+tr_opt_bool(Bool, State) -> tr_bool(Bool, State).
+
+tr_bool(true, _State) -> true;
+tr_bool(false, _State) -> false.
+
+tr_term_id_component(Sub, _State) ->
+ case Sub of
+ all -> all;
+ choose -> 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
+tr_MediaDescriptor(#'MediaDescriptor'{termStateDescr = TermState,
+ streams = Streams},
+ State) ->
+ #'MediaDescriptor'{termStateDescr = tr_opt_TerminationStateDescriptor(TermState, State),
+ streams = tr_opt_streams(Streams, State)}.
+
+tr_opt_streams(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_streams({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ oneStream -> tr_StreamParms(Val, State);
+ multiStream -> [tr_StreamDescriptor(SD, State) || SD <- Val]
+ end,
+ {Tag, Val2}.
+
+tr_StreamParms(#'StreamParms'{localControlDescriptor = LCD,
+ localDescriptor = LD,
+ remoteDescriptor = RD,
+ statisticsDescriptor = SD},
+ State) ->
+ LCD2 = tr_opt_LocalControlDescriptor(LCD, State),
+ LD2 = tr_opt_LocalRemoteDescriptor(LD, State),
+ RD2 = tr_opt_LocalRemoteDescriptor(RD, State),
+ SD2 = tr_opt_StatisticsDescriptor(SD, State),
+ #'StreamParms'{localControlDescriptor = LCD2,
+ localDescriptor = LD2,
+ remoteDescriptor = RD2,
+ statisticsDescriptor = SD2}.
+
+tr_StreamDescriptor(#'StreamDescriptor'{streamID = Id,
+ streamParms = Parms},
+ State) ->
+ #'StreamDescriptor'{streamID = tr_StreamID(Id, State),
+ streamParms = tr_StreamParms(Parms, 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
+tr_opt_LocalControlDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_LocalControlDescriptor(#'LocalControlDescriptor'{streamMode = Mode,
+ reserveGroup = Group,
+ reserveValue = Value,
+ propertyParms = Props},
+ State) ->
+ #'LocalControlDescriptor'{streamMode = tr_opt_StreamMode(Mode, State),
+ reserveGroup = tr_opt_bool(Group, State),
+ reserveValue = tr_opt_bool(Value, State),
+ propertyParms = [tr_PropertyParm(P, State) || P <- Props]}.
+
+tr_opt_StreamMode(Mode, _State) ->
+ case Mode of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ sendOnly -> sendOnly;
+ recvOnly -> recvOnly;
+ sendRecv -> sendRecv;
+ inactive -> inactive;
+ loopBack -> loopBack
+ end.
+
+tr_Name(Name, State) ->
+ %% BUGBUG: transform
+ %% BUGBUG: NAME = ALPHA *63(ALPHA / DIGIT / "_" )
+ tr_STRING(Name, State, 2, 2).
+
+tr_PkgdName(Name, State) ->
+ %% BUGBUG: transform
+ %% BUGBUG: pkgdName = (NAME / "*") SLASH (ItemID / "*" )
+ tr_OCTET_STRING(Name, State, 4, 4).
+
+%% 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.
+tr_opt_LocalRemoteDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_LocalRemoteDescriptor(#'LocalRemoteDescriptor'{propGrps = Groups},
+ State) ->
+ #'LocalRemoteDescriptor'{propGrps = [tr_PropertyGroup(G, State) || G <- Groups]}.
+
+tr_PropertyGroup(Props, State) ->
+ [tr_PropertyGroupParm(P, State) || P <- Props].
+
+tr_PropertyGroupParm(#'PropertyParm'{name = Name,
+ value = Value},
+ State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ #'PropertyParm'{name = resolve(property, Name, State, Constraint),
+ value = tr_OCTET_STRING(Value, State, 0, infinity)}.
+
+tr_PropertyParm(#'PropertyParm'{name = Name,
+ value = Value,
+ extraInfo = Extra},
+ State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ #'PropertyParm'{name = resolve(property, Name, State, Constraint),
+ value = tr_Value(Value, State),
+ extraInfo = tr_opt_extraInfo(Extra, State)}.
+
+tr_opt_extraInfo(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_extraInfo({relation, Rel}, _State) ->
+ Rel2 =
+ case Rel of
+ greaterThan -> greaterThan;
+ smallerThan -> smallerThan;
+ unequalTo -> unequalTo
+ end,
+ {relation, Rel2};
+tr_opt_extraInfo({range, Range}, State) ->
+ Range2 = tr_bool(Range, State),
+ {range, Range2};
+tr_opt_extraInfo({sublist, Sub}, State) ->
+ Sub2 = tr_bool(Sub, State),
+ {sublist, Sub2}.
+
+tr_opt_TerminationStateDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_TerminationStateDescriptor(#'TerminationStateDescriptor'{propertyParms = Props,
+ eventBufferControl = Control,
+ serviceState = Service},
+ State) ->
+ #'TerminationStateDescriptor'{propertyParms = [tr_PropertyParm(P, State) || P <- Props],
+ eventBufferControl = tr_opt_EventBufferControl(Control, State),
+ serviceState = tr_opt_ServiceState(Service, State)}.
+
+tr_opt_EventBufferControl(Control, _State) ->
+ case Control of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ off -> off;
+ lockStep -> lockStep
+ end.
+
+tr_opt_ServiceState(Service, _State) ->
+ case Service of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ test -> test;
+ outOfSvc -> outOfSvc;
+ inSvc -> inSvc
+ end.
+
+tr_MuxDescriptor(#'MuxDescriptor'{muxType = Type,
+ termList = IdList},
+ State) ->
+ #'MuxDescriptor'{muxType = tr_MuxType(Type, State),
+ termList = [tr_TerminationID(Id, State) || Id <- IdList]}.
+
+tr_MuxType(Type, _State) ->
+ case Type of
+ h221 -> h221;
+ h223 -> h223;
+ h226 -> h226;
+ v76 -> v76
+ end.
+
+tr_opt_StreamID(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_StreamID(Id, State) ->
+ tr_StreamID(Id, State).
+
+tr_StreamID(Id, State) ->
+ tr_UINT16(Id, State).
+
+tr_EventsDescriptor(#'EventsDescriptor'{requestID = Id,
+ eventList = Events},
+ State) ->
+ #'EventsDescriptor'{requestID = tr_opt_RequestID(Id, State),
+ eventList = [tr_RequestedEvent(E, State) || E <- Events]}.
+
+tr_RequestedEvent(#'RequestedEvent'{pkgdName = Name,
+ streamID = Id,
+ evParList = Parms,
+ eventAction = Actions},
+ State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ #'RequestedEvent'{pkgdName = resolve(event, Name, State, Constraint),
+ streamID = tr_opt_StreamID(Id, State),
+ eventAction = tr_opt_RequestedActions(Actions, State),
+ evParList = [tr_EventParameter(P, Name, State) || P <- Parms]}.
+
+tr_RegulatedEmbeddedDescriptor(
+ #'RegulatedEmbeddedDescriptor'{secondEvent = SE,
+ signalsDescriptor = SD}, State) ->
+ SE2 = tr_opt_SecondEventsDescriptor(SE, State),
+ SD2 = tr_opt_SignalsDescriptor(SD, State),
+ #'RegulatedEmbeddedDescriptor'{secondEvent = SE2,
+ signalsDescriptor = SD2}.
+
+tr_opt_NotifyBehaviour(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_NotifyBehaviour(NB, State) ->
+ tr_NotifyBehaviour(NB, State).
+
+tr_NotifyBehaviour({notifyImmediate, 'NULL'} = NB, _State) ->
+ NB;
+tr_NotifyBehaviour({notifyRegulated = Tag, Val}, State) ->
+ {Tag, tr_RegulatedEmbeddedDescriptor(Val, State)};
+tr_NotifyBehaviour({neverNotify, 'NULL'} = NB, _State) ->
+ NB.
+
+tr_opt_RequestedActions(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_RequestedActions(#'RequestedActions'{keepActive = KA,
+ eventDM = DM,
+ secondEvent = SE,
+ signalsDescriptor = SD,
+ notifyBehaviour = NB,
+ resetEventsDescriptor = RSD},
+ State) ->
+ KA2 = tr_opt_keepActive(KA, State),
+ DM2 = tr_opt_EventDM(DM, State),
+ SE2 = tr_opt_SecondEventsDescriptor(SE, State),
+ SD2 = tr_opt_SignalsDescriptor(SD, State),
+ NB2 = tr_opt_NotifyBehaviour(NB, State),
+ RSD2 = tr_opt_null(RSD, State),
+ #'RequestedActions'{keepActive = KA2,
+ eventDM = DM2,
+ secondEvent = SE2,
+ signalsDescriptor = SD2,
+ notifyBehaviour = NB2,
+ resetEventsDescriptor = RSD2}.
+
+tr_opt_keepActive(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_keepActive(Keep, State) ->
+ tr_bool(Keep, State).
+
+tr_opt_EventDM(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_EventDM({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ digitMapName -> tr_DigitMapName(Val, State);
+ digitMapValue -> tr_DigitMapValue(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_opt_SecondEventsDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_SecondEventsDescriptor(#'SecondEventsDescriptor'{requestID = Id,
+ eventList = Events},
+ State) ->
+ #'SecondEventsDescriptor'{requestID = tr_RequestID(Id, State), %% IG v6 6.8 withdrawn
+ eventList = [tr_SecondRequestedEvent(E, State) || E <- Events]}.
+
+tr_SecondRequestedEvent(#'SecondRequestedEvent'{pkgdName = Name,
+ streamID = Id,
+ evParList = Parms,
+ eventAction = Actions},
+ State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ #'SecondRequestedEvent'{pkgdName = resolve(event, Name, State, Constraint),
+ streamID = tr_opt_StreamID(Id, State),
+ eventAction = tr_opt_SecondRequestedActions(Actions, State),
+ evParList = [tr_EventParameter(P, Name, State) || P <- Parms]}.
+
+
+tr_opt_SecondRequestedActions(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_SecondRequestedActions(
+ #'SecondRequestedActions'{keepActive = KA,
+ eventDM = DM,
+ signalsDescriptor = SD,
+ notifyBehaviour = NB,
+ resetEventsDescriptor = RSD},
+ State) ->
+ KA2 = tr_opt_keepActive(KA, State),
+ DM2 = tr_opt_EventDM(DM, State),
+ SD2 = tr_opt_SignalsDescriptor(SD, State),
+ NB2 = tr_opt_NotifyBehaviour(NB, State),
+ RSD2 = tr_opt_null(RSD, State),
+ #'SecondRequestedActions'{keepActive = KA2,
+ eventDM = DM2,
+ signalsDescriptor = SD2,
+ notifyBehaviour = NB2,
+ resetEventsDescriptor = RSD2}.
+
+tr_EventBufferDescriptor(EventSpecs, State) ->
+ [tr_EventSpec(ES, State) || ES <- EventSpecs].
+
+tr_EventSpec(#'EventSpec'{eventName = Name,
+ streamID = Id,
+ eventParList = Parms},
+ State) ->
+ #'EventSpec'{eventName = tr_EventName(Name, State),
+ streamID = tr_opt_StreamID(Id, State),
+ eventParList = [tr_EventParameter(P, Name, State) || P <- Parms]}.
+
+tr_opt_SignalsDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_SignalsDescriptor(SigDesc, State) ->
+ tr_SignalsDescriptor(SigDesc, State).
+
+tr_SignalsDescriptor(SigDesc, State) when is_list(SigDesc) ->
+ [tr_SignalRequest(SigReq, State) || SigReq <- SigDesc].
+
+tr_SignalRequest({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ signal -> tr_Signal(Val, State);
+ seqSigList -> tr_SeqSigList(Val, State)
+ end,
+ {Tag, Val2}.
+
+
+tr_SeqSigList(#'SeqSigList'{id = Id,
+ signalList = SigList},
+ State) when is_list(SigList) ->
+ #'SeqSigList'{id = tr_UINT16(Id, State),
+ signalList = [tr_Signal(Sig, State) || Sig <- SigList]}.
+
+tr_Signal(#'Signal'{signalName = Name,
+ streamID = SID,
+ sigType = Type,
+ duration = Dur,
+ notifyCompletion = Compl,
+ keepActive = Keep,
+ sigParList = Parms,
+ direction = Dir,
+ requestID = RID,
+ intersigDelay = ID},
+ State) ->
+ Name2 = tr_SignalName(Name, State),
+ SID2 = tr_opt_StreamID(SID, State),
+ Type2 = tr_opt_SignalType(Type, State),
+ Dur2 = tr_opt_UINT16(Dur, State),
+ Compl2 = tr_opt_NotifyCompletion(Compl, State),
+ Keep2 = tr_opt_keepActive(Keep, State),
+ Parms2 = [tr_SigParameter(P, Name, State) || P <- Parms],
+ Dir2 = tr_opt_SignalDirection(Dir, State),
+ RID2 = tr_opt_RequestID(RID, State),
+ ID2 = tr_opt_UINT16(ID, State),
+ #'Signal'{signalName = Name2,
+ streamID = SID2,
+ sigType = Type2,
+ duration = Dur2,
+ notifyCompletion = Compl2,
+ keepActive = Keep2,
+ sigParList = Parms2,
+ direction = Dir2,
+ requestID = RID2,
+ intersigDelay = ID2}.
+
+tr_opt_NotifyCompletion(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_NotifyCompletion(Items, State) when is_list(Items) ->
+ [tr_notifyCompletionItem(I, State) || I <- Items].
+
+tr_notifyCompletionItem(Item, _State) ->
+ case Item of
+ onTimeOut -> onTimeOut;
+ onInterruptByEvent -> onInterruptByEvent;
+ onInterruptByNewSignalDescr -> onInterruptByNewSignalDescr;
+ otherReason -> otherReason;
+ onIteration -> onIteration
+ end.
+
+tr_opt_SignalType(asn1_NOVALUE = Type, _State) ->
+ Type;
+tr_opt_SignalType(Type, _State) ->
+ case Type of
+ brief -> brief;
+ onOff -> onOff;
+ timeOut -> timeOut
+ end.
+
+tr_opt_SignalDirection(asn1_NOVALUE = SD, _State) ->
+ SD;
+tr_opt_SignalDirection(SD, _State) ->
+ case SD of
+ internal -> internal;
+ external -> external;
+ both -> both
+ end.
+
+tr_SignalName(Name, State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ resolve(signal, Name, State, Constraint).
+
+tr_SigParameter(#'SigParameter'{sigParameterName = ParName,
+ value = Value,
+ extraInfo = Extra},
+ SigName,
+ State) ->
+ Constraint = fun(Item) -> tr_Name(Item, State) end,
+ N = resolve({signal_parameter, SigName}, ParName, State, Constraint),
+ #'SigParameter'{sigParameterName = N,
+ value = tr_Value(Value, State),
+ extraInfo = tr_opt_extraInfo(Extra, State)}.
+
+tr_opt_RequestID(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_RequestID(Id, State) ->
+ tr_RequestID(Id, State).
+
+tr_RequestID(Id, _State) when Id =:= ?megaco_all_request_id ->
+ ?megaco_all_request_id;
+tr_RequestID(Id, State) ->
+ tr_UINT32(Id, State).
+
+tr_ModemDescriptor(_MD, _State) ->
+ deprecated.
+
+tr_DigitMapDescriptor(#'DigitMapDescriptor'{digitMapName = Name,
+ digitMapValue = Value},
+ State) ->
+ #'DigitMapDescriptor'{digitMapName = tr_opt_DigitMapName(Name, State),
+ digitMapValue = tr_opt_DigitMapValue(Value, State)}.
+
+tr_opt_DigitMapName(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_DigitMapName(Name, State) ->
+ tr_DigitMapName(Name, State).
+
+tr_DigitMapName(Name, State) ->
+ Constraint = fun(Item) -> tr_Name(Item, State) end,
+ resolve(dialplan, Name, State, Constraint).
+
+tr_opt_DigitMapValue(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_DigitMapValue(Value, State) ->
+ tr_DigitMapValue(Value, State).
+
+tr_DigitMapValue(#'DigitMapValue'{digitMapBody = Body,
+ startTimer = Start,
+ shortTimer = Short,
+ longTimer = Long},
+ State) ->
+ #'DigitMapValue'{startTimer = tr_opt_timer(Start, State),
+ shortTimer = tr_opt_timer(Short, State),
+ longTimer = tr_opt_timer(Long, State),
+ digitMapBody = tr_STRING(Body, State)}. %% BUGBUG: digitMapBody not handled at all
+
+tr_opt_timer(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_timer(Timer, State) ->
+ tr_DIGIT(Timer, State, 0, 99).
+
+tr_ServiceChangeParm(
+ #'ServiceChangeParm'{serviceChangeMethod = Method,
+ serviceChangeAddress = Addr,
+ serviceChangeVersion = Version,
+ serviceChangeProfile = Profile,
+ serviceChangeReason = Reason,
+ serviceChangeDelay = Delay,
+ serviceChangeMgcId = MgcId,
+ timeStamp = Time,
+ serviceChangeInfo = Info,
+ serviceChangeIncompleteFlag = Incomplete},
+ State) ->
+ Method2 = tr_ServiceChangeMethod(Method, State),
+ Addr2 = tr_opt_ServiceChangeAddress(Addr, State),
+ Version2 = tr_opt_serviceChangeVersion(Version, State),
+ Profile2 = tr_opt_ServiceChangeProfile(Profile, State),
+ Reason2 = tr_serviceChangeReason(Reason, State),
+ Delay2 = tr_opt_serviceChangeDelay(Delay, State),
+ MgcId2 = tr_opt_serviceChangeMgcId(MgcId, State),
+ Time2 = tr_opt_TimeNotation(Time, State),
+ Info2 = tr_opt_AuditDescriptor(Info, State),
+ Incomplete2 = tr_opt_null(Incomplete, State),
+ #'ServiceChangeParm'{serviceChangeMethod = Method2,
+ serviceChangeAddress = Addr2,
+ serviceChangeVersion = Version2,
+ serviceChangeProfile = Profile2,
+ serviceChangeReason = Reason2,
+ serviceChangeDelay = Delay2,
+ serviceChangeMgcId = MgcId2,
+ timeStamp = Time2,
+ serviceChangeInfo = Info2,
+ serviceChangeIncompleteFlag = Incomplete2}.
+
+tr_ServiceChangeMethod(Method, _State) ->
+ case Method of
+ failover -> failover;
+ forced -> forced;
+ graceful -> graceful;
+ restart -> restart;
+ disconnected -> disconnected;
+ handOff -> handOff
+ end. %% BUGBUG: extension
+
+tr_opt_ServiceChangeAddress(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_ServiceChangeAddress({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ portNumber -> tr_portNumber(Val, State);
+ ip4Address -> tr_IP4Address(Val, State);
+ ip6Address -> tr_IP6Address(Val, State);
+ domainName -> tr_DomainName(Val, State);
+ deviceName -> tr_PathName(Val, State);
+ mtpAddress -> tr_mtpAddress(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_opt_serviceChangeVersion(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_serviceChangeVersion(Version, State) ->
+ tr_version(Version, State).
+
+tr_opt_ServiceChangeProfile(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+%% Decode
+tr_opt_ServiceChangeProfile({'ServiceChangeProfile', ProfileName}, State) ->
+ case string:tokens(ProfileName, "/") of
+ [Name0, Version0] ->
+ Name = tr_STRING(Name0, State, 1, 64),
+ Version = tr_version(list_to_integer(Version0), State),
+ #'ServiceChangeProfile'{profileName = Name,
+ version = Version}
+ end;
+%% Encode
+tr_opt_ServiceChangeProfile(#'ServiceChangeProfile'{profileName = Name0,
+ version = Version0},
+ State) ->
+ Name = tr_STRING(Name0, State, 1, 64),
+ Version = tr_version(Version0, State),
+ ProfileName = lists:flatten(io_lib:format("~s/~w", [Name, Version])),
+ {'ServiceChangeProfile', ProfileName}.
+
+tr_serviceChangeReason([_] = Reason, State) ->
+ tr_Value(Reason, State).
+
+tr_opt_serviceChangeDelay(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_serviceChangeDelay(Delay, State) ->
+ tr_UINT32(Delay, State).
+
+tr_opt_serviceChangeMgcId(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_serviceChangeMgcId(MgcId, State) ->
+ tr_MId(MgcId, State).
+
+tr_opt_portNumber(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_portNumber(Port, State) ->
+ tr_portNumber(Port, State).
+
+tr_portNumber(Port, State) when is_integer(Port) andalso (Port >= 0) ->
+ tr_UINT16(Port, State).
+
+tr_ServiceChangeResParm(#'ServiceChangeResParm'{serviceChangeMgcId = MgcId,
+ serviceChangeAddress = Addr,
+ serviceChangeVersion = Version,
+ serviceChangeProfile = Profile,
+ timeStamp = Time},
+ State) ->
+ #'ServiceChangeResParm'{serviceChangeMgcId = tr_opt_serviceChangeMgcId(MgcId, State),
+ serviceChangeAddress = tr_opt_ServiceChangeAddress(Addr, State),
+ serviceChangeVersion = tr_opt_serviceChangeVersion(Version, State),
+ serviceChangeProfile = tr_opt_ServiceChangeProfile(Profile, State),
+ timeStamp = tr_opt_TimeNotation(Time, State)}.
+
+tr_PackagesDescriptor(Items, State) when is_list(Items) ->
+ [tr_PackagesItem(I, State) || I <- Items].
+
+tr_PackagesItem(#'PackagesItem'{packageName = Name,
+ packageVersion = Version},
+ State) ->
+ Constraint = fun(Item) -> tr_Name(Item, State) end,
+ #'PackagesItem'{packageName = resolve(package, Name, State, Constraint),
+ packageVersion = tr_UINT16(Version, State)}.
+
+tr_opt_StatisticsDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_StatisticsDescriptor(Parms, State) ->
+ tr_StatisticsDescriptor(Parms, State).
+
+tr_StatisticsDescriptor(Parms, State) when is_list(Parms) ->
+ [tr_StatisticsParameter(P, State) || P <- Parms].
+
+tr_StatisticsParameter(#'StatisticsParameter'{statName = Name,
+ statValue = Value},
+ State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ #'StatisticsParameter'{statName = resolve(statistics, Name, State, Constraint),
+ statValue = tr_opt_Value(Value, State)}.
+
+tr_opt_TimeNotation(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_TimeNotation(#'TimeNotation'{date = Date,
+ time = Time},
+ State) ->
+ #'TimeNotation'{date = tr_STRING(Date, State, 8, 8), % "yyyymmdd"
+ time = tr_STRING(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.
+
+tr_opt_Value(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_Value(Value, State) ->
+ tr_Value(Value, State).
+
+tr_Value(Strings, _State) when is_list(Strings) ->
+ [[Char || Char <- String] || String <- Strings].
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Encode an octet string, escape } by \ if necessary
+tr_OCTET_STRING(String, _State, Min, Max) when is_list(String) ->
+ verify_count(length(String), Min, Max),
+ String.
+
+tr_QUOTED_STRING(String, _State) when is_list(String) ->
+ verify_count(length(String), 1, infinity),
+ String.
+
+%% 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
+tr_HEXDIG(Octets, _State, Min, Max) when is_list(Octets) ->
+ verify_count(length(Octets), Min, Max),
+ Octets.
+
+tr_DIGIT(Val, State, Min, Max) ->
+ tr_integer(Val, State, Min, Max).
+
+tr_STRING(String, _State) when is_list(String) ->
+ String.
+
+tr_STRING(String, _State, Min, Max) when is_list(String) ->
+ verify_count(length(String), Min, Max),
+ String.
+
+tr_opt_UINT16(Val, State) ->
+ tr_opt_integer(Val, State, 0, 65535).
+
+tr_UINT16(Val, State) ->
+ tr_integer(Val, State, 0, 65535).
+
+tr_UINT32(Val, State) ->
+ tr_integer(Val, State, 0, 4294967295).
+
+tr_opt_integer(asn1_NOVALUE, _State, _Min, _Max) ->
+ asn1_NOVALUE;
+tr_opt_integer(Int, State, Min, Max) ->
+ tr_integer(Int, State, Min, Max).
+
+tr_integer(Int, _State, Min, Max) ->
+ verify_count(Int, Min, Max),
+ Int.
+
+%% 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).
+
+
diff --git a/lib/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_prev3a.set.asn b/lib/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_prev3a.set.asn
new file mode 100644
index 0000000000..b9ba7ffdb4
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_prev3a.set.asn
@@ -0,0 +1 @@
+MEDIA-GATEWAY-CONTROL-prev3a.asn
diff --git a/lib/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_prev3b.set.asn b/lib/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_prev3b.set.asn
new file mode 100644
index 0000000000..0437bde310
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_prev3b.set.asn
@@ -0,0 +1 @@
+MEDIA-GATEWAY-CONTROL-prev3b.asn
diff --git a/lib/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_prev3c.set.asn b/lib/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_prev3c.set.asn
new file mode 100644
index 0000000000..e78055fbad
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_prev3c.set.asn
@@ -0,0 +1 @@
+MEDIA-GATEWAY-CONTROL-prev3c.asn
diff --git a/lib/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_v1.set.asn b/lib/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_v1.set.asn
new file mode 100644
index 0000000000..0f5a92dba1
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_v1.set.asn
@@ -0,0 +1 @@
+MEDIA-GATEWAY-CONTROL-v1.asn
diff --git a/lib/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_v2.set.asn b/lib/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_v2.set.asn
new file mode 100644
index 0000000000..7fc82b127f
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_v2.set.asn
@@ -0,0 +1 @@
+MEDIA-GATEWAY-CONTROL-v2.asn
diff --git a/lib/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_v3.set.asn b/lib/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_v3.set.asn
new file mode 100644
index 0000000000..1d7950a283
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_v3.set.asn
@@ -0,0 +1 @@
+MEDIA-GATEWAY-CONTROL-v3.asn
diff --git a/lib/megaco/src/binary/megaco_per_bin_encoder.erl b/lib/megaco/src/binary/megaco_per_bin_encoder.erl
new file mode 100644
index 0000000000..f7280f4e04
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_per_bin_encoder.erl
@@ -0,0 +1,447 @@
+%%
+%% %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%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose : Handle ASN.1 PER encoding of Megaco/H.248
+%%----------------------------------------------------------------------
+
+-module(megaco_per_bin_encoder).
+
+-behaviour(megaco_encoder).
+
+-export([encode_message/3, decode_message/3,
+ decode_mini_message/3,
+
+ encode_transaction/3,
+ encode_action_requests/3,
+ encode_action_request/3,
+ encode_action_reply/3,
+
+ version_of/2]).
+
+%% Backward compatible functions:
+-export([encode_message/2, decode_message/2]).
+
+-include_lib("megaco/src/engine/megaco_message_internal.hrl").
+
+-define(V1_ASN1_MOD, megaco_per_bin_media_gateway_control_v1).
+-define(V2_ASN1_MOD, megaco_per_bin_media_gateway_control_v2).
+-define(V3_ASN1_MOD, megaco_per_bin_media_gateway_control_v3).
+-define(PREV3A_ASN1_MOD, megaco_per_bin_media_gateway_control_prev3a).
+-define(PREV3B_ASN1_MOD, megaco_per_bin_media_gateway_control_prev3b).
+-define(PREV3C_ASN1_MOD, megaco_per_bin_media_gateway_control_prev3c).
+-define(V1_ASN1_MOD_DRV, megaco_per_bin_drv_media_gateway_control_v1).
+-define(V2_ASN1_MOD_DRV, megaco_per_bin_drv_media_gateway_control_v2).
+-define(V3_ASN1_MOD_DRV, megaco_per_bin_drv_media_gateway_control_v3).
+-define(PREV3A_ASN1_MOD_DRV, megaco_per_bin_drv_media_gateway_control_prev3a).
+-define(PREV3B_ASN1_MOD_DRV, megaco_per_bin_drv_media_gateway_control_prev3b).
+-define(PREV3C_ASN1_MOD_DRV, megaco_per_bin_drv_media_gateway_control_prev3c).
+
+-define(V1_TRANS_MOD, megaco_binary_transformer_v1).
+-define(V2_TRANS_MOD, megaco_binary_transformer_v2).
+-define(V3_TRANS_MOD, megaco_binary_transformer_v3).
+-define(PREV3A_TRANS_MOD, megaco_binary_transformer_prev3a).
+-define(PREV3B_TRANS_MOD, megaco_binary_transformer_prev3b).
+-define(PREV3C_TRANS_MOD, megaco_binary_transformer_prev3c).
+
+-define(BIN_LIB, megaco_binary_encoder_lib).
+
+
+%%----------------------------------------------------------------------
+%% Detect (check/get) message version
+%% Return {ok, Version} | {error, Reason}
+%%----------------------------------------------------------------------
+
+version_of([{version3,v3},driver|EC], Binary) ->
+ Decoders = [?V1_ASN1_MOD_DRV, ?V2_ASN1_MOD_DRV, ?V3_ASN1_MOD_DRV],
+ ?BIN_LIB:version_of(EC, Binary, 1, Decoders);
+version_of([{version3,prev3c},driver|EC], Binary) ->
+ Decoders = [?V1_ASN1_MOD_DRV, ?V2_ASN1_MOD_DRV, ?PREV3C_ASN1_MOD_DRV],
+ ?BIN_LIB:version_of(EC, Binary, 1, Decoders);
+version_of([{version3,prev3b},driver|EC], Binary) ->
+ Decoders = [?V1_ASN1_MOD_DRV, ?V2_ASN1_MOD_DRV, ?PREV3B_ASN1_MOD_DRV],
+ ?BIN_LIB:version_of(EC, Binary, 1, Decoders);
+version_of([{version3,prev3a},driver|EC], Binary) ->
+ Decoders = [?V1_ASN1_MOD_DRV, ?V2_ASN1_MOD_DRV, ?PREV3A_ASN1_MOD_DRV],
+ ?BIN_LIB:version_of(EC, Binary, 1, Decoders);
+version_of([driver|EC], Binary) ->
+ Decoders = [?V1_ASN1_MOD_DRV, ?V2_ASN1_MOD_DRV, ?V3_ASN1_MOD_DRV],
+ ?BIN_LIB:version_of(EC, Binary, 1, Decoders);
+version_of([{version3,v3}|EC], Binary) ->
+ Decoders = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?V3_ASN1_MOD],
+ ?BIN_LIB:version_of(EC, Binary, 1, Decoders);
+version_of([{version3,prev3c}|EC], Binary) ->
+ Decoders = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?PREV3C_ASN1_MOD],
+ ?BIN_LIB:version_of(EC, Binary, 1, Decoders);
+version_of([{version3,prev3b}|EC], Binary) ->
+ Decoders = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?PREV3B_ASN1_MOD],
+ ?BIN_LIB:version_of(EC, Binary, 1, Decoders);
+version_of([{version3,prev3a}|EC], Binary) ->
+ Decoders = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?PREV3A_ASN1_MOD],
+ ?BIN_LIB:version_of(EC, Binary, 1, Decoders);
+
+%% All values we need to take (special) care of has been delt with,
+%% so just pass the rest on
+version_of(EC, Binary) ->
+ Decoders = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?V3_ASN1_MOD],
+ ?BIN_LIB:version_of(EC, Binary, 1, Decoders).
+
+
+%%----------------------------------------------------------------------
+%% Convert a 'MegacoMessage' record into a binary
+%% Return {ok, Binary} | {error, Reason}
+%%----------------------------------------------------------------------
+
+encode_message(EC,
+ #'MegacoMessage'{mess = #'Message'{version = V}} = MegaMsg) ->
+ encode_message(EC, V, MegaMsg).
+
+
+%% -- Version 1 --
+
+encode_message([{version3, _},driver|EC], 1, MegaMsg) ->
+ AsnMod = ?V1_ASN1_MOD_DRV,
+ TransMod = ?V1_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message([driver|EC], 1, MegaMsg) ->
+ AsnMod = ?V1_ASN1_MOD_DRV,
+ TransMod = ?V1_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message([{version3,_}|EC], 1, MegaMsg) ->
+ AsnMod = ?V1_ASN1_MOD,
+ TransMod = ?V1_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+
+%% All values we need to take (special) care of has been delt with,
+%% so just pass the rest on
+encode_message(EC, 1, MegaMsg) ->
+ AsnMod = ?V1_ASN1_MOD,
+ TransMod = ?V1_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+
+
+%% -- Version 2 --
+
+encode_message([{version3,_},driver|EC], 2, MegaMsg) ->
+ AsnMod = ?V2_ASN1_MOD_DRV,
+ TransMod = ?V2_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message([driver|EC], 2, MegaMsg) ->
+ AsnMod = ?V2_ASN1_MOD_DRV,
+ TransMod = ?V2_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message([{version3,_}|EC], 2, MegaMsg) ->
+ AsnMod = ?V2_ASN1_MOD,
+ TransMod = ?V2_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+
+%% All values we need to take (special) care of has been delt with,
+%% so just pass the rest on
+encode_message(EC, 2, MegaMsg) ->
+ AsnMod = ?V2_ASN1_MOD,
+ TransMod = ?V2_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+
+
+%% -- Version 3 --
+
+encode_message([{version3,v3},driver|EC], 3, MegaMsg) ->
+ AsnMod = ?V3_ASN1_MOD_DRV,
+ TransMod = ?V3_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message([{version3,prev3c},driver|EC], 3, MegaMsg) ->
+ AsnMod = ?PREV3C_ASN1_MOD_DRV,
+ TransMod = ?PREV3C_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message([{version3,prev3b},driver|EC], 3, MegaMsg) ->
+ AsnMod = ?PREV3B_ASN1_MOD_DRV,
+ TransMod = ?PREV3B_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message([{version3,prev3a},driver|EC], 3, MegaMsg) ->
+ AsnMod = ?PREV3A_ASN1_MOD_DRV,
+ TransMod = ?PREV3A_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message([driver|EC], 3, MegaMsg) ->
+ AsnMod = ?V3_ASN1_MOD_DRV,
+ TransMod = ?V3_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message([{version3,v3}|EC], 3, MegaMsg) ->
+ AsnMod = ?V3_ASN1_MOD,
+ TransMod = ?V3_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message([{version3,prev3c}|EC], 3, MegaMsg) ->
+ AsnMod = ?PREV3C_ASN1_MOD,
+ TransMod = ?PREV3C_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message([{version3,prev3b}|EC], 3, MegaMsg) ->
+ AsnMod = ?PREV3B_ASN1_MOD,
+ TransMod = ?PREV3B_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message([{version3,prev3a}|EC], 3, MegaMsg) ->
+ AsnMod = ?PREV3A_ASN1_MOD,
+ TransMod = ?PREV3A_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+
+%% All values we need to take (special) care of has been delt with,
+%% so just pass the rest on
+encode_message(EC, 3, MegaMsg) ->
+ AsnMod = ?V3_ASN1_MOD,
+ TransMod = ?V3_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list).
+
+
+%%----------------------------------------------------------------------
+%% Convert a transaction (or transactions in the case of ack) record(s)
+%% into a binary
+%% Return {ok, Binary} | {error, Reason}
+%%----------------------------------------------------------------------
+
+%% encode_transaction([] = EC, 1, Trans) ->
+%% AsnMod = ?V1_ASN1_MOD,
+%% TransMod = ?V1_TRANS_MOD,
+%% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
+%% io_list);
+%% encode_transaction([native] = EC, 1, Trans) ->
+%% AsnMod = ?V1_ASN1_MOD,
+%% TransMod = ?V1_TRANS_MOD,
+%% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
+%% io_list);
+%% encode_transaction([driver|EC], 1, Trans) ->
+%% AsnMod = ?V1_ASN1_MOD_DRV,
+%% TransMod = ?V1_TRANS_MOD,
+%% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
+%% io_list);
+encode_transaction(_EC, 1, _Trans) ->
+ %% AsnMod = ?V1_ASN1_MOD,
+ %% TransMod = ?V1_TRANS_MOD,
+ %% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
+ %% io_list);
+ {error, not_implemented};
+
+%% encode_transaction([] = EC, 2, Trans) ->
+%% AsnMod = ?V2_ASN1_MOD,
+%% TransMod = ?V2_TRANS_MOD,
+%% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
+%% io_list);
+%% encode_transaction([native] = EC, 2, Trans) ->
+%% AsnMod = ?V2_ASN1_MOD,
+%% TransMod = ?V2_TRANS_MOD,
+%% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
+%% io_list);
+%% encode_transaction([driver|EC], 2, Trans) ->
+%% AsnMod = ?V2_ASN1_MOD_DRV,
+%% TransMod = ?V2_TRANS_MOD,
+%% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
+%% io_list);
+encode_transaction(_EC, 2, _Trans) ->
+ %% AsnMod = ?V2_ASN1_MOD,
+ %% TransMod = ?V2_TRANS_MOD,
+ %% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
+ %% io_list).
+ {error, not_implemented};
+
+%% encode_transaction([] = EC, 3, Trans) ->
+%% AsnMod = ?V3_ASN1_MOD,
+%% TransMod = ?V3_TRANS_MOD,
+%% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
+%% io_list);
+%% encode_transaction([native] = EC, 3, Trans) ->
+%% AsnMod = ?V3_ASN1_MOD,
+%% TransMod = ?V3_TRANS_MOD,
+%% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
+%% io_list);
+%% encode_transaction([driver|EC], 3, Trans) ->
+%% AsnMod = ?V3_ASN1_MOD_DRV,
+%% TransMod = ?V3_TRANS_MOD,
+%% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
+%% io_list);
+encode_transaction(_EC, 3, _Trans) ->
+ %% AsnMod = ?V3_ASN1_MOD,
+ %% TransMod = ?V3_TRANS_MOD,
+ %% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod, %% io_list).
+ {error, not_implemented}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a list of ActionRequest record's into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_requests(_EC, 1, ActReqs) when is_list(ActReqs) ->
+ %% ?BIN_LIB:encode_action_requests(EC, ActReqs,
+ %% ?V1_ASN1_MOD,
+ %% ?V1_TRANS_MOD,
+ %% io_list);
+ {error, not_implemented};
+encode_action_requests(_EC, 2, ActReqs) when is_list(ActReqs) ->
+ %% ?BIN_LIB:encode_action_requests(EC, ActReqs,
+ %% ?V1_ASN1_MOD,
+ %% ?V1_TRANS_MOD,
+ %% io_list).
+ {error, not_implemented};
+encode_action_requests(_EC, 3, ActReqs) when is_list(ActReqs) ->
+ %% ?BIN_LIB:encode_action_requests(EC, ActReqs,
+ %% ?V1_ASN1_MOD,
+ %% ?V1_TRANS_MOD,
+ %% io_list).
+ {error, not_implemented}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a ActionRequest record into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_request(_EC, 1, _ActReq) ->
+ %% ?BIN_LIB:encode_action_request(EC, ActReq,
+ %% ?V1_ASN1_MOD,
+ %% ?V1_TRANS_MOD,
+ %% io_list);
+ {error, not_implemented};
+encode_action_request(_EC, 2, _ActReq) ->
+ %% ?BIN_LIB:encode_action_request(EC, ActReq,
+ %% ?V1_ASN1_MOD,
+ %% ?V1_TRANS_MOD,
+ %% io_list).
+ {error, not_implemented};
+encode_action_request(_EC, 3, _ActReq) ->
+ %% ?BIN_LIB:encode_action_request(EC, ActReq,
+ %% ?V1_ASN1_MOD,
+ %% ?V1_TRANS_MOD,
+ %% io_list).
+ {error, not_implemented}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a action reply into a deep io list
+%% Not yest supported by this binary codec!
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+
+encode_action_reply(_EC, _V, _AcionReply) ->
+ {error, not_implemented}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a binary into a 'MegacoMessage' record
+%% Return {ok, MegacoMessageRecord} | {error, Reason}
+%%----------------------------------------------------------------------
+
+decode_message(EC, Binary) ->
+ decode_message(EC, 1, Binary).
+
+%% PER does not support partial decode, so this means V1
+decode_message(EC, dynamic, Binary) ->
+ decode_message(EC, 1, Binary);
+
+
+%% -- Version 1 --
+
+decode_message([{version3,_},driver|EC], 1, Binary) ->
+ AsnMod = ?V1_ASN1_MOD_DRV,
+ TransMod = ?V1_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([driver|EC], 1, Binary) ->
+ AsnMod = ?V1_ASN1_MOD_DRV,
+ TransMod = ?V1_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([{version3,_}|EC], 1, Binary) ->
+ AsnMod = ?V1_ASN1_MOD,
+ TransMod = ?V1_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+
+%% All values we need to take (special) care of has been delt with,
+%% so just pass the rest on
+decode_message(EC, 1, Binary) ->
+ AsnMod = ?V1_ASN1_MOD,
+ TransMod = ?V1_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+
+
+%% -- Version 2 --
+
+decode_message([{version3,_},driver|EC], 2, Binary) ->
+ AsnMod = ?V2_ASN1_MOD_DRV,
+ TransMod = ?V2_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([driver|EC], 2, Binary) ->
+ AsnMod = ?V2_ASN1_MOD_DRV,
+ TransMod = ?V2_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([{version3,_}|EC], 2, Binary) ->
+ AsnMod = ?V2_ASN1_MOD,
+ TransMod = ?V2_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+
+%% All values we need to take (special) care of has been delt with,
+%% so just pass the rest on
+decode_message(EC, 2, Binary) ->
+ AsnMod = ?V2_ASN1_MOD,
+ TransMod = ?V2_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+
+
+%% -- Version 3 --
+
+decode_message([{version3,v3},driver|EC], 3, Binary) ->
+ AsnMod = ?V3_ASN1_MOD_DRV,
+ TransMod = ?V3_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([{version3,prev3c},driver|EC], 3, Binary) ->
+ AsnMod = ?PREV3C_ASN1_MOD_DRV,
+ TransMod = ?PREV3C_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([{version3,prev3b},driver|EC], 3, Binary) ->
+ AsnMod = ?PREV3B_ASN1_MOD_DRV,
+ TransMod = ?PREV3B_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([{version3,prev3a},driver|EC], 3, Binary) ->
+ AsnMod = ?PREV3A_ASN1_MOD_DRV,
+ TransMod = ?PREV3A_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([driver|EC], 3, Binary) ->
+ AsnMod = ?V3_ASN1_MOD_DRV,
+ TransMod = ?V3_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([{version3,v3}|EC], 3, Binary) ->
+ AsnMod = ?V3_ASN1_MOD,
+ TransMod = ?V3_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([{version3,prev3c}|EC], 3, Binary) ->
+ AsnMod = ?PREV3C_ASN1_MOD,
+ TransMod = ?PREV3C_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([{version3,prev3b}|EC], 3, Binary) ->
+ AsnMod = ?PREV3B_ASN1_MOD,
+ TransMod = ?PREV3B_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([{version3,prev3a}|EC], 3, Binary) ->
+ AsnMod = ?PREV3A_ASN1_MOD,
+ TransMod = ?PREV3A_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+
+%% All values we need to take (special) care of has been delt with,
+%% so just pass the rest on
+decode_message(EC, 3, Binary) ->
+ AsnMod = ?V3_ASN1_MOD,
+ TransMod = ?V3_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary).
+
+
+decode_mini_message(_EC, _Vsn, _Bin) ->
+ {error, not_implemented}.
diff --git a/lib/megaco/src/binary/megaco_per_bin_media_gateway_control_prev3a.set.asn b/lib/megaco/src/binary/megaco_per_bin_media_gateway_control_prev3a.set.asn
new file mode 100644
index 0000000000..b9ba7ffdb4
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_per_bin_media_gateway_control_prev3a.set.asn
@@ -0,0 +1 @@
+MEDIA-GATEWAY-CONTROL-prev3a.asn
diff --git a/lib/megaco/src/binary/megaco_per_bin_media_gateway_control_prev3b.set.asn b/lib/megaco/src/binary/megaco_per_bin_media_gateway_control_prev3b.set.asn
new file mode 100644
index 0000000000..0437bde310
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_per_bin_media_gateway_control_prev3b.set.asn
@@ -0,0 +1 @@
+MEDIA-GATEWAY-CONTROL-prev3b.asn
diff --git a/lib/megaco/src/binary/megaco_per_bin_media_gateway_control_prev3c.set.asn b/lib/megaco/src/binary/megaco_per_bin_media_gateway_control_prev3c.set.asn
new file mode 100644
index 0000000000..e78055fbad
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_per_bin_media_gateway_control_prev3c.set.asn
@@ -0,0 +1 @@
+MEDIA-GATEWAY-CONTROL-prev3c.asn
diff --git a/lib/megaco/src/binary/megaco_per_bin_media_gateway_control_v1.set.asn b/lib/megaco/src/binary/megaco_per_bin_media_gateway_control_v1.set.asn
new file mode 100644
index 0000000000..0f5a92dba1
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_per_bin_media_gateway_control_v1.set.asn
@@ -0,0 +1 @@
+MEDIA-GATEWAY-CONTROL-v1.asn
diff --git a/lib/megaco/src/binary/megaco_per_bin_media_gateway_control_v2.set.asn b/lib/megaco/src/binary/megaco_per_bin_media_gateway_control_v2.set.asn
new file mode 100644
index 0000000000..7fc82b127f
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_per_bin_media_gateway_control_v2.set.asn
@@ -0,0 +1 @@
+MEDIA-GATEWAY-CONTROL-v2.asn
diff --git a/lib/megaco/src/binary/megaco_per_bin_media_gateway_control_v3.set.asn b/lib/megaco/src/binary/megaco_per_bin_media_gateway_control_v3.set.asn
new file mode 100644
index 0000000000..1d7950a283
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_per_bin_media_gateway_control_v3.set.asn
@@ -0,0 +1 @@
+MEDIA-GATEWAY-CONTROL-v3.asn
diff --git a/lib/megaco/src/binary/megaco_per_encoder.erl b/lib/megaco/src/binary/megaco_per_encoder.erl
new file mode 100644
index 0000000000..596e621c65
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_per_encoder.erl
@@ -0,0 +1,291 @@
+%%
+%% %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 : Handle ASN.1 PER encoding of Megaco/H.248
+%%----------------------------------------------------------------------
+
+-module(megaco_per_encoder).
+
+-behaviour(megaco_encoder).
+
+-export([encode_message/3, decode_message/3,
+ decode_mini_message/3,
+
+ encode_transaction/3,
+ encode_action_requests/3,
+ encode_action_request/3,
+ encode_action_reply/3,
+
+ version_of/2]).
+
+%% Backward compatible functions:
+-export([encode_message/2, decode_message/2]).
+
+-include_lib("megaco/src/engine/megaco_message_internal.hrl").
+
+-define(V1_ASN1_MOD, megaco_per_media_gateway_control_v1).
+-define(V2_ASN1_MOD, megaco_per_media_gateway_control_v2).
+-define(V3_ASN1_MOD, megaco_per_media_gateway_control_v3).
+-define(PREV3A_ASN1_MOD, megaco_per_media_gateway_control_prev3a).
+-define(PREV3B_ASN1_MOD, megaco_per_media_gateway_control_prev3b).
+-define(PREV3C_ASN1_MOD, megaco_per_media_gateway_control_prev3c).
+
+-define(V1_TRANS_MOD, megaco_binary_transformer_v1).
+-define(V2_TRANS_MOD, megaco_binary_transformer_v2).
+-define(V3_TRANS_MOD, megaco_binary_transformer_v3).
+-define(PREV3A_TRANS_MOD, megaco_binary_transformer_prev3a).
+-define(PREV3B_TRANS_MOD, megaco_binary_transformer_prev3b).
+-define(PREV3C_TRANS_MOD, megaco_binary_transformer_prev3c).
+
+-define(BIN_LIB, megaco_binary_encoder_lib).
+
+
+%%----------------------------------------------------------------------
+%% Detect (check/get) message version
+%% Return {ok, Version} | {error, Reason}
+%%----------------------------------------------------------------------
+
+version_of([{version3,v3}|EC], Binary) ->
+ Decoders = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?V3_ASN1_MOD],
+ ?BIN_LIB:version_of(EC, Binary, 1, Decoders);
+version_of([{version3,prev3c}|EC], Binary) ->
+ Decoders = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?PREV3C_ASN1_MOD],
+ ?BIN_LIB:version_of(EC, Binary, 1, Decoders);
+version_of([{version3,prev3b}|EC], Binary) ->
+ Decoders = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?PREV3B_ASN1_MOD],
+ ?BIN_LIB:version_of(EC, Binary, 1, Decoders);
+version_of([{version3,prev3a}|EC], Binary) ->
+ Decoders = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?PREV3A_ASN1_MOD],
+ ?BIN_LIB:version_of(EC, Binary, 1, Decoders);
+version_of(EC, Binary) ->
+ Decoders = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?V3_ASN1_MOD],
+ ?BIN_LIB:version_of(EC, Binary, 1, Decoders).
+
+
+%%----------------------------------------------------------------------
+%% Convert a 'MegacoMessage' record into a binary
+%% Return {ok, Binary} | {error, Reason}
+%%----------------------------------------------------------------------
+
+encode_message(EC,
+ #'MegacoMessage'{mess = #'Message'{version = V}} = MegaMsg) ->
+ encode_message(EC, V, MegaMsg).
+
+
+%% -- Version 1 --
+
+encode_message([{version3,_}|EC], 1, MegaMsg) ->
+ AsnMod = ?V1_ASN1_MOD,
+ TransMod = ?V1_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message(EC, 1, MegaMsg) ->
+ AsnMod = ?V1_ASN1_MOD,
+ TransMod = ?V1_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+
+
+%% -- Version 2 --
+
+encode_message([{version3,_}|EC], 2, MegaMsg) ->
+ AsnMod = ?V2_ASN1_MOD,
+ TransMod = ?V2_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message(EC, 2, MegaMsg) ->
+ AsnMod = ?V2_ASN1_MOD,
+ TransMod = ?V2_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+
+
+%% -- Version 3 --
+
+encode_message([{version3,v3}|EC], 3, MegaMsg) ->
+ AsnMod = ?V3_ASN1_MOD,
+ TransMod = ?V3_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message([{version3,prev3c}|EC], 3, MegaMsg) ->
+ AsnMod = ?PREV3C_ASN1_MOD,
+ TransMod = ?PREV3C_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message([{version3,prev3b}|EC], 3, MegaMsg) ->
+ AsnMod = ?PREV3B_ASN1_MOD,
+ TransMod = ?PREV3B_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message([{version3,prev3a}|EC], 3, MegaMsg) ->
+ AsnMod = ?PREV3A_ASN1_MOD,
+ TransMod = ?PREV3A_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message(EC, 3, MegaMsg) ->
+ AsnMod = ?V3_ASN1_MOD,
+ TransMod = ?V3_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list).
+
+
+%%----------------------------------------------------------------------
+%% Convert a transaction (or transactions in the case of ack) record(s)
+%% into a binary
+%% Return {ok, Binary} | {error, Reason}
+%%----------------------------------------------------------------------
+
+encode_transaction(_EC, 1, _Trans) ->
+%% AsnMod = ?V1_ASN1_MOD,
+%% TransMod = ?V1_TRANS_MOD,
+%% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
+%% io_list);
+ {error, not_implemented};
+encode_transaction(_EC, 2, _Trans) ->
+%% AsnMod = ?V2_ASN1_MOD,
+%% TransMod = ?V2_TRANS_MOD,
+%% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
+%% io_list);
+ {error, not_implemented};
+encode_transaction(_EC, 3, _Trans) ->
+%% AsnMod = ?V3_ASN1_MOD,
+%% TransMod = ?V3_TRANS_MOD,
+%% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
+%% io_list);
+ {error, not_implemented}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a list of ActionRequest record's into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_requests(_EC, 1, ActReqs) when is_list(ActReqs) ->
+%% AsnMod = ?V1_ASN1_MOD,
+%% TransMod = ?V1_TRANS_MOD,
+%% ?BIN_LIB:encode_action_requests(EC, ActReqs,
+%% AsnMod, TransMod,
+%% io_list);
+ {error, not_implemented};
+encode_action_requests(_EC, 2, ActReqs) when is_list(ActReqs) ->
+%% AsnMod = ?V2_ASN1_MOD,
+%% TransMod = ?V2_TRANS_MOD,
+%% ?BIN_LIB:encode_action_requests(EC, ActReqs,
+%% AsnMod, TransMod,
+%% io_list);
+ {error, not_implemented};
+encode_action_requests(_EC, 3, ActReqs) when is_list(ActReqs) ->
+%% AsnMod = ?V3_ASN1_MOD,
+%% TransMod = ?V3_TRANS_MOD,
+%% ?BIN_LIB:encode_action_requests(EC, ActReqs,
+%% AsnMod, TransMod,
+%% io_list);
+ {error, not_implemented}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a ActionRequest record into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_request(_EC, 1, _ActReq) ->
+%% AsnMod = ?V1_ASN1_MOD,
+%% TransMod = ?V1_TRANS_MOD,
+%% ?BIN_LIB:encode_action_request(EC, ActReq,
+%% AsnMod, TransMod,
+%% io_list);
+ {error, not_implemented};
+encode_action_request(_EC, 2, _ActReq) ->
+%% AsnMod = ?V2_ASN1_MOD,
+%% TransMod = ?V2_TRANS_MOD,
+%% ?BIN_LIB:encode_action_request(EC, ActReq,
+%% AsnMod, TransMod,
+%% io_list);
+ {error, not_implemented};
+encode_action_request(_EC, 3, _ActReq) ->
+%% AsnMod = ?V3_ASN1_MOD,
+%% TransMod = ?V3_TRANS_MOD,
+%% ?BIN_LIB:encode_action_request(EC, ActReq,
+%% AsnMod, TransMod,
+%% io_list);
+ {error, not_implemented}.
+
+
+
+%%----------------------------------------------------------------------
+%% Convert a action reply into a deep io list
+%% Not yest supported by this binary codec!
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+
+encode_action_reply(_EC, _V, _AcionReply) ->
+ {error, not_implemented}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a binary into a 'MegacoMessage' record
+%% Return {ok, MegacoMessageRecord} | {error, Reason}
+%%----------------------------------------------------------------------
+
+decode_message(EC, Binary) ->
+ decode_message(EC, 1, Binary).
+
+%% PER does not support partial decode, so this means V1
+decode_message(EC, dynamic, Binary) ->
+ decode_message(EC, 1, Binary);
+
+
+%% -- Version 1 --
+
+decode_message([{version3,_}|EC], 1, Binary) ->
+ AsnMod = ?V1_ASN1_MOD,
+ TransMod = ?V1_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, io_list);
+decode_message(EC, 1, Binary) ->
+ AsnMod = ?V1_ASN1_MOD,
+ TransMod = ?V1_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, io_list);
+
+%% -- Version 2 --
+
+decode_message([{version3,_}|EC], 2, Binary) ->
+ AsnMod = ?V2_ASN1_MOD,
+ TransMod = ?V2_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, io_list);
+decode_message(EC, 2, Binary) ->
+ AsnMod = ?V2_ASN1_MOD,
+ TransMod = ?V2_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, io_list);
+
+%% -- Version 3 --
+
+decode_message([{version3,v3}|EC], 3, Binary) ->
+ AsnMod = ?V3_ASN1_MOD,
+ TransMod = ?V3_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, io_list);
+decode_message([{version3,prev3c}|EC], 3, Binary) ->
+ AsnMod = ?PREV3C_ASN1_MOD,
+ TransMod = ?PREV3C_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, io_list);
+decode_message([{version3,prev3b}|EC], 3, Binary) ->
+ AsnMod = ?PREV3B_ASN1_MOD,
+ TransMod = ?PREV3B_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, io_list);
+decode_message([{version3,prev3a}|EC], 3, Binary) ->
+ AsnMod = ?PREV3A_ASN1_MOD,
+ TransMod = ?PREV3A_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, io_list);
+decode_message(EC, 3, Binary) ->
+ AsnMod = ?V3_ASN1_MOD,
+ TransMod = ?V3_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, io_list).
+
+decode_mini_message(_EC, _Vsn, _Bin) ->
+ {error, not_implemented}.
diff --git a/lib/megaco/src/binary/megaco_per_media_gateway_control_prev3a.set.asn b/lib/megaco/src/binary/megaco_per_media_gateway_control_prev3a.set.asn
new file mode 100644
index 0000000000..b9ba7ffdb4
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_per_media_gateway_control_prev3a.set.asn
@@ -0,0 +1 @@
+MEDIA-GATEWAY-CONTROL-prev3a.asn
diff --git a/lib/megaco/src/binary/megaco_per_media_gateway_control_prev3b.set.asn b/lib/megaco/src/binary/megaco_per_media_gateway_control_prev3b.set.asn
new file mode 100644
index 0000000000..0437bde310
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_per_media_gateway_control_prev3b.set.asn
@@ -0,0 +1 @@
+MEDIA-GATEWAY-CONTROL-prev3b.asn
diff --git a/lib/megaco/src/binary/megaco_per_media_gateway_control_prev3c.set.asn b/lib/megaco/src/binary/megaco_per_media_gateway_control_prev3c.set.asn
new file mode 100644
index 0000000000..e78055fbad
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_per_media_gateway_control_prev3c.set.asn
@@ -0,0 +1 @@
+MEDIA-GATEWAY-CONTROL-prev3c.asn
diff --git a/lib/megaco/src/binary/megaco_per_media_gateway_control_v1.set.asn b/lib/megaco/src/binary/megaco_per_media_gateway_control_v1.set.asn
new file mode 100644
index 0000000000..0f5a92dba1
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_per_media_gateway_control_v1.set.asn
@@ -0,0 +1 @@
+MEDIA-GATEWAY-CONTROL-v1.asn
diff --git a/lib/megaco/src/binary/megaco_per_media_gateway_control_v2.set.asn b/lib/megaco/src/binary/megaco_per_media_gateway_control_v2.set.asn
new file mode 100644
index 0000000000..7fc82b127f
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_per_media_gateway_control_v2.set.asn
@@ -0,0 +1 @@
+MEDIA-GATEWAY-CONTROL-v2.asn
diff --git a/lib/megaco/src/binary/megaco_per_media_gateway_control_v3.set.asn b/lib/megaco/src/binary/megaco_per_media_gateway_control_v3.set.asn
new file mode 100644
index 0000000000..1d7950a283
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_per_media_gateway_control_v3.set.asn
@@ -0,0 +1 @@
+MEDIA-GATEWAY-CONTROL-v3.asn
diff --git a/lib/megaco/src/binary/modules.mk b/lib/megaco/src/binary/modules.mk
new file mode 100644
index 0000000000..a86ce2aecc
--- /dev/null
+++ b/lib/megaco/src/binary/modules.mk
@@ -0,0 +1,128 @@
+#-*-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_binary_encoder \
+ megaco_binary_encoder_lib \
+ megaco_ber_encoder \
+ megaco_ber_media_gateway_control_v1 \
+ megaco_ber_media_gateway_control_v2 \
+ megaco_ber_media_gateway_control_prev3a \
+ megaco_ber_media_gateway_control_prev3b \
+ megaco_ber_media_gateway_control_prev3c \
+ megaco_ber_media_gateway_control_v3 \
+ megaco_ber_bin_encoder \
+ megaco_ber_bin_media_gateway_control_v1 \
+ megaco_ber_bin_media_gateway_control_v2 \
+ megaco_ber_bin_media_gateway_control_prev3a \
+ megaco_ber_bin_media_gateway_control_prev3b \
+ megaco_ber_bin_media_gateway_control_prev3c \
+ megaco_ber_bin_media_gateway_control_v3 \
+ megaco_ber_bin_drv_media_gateway_control_v1 \
+ megaco_ber_bin_drv_media_gateway_control_v2 \
+ megaco_ber_bin_drv_media_gateway_control_prev3a \
+ megaco_ber_bin_drv_media_gateway_control_prev3b \
+ megaco_ber_bin_drv_media_gateway_control_prev3c \
+ megaco_ber_bin_drv_media_gateway_control_v3 \
+ megaco_per_encoder \
+ megaco_per_media_gateway_control_v1 \
+ megaco_per_media_gateway_control_v2 \
+ megaco_per_media_gateway_control_prev3a \
+ megaco_per_media_gateway_control_prev3b \
+ megaco_per_media_gateway_control_prev3c \
+ megaco_per_media_gateway_control_v3 \
+ megaco_per_bin_encoder \
+ megaco_per_bin_media_gateway_control_v1 \
+ megaco_per_bin_media_gateway_control_v2 \
+ megaco_per_bin_media_gateway_control_prev3a \
+ megaco_per_bin_media_gateway_control_prev3b \
+ megaco_per_bin_media_gateway_control_prev3c \
+ megaco_per_bin_media_gateway_control_v3 \
+ megaco_per_bin_drv_media_gateway_control_v1 \
+ megaco_per_bin_drv_media_gateway_control_v2 \
+ megaco_per_bin_drv_media_gateway_control_prev3a \
+ megaco_per_bin_drv_media_gateway_control_prev3b \
+ megaco_per_bin_drv_media_gateway_control_prev3c \
+ megaco_per_bin_drv_media_gateway_control_v3 \
+ megaco_binary_name_resolver_v1 \
+ megaco_binary_name_resolver_v2 \
+ megaco_binary_name_resolver_prev3a \
+ megaco_binary_name_resolver_prev3b \
+ megaco_binary_name_resolver_prev3c \
+ megaco_binary_name_resolver_v3 \
+ megaco_binary_term_id \
+ megaco_binary_term_id_gen \
+ megaco_binary_transformer_v1 \
+ megaco_binary_transformer_v2 \
+ megaco_binary_transformer_prev3a \
+ megaco_binary_transformer_prev3b \
+ megaco_binary_transformer_prev3c \
+ megaco_binary_transformer_v3
+
+INTERNAL_HRL_FILES =
+
+ASN1_V1_SPEC = MEDIA-GATEWAY-CONTROL-v1
+ASN1_V2_SPEC = MEDIA-GATEWAY-CONTROL-v2
+ASN1_PREV3A_SPEC = MEDIA-GATEWAY-CONTROL-prev3a
+ASN1_PREV3B_SPEC = MEDIA-GATEWAY-CONTROL-prev3b
+ASN1_PREV3C_SPEC = MEDIA-GATEWAY-CONTROL-prev3c
+ASN1_V3_SPEC = MEDIA-GATEWAY-CONTROL-v3
+
+BER_ASN1_V1_SPEC = megaco_ber_media_gateway_control_v1
+BER_BIN_ASN1_V1_SPEC = megaco_ber_bin_media_gateway_control_v1
+BER_BIN_DRV_ASN1_V1_SPEC = megaco_ber_bin_drv_media_gateway_control_v1
+PER_ASN1_V1_SPEC = megaco_per_media_gateway_control_v1
+PER_BIN_ASN1_V1_SPEC = megaco_per_bin_media_gateway_control_v1
+PER_BIN_DRV_ASN1_V1_SPEC = megaco_per_bin_drv_media_gateway_control_v1
+
+BER_ASN1_V2_SPEC = megaco_ber_media_gateway_control_v2
+BER_BIN_ASN1_V2_SPEC = megaco_ber_bin_media_gateway_control_v2
+BER_BIN_DRV_ASN1_V2_SPEC = megaco_ber_bin_drv_media_gateway_control_v2
+PER_ASN1_V2_SPEC = megaco_per_media_gateway_control_v2
+PER_BIN_ASN1_V2_SPEC = megaco_per_bin_media_gateway_control_v2
+PER_BIN_DRV_ASN1_V2_SPEC = megaco_per_bin_drv_media_gateway_control_v2
+
+BER_ASN1_PREV3A_SPEC = megaco_ber_media_gateway_control_prev3a
+BER_BIN_ASN1_PREV3A_SPEC = megaco_ber_bin_media_gateway_control_prev3a
+BER_BIN_DRV_ASN1_PREV3A_SPEC = megaco_ber_bin_drv_media_gateway_control_prev3a
+PER_ASN1_PREV3A_SPEC = megaco_per_media_gateway_control_prev3a
+PER_BIN_ASN1_PREV3A_SPEC = megaco_per_bin_media_gateway_control_prev3a
+PER_BIN_DRV_ASN1_PREV3A_SPEC = megaco_per_bin_drv_media_gateway_control_prev3a
+
+BER_ASN1_PREV3B_SPEC = megaco_ber_media_gateway_control_prev3b
+BER_BIN_ASN1_PREV3B_SPEC = megaco_ber_bin_media_gateway_control_prev3b
+BER_BIN_DRV_ASN1_PREV3B_SPEC = megaco_ber_bin_drv_media_gateway_control_prev3b
+PER_ASN1_PREV3B_SPEC = megaco_per_media_gateway_control_prev3b
+PER_BIN_ASN1_PREV3B_SPEC = megaco_per_bin_media_gateway_control_prev3b
+PER_BIN_DRV_ASN1_PREV3B_SPEC = megaco_per_bin_drv_media_gateway_control_prev3b
+
+BER_ASN1_PREV3C_SPEC = megaco_ber_media_gateway_control_prev3c
+BER_BIN_ASN1_PREV3C_SPEC = megaco_ber_bin_media_gateway_control_prev3c
+BER_BIN_DRV_ASN1_PREV3C_SPEC = megaco_ber_bin_drv_media_gateway_control_prev3c
+PER_ASN1_PREV3C_SPEC = megaco_per_media_gateway_control_prev3c
+PER_BIN_ASN1_PREV3C_SPEC = megaco_per_bin_media_gateway_control_prev3c
+PER_BIN_DRV_ASN1_PREV3C_SPEC = megaco_per_bin_drv_media_gateway_control_prev3c
+
+BER_ASN1_V3_SPEC = megaco_ber_media_gateway_control_v3
+BER_BIN_ASN1_V3_SPEC = megaco_ber_bin_media_gateway_control_v3
+BER_BIN_DRV_ASN1_V3_SPEC = megaco_ber_bin_drv_media_gateway_control_v3
+PER_ASN1_V3_SPEC = megaco_per_media_gateway_control_v3
+PER_BIN_ASN1_V3_SPEC = megaco_per_bin_media_gateway_control_v3
+PER_BIN_DRV_ASN1_V3_SPEC = megaco_per_bin_drv_media_gateway_control_v3
+
diff --git a/lib/megaco/src/binary/old/megaco_ber_bin_drv_encoder.erl b/lib/megaco/src/binary/old/megaco_ber_bin_drv_encoder.erl
new file mode 100644
index 0000000000..a9217940a1
--- /dev/null
+++ b/lib/megaco/src/binary/old/megaco_ber_bin_drv_encoder.erl
@@ -0,0 +1,319 @@
+%%
+%% %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 : Handle ASN.1 BER encoding of Megaco/H.248
+%%----------------------------------------------------------------------
+
+-module(megaco_ber_bin_drv_encoder).
+
+-behaviour(megaco_encoder).
+
+-export([encode_message/3, decode_message/3,
+ decode_mini_message/3,
+
+ encode_transaction/3,
+ encode_action_requests/3,
+ encode_action_request/3,
+ encode_action_reply/3,
+
+ version_of/2]).
+
+%% Backward compatible functions:
+-export([encode_message/2, decode_message/2]).
+
+-include_lib("megaco/src/engine/megaco_message_internal.hrl").
+
+-define(V1_ASN1_MOD, megaco_ber_bin_drv_media_gateway_control_v1).
+-define(V2_ASN1_MOD, megaco_ber_bin_drv_media_gateway_control_v2).
+-define(V3_ASN1_MOD, megaco_ber_bin_drv_media_gateway_control_v3).
+-define(PREV3A_ASN1_MOD, megaco_ber_bin_drv_media_gateway_control_prev3a).
+-define(PREV3B_ASN1_MOD, megaco_ber_bin_drv_media_gateway_control_prev3b).
+-define(PREV3C_ASN1_MOD, megaco_ber_bin_drv_media_gateway_control_prev3c).
+
+-define(V1_TRANS_MOD, megaco_binary_transformer_v1).
+-define(V2_TRANS_MOD, megaco_binary_transformer_v2).
+-define(V3_TRANS_MOD, megaco_binary_transformer_v3).
+-define(PREV3A_TRANS_MOD, megaco_binary_transformer_prev3a).
+-define(PREV3B_TRANS_MOD, megaco_binary_transformer_prev3b).
+-define(PREV3C_TRANS_MOD, megaco_binary_transformer_prev3c).
+
+-define(BIN_LIB, megaco_binary_encoder_lib).
+
+
+%%----------------------------------------------------------------------
+%% Detect (check) which version a message is
+%% Return {ok, Version} | {error, Reason}
+%%----------------------------------------------------------------------
+
+version_of([{version3,v3}|EC], Binary) ->
+ Decoders = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?V3_ASN1_MOD],
+ ?BIN_LIB:version_of(EC, Binary, dynamic, Decoders);
+version_of([{version3,prev3c}|EC], Binary) ->
+ Decoders = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?PREV3C_ASN1_MOD],
+ ?BIN_LIB:version_of(EC, Binary, dynamic, Decoders);
+version_of([{version3,prev3b}|EC], Binary) ->
+ Decoders = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?PREV3B_ASN1_MOD],
+ ?BIN_LIB:version_of(EC, Binary, dynamic, Decoders);
+version_of([{version3,prev3a}|EC], Binary) ->
+ Decoders = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?PREV3A_ASN1_MOD],
+ ?BIN_LIB:version_of(EC, Binary, dynamic, Decoders);
+version_of(EC, Binary) ->
+ Decoders = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?V3_ASN1_MOD],
+ ?BIN_LIB:version_of(EC, Binary, dynamic, Decoders).
+
+
+%%----------------------------------------------------------------------
+%% Convert a 'MegacoMessage' record into a binary
+%% Return {ok, Binary} | {error, Reason}
+%%----------------------------------------------------------------------
+
+
+encode_message(EC,
+ #'MegacoMessage'{mess = #'Message'{version = V}} = MegaMsg) ->
+ encode_message(EC, V, MegaMsg).
+
+encode_message([{version3,_}|EC], 1, MegaMsg) ->
+ ?BIN_LIB:encode_message(EC, MegaMsg, ?V1_ASN1_MOD, ?V1_TRANS_MOD, io_list);
+encode_message(EC, 1, MegaMsg) ->
+ ?BIN_LIB:encode_message(EC, MegaMsg, ?V1_ASN1_MOD, ?V1_TRANS_MOD, io_list);
+encode_message([{version3,_}|EC], 2, MegaMsg) ->
+ ?BIN_LIB:encode_message(EC, MegaMsg, ?V2_ASN1_MOD, ?V2_TRANS_MOD, io_list);
+encode_message(EC, 2, MegaMsg) ->
+ ?BIN_LIB:encode_message(EC, MegaMsg, ?V2_ASN1_MOD, ?V2_TRANS_MOD, io_list);
+encode_message([{version3,v3}|EC], 3, MegaMsg) ->
+ ?BIN_LIB:encode_message(EC, MegaMsg, ?V3_ASN1_MOD, ?V3_TRANS_MOD, io_list);
+encode_message([{version3,prev3c}|EC], 3, MegaMsg) ->
+ ?BIN_LIB:encode_message(EC, MegaMsg,
+ ?PREV3C_ASN1_MOD, ?PREV3C_TRANS_MOD, io_list);
+encode_message([{version3,prev3b}|EC], 3, MegaMsg) ->
+ ?BIN_LIB:encode_message(EC, MegaMsg,
+ ?PREV3B_ASN1_MOD, ?PREV3B_TRANS_MOD, io_list);
+encode_message([{version3,prev3a}|EC], 3, MegaMsg) ->
+ ?BIN_LIB:encode_message(EC, MegaMsg,
+ ?PREV3A_ASN1_MOD, ?PREV3A_TRANS_MOD, io_list);
+encode_message(EC, 3, MegaMsg) ->
+ ?BIN_LIB:encode_message(EC, MegaMsg, ?V3_ASN1_MOD, ?V3_TRANS_MOD, io_list).
+
+
+%%----------------------------------------------------------------------
+%% Convert a transaction (or transactions in the case of ack) record(s)
+%% into a binary
+%% Return {ok, Binary} | {error, Reason}
+%%----------------------------------------------------------------------
+
+encode_transaction(EC, 1, Trans) ->
+ %% ?BIN_LIB:encode_transaction(EC, Trans,
+ %% ?V1_ASN1_MOD,
+ %% ?V1_TRANS_MOD,
+ %% io_list);
+ {error, not_implemented};
+encode_transaction(EC, 2, Trans) ->
+ %% ?BIN_LIB:encode_transaction(EC, Trans,
+ %% ?V2_ASN1_MOD,
+ %% ?V2_TRANS_MOD,
+ %% io_list).
+ {error, not_implemented};
+encode_transaction(EC, 3, Trans) ->
+ %% ?BIN_LIB:encode_transaction(EC, Trans,
+ %% ?V3_ASN1_MOD,
+ %% ?V3_TRANS_MOD,
+ %% io_list).
+ {error, not_implemented}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a list of ActionRequest record's into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_requests(EC, 1, ActReqs) when is_list(ActReqs) ->
+ %% ?BIN_LIB:encode_action_requests(EC, ActReqs,
+ %% ?V1_ASN1_MOD,
+ %% ?V1_TRANS_MOD,
+ %% io_list);
+ {error, not_implemented};
+encode_action_requests(EC, 2, ActReqs) when is_list(ActReqs) ->
+ %% ?BIN_LIB:encode_action_requests(EC, ActReqs,
+ %% ?V2_ASN1_MOD,
+ %% ?V2_TRANS_MOD,
+ %% io_list).
+ {error, not_implemented};
+encode_action_requests(EC, 3, ActReqs) when is_list(ActReqs) ->
+ %% ?BIN_LIB:encode_action_requests(EC, ActReqs,
+ %% ?V3_ASN1_MOD,
+ %% ?V3_TRANS_MOD,
+ %% io_list).
+ {error, not_implemented}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a ActionRequest record into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_request(EC, 1, ActReq) ->
+ %% ?BIN_LIB:encode_action_request(EC, ActReq,
+ %% ?V1_ASN1_MOD,
+ %% ?V1_TRANS_MOD,
+ %% io_list);
+ {error, not_implemented};
+encode_action_request(EC, 2, ActReq) ->
+ %% ?BIN_LIB:encode_action_request(EC, ActReq,
+ %% ?V2_ASN1_MOD,
+ %% ?V2_TRANS_MOD,
+ %% io_list).
+ {error, not_implemented};
+encode_action_request(EC, 3, ActReq) ->
+ %% ?BIN_LIB:encode_action_request(EC, ActReq,
+ %% ?V3_ASN1_MOD,
+ %% ?V3_TRANS_MOD,
+ %% io_list).
+ {error, not_implemented}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a action reply into a deep io list
+%% Not yest supported by this binary codec!
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+
+encode_action_reply(_EC, _V, _AcionReply) ->
+ {error, not_implemented}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a binary into a 'MegacoMessage' record
+%% Return {ok, MegacoMessageRecord} | {error, Reason}
+%%----------------------------------------------------------------------
+
+%% Old decode function
+decode_message(EC, Binary) ->
+ decode_message(EC, 1, Binary).
+
+%% Select from message
+%% This does not work at the moment so, we use version 1 for this
+decode_message([{version3,v3}|EC], dynamic, Binary) ->
+ Mods = [{?V1_ASN1_MOD, ?V1_TRANS_MOD},
+ {?V2_ASN1_MOD, ?V2_TRANS_MOD},
+ {?V3_ASN1_MOD, ?V3_TRANS_MOD}],
+ ?BIN_LIB:decode_message_dynamic(EC, Binary, Mods, binary);
+decode_message([{version3,prev3c}|EC], dynamic, Binary) ->
+ Mods = [{?V1_ASN1_MOD, ?V1_TRANS_MOD},
+ {?V2_ASN1_MOD, ?V2_TRANS_MOD},
+ {?PREV3C_ASN1_MOD, ?PREV3C_TRANS_MOD}],
+ ?BIN_LIB:decode_message_dynamic(EC, Binary, Mods, binary);
+decode_message([{version3,prev3b}|EC], dynamic, Binary) ->
+ Mods = [{?V1_ASN1_MOD, ?V1_TRANS_MOD},
+ {?V2_ASN1_MOD, ?V2_TRANS_MOD},
+ {?PREV3B_ASN1_MOD, ?PREV3B_TRANS_MOD}],
+ ?BIN_LIB:decode_message_dynamic(EC, Binary, Mods, binary);
+decode_message([{version3,prev3a}|EC], dynamic, Binary) ->
+ Mods = [{?V1_ASN1_MOD, ?V1_TRANS_MOD},
+ {?V2_ASN1_MOD, ?V2_TRANS_MOD},
+ {?PREV3A_ASN1_MOD, ?PREV3A_TRANS_MOD}],
+ ?BIN_LIB:decode_message_dynamic(EC, Binary, Mods, binary);
+decode_message(EC, dynamic, Binary) ->
+ Mods = [{?V1_ASN1_MOD, ?V1_TRANS_MOD},
+ {?V2_ASN1_MOD, ?V2_TRANS_MOD},
+ {?V3_ASN1_MOD, ?V3_TRANS_MOD}],
+ ?BIN_LIB:decode_message_dynamic(EC, Binary, Mods, binary);
+
+decode_message([{version3,_}|EC], 1, Binary) ->
+ AsnMod = ?V1_ASN1_MOD,
+ TransMod = ?V1_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message(EC, 1, Binary) ->
+ AsnMod = ?V1_ASN1_MOD,
+ TransMod = ?V1_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+
+decode_message([{version3,_}|EC], 2, Binary) ->
+ AsnMod = ?V2_ASN1_MOD,
+ TransMod = ?V2_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message(EC, 2, Binary) ->
+ AsnMod = ?V2_ASN1_MOD,
+ TransMod = ?V2_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+
+decode_message([{version3,v3}|EC], 3, Binary) ->
+ AsnMod = ?V3_ASN1_MOD,
+ TransMod = ?V3_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([{version3,prev3c}|EC], 3, Binary) ->
+ AsnMod = ?PREV3C_ASN1_MOD,
+ TransMod = ?PREV3C_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([{version3,prev3b}|EC], 3, Binary) ->
+ AsnMod = ?PREV3B_ASN1_MOD,
+ TransMod = ?PREV3B_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([{version3,prev3a}|EC], 3, Binary) ->
+ AsnMod = ?PREV3A_ASN1_MOD,
+ TransMod = ?PREV3A_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message(EC, 3, Binary) ->
+ AsnMod = ?V3_ASN1_MOD,
+ TransMod = ?V3_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+
+
+decode_mini_message([{version3,v3}|EC], dynamic, Bin) ->
+ Mods = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?V3_ASN1_MOD],
+ ?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
+decode_mini_message([{version3,prev3c}|EC], dynamic, Bin) ->
+ Mods = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?PREV3C_ASN1_MOD],
+ ?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
+decode_mini_message([{version3,prev3b}|EC], dynamic, Bin) ->
+ Mods = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?PREV3B_ASN1_MOD],
+ ?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
+decode_mini_message([{version3,prev3a}|EC], dynamic, Bin) ->
+ Mods = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?PREV3A_ASN1_MOD],
+ ?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
+decode_mini_message(EC, dynamic, Bin) ->
+ Mods = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?V3_ASN1_MOD],
+ ?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
+
+decode_mini_message([{version3,_}|EC], 1, Bin) ->
+ AsnMod = ?V1_ASN1_MOD,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message(EC, 1, Bin) ->
+ AsnMod = ?V1_ASN1_MOD,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message([{version3,_}|EC], 2, Bin) ->
+ AsnMod = ?V2_ASN1_MOD,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message(EC, 2, Bin) ->
+ AsnMod = ?V2_ASN1_MOD,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message([{version3,v3}|EC], 3, Bin) ->
+ AsnMod = ?V3_ASN1_MOD,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message([{version3,prev3c}|EC], 3, Bin) ->
+ AsnMod = ?PREV3C_ASN1_MOD,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message([{version3,prev3b}|EC], 3, Bin) ->
+ AsnMod = ?PREV3B_ASN1_MOD,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message([{version3,prev3a}|EC], 3, Bin) ->
+ AsnMod = ?PREV3A_ASN1_MOD,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message(EC, 3, Bin) ->
+ AsnMod = ?V3_ASN1_MOD,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary).
diff --git a/lib/megaco/src/binary/old/megaco_per_bin_drv_encoder.erl b/lib/megaco/src/binary/old/megaco_per_bin_drv_encoder.erl
new file mode 100644
index 0000000000..0afe6d9f36
--- /dev/null
+++ b/lib/megaco/src/binary/old/megaco_per_bin_drv_encoder.erl
@@ -0,0 +1,255 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2002-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 : Handle ASN.1 PER encoding of Megaco/H.248
+%%----------------------------------------------------------------------
+
+-module(megaco_per_bin_drv_encoder).
+
+-behaviour(megaco_encoder).
+
+-export([encode_message/2, decode_message/2,
+ encode_message/3, decode_message/3,
+ decode_mini_message/3,
+
+ encode_transaction/3,
+ encode_action_requests/3,
+ encode_action_request/3,
+ encode_action_reply/3,
+
+ version_of/2]).
+
+-include_lib("megaco/src/engine/megaco_message_internal.hrl").
+
+-define(V1_ASN1_MOD, megaco_per_bin_drv_media_gateway_control_v1).
+-define(V2_ASN1_MOD, megaco_per_bin_drv_media_gateway_control_v2).
+-define(V3_ASN1_MOD, megaco_per_bin_drv_media_gateway_control_v3).
+-define(PREV3A_ASN1_MOD, megaco_per_bin_drv_media_gateway_control_prev3a).
+-define(PREV3B_ASN1_MOD, megaco_per_bin_drv_media_gateway_control_prev3b).
+-define(PREV3C_ASN1_MOD, megaco_per_bin_drv_media_gateway_control_prev3c).
+
+-define(V1_TRANS_MOD, megaco_binary_transformer_v1).
+-define(V2_TRANS_MOD, megaco_binary_transformer_v2).
+-define(V3_TRANS_MOD, megaco_binary_transformer_V3).
+-define(PREV3A_TRANS_MOD, megaco_binary_transformer_prev3a).
+-define(PREV3B_TRANS_MOD, megaco_binary_transformer_prev3b).
+-define(PREV3C_TRANS_MOD, megaco_binary_transformer_prev3c).
+
+-define(BIN_LIB, megaco_binary_encoder_lib).
+
+
+%%----------------------------------------------------------------------
+%% Detect (check) which version a message is
+%% Return {ok, Version} | {error, Reason}
+%%----------------------------------------------------------------------
+
+version_of([{version3,v3}|EC], Binary) ->
+ Decoders = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?V3_ASN1_MOD],
+ ?BIN_LIB:version_of(EC, Binary, 1, Decoders);
+version_of([{version3,prev3c}|EC], Binary) ->
+ Decoders = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?PREV3C_ASN1_MOD],
+ ?BIN_LIB:version_of(EC, Binary, 1, Decoders);
+version_of([{version3,prev3b}|EC], Binary) ->
+ Decoders = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?PREV3B_ASN1_MOD],
+ ?BIN_LIB:version_of(EC, Binary, 1, Decoders);
+version_of([{version3,prev3a}|EC], Binary) ->
+ Decoders = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?PREV3A_ASN1_MOD],
+ ?BIN_LIB:version_of(EC, Binary, 1, Decoders);
+version_of(EC, Binary) ->
+ Decoders = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?V3_ASN1_MOD],
+ ?BIN_LIB:version_of(EC, Binary, 1, Decoders).
+
+
+%%----------------------------------------------------------------------
+%% Convert a 'MegacoMessage' record into a binary
+%% Return {ok, Binary} | {error, Reason}
+%%----------------------------------------------------------------------
+
+encode_message(EC,
+ #'MegacoMessage'{mess = #'Message'{version = V}} = MegaMsg) ->
+ encode_message(EC, V, MegaMsg).
+
+encode_message([{version3,_}|EC], 1, MegaMsg) ->
+ ?BIN_LIB:encode_message(EC, MegaMsg, ?V1_ASN1_MOD, ?V1_TRANS_MOD, io_list);
+encode_message(EC, 1, MegaMsg) ->
+ ?BIN_LIB:encode_message(EC, MegaMsg, ?V1_ASN1_MOD, ?V1_TRANS_MOD, io_list);
+encode_message([{version3,_}|EC], 2, MegaMsg) ->
+ ?BIN_LIB:encode_message(EC, MegaMsg, ?V2_ASN1_MOD, ?V2_TRANS_MOD, io_list);
+encode_message(EC, 2, MegaMsg) ->
+ ?BIN_LIB:encode_message(EC, MegaMsg, ?V2_ASN1_MOD, ?V2_TRANS_MOD, io_list);
+encode_message([{version3,v3}|EC], 3, MegaMsg) ->
+ ?BIN_LIB:encode_message(EC, MegaMsg, ?V3_ASN1_MOD, ?V3_TRANS_MOD, io_list);
+encode_message([{version3,prev3c}|EC], 3, MegaMsg) ->
+ ?BIN_LIB:encode_message(EC, MegaMsg,
+ ?PREV3C_ASN1_MOD, ?PREV3C_TRANS_MOD, io_list);
+encode_message([{version3,prev3b}|EC], 3, MegaMsg) ->
+ ?BIN_LIB:encode_message(EC, MegaMsg,
+ ?PREV3B_ASN1_MOD, ?PREV3B_TRANS_MOD, io_list);
+encode_message([{version3,prev3a}|EC], 3, MegaMsg) ->
+ ?BIN_LIB:encode_message(EC, MegaMsg,
+ ?PREV3A_ASN1_MOD, ?PREV3A_TRANS_MOD, io_list);
+encode_message(EC, 3, MegaMsg) ->
+ ?BIN_LIB:encode_message(EC, MegaMsg, ?V3_ASN1_MOD, ?V3_TRANS_MOD, io_list).
+
+
+%%----------------------------------------------------------------------
+%% Convert a transaction (or transactions in the case of ack) record(s)
+%% into a binary
+%% Return {ok, Binary} | {error, Reason}
+%%----------------------------------------------------------------------
+
+encode_transaction(_EC, 1, _Trans) ->
+ %% ?BIN_LIB:encode_transaction(EC,
+ %% Trans,
+ %% ?V1_ASN1_MOD,
+ %% ?V1_TRANS_MOD,
+ %% io_list);
+ {error, not_implemented};
+encode_transaction(_EC, 2, _Trans) ->
+ %% ?BIN_LIB:encode_transaction(EC,
+ %% Trans,
+ %% ?V2_ASN1_MOD,
+ %% ?V2_TRANS_MOD,
+ %% io_list).
+ {error, not_implemented};
+encode_transaction(EC, prev3a, Trans) ->
+ %% ?BIN_LIB:encode_transaction(EC, Trans,
+ %% ?V3_ASN1_MOD,
+ %% ?V3_TRANS_MOD,
+ %% io_list).
+ {error, not_implemented};
+encode_transaction(EC, 3, Trans) ->
+ encode_transaction(EC, prev3a, Trans).
+
+
+%%----------------------------------------------------------------------
+%% Convert a list of ActionRequest record's into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_requests(_EC, 1, ActReqs) when is_list(ActReqs) ->
+ %% ?BIN_LIB:encode_action_requests(EC, ActReqs,
+ %% ?V1_ASN1_MOD,
+ %% ?V1_TRANS_MOD,
+ %% io_list);
+ {error, not_implemented};
+encode_action_requests(_EC, 2, ActReqs) when is_list(ActReqs) ->
+ %% ?BIN_LIB:encode_action_requests(EC, ActReqs,
+ %% ?V1_ASN1_MOD,
+ %% ?V1_TRANS_MOD,
+ %% io_list).
+ {error, not_implemented};
+encode_action_requests(EC, 3, ActReqs) when is_list(ActReqs) ->
+ %% ?BIN_LIB:encode_action_requests(EC, ActReqs,
+ %% ?V3_ASN1_MOD,
+ %% ?V3_TRANS_MOD,
+ %% io_list).
+ {error, not_implemented}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a ActionRequest record into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_request(_EC, 1, _ActReq) ->
+ %% ?BIN_LIB:encode_action_request(EC, ActReq,
+ %% ?V1_ASN1_MOD,
+ %% ?V1_TRANS_MOD,
+ %% io_list);
+ {error, not_implemented};
+encode_action_request(_EC, 2, _ActReq) ->
+ %% ?BIN_LIB:encode_action_request(EC, ActReq,
+ %% ?V1_ASN1_MOD,
+ %% ?V1_TRANS_MOD,
+ %% io_list).
+ {error, not_implemented};
+encode_action_request(EC, 3, ActReq) ->
+ %% ?BIN_LIB:encode_action_request(EC, ActReq,
+ %% ?V3_ASN1_MOD,
+ %% ?V3_TRANS_MOD,
+ %% io_list).
+ {error, not_implemented}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a action reply into a deep io list
+%% Not yest supported by this binary codec!
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+
+encode_action_reply(_EC, _V, _AcionReply) ->
+ {error, not_implemented}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a binary into a 'MegacoMessage' record
+%% Return {ok, MegacoMessageRecord} | {error, Reason}
+%%----------------------------------------------------------------------
+
+%% Old decode function
+decode_message(EC, Binary) ->
+ decode_message(EC, 1, Binary).
+
+%% PER does not support partial decode, so this means V1
+decode_message(EC, dynamic, Binary) ->
+ decode_message(EC, 1, Binary);
+
+decode_message([{version3,_}|EC], 1, Binary) ->
+ AsnMod = ?V1_ASN1_MOD,
+ TransMod = ?V1_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message(EC, 1, Binary) ->
+ AsnMod = ?V1_ASN1_MOD,
+ TransMod = ?V1_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+
+decode_message([{version3,_}|EC], 2, Binary) ->
+ AsnMod = ?V2_ASN1_MOD,
+ TransMod = ?V2_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message(EC, 2, Binary) ->
+ AsnMod = ?V2_ASN1_MOD,
+ TransMod = ?V2_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+
+decode_message([{version3,v3}|EC], 3, Binary) ->
+ AsnMod = ?V3_ASN1_MOD,
+ TransMod = ?V3_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([{version3,prev3c}|EC], 3, Binary) ->
+ AsnMod = ?PREV3C_ASN1_MOD,
+ TransMod = ?PREV3C_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([{version3,prev3b}|EC], 3, Binary) ->
+ AsnMod = ?PREV3B_ASN1_MOD,
+ TransMod = ?PREV3B_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([{version3,prev3a}|EC], 3, Binary) ->
+ AsnMod = ?PREV3A_ASN1_MOD,
+ TransMod = ?PREV3A_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message(EC, 3, Binary) ->
+ AsnMod = ?V3_ASN1_MOD,
+ TransMod = ?V3_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary).
+
+decode_mini_message(_EC, _Vsn, _Bin) ->
+ {error, not_implemented}.
+
diff --git a/lib/megaco/src/engine/Makefile b/lib/megaco/src/engine/Makefile
new file mode 100644
index 0000000000..3943f4b957
--- /dev/null
+++ b/lib/megaco/src/engine/Makefile
@@ -0,0 +1,107 @@
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 1999-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)
+
+TARGET_FILES = \
+ $(MODULES:%=$(EBIN)/%.$(EMULATOR))
+
+
+# ----------------------------------------------------
+# FLAGS
+# ----------------------------------------------------
+ifeq ($(TYPE),debug)
+ERL_COMPILE_FLAGS += -Ddebug
+endif
+
+include ../app/megaco.mk
+
+ERL_COMPILE_FLAGS += \
+ $(MEGACO_ERL_COMPILE_FLAGS) \
+ -I../../include
+
+
+# ----------------------------------------------------
+# Targets
+# ----------------------------------------------------
+debug:
+ @${MAKE} TYPE=debug opt
+
+opt: $(TARGET_FILES)
+
+clean:
+ rm -f $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET)
+ rm -f errs core *~
+
+docs:
+
+info:
+ @echo "MODULES = $(MODULES)"
+ @echo ""
+
+
+# ----------------------------------------------------
+# Release Target
+# ----------------------------------------------------
+include $(ERL_TOP)/make/otp_release_targets.mk
+
+
+release_spec: opt
+ $(INSTALL_DIR) $(RELSYSDIR)/ebin
+ $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
+ $(INSTALL_DIR) $(RELSYSDIR)/src
+ $(INSTALL_DIR) $(RELSYSDIR)/src/engine
+ $(INSTALL_DATA) $(ERL_FILES) $(INTERNAL_HRL_FILES) $(RELSYSDIR)/src/engine
+ $(INSTALL_DIR) $(RELSYSDIR)/include
+
+
+release_docs_spec:
+
+
+# ----------------------------------------------------
+# Include dependencies
+# ----------------------------------------------------
+
+include depend.mk
+
diff --git a/lib/megaco/src/engine/depend.mk b/lib/megaco/src/engine/depend.mk
new file mode 100644
index 0000000000..8d8c83e923
--- /dev/null
+++ b/lib/megaco/src/engine/depend.mk
@@ -0,0 +1,81 @@
+#-*-makefile-*- ; force emacs to enter makefile-mode
+
+# %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%
+
+$(EBIN)/megaco_config.$(EMULATOR): megaco_config.erl \
+ ../../include/megaco.hrl \
+ ../app/megaco_internal.hrl
+
+$(EBIN)/megaco_digit_map.$(EMULATOR): megaco_digit_map.erl \
+ megaco_message_internal.hrl \
+ ../text/megaco_text_tokens.hrl
+
+$(EBIN)/megaco_encoder.$(EMULATOR): megaco_encoder.erl
+
+$(EBIN)/megaco_edist_compress.$(EMULATOR): megaco_edist_compress.erl
+
+$(EBIN)/megaco_erl_dist_encoder.$(EMULATOR): megaco_erl_dist_encoder.erl \
+ megaco_message_internal.hrl
+
+$(EBIN)/megaco_erl_dist_encoder_mc.$(EMULATOR): megaco_erl_dist_encoder_mc.erl \
+ megaco_message_internal.hrl \
+ ../app/megaco_internal.hrl
+
+$(EBIN)/megaco_filter.$(EMULATOR): megaco_filter.erl \
+ ../../include/megaco.hrl \
+ ../../include/megaco_message_v1.hrl \
+ ../app/megaco_internal.hrl
+
+$(EBIN)/megaco_messenger.$(EMULATOR): megaco_messenger.erl \
+ ../../include/megaco.hrl \
+ ../app/megaco_internal.hrl \
+ megaco_message_internal.hrl
+
+$(EBIN)/megaco_messenger_misc.$(EMULATOR): megaco_messenger_misc.erl \
+ ../../include/megaco.hrl \
+ ../app/megaco_internal.hrl \
+ megaco_message_internal.hrl
+
+$(EBIN)/megaco_misc_sup.$(EMULATOR): megaco_misc_sup.erl
+
+$(EBIN)/megaco_monitor.$(EMULATOR): megaco_monitor.erl
+
+$(EBIN)/megaco_sdp.$(EMULATOR): \
+ megaco_sdp.erl \
+ ../../include/megaco_sdp.hrl
+
+$(EBIN)/megaco_stats.$(EMULATOR): megaco_stats.erl
+
+$(EBIN)/megaco_sup.$(EMULATOR): megaco_sup.erl
+
+$(EBIN)/megaco_timer.$(EMULATOR): \
+ megaco_timer.erl \
+ ../../include/megaco.hrl
+
+$(EBIN)/megaco_trans_sender.$(EMULATOR): megaco_trans_sender.erl
+
+$(EBIN)/megaco_trans_sup.$(EMULATOR): megaco_trans_sup.erl
+
+$(EBIN)/megaco_transport.$(EMULATOR): megaco_transport.erl
+
+$(EBIN)/megaco_user.$(EMULATOR): megaco_user.erl
+
+$(EBIN)/megaco_user_default.$(EMULATOR): megaco_user_default.erl \
+ ../../include/megaco.hrl \
+ ../../include/megaco_message_v1.hrl
+
diff --git a/lib/megaco/src/engine/megaco_config.erl b/lib/megaco/src/engine/megaco_config.erl
new file mode 100644
index 0000000000..2058c53973
--- /dev/null
+++ b/lib/megaco/src/engine/megaco_config.erl
@@ -0,0 +1,2113 @@
+%%
+%% %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: Handle configuration of Megaco/H.248
+%%----------------------------------------------------------------------
+
+-module(megaco_config).
+
+-behaviour(gen_server).
+
+%% Application internal exports
+-export([
+ start_link/0,
+ stop/0,
+
+ start_user/2,
+ stop_user/1,
+
+ user_info/2,
+ update_user_info/3,
+ conn_info/2,
+ update_conn_info/3,
+ system_info/1,
+
+ %% incr_counter/2,
+ incr_trans_id_counter/1,
+ incr_trans_id_counter/2,
+
+ %% Verification functions
+ verify_val/2,
+ verify_strict_uint/1,
+ verify_strict_int/1, verify_strict_int/2,
+ verify_uint/1,
+ verify_int/1, verify_int/2,
+
+
+ %% Reply limit counter
+ cre_reply_counter/2,
+ get_reply_counter/2,
+ incr_reply_counter/2,
+ del_reply_counter/2,
+
+ %% Pending limit counter
+ cre_pending_counter/3,
+ get_pending_counter/2,
+ incr_pending_counter/2,
+ del_pending_counter/2,
+ %% Backward compatibillity functions (to be removed in later versions)
+ cre_pending_counter/1,
+ get_pending_counter/1,
+ incr_pending_counter/1,
+ del_pending_counter/1,
+
+ lookup_local_conn/1,
+ connect/4, finish_connect/4,
+ autoconnect/4,
+ disconnect/1,
+ connect_remote/3,
+ disconnect_remote/2,
+ init_conn_data/4,
+
+ trans_sender_exit/2
+
+ ]).
+
+
+%% gen_server callbacks
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
+ terminate/2, code_change/3]).
+
+-define(SERVER, ?MODULE).
+-record(state, {parent_pid}).
+
+-include_lib("megaco/include/megaco.hrl").
+-include_lib("megaco/src/app/megaco_internal.hrl").
+
+
+-ifdef(MEGACO_TEST_CODE).
+-define(megaco_test_init(),
+ (catch ets:new(megaco_test_data, [set, public, named_table]))).
+-else.
+-define(megaco_test_init(),
+ ok).
+-endif.
+
+-define(TID_CNT(LMID), {LMID, trans_id_counter}).
+
+
+%%%----------------------------------------------------------------------
+%%% API
+%%%----------------------------------------------------------------------
+
+start_link() ->
+ ?d("start_link -> entry", []),
+ gen_server:start_link({local, ?SERVER}, ?MODULE, [self()], []).
+
+stop() ->
+ ?d("stop -> entry", []),
+ call({stop, self()}).
+
+start_user(UserMid, Config) ->
+ call({start_user, UserMid, Config}).
+
+stop_user(UserMid) ->
+ call({stop_user, UserMid}).
+
+user_info(UserMid, all) ->
+ All0 = ets:match_object(megaco_config, {{UserMid, '_'}, '_'}),
+ All1 = [{Item, Val} || {{_, Item}, Val} <- All0, Item /= trans_sender],
+ case lists:keysearch(trans_id_counter, 1, All1) of
+ {value, {_, Val}} ->
+ lists:keyreplace(trans_id_counter, 1, All1, {trans_id, Val});
+ false when UserMid /= default ->
+ [{trans_id, undefined_serial}|All1];
+ false ->
+ All1
+ end;
+user_info(UserMid, receive_handle) ->
+ case call({receive_handle, UserMid}) of
+ {ok, RH} ->
+ RH;
+ {error, Reason} ->
+ exit(Reason)
+ end;
+user_info(UserMid, conn_data) ->
+ HandlePat = #megaco_conn_handle{local_mid = UserMid, remote_mid = '_'},
+ Pat = #conn_data{conn_handle = HandlePat,
+ serial = '_',
+ max_serial = '_',
+ request_timer = '_',
+ long_request_timer = '_',
+
+ auto_ack = '_',
+
+ trans_ack = '_',
+ trans_ack_maxcount = '_',
+
+ trans_req = '_',
+ trans_req_maxcount = '_',
+ trans_req_maxsize = '_',
+
+ trans_timer = '_',
+ trans_sender = '_',
+
+ pending_timer = '_',
+ sent_pending_limit = '_',
+ recv_pending_limit = '_',
+ reply_timer = '_',
+ control_pid = '_',
+ monitor_ref = '_',
+ send_mod = '_',
+ send_handle = '_',
+ encoding_mod = '_',
+ encoding_config = '_',
+ protocol_version = '_',
+ auth_data = '_',
+ user_mod = '_',
+ user_args = '_',
+ reply_action = '_',
+ reply_data = '_',
+ threaded = '_',
+ strict_version = '_',
+ long_request_resend = '_',
+ call_proxy_gc_timeout = '_',
+ cancel = '_',
+ resend_indication = '_',
+ segment_reply_ind = '_',
+ segment_recv_acc = '_',
+ segment_recv_timer = '_',
+ segment_send = '_',
+ segment_send_timer = '_',
+ max_pdu_size = '_',
+ request_keep_alive_timeout = '_'
+ },
+ %% ok = io:format("PATTERN: ~p~n", [Pat]),
+ ets:match_object(megaco_local_conn, Pat);
+user_info(UserMid, connections) ->
+ [C#conn_data.conn_handle || C <- user_info(UserMid, conn_data)];
+user_info(UserMid, mid) ->
+ ets:lookup_element(megaco_config, {UserMid, mid}, 2);
+user_info(UserMid, orig_pending_limit) ->
+ user_info(UserMid, sent_pending_limit);
+user_info(UserMid, trans_id) ->
+ case (catch user_info(UserMid, trans_id_counter)) of
+ {'EXIT', _} ->
+ %% There is only two cases where this can occure:
+ %% 1) The user does not exist
+ %% 2) Called before the first message is sent, use
+ %% undefined_serial, since there is no
+ %% "current transaction id"
+ case (catch user_info(UserMid, mid)) of
+ {'EXIT', _} ->
+ %% case 1:
+ exit({no_such_user, UserMid});
+ _ ->
+ undefined_serial
+ end;
+ Else ->
+ Else
+ end;
+user_info(UserMid, Item) ->
+ ets:lookup_element(megaco_config, {UserMid, Item}, 2).
+
+update_user_info(UserMid, orig_pending_limit, Val) ->
+ update_user_info(UserMid, sent_pending_limit, Val);
+update_user_info(UserMid, Item, Val) ->
+ call({update_user_info, UserMid, Item, Val}).
+
+conn_info(CH, Item)
+ when is_record(CH, megaco_conn_handle) andalso (Item /= cancel) ->
+ case Item of
+ conn_handle ->
+ CH;
+ mid ->
+ CH#megaco_conn_handle.local_mid;
+ local_mid ->
+ CH#megaco_conn_handle.local_mid;
+ remote_mid ->
+ CH#megaco_conn_handle.remote_mid;
+ conn_data ->
+ case lookup_local_conn(CH) of
+ [] ->
+ exit({no_such_connection, CH});
+ [ConnData] ->
+ ConnData
+ end;
+ _ ->
+ case lookup_local_conn(CH) of
+ [] ->
+ exit({no_such_connection, CH});
+ [ConnData] ->
+ conn_info(ConnData, Item)
+ end
+ end;
+conn_info(#conn_data{conn_handle = CH}, cancel) ->
+ %% To minimise raise-condition propabillity,
+ %% we always look in the table instead of
+ %% in the record for this one
+ ets:lookup_element(megaco_local_conn, CH, #conn_data.cancel);
+
+conn_info(CD, Item) when is_record(CD, conn_data) ->
+ case Item of
+ all ->
+ Tags0 = record_info(fields, conn_data),
+ Tags1 = replace(serial, trans_id, Tags0),
+ Tags = [mid, local_mid, remote_mid] ++
+ replace(max_serial, max_trans_id, Tags1),
+ [{Tag, conn_info(CD,Tag)} || Tag <- Tags,
+ Tag /= conn_data,
+ Tag /= trans_sender,
+ Tag /= cancel];
+ conn_data -> CD;
+ conn_handle -> CD#conn_data.conn_handle;
+ mid -> (CD#conn_data.conn_handle)#megaco_conn_handle.local_mid;
+ local_mid -> (CD#conn_data.conn_handle)#megaco_conn_handle.local_mid;
+ remote_mid -> (CD#conn_data.conn_handle)#megaco_conn_handle.remote_mid;
+ trans_id -> CH = CD#conn_data.conn_handle,
+ LocalMid = CH#megaco_conn_handle.local_mid,
+ Item2 = {LocalMid, trans_id_counter},
+ case (catch ets:lookup(megaco_config, Item2)) of
+ {'EXIT', _} ->
+ undefined_serial;
+ [] ->
+ user_info(LocalMid, min_trans_id);
+ [{_, Serial}] ->
+ Max = CD#conn_data.max_serial,
+ if
+ ((Max =:= infinity) andalso
+ is_integer(Serial) andalso
+ (Serial < 4294967295)) ->
+ Serial + 1;
+ (Max =:= infinity) andalso
+ is_integer(Serial) andalso
+ (Serial =:= 4294967295) ->
+ user_info(LocalMid,
+ min_trans_id);
+ Serial < Max ->
+ Serial + 1;
+ Serial =:= Max ->
+ user_info(LocalMid,
+ min_trans_id);
+ Serial =:= 4294967295 ->
+ user_info(LocalMid,
+ min_trans_id);
+ true ->
+ undefined_serial
+ end
+ end;
+ max_trans_id -> CD#conn_data.max_serial;
+ request_timer -> CD#conn_data.request_timer;
+ long_request_timer -> CD#conn_data.long_request_timer;
+
+ auto_ack -> CD#conn_data.auto_ack;
+
+ trans_ack -> CD#conn_data.trans_ack;
+ trans_ack_maxcount -> CD#conn_data.trans_ack_maxcount;
+
+ trans_req -> CD#conn_data.trans_req;
+ trans_req_maxcount -> CD#conn_data.trans_req_maxcount;
+ trans_req_maxsize -> CD#conn_data.trans_req_maxsize;
+
+ trans_timer -> CD#conn_data.trans_timer;
+
+ pending_timer -> CD#conn_data.pending_timer;
+ orig_pending_limit -> CD#conn_data.sent_pending_limit;
+ sent_pending_limit -> CD#conn_data.sent_pending_limit;
+ recv_pending_limit -> CD#conn_data.recv_pending_limit;
+ reply_timer -> CD#conn_data.reply_timer;
+ control_pid -> CD#conn_data.control_pid;
+ monitor_ref -> CD#conn_data.monitor_ref;
+ send_mod -> CD#conn_data.send_mod;
+ send_handle -> CD#conn_data.send_handle;
+ encoding_mod -> CD#conn_data.encoding_mod;
+ encoding_config -> CD#conn_data.encoding_config;
+ protocol_version -> CD#conn_data.protocol_version;
+ auth_data -> CD#conn_data.auth_data;
+ user_mod -> CD#conn_data.user_mod;
+ user_args -> CD#conn_data.user_args;
+ reply_action -> CD#conn_data.reply_action;
+ reply_data -> CD#conn_data.reply_data;
+ threaded -> CD#conn_data.threaded;
+ strict_version -> CD#conn_data.strict_version;
+ long_request_resend -> CD#conn_data.long_request_resend;
+ call_proxy_gc_timeout -> CD#conn_data.call_proxy_gc_timeout;
+ cancel -> CD#conn_data.cancel;
+ resend_indication -> CD#conn_data.resend_indication;
+ segment_reply_ind -> CD#conn_data.segment_reply_ind;
+ segment_recv_acc -> CD#conn_data.segment_recv_acc;
+ segment_recv_timer -> CD#conn_data.segment_recv_timer;
+ segment_send -> CD#conn_data.segment_send;
+ segment_send_timer -> CD#conn_data.segment_send_timer;
+ max_pdu_size -> CD#conn_data.max_pdu_size;
+ request_keep_alive_timeout -> CD#conn_data.request_keep_alive_timeout;
+ receive_handle ->
+ LocalMid = (CD#conn_data.conn_handle)#megaco_conn_handle.local_mid,
+ #megaco_receive_handle{local_mid = LocalMid,
+ encoding_mod = CD#conn_data.encoding_mod,
+ encoding_config = CD#conn_data.encoding_config,
+ send_mod = CD#conn_data.send_mod};
+ _ ->
+ exit({no_such_item, Item})
+ end;
+conn_info(BadHandle, _Item) ->
+ {error, {no_such_connection, BadHandle}}.
+
+replace(_, _, []) ->
+ [];
+replace(Item, WithItem, [Item|List]) ->
+ [WithItem|List];
+replace(Item, WithItem, [OtherItem|List]) ->
+ [OtherItem | replace(Item, WithItem, List)].
+
+
+update_conn_info(#conn_data{conn_handle = CH}, Item, Val) ->
+ do_update_conn_info(CH, Item, Val);
+update_conn_info(CH, Item, Val)
+ when is_record(CH, megaco_conn_handle) andalso (Item /= cancel) ->
+ do_update_conn_info(CH, Item, Val);
+update_conn_info(BadHandle, _Item, _Val) ->
+ {error, {no_such_connection, BadHandle}}.
+
+do_update_conn_info(CH, orig_pending_limit, Val) ->
+ do_update_conn_info(CH, sent_pending_limit, Val);
+do_update_conn_info(CH, Item, Val) ->
+ call({update_conn_data, CH, Item, Val}).
+
+
+system_info(all) ->
+ AllItems = [n_active_requests,
+ n_active_replies,
+ n_active_connections,
+ users,
+ connections,
+ text_config,
+ reply_counters,
+ pending_counters],
+ [{Item, system_info(Item)} || Item <- AllItems];
+system_info(Item) ->
+ case Item of
+ n_active_requests ->
+ ets:info(megaco_requests, size);
+ n_active_replies ->
+ ets:info(megaco_replies, size);
+ n_active_connections ->
+ ets:info(megaco_local_conn, size);
+ users ->
+ Pat = {{'_', mid}, '_'},
+ [Mid || {_, Mid} <- ets:match_object(megaco_config, Pat)];
+ connections ->
+ [C#conn_data.conn_handle || C <- ets:tab2list(megaco_local_conn)];
+ text_config ->
+ case ets:lookup(megaco_config, text_config) of
+ [] ->
+ [];
+ [{text_config, Conf}] ->
+ [Conf]
+ end;
+
+ reply_counters ->
+ reply_counters();
+
+ pending_counters ->
+ pending_counters();
+
+ recv_pending_counters ->
+ pending_counters(recv);
+
+ sent_pending_counters ->
+ pending_counters(sent);
+
+ BadItem ->
+ exit({no_such_item, BadItem})
+
+ end.
+
+
+get_env(Env, Default) ->
+ case application:get_env(megaco, Env) of
+ {ok, Val} -> Val;
+ undefined -> Default
+ end.
+
+lookup_local_conn(Handle) ->
+ ets:lookup(megaco_local_conn, Handle).
+
+
+autoconnect(RH, RemoteMid, SendHandle, ControlPid) ->
+ ?d("autoconnect -> entry with "
+ "~n RH: ~p"
+ "~n RemoteMid: ~p"
+ "~n SendHandle: ~p"
+ "~n ControlPid: ~p", [RH, RemoteMid, SendHandle, ControlPid]),
+ case RemoteMid of
+ {MidType, _MidValue} when is_atom(MidType) ->
+ call({connect, RH, RemoteMid, SendHandle, ControlPid, auto});
+ preliminary_mid ->
+ call({connect, RH, RemoteMid, SendHandle, ControlPid, auto});
+ BadMid ->
+ {error, {bad_remote_mid, BadMid}}
+ end.
+
+connect(RH, RemoteMid, SendHandle, ControlPid) ->
+ ?d("connect -> entry with "
+ "~n RH: ~p"
+ "~n RemoteMid: ~p"
+ "~n SendHandle: ~p"
+ "~n ControlPid: ~p", [RH, RemoteMid, SendHandle, ControlPid]),
+ case RemoteMid of
+ {MidType, _MidValue} when is_atom(MidType) ->
+ call({connect, RH, RemoteMid, SendHandle, ControlPid,
+ {plain, self()}});
+ preliminary_mid ->
+ call({connect, RH, RemoteMid, SendHandle, ControlPid,
+ {plain, self()}});
+ BadMid ->
+ {error, {bad_remote_mid, BadMid}}
+ end.
+
+finish_connect(ConnHandle, SendHandle, ControlPid, MFA) ->
+ ?d("finish_connect -> entry with "
+ "~n ConnHandle: ~p"
+ "~n SendHandle: ~p"
+ "~n ControlPid: ~p"
+ "~n MFA: ~p", [ConnHandle, SendHandle, ControlPid, MFA]),
+ call({finish_connect, ConnHandle, SendHandle, ControlPid, MFA}).
+
+connect_remote(ConnHandle, UserNode, Ref) ->
+ call({connect_remote, ConnHandle, UserNode, Ref}).
+
+disconnect(ConnHandle) ->
+ call({disconnect, ConnHandle}).
+
+disconnect_remote(ConnHandle, UserNode) ->
+ call({disconnect_remote, ConnHandle, UserNode}).
+
+
+incr_counter(Item, Incr) ->
+ try
+ begin
+ ets:update_counter(megaco_config, Item, Incr)
+ end
+ catch
+ error:_ ->
+ try
+ begin
+ cre_counter(Item, Incr)
+ end
+ catch
+ exit:_ ->
+ %% Ok, some other process got there before us,
+ %% so try again
+ ets:update_counter(megaco_config, Item, Incr)
+ end
+ end.
+%% incr_counter(Item, Incr) ->
+%% case (catch ets:update_counter(megaco_config, Item, Incr)) of
+%% {'EXIT', _} ->
+%% case (catch cre_counter(Item, Incr)) of
+%% {'EXIT', _} ->
+%% %% Ok, some other process got there before us,
+%% %% so try again
+%% ets:update_counter(megaco_config, Item, Incr);
+%% NewVal ->
+%% NewVal
+%% end;
+%% NewVal ->
+%% NewVal
+%% end.
+
+cre_counter(Item, Initial) ->
+ case whereis(?SERVER) =:= self() of
+ false ->
+ case call({cre_counter, Item, Initial}) of
+ {ok, Value} ->
+ Value;
+ Error ->
+ exit(Error)
+ end;
+ true ->
+ %% Check that the counter does not already exists
+ %% so we don't overwrite an already existing counter
+ case ets:lookup(megaco_config, Item) of
+ [] ->
+ ets:insert(megaco_config, {Item, Initial}),
+ {ok, Initial};
+ [_] ->
+ %% Ouch, now what?
+ {error, already_exists}
+
+ end
+ end.
+
+
+cre_reply_counter(ConnHandle, TransId) ->
+ Counter = {reply_counter, ConnHandle, TransId},
+ Initial = 1,
+ cre_counter(Counter, Initial).
+
+incr_reply_counter(ConnHandle, TransId) ->
+ Counter = {reply_counter, ConnHandle, TransId},
+ incr_counter(Counter, 1).
+
+get_reply_counter(ConnHandle, TransId) ->
+ Counter = {reply_counter, ConnHandle, TransId},
+ [{Counter, Val}] = ets:lookup(megaco_config, Counter),
+ Val.
+
+del_reply_counter(ConnHandle, TransId) ->
+ Counter = {reply_counter, ConnHandle, TransId},
+ ets:delete(megaco_config, Counter).
+
+reply_counters() ->
+ Pattern = {{reply_counter, '_', '_'}, '_'},
+ Counters1 = ets:match_object(megaco_config, Pattern),
+ [{ConnHandle, TransId, CounterVal} ||
+ {{reply_counter, ConnHandle, TransId}, CounterVal} <- Counters1].
+
+
+cre_pending_counter(TransId) ->
+ cre_pending_counter(sent, TransId, 0).
+
+cre_pending_counter(Direction, TransId, Initial) ->
+ Counter = {pending_counter, Direction, TransId},
+ cre_counter(Counter, Initial).
+
+incr_pending_counter(TransId) ->
+ incr_pending_counter(sent, TransId).
+
+incr_pending_counter(Direction, TransId) ->
+ Counter = {pending_counter, Direction, TransId},
+ incr_counter(Counter, 1).
+
+get_pending_counter(TransId) ->
+ get_pending_counter(sent, TransId).
+
+get_pending_counter(Direction, TransId) ->
+ Counter = {pending_counter, Direction, TransId},
+ [{Counter, Val}] = ets:lookup(megaco_config, Counter),
+ Val.
+
+del_pending_counter(TransId) ->
+ del_pending_counter(sent, TransId).
+
+del_pending_counter(Direction, TransId) ->
+ Counter = {pending_counter, Direction, TransId},
+ ets:delete(megaco_config, Counter).
+
+
+pending_counters() ->
+ Pattern = {{pending_counter, '_', '_'}, '_'},
+ Counters1 = ets:match_object(megaco_config, Pattern),
+ Counters2 = [{Direction, TransId, CounterVal} ||
+ {{pending_counter, Direction, TransId}, CounterVal} <-
+ Counters1],
+ RecvCounters = [{TransId, CounterVal} ||
+ {recv, TransId, CounterVal} <- Counters2],
+ SentCounters = [{TransId, CounterVal} ||
+ {sent, TransId, CounterVal} <- Counters2],
+ [{recv, RecvCounters}, {sent, SentCounters}].
+
+
+pending_counters(Direction)
+ when ((Direction =:= sent) orelse (Direction =:= recv)) ->
+ Pattern = {{pending_counter, Direction, '_'}, '_'},
+ Counters = ets:match_object(megaco_config, Pattern),
+ [{TransId, CounterVal} ||
+ {{pending_counter, D, TransId}, CounterVal} <-
+ Counters, (Direction == D)].
+
+%% A wrapping transaction id counter
+incr_trans_id_counter(ConnHandle) ->
+ incr_trans_id_counter(ConnHandle, 1).
+incr_trans_id_counter(ConnHandle, Incr)
+ when is_integer(Incr) andalso (Incr > 0) ->
+ case megaco_config:lookup_local_conn(ConnHandle) of
+ [] ->
+ {error, {no_such_connection, ConnHandle}};
+ [ConnData] ->
+ LocalMid = ConnHandle#megaco_conn_handle.local_mid,
+ Min = user_info(LocalMid, min_trans_id),
+ Max =
+ case ConnData#conn_data.max_serial of
+ infinity ->
+ 4294967295;
+ MS ->
+ MS
+ end,
+ Item = ?TID_CNT(LocalMid),
+ do_incr_trans_id_counter(ConnData, Item, Min, Max, Incr, -1)
+ end.
+
+do_incr_trans_id_counter(ConnData, _Item, _Min, _Max, 0, Serial) ->
+ ConnData2 = ConnData#conn_data{serial = Serial},
+ {ok, ConnData2};
+do_incr_trans_id_counter(ConnData, Item, Min, Max, N, _) ->
+ case (catch ets:update_counter(megaco_config, Item, {2, 1, Max, Min})) of
+ {'EXIT', _} ->
+ %% This can only happen for the first ever increment,
+ %% in which case N is equal to (the initial) Incr
+ ConnHandle = ConnData#conn_data.conn_handle,
+ init_trans_id_counter(ConnHandle, Item, N);
+ Serial ->
+ do_incr_trans_id_counter(ConnData, Item, Min, Max, N-1, Serial)
+ end.
+
+init_trans_id_counter(ConnHandle, Item, Incr) ->
+ case whereis(?SERVER) == self() of
+ false ->
+ call({init_trans_id_counter, ConnHandle, Item, Incr});
+ true ->
+ do_init_trans_id_counter(ConnHandle, Item, Incr)
+ end.
+
+do_init_trans_id_counter(ConnHandle, Item, Incr) ->
+ case megaco_config:lookup_local_conn(ConnHandle) of
+ [] ->
+ {error, {no_such_connection, ConnHandle}};
+ [ConnData] ->
+ %% Make sure that the counter still does not exist
+ LocalMid = ConnHandle#megaco_conn_handle.local_mid,
+ Min = user_info(LocalMid, min_trans_id),
+ Max =
+ case ConnData#conn_data.max_serial of
+ infinity ->
+ 4294967295;
+ MS ->
+ MS
+ end,
+ Item = ?TID_CNT(LocalMid),
+ Incr2 = {2, Incr, Max, Min},
+ case (catch ets:update_counter(megaco_config, Item, Incr2)) of
+ {'EXIT', _} ->
+ %% Yep, we are the first one here
+ Serial1 = Min + (Incr-1),
+ ets:insert(megaco_config, {Item, Serial1}),
+ ConnData2 = ConnData#conn_data{serial = Serial1},
+ {ok, ConnData2};
+ Serial2 ->
+ %% No, someone got there before we did
+ ConnData2 = ConnData#conn_data{serial = Serial2},
+ {ok, ConnData2}
+ end
+ end.
+
+%% For backward compatibillity (during code upgrade)
+reset_trans_id_counter(ConnHandle, Item, Serial) ->
+ LocalMid = ConnHandle#megaco_conn_handle.local_mid,
+ case megaco_config:lookup_local_conn(ConnHandle) of
+ [] ->
+ {error, {no_such_connection, ConnHandle}};
+ [ConnData] ->
+ do_reset_trans_id_counter(ConnData, LocalMid,
+ Item, Serial)
+ end.
+
+do_reset_trans_id_counter(ConnData, LocalMid, Item, Serial)
+ when is_integer(Serial) ->
+ Max = ConnData#conn_data.max_serial,
+ Overflow =
+ if
+ (Max == infinity) ->
+ Serial - 4294967295;
+
+ is_integer(Max) ->
+ Serial - Max
+ end,
+ NewSerial = user_info(LocalMid, min_trans_id) + (Overflow-1),
+ ConnData2 = ConnData#conn_data{serial = NewSerial},
+ ets:insert(megaco_config, {Item, NewSerial}),
+ {ok, ConnData2}.
+
+
+trans_sender_exit(Reason, CH) ->
+ ?d("trans_sender_exit -> entry with"
+ "~n Reason: ~p"
+ "~n CH: ~p", [Reason, CH]),
+ cast({trans_sender_exit, Reason, CH}).
+
+
+call(Request) ->
+ case (catch gen_server:call(?SERVER, Request, infinity)) of
+ {'EXIT', _} ->
+ {error, megaco_not_started};
+ Res ->
+ Res
+ end.
+
+
+cast(Msg) ->
+ case (catch gen_server:cast(?SERVER, Msg)) of
+ {'EXIT', _} ->
+ {error, megaco_not_started};
+ Res ->
+ Res
+ end.
+
+
+%%%----------------------------------------------------------------------
+%%% Callback functions from gen_server
+%%%----------------------------------------------------------------------
+
+%%----------------------------------------------------------------------
+%% Func: init/1
+%% Returns: {ok, State} |
+%% {ok, State, Timeout} |
+%% ignore |
+%% {stop, Reason}
+%%----------------------------------------------------------------------
+
+init([Parent]) ->
+ ?d("init -> entry with "
+ "~n Parent: ~p", [Parent]),
+ process_flag(trap_exit, true),
+ case (catch do_init()) of
+ ok ->
+ ?d("init -> init ok", []),
+ {ok, #state{parent_pid = Parent}};
+ Else ->
+ ?d("init -> init error: "
+ "~n ~p", [Else]),
+ {stop, Else}
+ end.
+
+do_init() ->
+ ?megaco_test_init(),
+ ets:new(megaco_config, [public, named_table, {keypos, 1}]),
+ ets:new(megaco_local_conn, [public, named_table, {keypos, 2}]),
+ ets:new(megaco_remote_conn, [public, named_table, {keypos, 2}, bag]),
+ megaco_stats:init(megaco_stats, global_snmp_counters()),
+ init_scanner(),
+ init_user_defaults(),
+ init_users().
+
+
+
+init_scanner() ->
+ case get_env(scanner, undefined) of
+ undefined ->
+ Key = text_config,
+ Data = [],
+ ets:insert(megaco_config, {Key, Data});
+ flex ->
+ start_scanner(megaco_flex_scanner_handler,
+ start_link, [], [gen_server]);
+ {flex, Opts} when is_list(Opts) -> % For future use
+ start_scanner(megaco_flex_scanner_handler,
+ start_link, [Opts], [gen_server]);
+ {M, F, A, Mods} when is_atom(M) andalso
+ is_atom(F) andalso
+ is_list(A) andalso
+ is_list(Mods) ->
+ start_scanner(M, F, A, Mods)
+ end.
+
+start_scanner(M, F, A, Mods) ->
+ case megaco_misc_sup:start_permanent_worker(M, F, A, Mods) of
+ {ok, Pid, Conf} when is_pid(Pid) ->
+ Key = text_config,
+ Data = [Conf],
+ ets:insert(megaco_config, {Key, Data});
+ Else ->
+ throw({scanner_start_failed, Else})
+ end.
+
+init_user_defaults() ->
+ init_user_default(min_trans_id, 1),
+ init_user_default(max_trans_id, infinity),
+ init_user_default(request_timer, #megaco_incr_timer{}),
+ init_user_default(long_request_timer, timer:seconds(60)),
+
+ init_user_default(auto_ack, false),
+
+ init_user_default(trans_ack, false),
+ init_user_default(trans_ack_maxcount, 10),
+
+ init_user_default(trans_req, false),
+ init_user_default(trans_req_maxcount, 10),
+ init_user_default(trans_req_maxsize, 2048),
+
+ init_user_default(trans_timer, 0),
+ init_user_default(trans_sender, undefined),
+
+ init_user_default(pending_timer, timer:seconds(30)),
+ init_user_default(sent_pending_limit, infinity),
+ init_user_default(recv_pending_limit, infinity),
+ init_user_default(reply_timer, timer:seconds(30)),
+ init_user_default(send_mod, megaco_tcp),
+ init_user_default(encoding_mod, megaco_pretty_text_encoder),
+ init_user_default(protocol_version, 1),
+ init_user_default(auth_data, asn1_NOVALUE),
+ init_user_default(encoding_config, []),
+ init_user_default(user_mod, megaco_user_default),
+ init_user_default(user_args, []),
+ init_user_default(reply_data, undefined),
+ init_user_default(threaded, false),
+ init_user_default(strict_version, true),
+ init_user_default(long_request_resend, false),
+ init_user_default(call_proxy_gc_timeout, timer:seconds(5)),
+ init_user_default(cancel, false),
+ init_user_default(resend_indication, false),
+ init_user_default(segment_reply_ind, false),
+ init_user_default(segment_recv_acc, false),
+ init_user_default(segment_recv_timer, timer:seconds(10)),
+ init_user_default(segment_send, none),
+ init_user_default(segment_send_timer, timer:seconds(5)),
+ init_user_default(max_pdu_size, infinity),
+ init_user_default(request_keep_alive_timeout, plain).
+
+init_user_default(Item, Default) when Item /= mid ->
+ Val = get_env(Item, Default),
+ case do_update_user(default, Item, Val) of
+ ok ->
+ ok;
+ {error, Reason} ->
+ throw(Reason)
+ end.
+
+init_users() ->
+ Users = get_env(users, []),
+ init_users(Users).
+
+init_users([]) ->
+ ok;
+init_users([{UserMid, Config} | Rest]) ->
+ case handle_start_user(UserMid, Config) of
+ ok ->
+ init_users(Rest);
+ Else ->
+ throw({bad_user, UserMid, Else})
+ end;
+init_users(BadConfig) ->
+ throw({bad_config, users, BadConfig}).
+
+%%----------------------------------------------------------------------
+%% Func: handle_call/3
+%% Returns: {reply, Reply, State} |
+%% {reply, Reply, State, Timeout} |
+%% {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, Reply, State} | (terminate/2 is called)
+%% {stop, Reason, State} (terminate/2 is called)
+%%----------------------------------------------------------------------
+
+handle_call({cre_counter, Item, Incr}, _From, S) ->
+ Reply = cre_counter(Item, Incr),
+ {reply, Reply, S};
+
+handle_call({del_counter, Item, Incr}, _From, S) ->
+ Reply = cre_counter(Item, Incr),
+ {reply, Reply, S};
+
+%% For backward compatibillity (code upgrade)
+handle_call({incr_trans_id_counter, ConnHandle}, _From, S) ->
+ Reply = incr_trans_id_counter(ConnHandle),
+ {reply, Reply, S};
+
+handle_call({init_trans_id_counter, ConnHandle, Item, Incr}, _From, S) ->
+ Reply = do_init_trans_id_counter(ConnHandle, Item, Incr),
+ {reply, Reply, S};
+
+%% For backward compatibillity (code upgrade)
+handle_call({reset_trans_id_counter, ConnHandle, Item, Serial}, _From, S) ->
+ Reply = reset_trans_id_counter(ConnHandle, Item, Serial),
+ {reply, Reply, S};
+
+handle_call({receive_handle, UserMid}, _From, S) ->
+ case catch make_receive_handle(UserMid) of
+ {'EXIT', _} ->
+ {reply, {error, {no_receive_handle, UserMid}}, S};
+ RH ->
+ {reply, {ok, RH}, S}
+ end;
+handle_call({connect, RH, RemoteMid, SendHandle, ControlPid}, _From, S) ->
+ Reply = handle_connect(RH, RemoteMid, SendHandle, ControlPid, auto),
+ {reply, Reply, S};
+handle_call({connect, RH, RemoteMid, SendHandle, ControlPid, Auto}, _From, S) ->
+ Reply = handle_connect(RH, RemoteMid, SendHandle, ControlPid, Auto),
+ {reply, Reply, S};
+
+handle_call({finish_connect, ConnHandle, SendHandle, ControlPid, MFA},
+ _From, S) ->
+ Reply = handle_finish_connect(ConnHandle, SendHandle, ControlPid, MFA),
+ {reply, Reply, S};
+
+handle_call({connect_remote, CH, UserNode, Ref}, _From, S) ->
+ Reply = handle_connect_remote(CH, UserNode, Ref),
+ {reply, Reply, S};
+
+handle_call({disconnect, ConnHandle}, _From, S) ->
+ Reply = handle_disconnect(ConnHandle),
+ {reply, Reply, S};
+handle_call({disconnect_remote, CH, UserNode}, _From, S) ->
+ Reply = handle_disconnect_remote(CH, UserNode),
+ {reply, Reply, S};
+
+handle_call({start_user, UserMid, Config}, _From, S) ->
+ Reply = handle_start_user(UserMid, Config),
+ {reply, Reply, S};
+handle_call({stop_user, UserMid}, _From, S) ->
+ Reply = handle_stop_user(UserMid),
+ {reply, Reply, S};
+handle_call({update_conn_data, CH, Item, Val}, _From, S) ->
+ case lookup_local_conn(CH) of
+ [] ->
+ {reply, {error, {no_such_connection, CH}}, S};
+ [CD] ->
+ Reply = handle_update_conn_data(CD, Item, Val),
+ {reply, Reply, S}
+ end;
+handle_call({update_user_info, UserMid, Item, Val}, _From, S) ->
+ case catch user_info(UserMid, mid) of
+ {'EXIT', _} ->
+ {reply, {error, {no_such_user, UserMid}}, S};
+ _ ->
+ Reply = do_update_user(UserMid, Item, Val),
+ {reply, Reply, S}
+ end;
+
+handle_call({stop, ParentPid}, _From, #state{parent_pid = ParentPid} = S) ->
+ Reason = normal,
+ Reply = ok,
+ {stop, Reason, Reply, S};
+
+handle_call(Req, From, S) ->
+ warning_msg("received unexpected request from ~p: "
+ "~n~w", [From, Req]),
+ {reply, {error, {bad_request, Req}}, S}.
+
+
+%%----------------------------------------------------------------------
+%% Func: handle_cast/2
+%% Returns: {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, State} (terminate/2 is called)
+%%----------------------------------------------------------------------
+
+handle_cast({trans_sender_exit, Reason, CH}, S) ->
+ warning_msg("transaction sender [~p] restarting: "
+ "~n~p", [CH, Reason]),
+ case lookup_local_conn(CH) of
+ [] ->
+ error_msg("connection data not found for ~p~n"
+ "when restarting transaction sender", [CH]);
+ [CD] ->
+ CD2 = trans_sender_start(CD#conn_data{trans_sender = undefined}),
+ ets:insert(megaco_local_conn, CD2)
+ end,
+ {noreply, S};
+
+handle_cast(Msg, S) ->
+ warning_msg("received unexpected message: "
+ "~n~w", [Msg]),
+ {noreply, S}.
+
+
+
+%%----------------------------------------------------------------------
+%% Func: handle_info/2
+%% Returns: {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, State} (terminate/2 is called)
+%%----------------------------------------------------------------------
+
+handle_info({'EXIT', Pid, Reason}, S) when Pid =:= S#state.parent_pid ->
+ {stop, Reason, S};
+
+handle_info(Info, S) ->
+ warning_msg("received unknown info: "
+ "~n~w", [Info]),
+ {noreply, S}.
+
+
+
+%%----------------------------------------------------------------------
+%% Func: terminate/2
+%% Purpose: Shutdown the server
+%% Returns: any (ignored by gen_server)
+%%----------------------------------------------------------------------
+
+terminate(_Reason, _State) ->
+ ok.
+
+
+%%----------------------------------------------------------------------
+%% Func: code_change/3
+%% Purpose: Convert process state when code is changed
+%% Returns: {ok, NewState}
+%%----------------------------------------------------------------------
+
+code_change(_Vsn, S, upgrade_from_pre_3_12) ->
+ upgrade_user_info_from_pre_3_12(),
+ upgrade_conn_data_from_pre_3_12(),
+ {ok, S};
+
+code_change(_Vsn, S, downgrade_to_pre_3_12) ->
+ downgrade_user_info_to_pre_3_12(),
+ downgrade_conn_data_to_pre_3_12(),
+ {ok, S};
+
+code_change(_Vsn, S, _Extra) ->
+ {ok, S}.
+
+
+%% -- Upgrade user info --
+
+upgrade_user_info_from_pre_3_12() ->
+ NewValues = [{request_keep_alive_timeout, plain}],
+ upgrade_user_info(NewValues).
+
+%% upgrade_user_info_from_pre_3_7() ->
+%% NewValues = [{segment_reply_ind, false},
+%% {segment_recv_acc, false},
+%% {segment_recv_timer, #megaco_incr_timer{}},
+%% {segment_send, none},
+%% {segment_send_timer, infinity},
+%% {max_pdu_size, infinity}],
+%% upgrade_user_info(NewValues).
+
+upgrade_user_info(NewValues) ->
+ Users = [default|system_info(users)],
+ F = fun({Item, Val}) ->
+ upgrade_user_info(Users, Item, Val)
+ end,
+ lists:foreach(F, NewValues),
+ ok.
+
+upgrade_user_info(Users, Item, Val) ->
+ F = fun(User) -> do_update_user(User, Item, Val) end,
+ lists:foreach(F, Users),
+ ok.
+
+
+%% %% -- Downgrade user info --
+
+downgrade_user_info_to_pre_3_12() ->
+ NewItems = [
+ request_keep_alive_timeout
+ ],
+ downgrade_user_info(NewItems).
+
+%% downgrade_user_info_to_pre_3_7() ->
+%% NewItems = [
+%% segment_reply_ind,
+%% segment_recv_acc,
+%% segment_recv_timer,
+%% segment_send,
+%% segment_send_timer,
+%% max_pdu_size
+%% ],
+%% downgrade_user_info(NewItems).
+
+downgrade_user_info(NewItems) ->
+ Users = [default|system_info(users)],
+ F = fun(Item) ->
+ downgrade_user_info(Users, Item)
+ end,
+ lists:foreach(F, NewItems),
+ ok.
+
+downgrade_user_info(Users, Item) ->
+ F = fun(User) -> do_downgrade_user_info(User, Item) end,
+ lists:foreach(F, Users),
+ ok.
+
+do_downgrade_user_info(User, Item) ->
+ ets:delete(megaco_config, {User, Item}).
+
+
+%% %% -- Upgrade conn data --
+
+upgrade_conn_data_from_pre_3_12() ->
+ Conns = system_info(connections),
+ Defaults = [{request_keep_alive_timeout, plain}],
+ upgrade_conn_data(Conns, Defaults).
+
+%% upgrade_conn_data_from_pre_3_7() ->
+%% Conns = system_info(connections),
+%% Defaults = [{segment_reply_ind, false},
+%% {segment_recv_acc, false},
+%% {segment_recv_timer, #megaco_incr_timer{}},
+%% {segment_send, false},
+%% {segment_send_timer, #megaco_incr_timer{}},
+%% {max_pdu_size, infinity}],
+%% upgrade_conn_data(Conns, Defaults).
+
+upgrade_conn_data(Conns, Defaults) ->
+ F = fun(CH) ->
+ case lookup_local_conn(CH) of
+ [] ->
+ ok;
+ [CD] ->
+ do_upgrade_conn_data(CD, Defaults)
+ end
+ end,
+ lists:foreach(F, Conns),
+ ok.
+
+do_upgrade_conn_data(OldStyleCD, Defaults) ->
+ NewStyleCD = new_conn_data(OldStyleCD, Defaults),
+ ets:insert(megaco_local_conn, NewStyleCD).
+
+%% Pre 3.12
+new_conn_data({conn_data, CH, Serial, MaxSerial, ReqTmr, LongReqTmr,
+ AutoAck,
+ TransAck, TransAckMaxCnt,
+ TransReq, TransReqMaxCnt, TransReqMaxSz,
+ TransTmr, TransSndr,
+
+ PendingTmr,
+ SentPendingLimit,
+ RecvPendingLimit,
+ ReplyTmr, CtrPid, MonRef,
+ Sendmod, SendHandle,
+ EncodeMod, EncodeConf,
+ ProtV, AuthData,
+ UserMod, UserArgs, ReplyAction, ReplyData,
+ Threaded,
+ StrictVersion,
+ LongReqResend,
+ Cancel,
+ ResendIndication,
+ SegmentReplyInd,
+ SegmentRecvAcc,
+ SegmentRecvTimer,
+ SegmentSend,
+ SegmentSendTimer,
+ MaxPDUSize
+ %% RequestKeepAliveTimerDefault - New values
+ },
+ Defaults) ->
+ #conn_data{conn_handle = CH,
+ serial = Serial,
+ max_serial = MaxSerial,
+ request_timer = ReqTmr,
+ long_request_timer = LongReqTmr,
+
+ auto_ack = AutoAck,
+
+ trans_ack = TransAck,
+ trans_ack_maxcount = TransAckMaxCnt,
+
+ trans_req = TransReq,
+ trans_req_maxcount = TransReqMaxCnt,
+ trans_req_maxsize = TransReqMaxSz,
+
+ trans_timer = TransTmr,
+ trans_sender = TransSndr,
+
+ pending_timer = PendingTmr,
+ sent_pending_limit = SentPendingLimit,
+ recv_pending_limit = RecvPendingLimit,
+
+ reply_timer = ReplyTmr,
+ control_pid = CtrPid,
+ monitor_ref = MonRef,
+ send_mod = Sendmod,
+ send_handle = SendHandle,
+ encoding_mod = EncodeMod,
+ encoding_config = EncodeConf,
+ protocol_version = ProtV,
+ auth_data = AuthData,
+ user_mod = UserMod,
+ user_args = UserArgs,
+ reply_action = ReplyAction,
+ reply_data = ReplyData,
+ threaded = Threaded,
+ strict_version = StrictVersion,
+ long_request_resend = LongReqResend,
+ cancel = Cancel,
+ resend_indication = ResendIndication,
+ segment_reply_ind = SegmentReplyInd,
+ segment_recv_acc = SegmentRecvAcc,
+ segment_recv_timer = SegmentRecvTimer,
+ segment_send = SegmentSend,
+ segment_send_timer = SegmentSendTimer,
+ max_pdu_size = MaxPDUSize,
+ request_keep_alive_timeout = get_default(request_keep_alive_timeout, Defaults)
+ }.
+
+
+get_default(Key, Defaults) ->
+ {value, {Key, Default}} = lists:keysearch(Key, 1, Defaults),
+ Default.
+
+
+%% %% -- Downgrade conn data --
+
+downgrade_conn_data_to_pre_3_12() ->
+ Conns = system_info(connections),
+ Downgrade = fun(NewCD) -> old_conn_data_to_pre_3_12(NewCD) end,
+ downgrade_conn_data(Downgrade, Conns).
+
+downgrade_conn_data(Downgrade, Conns) ->
+ F = fun(CH) ->
+ case lookup_local_conn(CH) of
+ [] ->
+ ok;
+ [CD] ->
+ do_downgrade_conn_data(Downgrade, CD)
+ end
+ end,
+ lists:foreach(F, Conns).
+
+do_downgrade_conn_data(Downgrade, NewStyleCD) ->
+ OldStyleCD = Downgrade(NewStyleCD),
+ ets:insert(megaco_local_conn, OldStyleCD).
+
+old_conn_data_to_pre_3_12(
+ #conn_data{conn_handle = CH,
+ serial = Serial,
+ max_serial = MaxSerial,
+ request_timer = ReqTmr,
+ long_request_timer = LongReqTmr,
+
+ auto_ack = AutoAck,
+
+ trans_ack = TransAck,
+ trans_ack_maxcount = TransAckMaxCnt,
+
+ trans_req = TransReq,
+ trans_req_maxcount = TransReqMaxCnt,
+ trans_req_maxsize = TransReqMaxSz,
+
+ trans_timer = TransTmr,
+ trans_sender = TransSndr,
+
+ pending_timer = PendingTmr,
+ sent_pending_limit = SentPendingLimit,
+ recv_pending_limit = RecvPendingLimit,
+
+ reply_timer = ReplyTmr,
+ control_pid = CtrPid,
+ monitor_ref = MonRef,
+ send_mod = Sendmod,
+ send_handle = SendHandle,
+ encoding_mod = EncodeMod,
+ encoding_config = EncodeConf,
+ protocol_version = ProtV,
+ auth_data = AuthData,
+ user_mod = UserMod,
+ user_args = UserArgs,
+ reply_action = ReplyAction,
+ reply_data = ReplyData,
+ threaded = Threaded,
+ strict_version = StrictVersion,
+ long_request_resend = LongReqResend,
+ cancel = Cancel,
+ resend_indication = ResendIndication,
+ segment_reply_ind = SegmentRecvAcc,
+ segment_recv_acc = SegmentRecvAcc,
+ segment_recv_timer = SegmentRecvTimer,
+ segment_send = SegmentSend,
+ segment_send_timer = SegmentSendTimer,
+ max_pdu_size = MaxPDUSize
+ %% request_keep_alive_timeout = RequestKeepAliveTimeout
+ }) ->
+ {conn_data, CH, Serial, MaxSerial, ReqTmr, LongReqTmr,
+ AutoAck,
+ TransAck, TransAckMaxCnt,
+ TransReq, TransReqMaxCnt, TransReqMaxSz,
+ TransTmr, TransSndr,
+ PendingTmr,
+ SentPendingLimit,
+ RecvPendingLimit,
+ ReplyTmr, CtrPid, MonRef,
+ Sendmod, SendHandle,
+ EncodeMod, EncodeConf,
+ ProtV, AuthData,
+ UserMod, UserArgs, ReplyAction, ReplyData,
+ Threaded,
+ StrictVersion,
+ LongReqResend,
+ Cancel,
+ ResendIndication,
+ SegmentRecvAcc,
+ SegmentRecvAcc,
+ SegmentRecvTimer,
+ SegmentSend,
+ SegmentSendTimer,
+ MaxPDUSize}.
+
+
+
+%%%----------------------------------------------------------------------
+%%% Internal functions
+%%%----------------------------------------------------------------------
+
+handle_start_user(default, _Config) ->
+ {error, bad_user_mid};
+handle_start_user(Mid, Config) ->
+ case catch user_info(Mid, mid) of
+ {'EXIT', _} ->
+ DefaultConfig = user_info(default, all),
+ do_handle_start_user(Mid, DefaultConfig),
+ do_handle_start_user(Mid, Config);
+ _LocalMid ->
+ {error, {user_already_exists, Mid}}
+ end.
+
+do_handle_start_user(UserMid, [{Item, Val} | Rest]) ->
+ case do_update_user(UserMid, Item, Val) of
+ ok ->
+ do_handle_start_user(UserMid, Rest);
+ {error, Reason} ->
+ ets:match_delete(megaco_config, {{UserMid, '_'}, '_'}),
+ {error, Reason}
+ end;
+do_handle_start_user(UserMid, []) ->
+ do_update_user(UserMid, mid, UserMid),
+ ok;
+do_handle_start_user(UserMid, BadConfig) ->
+ ets:match_delete(megaco_config, {{UserMid, '_'}, '_'}),
+ {error, {bad_user_config, UserMid, BadConfig}}.
+
+do_update_user(UserMid, Item, Val) ->
+ case verify_val(Item, Val) of
+ true ->
+ ets:insert(megaco_config, {{UserMid, Item}, Val}),
+ ok;
+ false ->
+ {error, {bad_user_val, UserMid, Item, Val}}
+ end.
+
+verify_val(Item, Val) ->
+ case Item of
+ mid -> true;
+ local_mid -> true;
+ remote_mid -> true;
+ min_trans_id -> verify_strict_uint(Val, 4294967295); % uint32
+ max_trans_id -> verify_uint(Val, 4294967295); % uint32
+ request_timer -> verify_timer(Val);
+ long_request_timer -> verify_timer(Val);
+
+ auto_ack -> verify_bool(Val);
+
+ trans_ack -> verify_bool(Val);
+ trans_ack_maxcount -> verify_uint(Val);
+
+ trans_req -> verify_bool(Val);
+ trans_req_maxcount -> verify_uint(Val);
+ trans_req_maxsize -> verify_uint(Val);
+
+ trans_timer -> verify_timer(Val) and (Val >= 0);
+ trans_sender when Val == undefined -> true;
+
+ pending_timer -> verify_timer(Val);
+ sent_pending_limit -> verify_uint(Val) andalso
+ (Val > 0);
+ recv_pending_limit -> verify_uint(Val) andalso
+ (Val > 0);
+ reply_timer -> verify_timer(Val);
+ control_pid when is_pid(Val) -> true;
+ monitor_ref -> true; % Internal usage only
+ send_mod when is_atom(Val) -> true;
+ send_handle -> true;
+ encoding_mod when is_atom(Val) -> true;
+ encoding_config when is_list(Val) -> true;
+ protocol_version -> verify_strict_uint(Val);
+ auth_data -> true;
+ user_mod when is_atom(Val) -> true;
+ user_args when is_list(Val) -> true;
+ reply_data -> true;
+ threaded -> verify_bool(Val);
+ strict_version -> verify_bool(Val);
+ long_request_resend -> verify_bool(Val);
+ call_proxy_gc_timeout -> verify_strict_uint(Val);
+ cancel -> verify_bool(Val);
+ resend_indication -> verify_resend_indication(Val);
+
+ segment_reply_ind -> verify_bool(Val);
+ segment_recv_acc -> verify_bool(Val);
+ segment_recv_timer -> verify_timer(Val);
+ segment_send -> verify_segmentation_window(Val);
+ segment_send_timer -> verify_timer(Val);
+ max_pdu_size -> verify_int(Val) andalso (Val > 0);
+ request_keep_alive_timeout ->
+ (verify_int(Val) andalso (Val >= 0)) orelse (Val =:= plain);
+
+ _ -> false
+ end.
+
+
+
+verify_bool(true) -> true;
+verify_bool(false) -> true;
+verify_bool(_) -> false.
+
+verify_resend_indication(flag) -> true;
+verify_resend_indication(Val) -> verify_bool(Val).
+
+-spec verify_strict_int(Int :: integer()) -> boolean().
+verify_strict_int(Int) when is_integer(Int) -> true;
+verify_strict_int(_) -> false.
+
+-spec verify_strict_int(Int :: integer(),
+ Max :: integer() | 'infinity') -> boolean().
+verify_strict_int(Int, infinity) ->
+ verify_strict_int(Int);
+verify_strict_int(Int, Max) ->
+ verify_strict_int(Int) andalso verify_strict_int(Max) andalso (Int =< Max).
+
+-spec verify_strict_uint(Int :: non_neg_integer()) -> boolean().
+verify_strict_uint(Int) when is_integer(Int) andalso (Int >= 0) -> true;
+verify_strict_uint(_) -> false.
+
+-spec verify_strict_uint(Int :: non_neg_integer(),
+ Max :: non_neg_integer() | 'infinity') -> boolean().
+verify_strict_uint(Int, infinity) ->
+ verify_strict_uint(Int);
+verify_strict_uint(Int, Max) ->
+ verify_strict_int(Int, 0, Max).
+
+-spec verify_uint(Val :: non_neg_integer() | 'infinity') -> boolean().
+verify_uint(infinity) -> true;
+verify_uint(Val) -> verify_strict_uint(Val).
+
+-spec verify_int(Val :: integer() | 'infinity') -> boolean().
+verify_int(infinity) -> true;
+verify_int(Val) -> verify_strict_int(Val).
+
+-spec verify_int(Int :: integer() | 'infinity',
+ Max :: integer() | 'infinity') -> boolean().
+verify_int(Int, infinity) ->
+ verify_int(Int);
+verify_int(infinity, _Max) ->
+ true;
+verify_int(Int, Max) ->
+ verify_strict_int(Int) andalso verify_strict_int(Max) andalso (Int =< Max).
+
+-spec verify_uint(Int :: non_neg_integer() | 'infinity',
+ Max :: non_neg_integer() | 'infinity') -> boolean().
+verify_uint(Int, infinity) ->
+ verify_uint(Int);
+verify_uint(infinity, _Max) ->
+ true;
+verify_uint(Int, Max) ->
+ verify_strict_int(Int, 0, Max).
+
+-spec verify_strict_int(Int :: integer(),
+ Min :: integer(),
+ Max :: integer()) -> boolean().
+verify_strict_int(Val, Min, Max)
+ when (is_integer(Val) andalso
+ is_integer(Min) andalso
+ is_integer(Max) andalso
+ (Val >= Min) andalso
+ (Val =< Max)) ->
+ true;
+verify_strict_int(_Val, _Min, _Max) ->
+ false.
+
+-spec verify_int(Val :: integer() | 'infinity',
+ Min :: integer(),
+ Max :: integer() | 'infinity') -> boolean().
+verify_int(infinity, Min, infinity) ->
+ verify_strict_int(Min);
+verify_int(Val, Min, infinity) ->
+ verify_strict_int(Val) andalso
+ verify_strict_int(Min) andalso (Val >= Min);
+verify_int(Int, Min, Max) ->
+ verify_strict_int(Int, Min, Max).
+
+verify_timer(Timer) ->
+ megaco_timer:verify(Timer).
+
+verify_segmentation_window(none) ->
+ true;
+verify_segmentation_window(K) ->
+ verify_int(K, 1, infinity).
+
+handle_stop_user(UserMid) ->
+ case catch user_info(UserMid, mid) of
+ {'EXIT', _} ->
+ {error, {no_such_user, UserMid}};
+ _ ->
+ case catch user_info(UserMid, connections) of
+ [] ->
+ ets:match_delete(megaco_config, {{UserMid, '_'}, '_'}),
+ ok;
+ {'EXIT', _} ->
+ {error, {no_such_user, UserMid}};
+ _Else ->
+ {error, {active_connections, UserMid}}
+ end
+ end.
+
+handle_update_conn_data(CD, Item = receive_handle, RH) ->
+ UserMid = (CD#conn_data.conn_handle)#megaco_conn_handle.local_mid,
+ if
+ is_record(RH, megaco_receive_handle) andalso
+ is_atom(RH#megaco_receive_handle.encoding_mod) andalso
+ is_list(RH#megaco_receive_handle.encoding_config) andalso
+ is_atom(RH#megaco_receive_handle.send_mod) andalso
+ (RH#megaco_receive_handle.local_mid /= UserMid) ->
+ CD2 = CD#conn_data{
+ encoding_mod = RH#megaco_receive_handle.encoding_mod,
+ encoding_config = RH#megaco_receive_handle.encoding_config,
+ send_mod = RH#megaco_receive_handle.send_mod},
+ ets:insert(megaco_local_conn, CD2),
+ ok;
+ true ->
+ {error, {bad_user_val, UserMid, Item, RH}}
+ end;
+handle_update_conn_data(CD, Item, Val) ->
+ case verify_val(Item, Val) of
+ true ->
+ CD2 = replace_conn_data(CD, Item, Val),
+ ets:insert(megaco_local_conn, CD2),
+ ok;
+ false ->
+ UserMid = (CD#conn_data.conn_handle)#megaco_conn_handle.local_mid,
+ {error, {bad_user_val, UserMid, Item, Val}}
+ end.
+
+replace_conn_data(CD, Item, Val) ->
+ case Item of
+ trans_id -> CD#conn_data{serial = Val};
+ max_trans_id -> CD#conn_data{max_serial = Val};
+ request_timer -> CD#conn_data{request_timer = Val};
+ long_request_timer -> CD#conn_data{long_request_timer = Val};
+
+ auto_ack -> update_auto_ack(CD, Val);
+
+ %% Accumulate trans ack before sending
+ trans_ack -> update_trans_ack(CD, Val);
+ trans_ack_maxcount -> update_trans_ack_maxcount(CD, Val);
+
+ %% Accumulate trans req before sending
+ trans_req -> update_trans_req(CD, Val);
+ trans_req_maxcount -> update_trans_req_maxcount(CD, Val);
+ trans_req_maxsize -> update_trans_req_maxsize(CD, Val);
+
+ trans_timer -> update_trans_timer(CD, Val);
+ %% trans_sender - Automagically updated by
+ %% update_auto_ack & update_trans_timer &
+ %% update_trans_ack & update_trans_req
+
+ pending_timer -> CD#conn_data{pending_timer = Val};
+ sent_pending_limit -> CD#conn_data{sent_pending_limit = Val};
+ recv_pending_limit -> CD#conn_data{recv_pending_limit = Val};
+ reply_timer -> CD#conn_data{reply_timer = Val};
+ control_pid -> CD#conn_data{control_pid = Val};
+ monitor_ref -> CD#conn_data{monitor_ref = Val};
+ send_mod -> CD#conn_data{send_mod = Val};
+ send_handle -> CD#conn_data{send_handle = Val};
+ encoding_mod -> CD#conn_data{encoding_mod = Val};
+ encoding_config -> CD#conn_data{encoding_config = Val};
+ protocol_version -> CD#conn_data{protocol_version = Val};
+ auth_data -> CD#conn_data{auth_data = Val};
+ user_mod -> CD#conn_data{user_mod = Val};
+ user_args -> CD#conn_data{user_args = Val};
+ reply_action -> CD#conn_data{reply_action = Val};
+ reply_data -> CD#conn_data{reply_data = Val};
+ threaded -> CD#conn_data{threaded = Val};
+ strict_version -> CD#conn_data{strict_version = Val};
+ long_request_resend -> CD#conn_data{long_request_resend = Val};
+ call_proxy_gc_timeout -> CD#conn_data{call_proxy_gc_timeout = Val};
+ cancel -> CD#conn_data{cancel = Val};
+ resend_indication -> CD#conn_data{resend_indication = Val};
+ segment_reply_ind -> CD#conn_data{segment_reply_ind = Val};
+ segment_recv_acc -> CD#conn_data{segment_recv_acc = Val};
+ segment_recv_timer -> CD#conn_data{segment_recv_timer = Val};
+ segment_send -> CD#conn_data{segment_send = Val};
+ segment_send_timer -> CD#conn_data{segment_send_timer = Val};
+ max_pdu_size -> CD#conn_data{max_pdu_size = Val};
+ request_keep_alive_timeout -> CD#conn_data{request_keep_alive_timeout = Val}
+ end.
+
+%% update auto_ack
+update_auto_ack(#conn_data{trans_sender = Pid,
+ trans_req = false} = CD,
+ false) when is_pid(Pid) ->
+ megaco_trans_sender:stop(Pid),
+ CD#conn_data{auto_ack = false, trans_sender = undefined};
+
+update_auto_ack(#conn_data{trans_timer = To,
+ trans_ack = true,
+ trans_sender = undefined} = CD,
+ true) when To > 0 ->
+ #conn_data{conn_handle = CH,
+ trans_ack_maxcount = AcksMax,
+ trans_req_maxcount = ReqsMax,
+ trans_req_maxsize = ReqsMaxSz} = CD,
+ {ok, Pid} = megaco_trans_sup:start_trans_sender(CH, To, ReqsMaxSz,
+ ReqsMax, AcksMax),
+
+ %% Make sure we are notified when/if the transaction
+ %% sender goes down.
+ %% Do we need to store the ref? Will we ever need to
+ %% cancel this (apply_at_exit)?
+ megaco_monitor:apply_at_exit(?MODULE, trans_sender_exit, [CH], Pid),
+
+ CD#conn_data{auto_ack = true, trans_sender = Pid};
+
+update_auto_ack(CD, Val) ->
+ ?d("update_auto_ack -> entry with ~p", [Val]),
+ CD#conn_data{auto_ack = Val}.
+
+%% update trans_ack
+update_trans_ack(#conn_data{auto_ack = true,
+ trans_req = false,
+ trans_sender = Pid} = CD,
+ false) when is_pid(Pid) ->
+ megaco_trans_sender:stop(Pid),
+ CD#conn_data{trans_ack = false, trans_sender = undefined};
+
+update_trans_ack(#conn_data{trans_timer = To,
+ auto_ack = true,
+ trans_sender = undefined} = CD,
+ true) when To > 0 ->
+ #conn_data{conn_handle = CH,
+ trans_ack_maxcount = AcksMax,
+ trans_req_maxcount = ReqsMax,
+ trans_req_maxsize = ReqsMaxSz} = CD,
+ {ok, Pid} = megaco_trans_sup:start_trans_sender(CH, To, ReqsMaxSz,
+ ReqsMax, AcksMax),
+
+ %% Make sure we are notified when/if the transaction
+ %% sender goes down.
+ %% Do we need to store the ref? Will we ever need to
+ %% cancel this (apply_at_exit)?
+ megaco_monitor:apply_at_exit(?MODULE, trans_sender_exit, [CH], Pid),
+
+ CD#conn_data{trans_ack = true, trans_sender = Pid};
+
+update_trans_ack(CD, Val) ->
+ ?d("update_trans_ack -> entry with ~p", [Val]),
+ CD#conn_data{trans_ack = Val}.
+
+%% update trans_req
+update_trans_req(#conn_data{trans_ack = false,
+ trans_sender = Pid} = CD,
+ false) when is_pid(Pid) ->
+ megaco_trans_sender:stop(Pid),
+ CD#conn_data{trans_req = false, trans_sender = undefined};
+
+update_trans_req(#conn_data{trans_timer = To,
+ trans_sender = undefined} = CD,
+ true) when To > 0 ->
+ #conn_data{conn_handle = CH,
+ trans_ack_maxcount = AcksMax,
+ trans_req_maxcount = ReqsMax,
+ trans_req_maxsize = ReqsMaxSz} = CD,
+ {ok, Pid} = megaco_trans_sup:start_trans_sender(CH, To, ReqsMaxSz,
+ ReqsMax, AcksMax),
+
+ %% Make sure we are notified when/if the transaction
+ %% sender goes down.
+ %% Do we need to store the ref? Will we ever need to
+ %% cancel this (apply_at_exit)?
+ megaco_monitor:apply_at_exit(?MODULE, trans_sender_exit, [CH], Pid),
+
+ CD#conn_data{trans_req = true, trans_sender = Pid};
+
+update_trans_req(CD, Val) ->
+ ?d("update_trans_req -> entry with ~p", [Val]),
+ CD#conn_data{trans_req = Val}.
+
+%% update trans_timer
+update_trans_timer(#conn_data{auto_ack = true,
+ trans_ack = true,
+ trans_sender = undefined} = CD,
+ To) when To > 0 ->
+ #conn_data{conn_handle = CH,
+ trans_ack_maxcount = AcksMax,
+ trans_req_maxcount = ReqsMax,
+ trans_req_maxsize = ReqsMaxSz} = CD,
+ {ok, Pid} = megaco_trans_sup:start_trans_sender(CH, To, ReqsMaxSz,
+ ReqsMax, AcksMax),
+
+ %% Make sure we are notified when/if the transaction
+ %% sender goes down.
+ %% Do we need to store the ref? Will we ever need to
+ %% cancel this (apply_at_exit)?
+ megaco_monitor:apply_at_exit(?MODULE, trans_sender_exit, [CH], Pid),
+
+ CD#conn_data{trans_timer = To, trans_sender = Pid};
+
+update_trans_timer(#conn_data{trans_req = true,
+ trans_sender = undefined} = CD,
+ To) when To > 0 ->
+ #conn_data{conn_handle = CH,
+ trans_ack_maxcount = AcksMax,
+ trans_req_maxcount = ReqsMax,
+ trans_req_maxsize = ReqsMaxSz} = CD,
+ {ok, Pid} = megaco_trans_sup:start_trans_sender(CH, To, ReqsMaxSz,
+ ReqsMax, AcksMax),
+
+ %% Make sure we are notified when/if the transaction
+ %% sender goes down.
+ %% Do we need to store the ref? Will we ever need to
+ %% cancel this (apply_at_exit)?
+ megaco_monitor:apply_at_exit(?MODULE, trans_sender_exit, [CH], Pid),
+
+ CD#conn_data{trans_timer = To, trans_sender = Pid};
+
+update_trans_timer(#conn_data{trans_sender = Pid} = CD, 0) when is_pid(Pid) ->
+ megaco_trans_sender:stop(Pid),
+ CD#conn_data{trans_timer = 0, trans_sender = undefined};
+
+update_trans_timer(#conn_data{trans_sender = Pid} = CD, To)
+ when is_pid(Pid) and (To > 0) ->
+ megaco_trans_sender:timeout(Pid, To),
+ CD#conn_data{trans_timer = To};
+
+update_trans_timer(CD, To) when To > 0 ->
+ CD#conn_data{trans_timer = To}.
+
+%% update trans_ack_maxcount
+update_trans_ack_maxcount(#conn_data{trans_sender = Pid} = CD, Max)
+ when is_pid(Pid) and (Max > 0) ->
+ megaco_trans_sender:ack_maxcount(Pid, Max),
+ CD#conn_data{trans_ack_maxcount = Max};
+
+update_trans_ack_maxcount(CD, Max)
+ when Max > 0 ->
+ ?d("update_trans_ack_maxcount -> entry with ~p", [Max]),
+ CD#conn_data{trans_ack_maxcount = Max}.
+
+%% update trans_req_maxcount
+update_trans_req_maxcount(#conn_data{trans_sender = Pid} = CD, Max)
+ when is_pid(Pid) and (Max > 0) ->
+ megaco_trans_sender:req_maxcount(Pid, Max),
+ CD#conn_data{trans_req_maxcount = Max};
+
+update_trans_req_maxcount(CD, Max)
+ when Max > 0 ->
+ ?d("update_trans_req_maxcount -> entry with ~p", [Max]),
+ CD#conn_data{trans_req_maxcount = Max}.
+
+%% update trans_req_maxsize
+update_trans_req_maxsize(#conn_data{trans_sender = Pid} = CD, Max)
+ when is_pid(Pid) and (Max > 0) ->
+ megaco_trans_sender:req_maxsize(Pid, Max),
+ CD#conn_data{trans_req_maxsize = Max};
+
+update_trans_req_maxsize(CD, Max)
+ when Max > 0 ->
+ ?d("update_trans_req_maxsize -> entry with ~p", [Max]),
+ CD#conn_data{trans_req_maxsize = Max}.
+
+
+
+handle_connect(RH, RemoteMid, SendHandle, ControlPid, Auto) ->
+ LocalMid = RH#megaco_receive_handle.local_mid,
+ ConnHandle = #megaco_conn_handle{local_mid = LocalMid,
+ remote_mid = RemoteMid},
+ ?d("handle_connect -> entry with"
+ "~n ConnHandle: ~p", [ConnHandle]),
+ case ets:lookup(megaco_local_conn, ConnHandle) of
+ [] ->
+ PrelMid = preliminary_mid,
+ PrelHandle = ConnHandle#megaco_conn_handle{remote_mid = PrelMid},
+ case ets:lookup(megaco_local_conn, PrelHandle) of
+ [] ->
+ case (catch init_conn_data(RH,
+ RemoteMid, SendHandle,
+ ControlPid, Auto)) of
+ {'EXIT', _Reason} ->
+ ?d("handle_connect -> init conn data failed: "
+ "~n ~p",[_Reason]),
+ {error, {no_such_user, LocalMid}};
+ ConnData ->
+ ?d("handle_connect -> new connection"
+ "~n ConnData: ~p", [ConnData]),
+ %% Brand new connection, use
+ %% When is the preliminary_mid used?
+ create_snmp_counters(ConnHandle),
+ %% Maybe start transaction sender
+ ConnData2 = trans_sender_start(ConnData),
+ ets:insert(megaco_local_conn, ConnData2),
+ {ok, ConnData2}
+ end;
+ [PrelData] ->
+ ?d("handle_connect -> connection upgrade"
+ "~n PrelData: ~p", [PrelData]),
+ %% OK, we need to fix the snmp counters. Used
+ %% with the temporary (preliminary_mid) conn_handle.
+ create_snmp_counters(ConnHandle),
+ ConnData = PrelData#conn_data{conn_handle = ConnHandle},
+ trans_sender_upgrade(ConnData),
+ ets:insert(megaco_local_conn, ConnData),
+ ets:delete(megaco_local_conn, PrelHandle),
+ update_snmp_counters(ConnHandle, PrelHandle),
+ TH = ConnHandle#megaco_conn_handle{local_mid = PrelMid,
+ remote_mid = RemoteMid},
+ TD = ConnData#conn_data{conn_handle = TH},
+ ?report_debug(TD,
+ "Upgrade preliminary_mid to "
+ "actual remote_mid",
+ [{preliminary_mid, preliminary_mid},
+ {local_mid, LocalMid},
+ {remote_mid, RemoteMid}]),
+ {ok, ConnData}
+ end;
+ [_ConnData] ->
+ {error, {already_connected, ConnHandle}}
+ end.
+
+handle_finish_connect(ConnHandle, SendHandle, ControlPid, MFA) ->
+ case (catch ets:lookup(megaco_local_conn, ConnHandle)) of
+ [#conn_data{monitor_ref = connected} = CD] ->
+ {M, F, A} = MFA,
+ Ref = megaco_monitor:apply_at_exit(M, F, A, ControlPid),
+ ConnData2 = CD#conn_data{monitor_ref = Ref,
+ control_pid = ControlPid,
+ send_handle = SendHandle},
+ ets:insert(megaco_local_conn, ConnData2),
+ {ok, Ref};
+ [#conn_data{monitor_ref = Ref}] ->
+ {ok, Ref};
+ [] ->
+ {error, {no_such_connection, ConnHandle}}
+ end.
+
+
+%% also trans_req == true
+trans_sender_start(#conn_data{conn_handle = CH,
+ auto_ack = true,
+ trans_ack = true,
+ trans_ack_maxcount = AcksMax,
+ trans_req_maxcount = ReqsMax,
+ trans_req_maxsize = ReqsMaxSz,
+ trans_timer = To,
+ trans_sender = undefined} = CD)
+ when To > 0 ->
+
+ ?d("trans_sender_start(ack) -> entry when"
+ "~n CH: ~p"
+ "~n To: ~p"
+ "~n AcksMax: ~p"
+ "~n ReqsMax: ~p"
+ "~n ReqsMaxSz: ~p", [CH, To, ReqsMaxSz, ReqsMax, AcksMax]),
+
+ {ok, Pid} = megaco_trans_sup:start_trans_sender(CH, To, ReqsMaxSz,
+ ReqsMax, AcksMax),
+
+ ?d("trans_sender_start(ack) -> Pid: ~p", [Pid]),
+
+ %% Make sure we are notified when/if the transaction
+ %% sender goes down.
+ %% Do we need to store the ref? Will we ever need to
+ %% cancel this (apply_at_exit)?
+ megaco_monitor:apply_at_exit(?MODULE, trans_sender_exit, [CH], Pid),
+
+ CD#conn_data{trans_sender = Pid};
+
+trans_sender_start(#conn_data{conn_handle = CH,
+ trans_req = true,
+ trans_ack_maxcount = AcksMax,
+ trans_req_maxcount = ReqsMax,
+ trans_req_maxsize = ReqsMaxSz,
+ trans_timer = To,
+ trans_sender = undefined} = CD)
+ when To > 0 ->
+
+ ?d("trans_sender_start(req) -> entry when"
+ "~n CH: ~p"
+ "~n To: ~p"
+ "~n AcksMax: ~p"
+ "~n ReqsMax: ~p"
+ "~n ReqsMaxSz: ~p", [CH, To, ReqsMaxSz, ReqsMax, AcksMax]),
+
+ {ok, Pid} = megaco_trans_sup:start_trans_sender(CH, To, ReqsMaxSz,
+ ReqsMax, AcksMax),
+
+ ?d("trans_sender_start(req) -> Pid: ~p", [Pid]),
+
+ %% Make sure we are notified when/if the transaction
+ %% sender goes down.
+ %% Do we need to store the ref? Will we ever need to
+ %% cancel this (apply_at_exit)?
+ megaco_monitor:apply_at_exit(?MODULE, trans_sender_exit, [CH], Pid),
+
+ CD#conn_data{trans_sender = Pid};
+
+trans_sender_start(CD) ->
+ ?d("trans_sender_start -> undefined", []),
+ CD#conn_data{trans_sender = undefined}.
+
+trans_sender_upgrade(#conn_data{conn_handle = CH,
+ trans_sender = Pid})
+ when is_pid(Pid) ->
+ ?d("trans_sende_upgrade -> entry when"
+ "~n CH: ~p"
+ "~n Pid: ~p", [CH, Pid]),
+ megaco_trans_sender:upgrade(Pid, CH);
+trans_sender_upgrade(_CD) ->
+ ok.
+
+
+handle_connect_remote(ConnHandle, UserNode, Ref) ->
+ Pat = #remote_conn_data{conn_handle = ConnHandle,
+ user_node = UserNode,
+ monitor_ref = '_'},
+ case ets:match_object(megaco_remote_conn, Pat) of
+ [] ->
+ RCD = #remote_conn_data{conn_handle = ConnHandle,
+ user_node = UserNode,
+ monitor_ref = Ref},
+ ets:insert(megaco_remote_conn, RCD),
+ ok;
+ _ ->
+ {error, {already_connected, ConnHandle, UserNode}}
+ end.
+
+init_conn_data(RH, RemoteMid, SendHandle, ControlPid) ->
+ init_conn_data(RH, RemoteMid, SendHandle, ControlPid, auto).
+init_conn_data(RH, RemoteMid, SendHandle, ControlPid, Auto) ->
+ Mid = RH#megaco_receive_handle.local_mid,
+ ConnHandle = #megaco_conn_handle{local_mid = Mid,
+ remote_mid = RemoteMid},
+ EncodingMod = RH#megaco_receive_handle.encoding_mod,
+ EncodingConfig = RH#megaco_receive_handle.encoding_config,
+ SendMod = RH#megaco_receive_handle.send_mod,
+ MonitorRef =
+ case Auto of
+ auto ->
+ undefined_auto_monitor_ref;
+ {plain, ConnectorPid} ->
+ {connecting, ConnectorPid}
+ end,
+ #conn_data{conn_handle = ConnHandle,
+ serial = undefined_serial,
+ max_serial = user_info(Mid, max_trans_id),
+ request_timer = user_info(Mid, request_timer),
+ long_request_timer = user_info(Mid, long_request_timer),
+
+ auto_ack = user_info(Mid, auto_ack),
+ trans_ack = user_info(Mid, trans_req),
+ trans_req = user_info(Mid, trans_req),
+
+ trans_timer = user_info(Mid, trans_timer),
+ trans_req_maxsize = user_info(Mid, trans_req_maxsize),
+ trans_req_maxcount = user_info(Mid, trans_req_maxcount),
+ trans_ack_maxcount = user_info(Mid, trans_ack_maxcount),
+
+ pending_timer = user_info(Mid, pending_timer),
+ sent_pending_limit = user_info(Mid, sent_pending_limit),
+ recv_pending_limit = user_info(Mid, recv_pending_limit),
+ reply_timer = user_info(Mid, reply_timer),
+ control_pid = ControlPid,
+ monitor_ref = MonitorRef,
+ send_mod = SendMod,
+ send_handle = SendHandle,
+ encoding_mod = EncodingMod,
+ encoding_config = EncodingConfig,
+ protocol_version = user_info(Mid, protocol_version),
+ auth_data = user_info(Mid, auth_data),
+ user_mod = user_info(Mid, user_mod),
+ user_args = user_info(Mid, user_args),
+ reply_action = undefined,
+ reply_data = user_info(Mid, reply_data),
+ threaded = user_info(Mid, threaded),
+ strict_version = user_info(Mid, strict_version),
+ long_request_resend = user_info(Mid, long_request_resend),
+ call_proxy_gc_timeout = user_info(Mid, call_proxy_gc_timeout),
+ cancel = false,
+ resend_indication = user_info(Mid, resend_indication),
+ segment_reply_ind = user_info(Mid, segment_reply_ind),
+ segment_recv_acc = user_info(Mid, segment_recv_acc),
+ segment_recv_timer = user_info(Mid, segment_recv_timer),
+ segment_send = user_info(Mid, segment_send),
+ segment_send_timer = user_info(Mid, segment_send_timer),
+ max_pdu_size = user_info(Mid, max_pdu_size),
+ request_keep_alive_timeout = user_info(Mid, request_keep_alive_timeout)
+ }.
+
+handle_disconnect(ConnHandle) when is_record(ConnHandle, megaco_conn_handle) ->
+ case ets:lookup(megaco_local_conn, ConnHandle) of
+ [ConnData] ->
+ ets:delete(megaco_local_conn, ConnHandle),
+ RemoteConnData = handle_disconnect_remote(ConnHandle, '_'),
+ {ok, ConnData, RemoteConnData};
+ [] ->
+ {error, {already_disconnected, ConnHandle}}
+ end.
+
+handle_disconnect_remote(ConnHandle, UserNode) ->
+ Pat = #remote_conn_data{conn_handle = ConnHandle,
+ user_node = UserNode,
+ monitor_ref = '_'},
+ RemoteConnData = ets:match_object(megaco_remote_conn, Pat),
+ ets:match_delete(megaco_remote_conn, Pat),
+ RemoteConnData.
+
+make_receive_handle(UserMid) ->
+ #megaco_receive_handle{local_mid = UserMid,
+ encoding_mod = user_info(UserMid, encoding_mod),
+ encoding_config = user_info(UserMid, encoding_config),
+ send_mod = user_info(UserMid, send_mod)}.
+
+
+%%-----------------------------------------------------------------
+%% Func: create_snmp_counters/1, update_snmp_counters/2
+%% Description: create/update all the SNMP statistic counters
+%%-----------------------------------------------------------------
+
+create_snmp_counters(CH) ->
+ create_snmp_counters(CH, snmp_counters()).
+
+% create_snmp_counters(CH, []) ->
+% ok;
+% create_snmp_counters(CH, [Counter|Counters]) ->
+% Key = {CH, Counter},
+% ets:insert(megaco_stats, {Key, 0}),
+% create_snmp_counters(CH, Counters).
+
+create_snmp_counters(CH, Counters) ->
+ F = fun(Counter) ->
+ Key = {CH, Counter},
+ ets:insert(megaco_stats, {Key, 0})
+ end,
+ lists:foreach(F, Counters).
+
+
+update_snmp_counters(CH, PrelCH) ->
+ update_snmp_counters(CH, PrelCH, snmp_counters()).
+
+update_snmp_counters(_CH, _PrelCH, []) ->
+ ok;
+update_snmp_counters(CH, PrelCH, [Counter|Counters]) ->
+ PrelKey = {PrelCH, Counter},
+ Key = {CH, Counter},
+ [{PrelKey,PrelVal}] = ets:lookup(megaco_stats, PrelKey),
+ ets:update_counter(megaco_stats, Key, PrelVal),
+ ets:delete(megaco_stats, PrelKey),
+ update_snmp_counters(CH, PrelCH, Counters).
+
+
+global_snmp_counters() ->
+ [medGwyGatewayNumErrors].
+
+snmp_counters() ->
+ [medGwyGatewayNumTimerRecovery,
+ medGwyGatewayNumErrors].
+
+
+
+%%-----------------------------------------------------------------
+
+%% Time in milli seconds
+%% t() ->
+%% {A,B,C} = erlang:now(),
+%% A*1000000000+B*1000+(C div 1000).
+
+
+%%-----------------------------------------------------------------
+
+warning_msg(F, A) ->
+ ?megaco_warning("Config server: " ++ F, A).
+
+error_msg(F, A) ->
+ ?megaco_error("Config server: " ++ F, A).
+
diff --git a/lib/megaco/src/engine/megaco_digit_map.erl b/lib/megaco/src/engine/megaco_digit_map.erl
new file mode 100644
index 0000000000..de28686d6d
--- /dev/null
+++ b/lib/megaco/src/engine/megaco_digit_map.erl
@@ -0,0 +1,856 @@
+%%
+%% %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: Parse and evaluate digit maps
+%%----------------------------------------------------------------------
+%%
+%% digitMap = digitString
+%% / LWSP "(" LWSP digitStringList LWSP ")" LWSP
+%% digitStringList = digitString *( LWSP "|" LWSP digitString )
+%% digitString = 1*(digitStringElement)
+%% digitStringElement = digitPosition [DOT]
+%% digitPosition = digitMapLetter / digitMapRange
+%% digitMapRange = ("x" / LWSP "[" LWSP digitLetter LWSP "]" LWSP)
+%% digitLetter = *((DIGIT "-" DIGIT ) / digitMapLetter)
+%% digitMapLetter = DIGIT ; Basic event symbols
+%% / %x41-4B ; a-k
+%% / %x61-6B ; A-K
+%% / "T" ; Start inter-event timers
+%% / "S" ; Short inter-event timers
+%% / "L" ; Long inter-event timers, e.g. 16 sec
+%% / "Z" ; Long duration modifier
+%% DIGIT = %x30-39 ; 0-9
+%%
+%%----------------------------------------------------------------------
+%% Example of a digit map:
+%%
+%% (0| 00|[1-7]xxx|8xxxxxxx|Fxxxxxxx|Exx|91xxxxxxxxxx|9011x.)
+%%
+%% DM = "(0| 00|[1-7]xxx|8xxxxxxx|Fxxxxxxx|Exx|91xxxxxxxxxx|9011x.)".
+%% DM = "xxx | xxL3 | xxS4".
+%% megaco:parse_digit_map(DM).
+%% megaco:test_digit_event(DM, "1234").
+%% megaco:test_digit_event(DM, "12ssss3").
+%% megaco:test_digit_event(DM, "12ssss4").
+%% megaco:test_digit_event(DM, "12ssss5").
+%%
+%%----------------------------------------------------------------------
+
+-module(megaco_digit_map).
+
+-export([parse/1, eval/1, eval/2, report/2, test/2]). % Public
+-export([test_eval/2]). % Internal
+
+-include_lib("megaco/src/app/megaco_internal.hrl").
+-include("megaco_message_internal.hrl").
+-include_lib("megaco/src/text/megaco_text_tokens.hrl").
+
+-record(state_transition, {mode, next, cont}).
+
+-record(timers, {mode = state_dependent,
+ start = 0,
+ short = timer_to_millis(3),
+ long = timer_to_millis(9),
+ duration = 100, % (not used) 100 ms <-> 9.9 sec
+ unexpected = reject}). % ignore | reject
+
+
+%%----------------------------------------------------------------------
+%% Parses a digit map body, represented as a list of chars,
+%% into a list of state transitions.
+%%
+%% Returns {ok, StateTransitionList} | {error, Reason}
+%%
+%%----------------------------------------------------------------------
+
+parse(DigitMapBody) when is_list(DigitMapBody) ->
+ ?d("parse -> entry with"
+ "~n DigitMapBody: ~p", [DigitMapBody]),
+ case parse_digit_map(DigitMapBody) of
+ {ok, STL} ->
+ {ok, duration_cleanup(STL, [])};
+ {error, Reason} ->
+ {error, Reason}
+ end;
+parse(_DigitMapBody) ->
+ {error, not_a_digit_map_body}.
+
+duration_cleanup([], Acc) ->
+ Acc;
+duration_cleanup([STL|T], Acc) ->
+ #state_transition{cont = Events} = STL,
+ Events2 = duration_events_cleanup(Events, []),
+ duration_cleanup(T, [STL#state_transition{cont = Events2}|Acc]).
+
+duration_events_cleanup([], Acc) ->
+ lists:reverse(Acc);
+duration_events_cleanup([duration_event, Event|Events], Acc) ->
+ duration_events_cleanup(Events, [{duration_event, Event}|Acc]);
+duration_events_cleanup([Event|Events], Acc) ->
+ duration_events_cleanup(Events, [Event|Acc]).
+
+parse_digit_map(Chars) ->
+ parse_digit_map(Chars, 1, [], []).
+
+parse_digit_map(Chars, Line, DS, STL) ->
+ ?d("parse_digit_map -> entry with"
+ "~n Chars: ~p"
+ "~n DS: ~p", [Chars, DS]),
+ case megaco_text_scanner:skip_sep_chars(Chars, Line) of
+ {[], _Line2} when (DS =/= []) ->
+ case parse_digit_string(DS) of
+ {ok, DS2} ->
+ ST = #state_transition{mode = state_dependent,
+ next = start,
+ cont = DS2},
+ STL2 = lists:reverse([ST | STL]),
+ {ok, STL2};
+ {error, Reason} ->
+ {error, Reason}
+ end;
+ {[Char | Chars2], Line2} ->
+ case Char of
+ $( when (DS =:= []) andalso (STL =:= []) ->
+ parse_digit_map(Chars2, Line2, DS, STL);
+ $) when (DS =/= []) ->
+ case megaco_text_scanner:skip_sep_chars(Chars2, Line2) of
+ {[], _Line3} ->
+ case parse_digit_string(DS) of
+ {ok, DS2} ->
+ ST = #state_transition{mode = state_dependent,
+ next = start,
+ cont = DS2},
+ STL2 = lists:reverse([ST | STL]),
+ {ok, STL2};
+ {error, Reason} ->
+ {error, Reason}
+ end;
+ {Chars3, Line3} ->
+ Trash = lists:reverse(Chars3),
+ {error, {round_bracket_mismatch, Trash, Line3}}
+ end;
+ $| when (DS =/= []) ->
+ case parse_digit_string(DS) of
+ {ok, DS2} ->
+ ST = #state_transition{mode = state_dependent,
+ next = start,
+ cont = DS2},
+ parse_digit_map(Chars2, Line2, [], [ST | STL]);
+ {error, Reason} ->
+ {error, Reason}
+ end;
+ _ when ( Char =/= $( ) andalso
+ ( Char =/= $| ) andalso
+ ( Char =/= $) ) ->
+ parse_digit_map(Chars2, Line2, [Char | DS], STL);
+ _ ->
+ {error, {round_bracket_mismatch, Line2}}
+ end;
+ {[], Line2} ->
+ {error, {digit_string_expected, Line2}}
+ end.
+
+parse_digit_string(Chars) ->
+ ?d("parse_digit_string -> entry with"
+ "~n Chars: ~p", [Chars]),
+ parse_digit_string(Chars, []).
+
+parse_digit_string([Char | Chars], DS) ->
+ ?d("parse_digit_string -> entry with"
+ "~n Char: ~p"
+ "~n Chars: ~p"
+ "~n DS: ~p", [[Char], Chars, DS]),
+ case Char of
+ $] ->
+ parse_digit_letter(Chars, [], DS);
+ $[ ->
+ {error, square_bracket_mismatch};
+ $x ->
+ parse_digit_string(Chars, [{range, $0, $9} | DS]);
+ $. ->
+ parse_digit_string(Chars, [zero_or_more | DS]);
+
+ I when (I >= $0) andalso (I =< $9) ->
+ parse_digit_string(Chars, [{single, I} | DS]);
+
+ A when (A >= $a) andalso (A =< $k) ->
+ parse_digit_string(Chars, [{single, A} | DS]);
+ A when (A >= $A) andalso (A =< $K) ->
+ parse_digit_string(Chars, [{single, A} | DS]);
+
+ $S ->
+ parse_digit_string(Chars, [use_short_timer | DS]);
+ $s ->
+ parse_digit_string(Chars, [use_short_timer | DS]);
+
+ $L ->
+ parse_digit_string(Chars, [use_long_timer | DS]);
+ $l ->
+ parse_digit_string(Chars, [use_long_timer | DS]);
+
+ $Z when length(Chars) > 0 ->
+ parse_digit_string(Chars, [duration_event | DS]);
+ $z when length(Chars) > 0 ->
+ parse_digit_string(Chars, [duration_event | DS]);
+
+ $Z ->
+ {error, duration_not_allowed_as_last_char};
+ $z ->
+ {error, duration_not_allowed_as_last_char};
+
+ BadChar ->
+ {error, {illegal_char_in_digit_string, BadChar}}
+ end;
+parse_digit_string([], DM) ->
+ ?d("parse_digit_string -> entry when done with"
+ "~n DM: ~p", [DM]),
+ {ok, DM}.
+
+
+parse_digit_letter([Char | Chars], DL, DS) ->
+ ?d("parse_digit_letter -> entry with"
+ "~n Char: ~p"
+ "~n Chars: ~p"
+ "~n DL: ~p"
+ "~n DS: ~p", [[Char], Chars, DL, DS]),
+ case Char of
+ $[ ->
+ parse_digit_string(Chars, [{letter, DL} | DS]);
+ $] ->
+ {error, square_bracket_mismatch};
+ To when (To >= $0) andalso (To =< $9) ->
+ case Chars of
+ [$-, From | Chars2] when (From >= $0) andalso (From =< $9) ->
+ parse_digit_letter(Chars2, [{range, From, To} | DL], DS);
+ _ ->
+ parse_digit_letter(Chars, [{single, To} | DL], DS)
+ end;
+
+ A when (A >= $a) andalso (A =< $k) ->
+ parse_digit_letter(Chars, [{single, A} | DL], DS);
+ A when (A >= $A) andalso (A =< $K) ->
+ parse_digit_letter(Chars, [{single, A} | DL], DS);
+
+ $S ->
+ parse_digit_letter(Chars, [use_short_timer | DL], DS);
+ $s ->
+ parse_digit_letter(Chars, [use_short_timer | DL], DS);
+
+ $L ->
+ parse_digit_letter(Chars, [use_long_timer | DL], DS);
+ $l ->
+ parse_digit_letter(Chars, [use_long_timer | DL], DS);
+
+ $Z ->
+ parse_digit_letter(Chars, [duration_event | DL], DS);
+ $z ->
+ parse_digit_letter(Chars, [duration_event | DL], DS);
+
+ BadChar ->
+ {error, {illegal_char_between_square_brackets, BadChar}}
+ end;
+parse_digit_letter([], _DL, _DS) ->
+ {error, square_bracket_mismatch}.
+
+
+%%----------------------------------------------------------------------
+%% Collect digit map letters according to digit map
+%% Returns {ok, Letters} | {error, Reason}
+%%----------------------------------------------------------------------
+
+eval(DMV) when is_record(DMV, 'DigitMapValue') ->
+ case parse(DMV#'DigitMapValue'.digitMapBody) of
+ {ok, DigitMapBody} ->
+ eval(DigitMapBody, DMV);
+ {error, Reason} ->
+ {error, Reason}
+ end;
+eval(STL) when is_list(STL) ->
+ eval(STL, #timers{}).
+
+eval(STL, #'DigitMapValue'{startTimer = Start,
+ shortTimer = Short,
+ longTimer = Long,
+ durationTimer = Duration}) ->
+ Timers = #timers{start = timer_to_millis(Start),
+ short = timer_to_millis(Short),
+ long = timer_to_millis(Long),
+ duration = duration_to_millis(Duration)},
+ eval(STL, Timers);
+eval(STL, {ignore, #'DigitMapValue'{startTimer = Start,
+ shortTimer = Short,
+ longTimer = Long,
+ durationTimer = Duration}}) ->
+ Timers = #timers{start = timer_to_millis(Start),
+ short = timer_to_millis(Short),
+ long = timer_to_millis(Long),
+ duration = duration_to_millis(Duration),
+ unexpected = ignore},
+ eval(STL, Timers);
+eval(STL, {reject, #'DigitMapValue'{startTimer = Start,
+ shortTimer = Short,
+ longTimer = Long,
+ durationTimer = Duration}}) ->
+ Timers = #timers{start = timer_to_millis(Start),
+ short = timer_to_millis(Short),
+ long = timer_to_millis(Long),
+ duration = duration_to_millis(Duration),
+ unexpected = reject},
+ eval(STL, Timers);
+eval(STL, Timers) when is_list(STL) andalso
+ is_record(hd(STL), state_transition) andalso
+ is_record(Timers, timers) ->
+ ?d("eval -> entry with"
+ "~n STL: ~p"
+ "~n Timers: ~p", [STL, Timers]),
+ case collect(start, mandatory_event, Timers, lists:reverse(STL), []) of
+ {error, _} = Error ->
+ ?d("eval -> error:"
+ "~n Error: ~p", [Error]),
+ Error;
+ OK ->
+ ?d("eval -> ok:"
+ "~n OK: ~p", [OK]),
+ OK
+ end;
+eval(DigitMapBody, ignore) ->
+ eval(DigitMapBody, #timers{unexpected = ignore});
+eval(DigitMapBody, reject) ->
+ eval(DigitMapBody, #timers{unexpected = reject});
+eval(DigitMapBody, Timers) ->
+ case parse(DigitMapBody) of
+ {ok, STL} ->
+ eval(STL, Timers);
+ {error, Reason} ->
+ {error, Reason}
+ end.
+
+%% full | unambiguous
+
+collect(Event, State, Timers, STL, Letters) ->
+ ?d("collect -> entry with"
+ "~n Event: ~p"
+ "~n State: ~p"
+ "~n Timers: ~p"
+ "~n STL: ~p", [Event, State, Timers, STL]),
+ case handle_event(Event, State, Timers, STL, Letters) of
+ {completed_full, _Timers2, _STL2, Letters2} ->
+ completed(full, Letters2);
+ {completed, _Timers2, _STL2, Letters2} ->
+ completed(unambiguous, Letters2);
+ {State2, Timers2, STL2, Letters2} ->
+ ?d("collect -> "
+ "~n State2: ~p"
+ "~n Timers2: ~p"
+ "~n Letters2: ~p", [State2, Timers2, Letters2]),
+ MaxWait = choose_timer(State2, Event, Timers2),
+ ?d("collect -> Timer choosen: "
+ "~n MaxWait: ~p", [MaxWait]),
+ receive
+ {?MODULE, _FromPid, Event2} ->
+ ?d("collect -> Got event: "
+ "~n ~p", [Event2]),
+ collect(Event2, State2, Timers2, STL2, Letters2)
+ after MaxWait ->
+ ?d("collect -> timeout after ~w", [MaxWait]),
+ collect(inter_event_timeout,
+ State2, Timers2, STL2, Letters2)
+ end;
+
+ {error, Reason} ->
+ ?d("collect -> error: "
+ "~n Reason: ~p", [Reason]),
+ {error, Reason}
+ end.
+
+choose_timer(_State, start, #timers{start = 0}) ->
+ ?d("choose_timer(start) -> entry", []),
+ infinity;
+choose_timer(_State, start, #timers{start = T}) ->
+ ?d("choose_timer(start) -> entry with"
+ "~n T: ~p", [T]),
+ T;
+choose_timer(State, _Event, T) ->
+ ?d("choose_timer(~p) -> entry with"
+ "~n State: ~p"
+ "~n T: ~p", [_Event, State, T]),
+ do_choose_timer(State, T).
+
+do_choose_timer(mandatory_event, #timers{mode = state_dependent, long = T}) ->
+ T;
+do_choose_timer(optional_event, #timers{mode = state_dependent, short = T}) ->
+ T;
+do_choose_timer(_State, #timers{mode = use_short_timer, short = T}) ->
+ T;
+do_choose_timer(_State, #timers{mode = use_long_timer, long = T}) ->
+ T.
+
+timer_to_millis(asn1_NOVALUE) -> infinity;
+timer_to_millis(infinity) -> infinity;
+timer_to_millis(Seconds) -> timer:seconds(Seconds).
+
+%% Time for duration is in hundreds of milliseconds
+duration_to_millis(asn1_NOVALUE) -> 100;
+duration_to_millis(Time) when is_integer(Time) -> Time*100.
+
+completed(Kind, {Letters, Event}) when is_list(Letters) ->
+ ?d("completed -> entry with"
+ "~n Kind: ~p"
+ "~n Event: ~s", [Kind, [Event]]),
+ {ok, {Kind, duration_letter_cleanup(Letters, []), Event}};
+completed(Kind, Letters) when is_list(Letters) ->
+ ?d("completed -> entry with"
+ "~n Kind: ~p", [Kind]),
+ {ok, {Kind, duration_letter_cleanup(Letters, [])}}.
+
+duration_letter_cleanup([], Acc) ->
+ Acc;
+duration_letter_cleanup([{long, Letter}|Letters], Acc) ->
+ duration_letter_cleanup(Letters, [$Z,Letter|Acc]);
+duration_letter_cleanup([Letter|Letters], Acc) ->
+ duration_letter_cleanup(Letters, [Letter|Acc]).
+
+unexpected_event(Event, STL, Letters) ->
+ Expected = [Next || #state_transition{next = Next} <- STL],
+ SoFar = lists:reverse(Letters),
+ Reason = {unexpected_event, Event, SoFar, Expected},
+ {error, Reason}.
+
+
+%%----------------------------------------------------------------------
+%% Handles a received event according to digit map
+%% State ::= optional_event | mandatory_event
+%%
+%% Returns {State, NewSTL, Letters} | {error, Reason}
+%%----------------------------------------------------------------------
+handle_event(inter_event_timeout, optional_event, Timers, STL, Letters) ->
+ {completed_full, Timers, STL, Letters}; % 7.1.14.5 2
+handle_event(cancel, _State, _Timers, STL, Letters) ->
+ unexpected_event(cancel, STL, Letters);
+handle_event(start, _State, Timers, STL, Letters) ->
+ {State2, Timers2, STL2} = compute(Timers, STL),
+ {State2, Timers2, STL2, Letters};
+handle_event(Event, State, Timers, STL, Letters) ->
+ ?d("handle_event -> entry when"
+ "~n Event: ~p"
+ "~n State: ~p"
+ "~n Timers: ~p"
+ "~n Letters: ~p", [Event, State, Timers, Letters]),
+ {STL2, Collect, KeepDur} = match_event(Event, STL),
+ ?d("handle_event -> match event result: "
+ "~n Collect: ~p"
+ "~n KeepDur: ~p"
+ "~n STL2: ~p", [Collect, KeepDur, STL2]),
+ case STL2 of
+ [] when (State =:= optional_event) -> % 7.1.14.5 5
+ ?d("handle_event -> complete-full with event - 7.1.14.5 5", []),
+ {completed_full, Timers, [], {Letters, Event}};
+ [] when (Timers#timers.unexpected =:= ignore) ->
+ ok = io:format("<WARNING> Ignoring unexpected event: ~p~n"
+ "Expected: ~p~n",
+ [Event, STL]),
+ {State, Timers, STL, Letters};
+ [] when (Timers#timers.unexpected =:= reject) ->
+ ?d("handle_event -> unexpected (reject)", []),
+ unexpected_event(Event, STL, Letters);
+ _ ->
+ {State3, Timers2, STL3} = compute(Timers, STL2),
+ ?d("handle_event -> computed: "
+ "~n State3: ~p"
+ "~n Timers2: ~p"
+ "~n STL3: ~p", [State3, Timers2, STL3]),
+ case Collect of
+ true when (KeepDur =:= true) ->
+ {State3, Timers2, STL3, [Event | Letters]};
+ true ->
+ case Event of
+ {long, ActualEvent} ->
+ {State3, Timers2, STL3, [ActualEvent | Letters]};
+ _ ->
+ {State3, Timers2, STL3, [Event | Letters]}
+ end;
+ false ->
+ {State3, Timers2, STL3, Letters}
+ end
+ end.
+
+match_event(Event, STL) ->
+ MatchingDuration = matching_duration_event(Event, STL),
+ match_event(Event, STL, [], false, false, MatchingDuration).
+
+match_event(Event, [ST | OldSTL], NewSTL, Collect, KeepDur, MatchingDuration)
+ when is_record(ST, state_transition) ->
+ ?d("match_event -> entry with"
+ "~n Event: ~p"
+ "~n ST: ~p"
+ "~n NewSTL: ~p"
+ "~n Collect: ~p"
+ "~n KeepDur: ~p"
+ "~n MatchingDuration: ~p",
+ [Event, ST, NewSTL, Collect, KeepDur, MatchingDuration]),
+ case ST#state_transition.next of
+ {single, Event} ->
+ ?d("match_event -> keep ST (1)", []),
+ match_event(Event, OldSTL, [ST | NewSTL], true, KeepDur,
+ MatchingDuration);
+
+ {single, Single} when (Event =:= {long, Single}) andalso
+ (MatchingDuration =:= false) ->
+ %% Chap 7.1.14.5 point 4
+ ?d("match_event -> keep ST - change to ordinary event (2)", []),
+ match_event(Event, OldSTL, [ST | NewSTL], true, KeepDur,
+ MatchingDuration);
+
+ {range, From, To} when (Event >= From) andalso (Event =< To) ->
+ ?d("match_event -> keep ST (3)", []),
+ ST2 = ST#state_transition{next = {single, Event}},
+ match_event(Event, OldSTL, [ST2 | NewSTL], true, KeepDur,
+ MatchingDuration);
+
+ {range, From, To} ->
+ case Event of
+ {long, R} when (R >= From) andalso
+ (R =< To) andalso
+ (MatchingDuration =:= false) ->
+ ?d("match_event -> keep ST (4)", []),
+ ST2 = ST#state_transition{next = {single, R}},
+ match_event(Event, OldSTL, [ST2 | NewSTL], true, true,
+ MatchingDuration);
+ _ ->
+ ?d("match_event -> drop ST - "
+ "change to ordinary event (5)", []),
+ match_event(Event, OldSTL, NewSTL, Collect, KeepDur,
+ MatchingDuration)
+ end;
+
+ {duration_event, {single, Single}} when (Event =:= {long, Single}) ->
+ ?d("match_event -> keep ST (5)", []),
+ match_event(Event, OldSTL, [ST | NewSTL], true, true,
+ MatchingDuration);
+
+ {duration_event, {range, From, To}} ->
+ case Event of
+ {long, R} when (R >= From) andalso (R =< To) ->
+ ?d("match_event -> keep ST (6)", []),
+ match_event(Event, OldSTL, [ST | NewSTL], true, true,
+ MatchingDuration);
+ _ ->
+ ?d("match_event -> drop ST (7)", []),
+ match_event(Event, OldSTL, NewSTL, Collect, KeepDur,
+ MatchingDuration)
+ end;
+
+ Event ->
+ ?d("match_event -> keep ST (8)", []),
+ match_event(Event, OldSTL, [ST | NewSTL], Collect, KeepDur,
+ MatchingDuration);
+
+ {letter, Letters} ->
+ case match_letter(Event, Letters, MatchingDuration) of
+ {true, ChangedEvent} ->
+ ?d("match_event -> keep ST (9)", []),
+ ST2 = ST#state_transition{next = ChangedEvent},
+ match_event(Event, OldSTL, [ST2 | NewSTL], true, KeepDur,
+ MatchingDuration);
+ true ->
+ ?d("match_event -> keep ST (10)", []),
+ match_event(Event, OldSTL, [ST | NewSTL], true, KeepDur,
+ MatchingDuration);
+ false ->
+ ?d("match_event -> drop ST (11)", []),
+ match_event(Event, OldSTL, NewSTL, Collect, KeepDur,
+ MatchingDuration)
+ end;
+
+ _ ->
+ ?d("match_event -> drop ST (12)", []),
+ match_event(Event, OldSTL, NewSTL, Collect, KeepDur,
+ MatchingDuration)
+ end;
+match_event(Event, [H | T], NewSTL, Collect, KeepDur0, MatchingDuration)
+ when is_list(H) ->
+ ?d("match_event -> entry with"
+ "~n Event: ~p"
+ "~n H: ~p"
+ "~n NewSTL: ~p"
+ "~n Collect: ~p"
+ "~n KeepDur0: ~p"
+ "~n MatchingDuration: ~p",
+ [Event, H, NewSTL, Collect, KeepDur0, MatchingDuration]),
+ {NewSTL2, _Letters, KeepDur} =
+ match_event(Event, H, NewSTL, Collect, KeepDur0, MatchingDuration),
+ ?d("match_event -> "
+ "~n NewSTLs: ~p", [NewSTL2]),
+ match_event(Event, T, NewSTL2, Collect, KeepDur,
+ MatchingDuration);
+match_event(_Event, [], NewSTL, Collect, KeepDur, _MatchingDuration) ->
+ ?d("match_event -> entry with"
+ "~n NewSTL: ~p"
+ "~n Collect: ~p"
+ "~n KeepDur: ~p", [NewSTL, Collect, KeepDur]),
+ {lists:reverse(NewSTL), Collect, KeepDur}.
+
+
+match_letter(_Event, [], _MatchingDuration) ->
+ false;
+match_letter(Event, [Letter | Letters], MatchingDuration) ->
+ ?d("match_letter -> entry with"
+ "~n Event: ~p"
+ "~n Letter: ~p",
+ [Event, Letter]),
+ case Letter of
+ {single, Event} ->
+ ?d("match_letter -> keep ST (1)", []),
+ true;
+
+ {single, Single} when (Event =:= {long, Single}) andalso
+ (MatchingDuration =:= false) ->
+ %% Chap 7.1.14.5 point 4
+ ?d("match_letter -> keep ST - change to ordinary event (2)", []),
+ true;
+
+ {range, From, To} when (Event >= From) andalso (Event =< To) ->
+ ?d("match_letter -> keep ST (3)", []),
+ {true, {single, Event}};
+
+ {range, From, To} ->
+ case Event of
+ {long, R} when (R >= From) andalso
+ (R =< To) andalso
+ (MatchingDuration =:= false) ->
+ ?d("match_letter -> keep ST (4)", []),
+ {true, {single, R}};
+ _ ->
+ ?d("match_letter -> drop ST - "
+ "change to ordinary event (5)", []),
+ match_letter(Event, Letters, MatchingDuration)
+ end;
+
+ {duration_event, {single, Single}} when (Event =:= {long, Single}) ->
+ ?d("match_letter -> keep ST (5)", []),
+ true;
+
+ {duration_event, {range, From, To}} ->
+ case Event of
+ {long, R} when (R >= From) andalso (R =< To) ->
+ ?d("match_letter -> keep ST (6)", []),
+ true;
+ _ ->
+ ?d("match_letter -> drop ST (7)", []),
+ match_letter(Event, Letters, MatchingDuration)
+ end;
+
+ _ ->
+ ?d("match_letter -> drop ST (8)", []),
+ match_letter(Event, Letters, MatchingDuration)
+
+ end.
+
+
+
+
+matching_duration_event({long, Event}, STL) ->
+ Nexts = [Next || #state_transition{next = Next} <- STL],
+ mde(Event, Nexts);
+matching_duration_event(_Event, _STL) ->
+ false.
+
+
+mde(_, []) ->
+ false;
+mde(Event, [{duration_event, {single, Event}}|_]) ->
+ true;
+mde(Event, [{duration_event, {range, From, To}}|_])
+ when Event >= From, Event =< To ->
+ true;
+mde(Event, [_|Nexts]) ->
+ mde(Event, Nexts).
+
+
+%%----------------------------------------------------------------------
+%% Compute new state transitions
+%% Returns {State, Timers, NewSTL}
+%%----------------------------------------------------------------------
+compute(Timers, OldSTL) ->
+ ?d("compute -> entry with"
+ "~n Timers: ~p"
+ "~n OldSTL: ~p", [Timers, OldSTL]),
+ {State, GlobalMode, NewSTL} =
+ compute(mandatory_event, state_dependent, OldSTL, []),
+ ?d("compute -> "
+ "~n State: ~p"
+ "~n GlobalMode: ~p"
+ "~n NewSTL: ~p", [State, GlobalMode, NewSTL]),
+ Timers2 = Timers#timers{mode = GlobalMode},
+ ?d("compute -> "
+ "~n Timers2: ~p", [Timers2]),
+ {State, Timers2, NewSTL}.
+
+compute(State, GlobalMode, [ST | OldSTL], NewSTL)
+ when is_record(ST, state_transition) ->
+ ?d("compute(~w) -> entry with"
+ "~n GlobalMode: ~p"
+ "~n ST: ~p"
+ "~n NewSTL: ~p", [State, GlobalMode, ST, NewSTL]),
+ Cont = ST#state_transition.cont,
+ Mode = ST#state_transition.mode,
+ {State2, GlobalMode2, NewSTL2} =
+ compute_cont(Cont, Mode, GlobalMode, State, NewSTL),
+ compute(State2, GlobalMode2, OldSTL, NewSTL2);
+compute(State, GlobalMode, [H | T], NewSTL) when is_list(H) ->
+ ?d("compute(~w) -> entry with"
+ "~n GlobalMode: ~p"
+ "~n H: ~p"
+ "~n NewSTL: ~p", [State, GlobalMode, H, NewSTL]),
+ {State2, GlobalMode2, NewSTL2} = compute(State, GlobalMode, H, NewSTL),
+ compute(State2, GlobalMode2, T, NewSTL2);
+compute(State, GlobalMode, [], NewSTL) ->
+ ?d("compute(~w) -> entry with"
+ "~n GlobalMode: ~p"
+ "~n NewSTL: ~p", [State, GlobalMode, NewSTL]),
+ case NewSTL of
+ [] -> {completed, GlobalMode, NewSTL};
+ _ -> {State, GlobalMode, NewSTL}
+ end.
+
+compute_cont([Next | Cont] = All, Mode, GlobalMode, State, STL) ->
+ ?d("compute_cont -> entry with"
+ "~n Next: ~p"
+ "~n Mode: ~p"
+ "~n GlobalMode: ~p", [Next, Mode, GlobalMode]),
+ case Next of
+ %% Retain long timer if that has already been choosen
+ use_short_timer when GlobalMode =:= use_long_timer ->
+ compute_cont(Cont, Mode, GlobalMode, State, STL);
+ use_short_timer ->
+ Mode2 = use_short_timer,
+ compute_cont(Cont, Mode2, GlobalMode, State, STL);
+ use_long_timer ->
+ Mode2 = use_long_timer,
+ compute_cont(Cont, Mode2, GlobalMode, State, STL);
+ [] ->
+ %% Skip empty list
+ case Cont of
+ [zero_or_more | Cont2] ->
+ compute_cont(Cont2, Mode, GlobalMode, State, STL);
+ _ ->
+ compute_cont(Cont, Mode, GlobalMode, State, STL)
+ end;
+ _ ->
+ GlobalMode2 =
+ case Mode of
+ state_dependent -> GlobalMode;
+ _ -> Mode
+ end,
+ case Cont of
+ [zero_or_more | Cont2] ->
+ ST = make_cont(Mode, Next, All),
+ compute_cont(Cont2, Mode, GlobalMode2, State, [ST | STL]);
+ _ ->
+ ST = make_cont(Mode, Next, Cont),
+ {State, GlobalMode2, [ST | STL]}
+ end
+ end;
+compute_cont([], GlobalMode, _Mode, _State, STL) ->
+ {optional_event, GlobalMode, STL}.
+
+make_cont(Mode, [Next | Cont2], Cont) ->
+ #state_transition{mode = Mode, next = Next, cont = [Cont2 | Cont]};
+make_cont(Mode, Next, Cont) ->
+ #state_transition{mode = Mode, next = Next, cont = Cont}.
+
+
+%%----------------------------------------------------------------------
+%% Send one or more events to event collector process
+%%
+%% Events ::= Event* | Event
+%% Event ::= $0-$9 | $a-$k | $A-$K | $S | $L | $Z
+%% $S means sleep one second
+%% $L means sleep ten seconds
+%% $Z means cancel
+%% Returns ok | {error, Reason}
+%%----------------------------------------------------------------------
+
+report(Pid, [H | T])->
+ case report(Pid, H) of
+ ok ->
+ report(Pid, T);
+ {error, Reason} ->
+ {error, Reason}
+ end;
+report(_Pid, [])->
+ ok;
+report(Pid, Event) when is_pid(Pid) ->
+ case Event of
+ I when I >= $0, I =< $9 -> cast(Pid, Event);
+ A when A >= $a, A =< $k -> cast(Pid, Event);
+ A when A >= $A, A =< $K -> cast(Pid, Event);
+ cancel -> cast(Pid, Event);
+ $Z -> cast(Pid, cancel);
+ $z -> cast(Pid, cancel);
+ $R -> timer:sleep(100); % 100 ms
+ $r -> timer:sleep(100); % 100 ms
+ $S -> sleep(1); % 1 sec (1000 ms)
+ $s -> sleep(1); % 1 sec (1000 ms)
+ $L -> sleep(10); % 10 sec (10000 ms)
+ $l -> sleep(10); % 10 sec (10000 ms)
+ {long, I} when (I >= $0) and (I =< $9) -> cast(Pid, {long, I});
+ {long, A} when (A >= $a) and (A =< $k) -> cast(Pid, {long, A});
+ {long, A} when (A >= $A) and (A =< $K) -> cast(Pid, {long, A});
+%% {long, I} when (I >= $0) and (I =< $9) -> long(Pid, I);
+%% {long, A} when (A >= $a) and (A =< $k) -> long(Pid, A);
+%% {long, A} when (A >= $A) and (A =< $K) -> long(Pid, A);
+ _ -> {error, {illegal_event, Event}}
+ end.
+
+%% long(Pid, Event) ->
+%% cast(Pid, long),
+%% cast(Pid, Event).
+%%
+sleep(Sec) ->
+ timer:sleep(timer:seconds(Sec)),
+ ok.
+
+cast(Pid, Event) ->
+ Pid ! {?MODULE, self(), Event},
+ ok.
+
+%%----------------------------------------------------------------------
+%% Feed digit map collector with events
+%% Returns: {ok, Letters} | {error, Reason}
+%%----------------------------------------------------------------------
+
+test(DigitMap, Events) ->
+ Self = self(),
+ Pid = spawn_link(?MODULE, test_eval, [DigitMap, Self]),
+ report(Pid, Events),
+ receive
+ {Self, Pid, Res} ->
+ Res;
+ {'EXIT', Pid, Reason} ->
+ {error, {'EXIT', Reason}}
+ end.
+
+test_eval(DigitMap, Parent) ->
+ Res = eval(DigitMap),
+ unlink(Parent),
+ Parent ! {Parent, self(), Res},
+ exit(normal).
diff --git a/lib/megaco/src/engine/megaco_edist_compress.erl b/lib/megaco/src/engine/megaco_edist_compress.erl
new file mode 100644
index 0000000000..544e3b8ff0
--- /dev/null
+++ b/lib/megaco/src/engine/megaco_edist_compress.erl
@@ -0,0 +1,33 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2007-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: Megaco erlang dist compress behaviour module
+%%----------------------------------------------------------------------
+
+-module(megaco_edist_compress).
+
+-export([behaviour_info/1]).
+
+behaviour_info(callbacks) ->
+ [{encode,2},
+ {decode,2}];
+behaviour_info(_) ->
+ undefined.
diff --git a/lib/megaco/src/engine/megaco_encoder.erl b/lib/megaco/src/engine/megaco_encoder.erl
new file mode 100644
index 0000000000..a07ee1a6bc
--- /dev/null
+++ b/lib/megaco/src/engine/megaco_encoder.erl
@@ -0,0 +1,37 @@
+%%
+%% %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: Megaco encoder behaviour module
+%%----------------------------------------------------------------------
+
+-module(megaco_encoder).
+
+-export([behaviour_info/1]).
+
+behaviour_info(callbacks) ->
+ [{encode_message, 3},
+ {decode_message, 3},
+ {decode_mini_message, 3},
+ {encode_transaction, 3},
+ {encode_action_requests, 3},
+ {encode_action_reply, 3}];
+behaviour_info(_) ->
+ undefined.
diff --git a/lib/megaco/src/engine/megaco_erl_dist_encoder.erl b/lib/megaco/src/engine/megaco_erl_dist_encoder.erl
new file mode 100644
index 0000000000..e8ade615df
--- /dev/null
+++ b/lib/megaco/src/engine/megaco_erl_dist_encoder.erl
@@ -0,0 +1,275 @@
+%%
+%% %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: Externalize/internalize Megaco/H.248 messages
+%%----------------------------------------------------------------------
+
+-module(megaco_erl_dist_encoder).
+
+-behaviour(megaco_encoder).
+
+-export([encode_message/3, decode_message/3,
+ decode_mini_message/3,
+
+ encode_transaction/3,
+ encode_action_requests/3,
+ encode_action_request/3,
+ encode_command_request/3,
+ encode_action_reply/3
+ ]).
+-export([version_of/2]).
+
+%% Backward compatible funcs:
+-export([encode_message/2, decode_message/2]).
+
+
+-include("megaco_message_internal.hrl").
+
+-define(MC_MOD, megaco_erl_dist_encoder_mc).
+
+
+%%----------------------------------------------------------------------
+%% Convert a 'MegacoMessage' record into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+
+encode_message(Config,
+ #'MegacoMessage'{mess = #'Message'{version = V}} = MegaMsg) ->
+ encode_message(Config, V, MegaMsg).
+
+encode_message([{version3, _}|EC], Vsn, MegaMsg) ->
+ encode_message(EC, Vsn, MegaMsg);
+encode_message([megaco_compressed|Config], Vsn, MegaMsg)
+ when is_record(MegaMsg, 'MegacoMessage') ->
+ {ok, erlang:term_to_binary(?MC_MOD:encode(MegaMsg, Vsn), Config)};
+encode_message([{megaco_compressed, Mod}|Config], Vsn, MegaMsg)
+ when is_atom(Mod) and is_record(MegaMsg, 'MegacoMessage') ->
+ {ok, erlang:term_to_binary(Mod:encode(MegaMsg, Vsn), Config)};
+encode_message(Config, _Vsn, MegaMsg)
+ when is_record(MegaMsg, 'MegacoMessage') ->
+ {ok, erlang:term_to_binary(MegaMsg, Config)};
+encode_message(_Config, _Vsn, _MegaMsg) ->
+ {error, not_a_megaco_message}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a transaction record into a binary
+%% Return {ok, Bin} | {error, Reason}
+%%----------------------------------------------------------------------
+
+encode_transaction([{version3, _}|EC], Vsn, Trans) ->
+ encode_transaction(EC, Vsn, Trans);
+encode_transaction([megaco_compressed|Config], _Vsn, Trans) ->
+ {ok, erlang:term_to_binary(?MC_MOD:encode(Trans), Config)};
+encode_transaction([{megaco_compressed, Mod}|Config], _Vsn, Trans) ->
+ {ok, erlang:term_to_binary(Mod:encode(Trans), Config)};
+encode_transaction(Config, _Vsn, Trans) ->
+ {ok, erlang:term_to_binary(Trans, Config)}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a list of ActionRequest record's into a binary
+%% Return {ok, Binary} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_requests([{version3, _}|EC], Vsn, ActReqs) ->
+ encode_action_requests(EC, Vsn, ActReqs);
+encode_action_requests([megaco_compressed|Config], Vsn, ActReqs0)
+ when is_list(ActReqs0) ->
+ ActReqs = [?MC_MOD:encode(AR, Vsn) || AR <- ActReqs0],
+ {ok, erlang:term_to_binary(ActReqs, Config)};
+encode_action_requests([{megaco_compressed, Mod}|Config], Vsn, ActReqs0)
+ when is_list(ActReqs0) ->
+ ActReqs = [Mod:encode(AR, Vsn) || AR <- ActReqs0],
+ {ok, erlang:term_to_binary(ActReqs, Config)};
+encode_action_requests(Config, _Vsn, ActReqs)
+ when is_list(ActReqs) ->
+ {ok, erlang:term_to_binary(ActReqs, Config)}.
+
+
+
+%%----------------------------------------------------------------------
+%% Convert a ActionRequest record into a binary
+%% Return {ok, Binary} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_request([{version3, _}|EC], Vsn, ActReq) ->
+ encode_action_request(EC, Vsn, ActReq);
+encode_action_request([megaco_compressed|Config], Vsn, ActReq)
+ when is_tuple(ActReq) ->
+ {ok, erlang:term_to_binary(?MC_MOD:encode(ActReq, Vsn), Config)};
+encode_action_request([{megaco_compressed, Mod}|Config], Vsn, ActReq)
+ when is_tuple(ActReq) ->
+ {ok, erlang:term_to_binary(Mod:encode(ActReq, Vsn), Config)};
+encode_action_request(Config, _Vsn, ActReq)
+ when is_tuple(ActReq) ->
+ {ok, erlang:term_to_binary(ActReq, Config)}.
+
+
+
+%%----------------------------------------------------------------------
+%% Convert a CommandRequest record into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_command_request([{version3, _}|EC], Vsn, CmdReq) ->
+ encode_command_request(EC, Vsn, CmdReq);
+encode_command_request([megaco_compressed|Config], Vsn, CmdReq)
+ when is_tuple(CmdReq) ->
+ {ok, erlang:term_to_binary(?MC_MOD:encode(CmdReq, Vsn), Config)};
+encode_command_request([{megaco_compressed, Mod}|Config], Vsn, CmdReq)
+ when is_tuple(CmdReq) ->
+ {ok, erlang:term_to_binary(Mod:encode(CmdReq, Vsn), Config)};
+encode_command_request(Config, _Vsn, CmdReq)
+ when is_tuple(CmdReq) ->
+ {ok, erlang:term_to_binary(CmdReq, Config)}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a action reply into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_reply([{version3, _}|EC], Vsn, ActRep) ->
+ encode_action_reply(EC, Vsn, ActRep);
+encode_action_reply([megaco_compressed|Config], Vsn, ActRep)
+ when is_tuple(ActRep) ->
+ {ok, erlang:term_to_binary(?MC_MOD:encode(ActRep, Vsn), Config)};
+encode_action_reply([{megaco_compressed, Mod}|Config], Vsn, ActRep)
+ when is_tuple(ActRep) ->
+ {ok, erlang:term_to_binary(Mod:encode(ActRep, Vsn), Config)};
+encode_action_reply(Config, _Vsn, ActRep)
+ when is_tuple(ActRep) ->
+ {ok, erlang:term_to_binary(ActRep, Config)}.
+
+
+%%----------------------------------------------------------------------
+%% Get the megaco version of the message
+%% Return {ok, Version} | {error, Reason}
+%%----------------------------------------------------------------------
+
+version_of(Config, Bin) when is_binary(Bin) ->
+ case decode_message(Config, 1, Bin) of
+ {ok, M} ->
+ V = (M#'MegacoMessage'.mess)#'Message'.version,
+ {ok, V};
+ Error ->
+ Error
+ end.
+
+decode_message(Config, Bin) ->
+ decode_message(Config, 1, Bin).
+
+decode_message([{version3, _}|EC], V, Bin) ->
+ decode_message(EC, V, Bin);
+decode_message([megaco_compressed = MC|_Config], Vsn, Bin) ->
+ case catch erlang:binary_to_term(Bin) of
+ Msg when is_tuple(Msg) ->
+ case (?MC_MOD:decode(Msg, Vsn)) of
+ MegaMsg when is_record(MegaMsg, 'MegacoMessage') ->
+ {ok, dm(MegaMsg, MC, Vsn)};
+ _ ->
+ {error, {bad_message, Msg}}
+ end;
+ {'EXIT', _Reason} ->
+ {error, bad_binary}
+ end;
+decode_message([{megaco_compressed, Mod} = MC|_Config], Vsn, Bin)
+ when is_atom(Mod) ->
+ case catch erlang:binary_to_term(Bin) of
+ Msg when is_tuple(Msg) ->
+ case (Mod:decode(Msg, Vsn)) of
+ MegaMsg when is_record(MegaMsg, 'MegacoMessage') ->
+ {ok, dm(MegaMsg, MC, Vsn)};
+ _ ->
+ {error, {bad_message, Msg}}
+ end;
+ {'EXIT', _Reason} ->
+ {error, bad_binary}
+ end;
+decode_message(_Config, Vsn, Bin) ->
+ case catch erlang:binary_to_term(Bin) of
+ MegaMsg when is_record(MegaMsg, 'MegacoMessage') ->
+ {ok, dm(MegaMsg, undefined, Vsn)};
+ {'EXIT', _Reason} ->
+ {error, bad_binary}
+ end.
+
+
+decode_mini_message(EC, Vsn, Bin) when is_binary(Bin) ->
+ decode_message(EC, Vsn, Bin).
+
+
+%% This crap is because the transactions or the action-requests
+%% might have been encoded separetely
+
+dm(#'MegacoMessage'{mess = Mess} = M, MC, Vsn) ->
+ #'Message'{messageBody = Body} = Mess,
+ case Body of
+ {transactions, Transactions} ->
+ Body2 = {transactions, dmt(Transactions, [], MC, Vsn)},
+ Mess2 = Mess#'Message'{messageBody = Body2},
+ M#'MegacoMessage'{mess = Mess2};
+ _ ->
+ M
+ end.
+
+dmt([], Acc, _, _Vsn) ->
+ lists:reverse(Acc);
+dmt([Trans0|Transactions], Acc, MC, Vsn) when is_binary(Trans0) ->
+ Trans1 = erlang:binary_to_term(Trans0),
+ Trans2 = dmt1(Trans1, MC, Vsn),
+ dmt(Transactions, [Trans2|Acc], MC, Vsn);
+dmt([{Tag, Trans0}|Transactions], Acc, MC, Vsn) when is_binary(Trans0) ->
+ Trans1 = erlang:binary_to_term(Trans0),
+ Trans2 = dmt1(Trans1, MC, Vsn),
+ dmt(Transactions, [{Tag, Trans2}|Acc], MC, Vsn);
+dmt([{transactionRequest,
+ #'TransactionRequest'{actions = Acts0} = TR0}|Transactions],
+ Acc, MC, Vsn)
+ when is_binary(Acts0) ->
+ Acts1 = erlang:binary_to_term(Acts0),
+ Acts2 = dmt1(Acts1, MC, Vsn),
+ TR1 = TR0#'TransactionRequest'{actions = Acts2},
+ dmt(Transactions, [{transactionRequest, TR1}|Acc], MC, Vsn);
+dmt([{transactionRequest,
+ #'TransactionRequest'{actions = Acts0} = TR0}|Transactions],
+ Acc, MC, Vsn) ->
+ Acts2 = [dmt2(AR, MC, Vsn) || AR <- Acts0],
+ TR1 = TR0#'TransactionRequest'{actions = Acts2},
+ dmt(Transactions, [{transactionRequest, TR1}|Acc], MC, Vsn);
+dmt([Trans|Transactions], Acc, MC, Vsn) ->
+ dmt(Transactions, [Trans|Acc], MC, Vsn).
+
+dmt1(L, megaco_compressed, Vsn) when is_list(L) ->
+ [?MC_MOD:decode(E, Vsn) || E <- L];
+dmt1(L, {megaco_compressed, Mod}, Vsn) when is_list(L) ->
+ [Mod:decode(E, Vsn) || E <- L];
+dmt1(T, megaco_compressed, Vsn) when is_tuple(T) ->
+ ?MC_MOD:decode(T, Vsn);
+dmt1(T, {megaco_compressed, Mod}, Vsn) when is_tuple(T) ->
+ Mod:decode(T, Vsn);
+dmt1(Else, _, _Vsn) ->
+ Else.
+
+dmt2(Bin, MC, Vsn) when is_binary(Bin) ->
+ AR = erlang:binary_to_term(Bin),
+ dmt1(AR, MC, Vsn);
+dmt2(AR, _MC, _Vsn) ->
+ AR.
+
+
diff --git a/lib/megaco/src/engine/megaco_erl_dist_encoder_mc.erl b/lib/megaco/src/engine/megaco_erl_dist_encoder_mc.erl
new file mode 100644
index 0000000000..52395ae516
--- /dev/null
+++ b/lib/megaco/src/engine/megaco_erl_dist_encoder_mc.erl
@@ -0,0 +1,1894 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2007-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: Externalize/internalize Megaco/H.248 messages
+%%----------------------------------------------------------------------
+
+-module(megaco_erl_dist_encoder_mc).
+
+-behaviour(megaco_edist_compress).
+
+-export([
+ encode/1, encode/2,
+ decode/1, decode/2
+ ]).
+
+
+-include("megaco_message_internal.hrl").
+-include_lib("megaco/src/app/megaco_internal.hrl").
+
+
+%%----------------------------------------------------------------------
+%% Megaco compress a Megaco record into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+
+encode(M) ->
+ e(M, 1).
+
+encode(M, Vsn) ->
+ ?d("encode -> entry with"
+ "~n M: ~p"
+ "~n Vsn: ~p", [M, Vsn]),
+ Result = e(M, Vsn),
+ ?d("encode -> "
+ "~n Result: ~p", [Result]),
+ Result.
+
+decode(M) ->
+ d(M, 1).
+
+decode(M, Vsn) ->
+ ?d("decode -> entry with"
+ "~n M: ~p"
+ "~n Vsn: ~p", [M, Vsn]),
+ Result = d(M, Vsn),
+ ?d("decode -> "
+ "~n Result: ~p", [Result]),
+ Result.
+
+
+el(L, V) when is_list(L) -> [e(T, V) || T <- L];
+el(L, _V) -> L.
+dl(L, V) when is_list(L) -> [d(T, V) || T <- L];
+dl(L, _V) -> L.
+
+ell(L, V) when is_list(L) -> [el(T, V) || T <- L];
+ell(L, _V) -> L.
+dll(L, V) when is_list(L) -> [dl(T, V) || T <- L];
+dll(L, _V) -> L.
+
+e(asn1_NOVALUE, _) ->
+ {1};
+e('NULL', _V) ->
+ {2};
+e(sendRecv, _V) ->
+ {3};
+e(recvOnly, _V) ->
+ {4};
+e(restart, _V) ->
+ {5};
+e(mediaToken, _V) ->
+ {6};
+e(eventsToken, _V) ->
+ {7};
+e(signalsToken, _V) ->
+ {8};
+e(digitMapToken, _V) ->
+ {9};
+e(statsToken, _V) ->
+ {10};
+e(packagesToken, _V) ->
+ {11};
+e(h221, _V) ->
+ {12};
+e(h223, _V) ->
+ {13};
+e(h226, _V) ->
+ {14};
+e(v76, _V) ->
+ {15};
+
+e({'MegacoMessage', asn1_NOVALUE, {'Message', 1 = V, Mid, Body}}, _) ->
+ {20, e(Mid, V), e(Body, V)};
+e({'MegacoMessage', asn1_NOVALUE, {'Message', 2 = V, Mid, Body}}, _) ->
+ {21, e(Mid, V), e(Body, V)};
+e({'MegacoMessage', asn1_NOVALUE, {'Message', V, Mid, Body}}, _) ->
+ {22, V, e(Mid, V), e(Body, V)};
+e({'MegacoMessage', AuthHeader, {'Message', 1 = V, Mid, Body}}, _) ->
+ {23, e(AuthHeader, V), V, e(Mid, V), e(Body, V)};
+e({'MegacoMessage', AuthHeader, {'Message', 2 = V, Mid, Body}}, _) ->
+ {24, e(AuthHeader, V), V, e(Mid, V), e(Body, V)};
+e({'MegacoMessage', AuthHeader, {'Message', V, Mid, Body}}, _) ->
+ {25, V, e(AuthHeader, V), V, e(Mid, V), e(Body, V)};
+e({'MegacoMessage', AuthHeader, Mess}, V) ->
+ {26, e(AuthHeader, V), e(Mess, V)};
+e({'Message', V, Mid, Body}, _) ->
+ {27, V, e(Mid, V), e(Body, V)};
+
+e({domainName, {'DomainName', Name, asn1_NOVALUE}}, _V) ->
+ {30, Name};
+e({domainName, {'DomainName', Name, PortNumber}}, _V) ->
+ {31, Name, PortNumber};
+e({domainName, N}, V) ->
+ {32, e(N, V)};
+e({'DomainName', Name, asn1_NOVALUE}, _V) ->
+ {33, Name};
+e({'DomainName', Name, PortNumber}, _V) ->
+ {34, Name, PortNumber};
+e({ip4Address, {'IP4Address', Addr, asn1_NOVALUE}}, _V) ->
+ {35, Addr};
+e({ip4Address, {'IP4Address', Addr, PortNumber}}, _V) ->
+ {36, Addr, PortNumber};
+e({ip4Address, A}, V) ->
+ {37, e(A, V)};
+e({'IP4Address', Addr, asn1_NOVALUE}, _V) ->
+ {38, Addr};
+e({'IP4Address', Addr, PortNumber}, _V) ->
+ {39, Addr, PortNumber};
+e({ip6Address, {'IP6Address', Addr, asn1_NOVALUE}}, _V) ->
+ {40, Addr};
+e({ip6Address, {'IP6Address', Addr, PortNumber}}, _V) ->
+ {41, Addr, PortNumber};
+e({ip6Address, A}, V) ->
+ {42, e(A, V)};
+e({'IP6Address', Addr, asn1_NOVALUE}, _V) ->
+ {43, Addr};
+e({'IP6Address', Addr, PortNumber}, _V) ->
+ {44, Addr, PortNumber};
+
+e({transactions, [Transaction]}, V) ->
+ {50, e(Transaction, V)};
+e({transactions, Transactions}, V) ->
+ {51, el(Transactions, V)};
+e({messageError, {'ErrorDescriptor', EC, asn1_NOVALUE}}, _V) ->
+ {52, EC};
+e({messageError, {'ErrorDescriptor', EC, ET}}, _V) ->
+ {53, EC, ET};
+e({messageError, Error}, V) ->
+ {54, e(Error, V)};
+e({transactionRequest, {'TransactionRequest', TransId, Actions}}, V) ->
+ {55, TransId, el(Actions, V)};
+e({transactionPending, {'TransactionPending', TransId}}, _V) ->
+ {56, TransId};
+e({transactionReply, {'TransactionReply', TransId, asn1_NOVALUE, TransRes}}, V) ->
+ {57, TransId, e(TransRes, V)};
+e({transactionReply, {'TransactionReply', TransId, 'NULL', TransRes}}, V) ->
+ {58, TransId, e(TransRes, V)};
+e({transactionReply, {'TransactionReply', TransId, ImmAckReq, TransRes}}, V) ->
+ {59, TransId, e(ImmAckReq, V), e(TransRes, V)};
+e({transactionResponseAck, T}, V) ->
+ {60, el(T, V)};
+e({'TransactionAck', FirstAck, asn1_NOVALUE}, _V) ->
+ {61, FirstAck};
+e({'TransactionAck', FirstAck, LastAck}, _V) ->
+ {62, FirstAck, LastAck};
+
+e({'ErrorDescriptor', EC, asn1_NOVALUE}, _V) ->
+ {70, EC};
+e({'ErrorDescriptor', EC, ET}, _V) ->
+ {71, EC, ET};
+
+e({'ActionRequest', Cid, CtxReq, CtxAAR, [CmdReq]}, V) ->
+ {80, Cid, e(CtxReq, V), e(CtxAAR, V), e(CmdReq, V)};
+e({'ActionRequest', Cid, CtxReq, CtxAAR, CmdReqs}, V) ->
+ {81, Cid, e(CtxReq, V), e(CtxAAR, V), el(CmdReqs, V)};
+
+e({'ContextRequest', P, E, T}, V) when V < 3 ->
+ {90, e(P, V), e(E, V), el(T, V)};
+e({'ContextRequest', P, E, T, asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE}, V)
+ when V >= 3 ->
+ {91, e(P, V), e(E, V), el(T, V)};
+e({'ContextRequest', P, E, T, IC, asn1_NOVALUE, asn1_NOVALUE}, V)
+ when V >= 3 ->
+ {92, e(P, V), e(E, V), el(T, V), e(IC, V)};
+e({'ContextRequest', P, E, T, IC, CP, asn1_NOVALUE}, V)
+ when V >= 3 ->
+ {93, e(P, V), e(E, V), el(T, V), e(IC, V), el(CP, V)};
+e({'ContextRequest', P, E, T, IC, CP, CL}, V)
+ when V >= 3 ->
+ {94, e(P, V), e(E, V), el(T, V), e(IC, V), el(CP, V), el(CL, V)};
+
+e({'ContextAttrAuditRequest', P, E, T}, V) when V < 3 ->
+ {100, e(P, V), e(E, V), e(T, V)};
+e({'ContextAttrAuditRequest', P, E, T,
+ asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE}, V)
+ when V >= 3 ->
+ {101, e(P, V), e(E, V), e(T, V)};
+e({'ContextAttrAuditRequest', P, E, T,
+ IC, asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE}, V)
+ when V >= 3 ->
+ {102, e(P, V), e(E, V), e(T, V),
+ e(IC, V)};
+e({'ContextAttrAuditRequest', P, E, T,
+ IC, CPA, asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE}, V)
+ when V >= 3 ->
+ {103, e(P, V), e(E, V), e(T, V),
+ e(IC, V), el(CPA, V)};
+e({'ContextAttrAuditRequest', P, E, T,
+ IC, CPA, SP, asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE}, V)
+ when V >= 3 ->
+ {104, e(P, V), e(E, V), e(T, V),
+ e(IC, V), el(CPA, V), e(SP, V)};
+e({'ContextAttrAuditRequest', P, E, T,
+ IC, CPA, SP, SE, asn1_NOVALUE, asn1_NOVALUE}, V)
+ when V >= 3 ->
+ {105, e(P, V), e(E, V), e(T, V),
+ e(IC, V), el(CPA, V), e(SP, V), e(SE, V)};
+e({'ContextAttrAuditRequest', P, E, T,
+ IC, CPA, SP, SE, SIC, asn1_NOVALUE}, V)
+ when V >= 3 ->
+ {106, e(P, V), e(E, V), e(T, V),
+ e(IC, V), el(CPA, V), e(SP, V), e(SE, V), e(SIC, V)};
+e({'ContextAttrAuditRequest', P, E, T,
+ IC, CPA, SP, SE, SIC, SL}, V)
+ when V >= 3 ->
+ {107, e(P, V), e(E, V), e(T, V),
+ e(IC, V), el(CPA, V), e(SP, V), e(SE, V), e(SIC, V), e(SL, V)};
+
+e({'CommandRequest', Cmd, asn1_NOVALUE, asn1_NOVALUE}, V) ->
+ {110, e(Cmd, V)};
+e({'CommandRequest', Cmd, 'NULL', asn1_NOVALUE}, V) ->
+ {111, e(Cmd, V)};
+e({'CommandRequest', Cmd, asn1_NOVALUE, 'NULL'}, V) ->
+ {112, e(Cmd, V)};
+e({'CommandRequest', Cmd, 'NULL', 'NULL'}, V) ->
+ {113, e(Cmd, V)};
+e({'CommandRequest', Cmd, Opt, WR}, V) ->
+ {114, e(Cmd, V), e(Opt, V), e(WR, V)};
+
+e({'TopologyRequest', From, To, Dir}, 1 = V) ->
+ {120, e(From, V), e(To, V), e(Dir, V)};
+e({'TopologyRequest', From, To, Dir, SID}, 2 = V) ->
+ {121, e(From, V), e(To, V), e(Dir, V), e(SID, V)};
+e({'TopologyRequest', From, To, Dir, SID, asn1_NOVALUE}, V) when (V >= 3) ->
+ {122, e(From, V), e(To, V), e(Dir, V), e(SID, V)};
+e({'TopologyRequest', From, To, Dir, SID, TDE}, V) when (V >= 3) ->
+ {123, e(From, V), e(To, V), e(Dir, V), e(SID, V), e(TDE, V)};
+
+e({modReq, {'AmmRequest', TID, []}}, V) ->
+ {130, el(TID, V)};
+e({modReq, {'AmmRequest', TID, [Desc]}}, V) ->
+ {131, el(TID, V), e(Desc, V)};
+e({modReq, {'AmmRequest', TID, Descs}}, V) ->
+ {132, el(TID, V), el(Descs, V)};
+e({addReq, {'AmmRequest', TID, []}}, V) ->
+ {133, el(TID, V)};
+e({addReq, {'AmmRequest', TID, [Desc]}}, V) ->
+ {134, el(TID, V), e(Desc, V)};
+e({addReq, {'AmmRequest', TID, Descs}}, V) ->
+ {135, el(TID, V), el(Descs, V)};
+e({'AmmRequest', TID, Descs}, V) ->
+ {136, el(TID, V), el(Descs, V)};
+
+e({subtractReq, {'SubtractRequest', TID, asn1_NOVALUE}}, V) ->
+ {140, el(TID, V)};
+e({subtractReq, {'SubtractRequest', TID, AudDesc}}, V) ->
+ {141, el(TID, V), e(AudDesc, V)};
+e({'SubtractRequest', TID, asn1_NOVALUE}, V) ->
+ {142, el(TID, V)};
+e({'SubtractRequest', TID, AudDesc}, V) ->
+ {143, el(TID, V), e(AudDesc, V)};
+
+e({auditValueRequest, AR}, V) ->
+ {150, e(AR, V)};
+
+e({'AuditRequest', TID, AudDesc}, V) when V < 3 ->
+ {160, e(TID, V), e(AudDesc, V)};
+e({'AuditRequest', TID, AudDesc, asn1_NOVALUE}, V) when V >= 3 ->
+ {161, e(TID, V), e(AudDesc, V)};
+e({'AuditRequest', TID, AudDesc, TIDs}, V) when V >= 3 ->
+ {162, e(TID, V), e(AudDesc, V), el(TIDs, V)};
+
+e({actionReplies, [AR]}, V) ->
+ {170, e(AR, V)};
+e({actionReplies, ARs}, V) ->
+ {171, el(ARs, V)};
+
+e({'ActionReply', CID, asn1_NOVALUE, asn1_NOVALUE, [CmdRep]}, V) ->
+ {180, CID, e(CmdRep, V)};
+e({'ActionReply', CID, asn1_NOVALUE, asn1_NOVALUE, CmdRep}, V) ->
+ {181, CID, el(CmdRep, V)};
+e({'ActionReply', CID, asn1_NOVALUE, CtxRep, [CmdRep]}, V) ->
+ {182, CID, e(CtxRep, V), e(CmdRep, V)};
+e({'ActionReply', CID, asn1_NOVALUE, CtxRep, CmdRep}, V) ->
+ {183, CID, e(CtxRep, V), el(CmdRep, V)};
+e({'ActionReply', CID, ED, asn1_NOVALUE, [CmdRep]}, V) ->
+ {184, CID, e(ED, V), e(CmdRep, V)};
+e({'ActionReply', CID, ED, asn1_NOVALUE, CmdRep}, V) ->
+ {185, CID, e(ED, V), el(CmdRep, V)};
+e({'ActionReply', CID, ED, CtxRep, [CmdRep]}, V) ->
+ {186, CID, e(ED, V), e(CtxRep, V), e(CmdRep, V)};
+e({'ActionReply', CID, ED, CtxRep, CmdRep}, V) ->
+ {187, CID, e(ED, V), e(CtxRep, V), el(CmdRep, V)};
+
+e({'AuditDescriptor', asn1_NOVALUE}, 1 = _V) ->
+ {190};
+e({'AuditDescriptor', AT}, 1 = V) ->
+ {191, el(AT, V)};
+e({'AuditDescriptor', asn1_NOVALUE, asn1_NOVALUE}, V) when V >= 2 ->
+ {192};
+e({'AuditDescriptor', AT, APT}, V)
+ when is_list(AT) andalso is_list(APT) andalso (V >= 2) ->
+ {193, el(AT, V), el(APT, V)};
+e({'AuditDescriptor', AT, APT}, V)
+ when is_list(APT) andalso (V >= 2) ->
+ {194, e(AT, V), el(APT, V)};
+e({'AuditDescriptor', AT, APT}, V)
+ when is_list(AT) andalso (V >= 2) ->
+ {195, el(AT, V), e(APT, V)};
+e({'AuditDescriptor', AT, APT}, V) when (V >= 2) ->
+ {196, e(AT, V), e(APT, V)};
+
+e({notifyReq, {'NotifyRequest', TID, OED, asn1_NOVALUE}}, V) ->
+ {200, el(TID, V), e(OED, V)};
+e({notifyReq, {'NotifyRequest', TID, OED, ED}}, V) ->
+ {201, el(TID, V), e(OED, V), e(ED, V)};
+e({'NotifyRequest', TID, OED}, V) ->
+ {202, el(TID, V), e(OED, V)};
+e({'NotifyRequest', TID, OED, ED}, V) ->
+ {203, el(TID, V), e(OED, V), e(ED, V)};
+
+e({'ObservedEventsDescriptor', RID, OEL}, V) ->
+ {210, RID, el(OEL, V)};
+
+e({'ObservedEvent', EN, SID, EPL, TN}, V) ->
+ {220, EN, e(SID, V), el(EPL, V), e(TN, V)};
+
+e({'EventParameter', "type", ["est"], asn1_NOVALUE}, _V) ->
+ {230};
+e({'EventParameter', "type", [Val], asn1_NOVALUE}, _V) ->
+ {231, Val};
+e({'EventParameter', "type", Val, asn1_NOVALUE}, _V) ->
+ {232, Val};
+e({'EventParameter', "Generalcause", ["NR"], asn1_NOVALUE}, _V) ->
+ {233};
+e({'EventParameter', "Generalcause", ["UR"], asn1_NOVALUE}, _V) ->
+ {234};
+e({'EventParameter', "Generalcause", ["FT"], asn1_NOVALUE}, _V) ->
+ {235};
+e({'EventParameter', "Generalcause", ["FP"], asn1_NOVALUE}, _V) ->
+ {236};
+e({'EventParameter', "Generalcause", ["IW"], asn1_NOVALUE}, _V) ->
+ {237};
+e({'EventParameter', "Generalcause", ["UN"], asn1_NOVALUE}, _V) ->
+ {238};
+e({'EventParameter', "Generalcause", [Val], asn1_NOVALUE}, _V) ->
+ {239, Val};
+e({'EventParameter', "Generalcause", Val, asn1_NOVALUE}, _V) ->
+ {240, Val};
+e({'EventParameter', "Failurecause", [Val], asn1_NOVALUE}, _V) ->
+ {241, Val};
+e({'EventParameter', "Failurecause", Val, asn1_NOVALUE}, _V) ->
+ {242, Val};
+e({'EventParameter', EPN, Val, asn1_NOVALUE}, _V) ->
+ {243, EPN, Val};
+e({'EventParameter', EPN, Val, EI}, _V) ->
+ {244, EPN, Val, EI};
+
+e({serviceChangeReq, {'ServiceChangeRequest', TID, SCPs}}, V) ->
+ {260, el(TID, V), e(SCPs, V)};
+e({serviceChangeReq, SCR}, V) ->
+ {261, e(SCR, V)};
+e({'ServiceChangeRequest', TID, SCPs}, V) ->
+ {262, el(TID, V), e(SCPs, V)};
+
+e({serviceChangeReply, {'ServiceChangeReply', TID, SCR}}, V) ->
+ {270, el(TID, V), e(SCR, V)};
+e({serviceChangeReply, SCR}, V) ->
+ {271, e(SCR, V)};
+e({'ServiceChangeReply', TID, SCR}, V) -> %% KOLLA
+ {272, el(TID, V), e(SCR, V)};
+
+e({mediaDescriptor, {'MediaDescriptor', TSD, S}}, V) ->
+ {280, e(TSD, V), e(S, V)};
+e({mediaDescriptor, MD}, V) ->
+ {281, e(MD, V)};
+e({'MediaDescriptor', TSD, S}, V) ->
+ {282, e(TSD, V), e(S, V)};
+
+e({oneStream, S}, V) ->
+ {290, e(S, V)};
+e({multiStream, S}, V) ->
+ {291, el(S, V)};
+e({'StreamDescriptor', SID, SP}, V) ->
+ {292, e(SID, V), e(SP, V)};
+
+e({'StreamParms', LCD, asn1_NOVALUE, asn1_NOVALUE}, V) when V < 3 ->
+ {300, e(LCD, V)};
+e({'StreamParms', LCD, LD, asn1_NOVALUE}, V) when V < 3 ->
+ {301, e(LCD, V), e(LD, V)};
+e({'StreamParms', LCD, LD, RD}, V) when V < 3 ->
+ {302, e(LCD, V), e(LD, V), e(RD, V)};
+
+e({'StreamParms', LCD, asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE}, V)
+ when V >= 3 ->
+ {303, e(LCD, V)};
+e({'StreamParms', LCD, LD, asn1_NOVALUE, asn1_NOVALUE}, V)
+ when V >= 3 ->
+ {304, e(LCD, V), e(LD, V)};
+e({'StreamParms', LCD, LD, RD, asn1_NOVALUE}, V)
+ when V >= 3 ->
+ {305, e(LCD, V), e(LD, V), e(RD, V)};
+e({'StreamParms', LCD, LD, RD, SD}, V)
+ when V >= 3 ->
+ {306, e(LCD, V), e(LD, V), e(RD, V), el(SD, V)};
+
+e({'LocalControlDescriptor', SM, RV, RG, PP}, V) ->
+ {310, e(SM, V), e(RV, V), e(RG, V), el(PP, V)};
+
+e({'PropertyParm', "v", [Val], asn1_NOVALUE}, _V) ->
+ {320, Val};
+e({'PropertyParm', "v", Val, asn1_NOVALUE}, _V) ->
+ {321, Val};
+e({'PropertyParm', "o", [Val], asn1_NOVALUE}, _V) ->
+ {332, Val};
+e({'PropertyParm', "o", Val, asn1_NOVALUE}, _V) ->
+ {333, Val};
+e({'PropertyParm', "s", [Val], asn1_NOVALUE}, _V) ->
+ {334, Val};
+e({'PropertyParm', "s", Val, asn1_NOVALUE}, _V) ->
+ {335, Val};
+e({'PropertyParm', "i", [Val], asn1_NOVALUE}, _V) ->
+ {336, Val};
+e({'PropertyParm', "i", Val, asn1_NOVALUE}, _V) ->
+ {337, Val};
+e({'PropertyParm', "u", [Val], asn1_NOVALUE}, _V) ->
+ {338, Val};
+e({'PropertyParm', "u", Val, asn1_NOVALUE}, _V) ->
+ {339, Val};
+e({'PropertyParm', "e", [Val], asn1_NOVALUE}, _V) ->
+ {340, Val};
+e({'PropertyParm', "e", Val, asn1_NOVALUE}, _V) ->
+ {341, Val};
+e({'PropertyParm', "p", [Val], asn1_NOVALUE}, _V) ->
+ {342, Val};
+e({'PropertyParm', "p", Val, asn1_NOVALUE}, _V) ->
+ {343, Val};
+e({'PropertyParm', "c", [Val], asn1_NOVALUE}, _V) ->
+ {344, Val};
+e({'PropertyParm', "c", Val, asn1_NOVALUE}, _V) ->
+ {345, Val};
+e({'PropertyParm', "b", [Val], asn1_NOVALUE}, _V) ->
+ {346, Val};
+e({'PropertyParm', "b", Val, asn1_NOVALUE}, _V) ->
+ {347, Val};
+e({'PropertyParm', "z", [Val], asn1_NOVALUE}, _V) ->
+ {348, Val};
+e({'PropertyParm', "z", Val, asn1_NOVALUE}, _V) ->
+ {349, Val};
+e({'PropertyParm', "k", [Val], asn1_NOVALUE}, _V) ->
+ {350, Val};
+e({'PropertyParm', "k", Val, asn1_NOVALUE}, _V) ->
+ {351, Val};
+e({'PropertyParm', "a", [Val], asn1_NOVALUE}, _V) ->
+ {352, Val};
+e({'PropertyParm', "a", Val, asn1_NOVALUE}, _V) ->
+ {353, Val};
+e({'PropertyParm', "t", [Val], asn1_NOVALUE}, _V) ->
+ {354, Val};
+e({'PropertyParm', "t", Val, asn1_NOVALUE}, _V) ->
+ {355, Val};
+e({'PropertyParm', "r", [Val], asn1_NOVALUE}, _V) ->
+ {356, Val};
+e({'PropertyParm', "r", Val, asn1_NOVALUE}, _V) ->
+ {357, Val};
+e({'PropertyParm', "m", [Val], asn1_NOVALUE}, _V) ->
+ {358, Val};
+e({'PropertyParm', "m", Val, asn1_NOVALUE}, _V) ->
+ {359, Val};
+e({'PropertyParm', "nt/jit", [Val], asn1_NOVALUE}, _V) ->
+ {360, Val};
+e({'PropertyParm', "nt/jit", Val, asn1_NOVALUE}, _V) ->
+ {361, Val};
+e({'PropertyParm', "tdmc/ec", ["on"], asn1_NOVALUE}, _V) ->
+ {362};
+e({'PropertyParm', "tdmc/ec", ["off"], asn1_NOVALUE}, _V) ->
+ {363};
+e({'PropertyParm', "tdmc/gain", ["automatic"], asn1_NOVALUE}, _V) ->
+ {364};
+e({'PropertyParm', "tdmc/gain", [Val], asn1_NOVALUE}, _V) ->
+ {365, Val};
+e({'PropertyParm', "tdmc/gain", Val, asn1_NOVALUE}, _V) ->
+ {366, Val};
+e({'PropertyParm', "maxNumberOfContexts", [Val], asn1_NOVALUE}, _V) ->
+ {367, Val};
+e({'PropertyParm', "maxNumberOfContexts", Val, asn1_NOVALUE}, _V) ->
+ {368, Val};
+e({'PropertyParm', "maxTerminationsPerContext", [Val], asn1_NOVALUE}, _V) ->
+ {369, Val};
+e({'PropertyParm', "maxTerminationsPerContext", Val, asn1_NOVALUE}, _V) ->
+ {370, Val};
+e({'PropertyParm', "normalMGExecutionTime", [Val], asn1_NOVALUE}, _V) ->
+ {371, Val};
+e({'PropertyParm', "normalMGExecutionTime", Val, asn1_NOVALUE}, _V) ->
+ {372, Val};
+e({'PropertyParm', "normalMGCExecutionTime", [Val], asn1_NOVALUE}, _V) ->
+ {373, Val};
+e({'PropertyParm', "normalMGCExecutionTime", Val, asn1_NOVALUE}, _V) ->
+ {374, Val};
+e({'PropertyParm', "MGProvisionalResponseTimerValue", [Val], asn1_NOVALUE}, _V) ->
+ {375, Val};
+e({'PropertyParm', "MGProvisionalResponseTimerValue", Val, asn1_NOVALUE}, _V) ->
+ {376, Val};
+e({'PropertyParm', "MGCProvisionalResponseTimerValue", [Val], asn1_NOVALUE}, _V) ->
+ {377, Val};
+e({'PropertyParm', "MGCProvisionalResponseTimerValue", Val, asn1_NOVALUE}, _V) ->
+ {378, Val};
+e({'PropertyParm', N, [Val], asn1_NOVALUE}, _V) ->
+ {379, N, Val};
+e({'PropertyParm', N, Val, asn1_NOVALUE}, _V) ->
+ {380, N, Val};
+e({'PropertyParm', N, Val, EI}, _V) ->
+ {381, N, Val, EI};
+
+e({'LocalRemoteDescriptor', [[PG]]}, V) ->
+ {400, e(PG, V)};
+e({'LocalRemoteDescriptor', [PG]}, V) ->
+ {401, el(PG, V)};
+e({'LocalRemoteDescriptor', PG}, V) ->
+ {402, ell(PG, V)};
+
+e({'TerminationStateDescriptor', PP, EBC, SS}, V) ->
+ {410, el(PP, V), e(EBC, V), e(SS, V)};
+
+e({eventsDescriptor, {'EventsDescriptor', RID, [E]}}, V) ->
+ {420, e(RID, V), e(E, V)};
+e({eventsDescriptor, {'EventsDescriptor', RID, EL}}, V) ->
+ {421, e(RID, V), el(EL, V)};
+e({eventsDescriptor, ED}, V) ->
+ {422, e(ED, V)};
+e({'EventsDescriptor', RID, [E]}, V) ->
+ {423, e(RID, V), e(E, V)};
+e({'EventsDescriptor', RID, EL}, V) ->
+ {424, e(RID, V), el(EL, V)};
+
+e({'RequestedEvent', PN, SID, EA, EPL}, V) ->
+ {425, PN, e(SID, V), e(EA, V), el(EPL, V)};
+
+e({'RegulatedEmbeddedDescriptor', SED, SD}, V) ->
+ {430, e(SED, V), el(SD, V)};
+
+e({notifyImmediate, NI}, V) ->
+ {435, e(NI, V)};
+e({notifyRegulated, NR}, V) ->
+ {436, e(NR, V)};
+e({neverNotify, NN}, V) ->
+ {437, e(NN, V)};
+
+e({'RequestedActions', KA, EDM, SE, SD}, V) ->
+ {440, e(KA, V), e(EDM, V), e(SE, V), e(SD, V)};
+
+e({'RequestedActions', KA, EDM, SE, SD, asn1_NOVALUE, asn1_NOVALUE}, V)
+ when V >= 3 ->
+ {441, e(KA, V), e(EDM, V), e(SE, V), e(SD, V)};
+e({'RequestedActions', KA, EDM, SE, SD, NB, asn1_NOVALUE}, V)
+ when V >= 3 ->
+ {442, e(KA, V), e(EDM, V), e(SE, V), e(SD, V), e(NB, V)};
+e({'RequestedActions', KA, EDM, SE, SD, NB, RED}, V)
+ when V >= 3 ->
+ {443, e(KA, V), e(EDM, V), e(SE, V), e(SD, V), e(NB, V), e(RED, V)};
+
+e({'SecondEventsDescriptor', RID, [E]}, V) ->
+ {450, e(RID, V), e(E, V)};
+e({'SecondEventsDescriptor', RID, EL}, V) ->
+ {451, e(RID, V), el(EL, V)};
+
+e({'SecondRequestedEvent', PN, SID, EA, EPL}, V) ->
+ {460, PN, e(SID, V), e(EA, V), e(EPL, V)};
+
+e({'SecondRequestedActions', KA, EDM, SD}, V) ->
+ {470, e(KA, V), e(EDM, V), e(SD, V)};
+
+e({'SecondRequestedActions', KA, EDM, SD, asn1_NOVALUE, asn1_NOVALUE}, V)
+ when V >= 3 ->
+ {471, e(KA, V), e(EDM, V), e(SD, V)};
+e({'SecondRequestedActions', KA, EDM, SD, NB, asn1_NOVALUE}, V)
+ when V >= 3 ->
+ {472, e(KA, V), e(EDM, V), e(SD, V), e(NB, V)};
+e({'SecondRequestedActions', KA, EDM, SD, NB, RED}, V)
+ when V >= 3 ->
+ {473, e(KA, V), e(EDM, V), e(SD, V), e(NB, V), e(RED, V)};
+
+e({'EventSpec', EN, SID, EPL}, V) ->
+ {480, EN, e(SID, V), el(EPL, V)};
+
+e({'SeqSigList', ID, SL}, V) ->
+ {490, ID, el(SL, V)};
+
+e({signalsDescriptor, S}, V) ->
+ {500, el(S, V)};
+e({signal, S}, V) ->
+ {510, e(S, V)};
+
+e({'Signal', SN, SID, ST, D, NC, KA, SPL}, V) ->
+ {520, SN, e(SID, V), e(ST, V), e(D, V), e(NC, V), e(KA, V), el(SPL, V)};
+
+e({'Signal', SN, SID, ST, D, NC, KA, SPL,
+ asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE}, V)
+ when V >= 3 ->
+ {521, SN, e(SID, V), e(ST, V), e(D, V), e(NC, V), e(KA, V), el(SPL, V)};
+e({'Signal', SN, SID, ST, D, NC, KA, SPL,
+ SD, asn1_NOVALUE, asn1_NOVALUE}, V)
+ when V >= 3 ->
+ {522, SN, e(SID, V), e(ST, V), e(D, V), e(NC, V), e(KA, V), el(SPL, V),
+ e(SD, V)};
+e({'Signal', SN, SID, ST, D, NC, KA, SPL,
+ SD, RID, asn1_NOVALUE}, V)
+ when V >= 3 ->
+ {523, SN, e(SID, V), e(ST, V), e(D, V), e(NC, V), e(KA, V), el(SPL, V),
+ e(SD, V), e(RID, V)};
+e({'Signal', SN, SID, ST, D, NC, KA, SPL,
+ SD, RID, IsD}, V)
+ when V >= 3 ->
+ {524, SN, e(SID, V), e(ST, V), e(D, V), e(NC, V), e(KA, V), el(SPL, V),
+ e(SD, V), e(RID, V), e(IsD, V)};
+
+e({'SigParameter', SPN, Val, asn1_NOVALUE}, _V) ->
+ {530, SPN, Val};
+e({'SigParameter', SPN, Val, EI}, _V) ->
+ {531, SPN, Val, EI};
+
+e({modemDescriptor, MD}, V) ->
+ {550, e(MD, V)};
+e({'ModemDescriptor', MTL, MPL, asn1_NOVALUE}, _V) ->
+ {551, MTL, MPL};
+e({'ModemDescriptor', MTL, MPL, NSD}, _V) ->
+ {552, MTL, MPL, NSD};
+
+e({digitMapDescriptor, {'DigitMapDescriptor', DMN, DMV}}, V) ->
+ {560, DMN, e(DMV, V)};
+e({digitMapDescriptor, DMD}, V) ->
+ {561, e(DMD, V)};
+e({'DigitMapDescriptor', DMN, DMV}, V) ->
+ {562, DMN, e(DMV, V)};
+
+e({'DigitMapValue', Start, Stop, Long, DMB}, 1 = V) ->
+ {570, e(Start, V), e(Stop, V), e(Long, V), DMB};
+e({'DigitMapValue', Start, Stop, Long, DMB, Dur}, V) when V >= 2 ->
+ {571, e(Start, V), e(Stop, V), e(Long, V), DMB, e(Dur, V)};
+
+e({'ServiceChangeParm', M, A, Ver, Prof, R, D, Id, asn1_NOVALUE, asn1_NOVALUE}, V) ->
+ {580, e(M, V), e(A, V), e(Ver, V), e(Prof, V), R, e(D, V), e(Id, V)};
+e({'ServiceChangeParm', M, A, Ver, Prof, R, D, Id, TS, asn1_NOVALUE}, V) ->
+ {581, e(M, V), e(A, V), e(Ver, V), e(Prof, V), R, e(D, V), e(Id, V),
+ e(TS, V)};
+e({'ServiceChangeParm', M, A, Ver, Prof, R, D, Id, TS, NSD}, V) ->
+ {582, e(M, V), e(A, V), e(Ver, V), e(Prof, V), R, e(D, V), e(Id, V),
+ e(TS, V), NSD};
+
+e({'ServiceChangeParm', M, A, Ver, Prof, R, D, Id, TS, NSD, asn1_NOVALUE}, V)
+ when V == 2 ->
+ {583, e(M, V), e(A, V), e(Ver, V), e(Prof, V), R, e(D, V), e(Id, V),
+ e(TS, V), NSD};
+e({'ServiceChangeParm', M, A, Ver, Prof, R, D, Id, TS, NSD, Info}, V)
+ when V == 2 ->
+ {584, e(M, V), e(A, V), e(Ver, V), e(Prof, V), R, e(D, V), e(Id, V),
+ e(TS, V), NSD, e(Info, V)};
+
+e({'ServiceChangeParm', M, A, Ver, Prof, R, D, Id, TS, NSD,
+ asn1_NOVALUE, asn1_NOVALUE}, V)
+ when V >= 3 ->
+ {585, e(M, V), e(A, V), e(Ver, V), e(Prof, V), R, e(D, V), e(Id, V),
+ e(TS, V), NSD};
+e({'ServiceChangeParm', M, A, Ver, Prof, R, D, Id, TS, NSD, Info,
+ asn1_NOVALUE}, V)
+ when V >= 3 ->
+ {586, e(M, V), e(A, V), e(Ver, V), e(Prof, V), R, e(D, V), e(Id, V),
+ e(TS, V), e(TS, V), NSD, e(Info, V)};
+e({'ServiceChangeParm', M, A, Ver, Prof, R, D, Id, TS, NSD, Info, Flag}, V)
+ when V >= 3 ->
+ {587, e(M, V), e(A, V), e(Ver, V), e(Prof, V), R, e(D, V), e(Id, V),
+ e(TS, V), NSD, e(Info, V), e(Flag, V)};
+
+e({serviceChangeResParms, {'ServiceChangeResParm', Id, A, Ver, Prof, TS}}, V) ->
+ {590, Id, e(A, V), Ver, e(Prof, V), TS};
+e({serviceChangeResParms, SCRP}, V) ->
+ {591, e(SCRP, V)};
+e({'ServiceChangeResParm', Id, A, Ver, Prof, TS}, V) ->
+ {592, Id, e(A, V), Ver, e(Prof, V), TS};
+
+e({portNumber, N}, _V) ->
+ {600, N};
+
+e({'TimeNotation', D, T}, _V) ->
+ {610, D, T};
+
+e({'ServiceChangeProfile', N, Ver}, _V) ->
+ {620, N, Ver};
+
+e({digitMapName, N}, _V) ->
+ {630, N};
+
+e({megaco_term_id, false, Id}, _V) ->
+ {640, Id};
+e({megaco_term_id, true, [[$*]]}, _V) ->
+ {641};
+e({megaco_term_id, true, [[$$]]}, _V) ->
+ {642};
+e({megaco_term_id, true, Id}, _V) ->
+ {643, Id};
+e({'TerminationID', W, ID}, _V) ->
+ {644, W, ID};
+
+e({modReply, {'AmmsReply', TID, asn1_NOVALUE}}, V) ->
+ {650, el(TID, V)};
+e({modReply, {'AmmsReply', TID, [TA]}}, V) ->
+ {651, el(TID, V), e(TA, V)};
+e({modReply, {'AmmsReply', TID, TA}}, V) when is_list(TA) ->
+ {652, el(TID, V), el(TA, V)};
+e({modReply, R}, V) ->
+ {653, e(R, V)};
+
+e({moveReply, AR}, V) ->
+ {655, e(AR, V)};
+
+e({addReply, {'AmmsReply', TID, asn1_NOVALUE}}, V) ->
+ {660, el(TID, V)};
+e({addReply, {'AmmsReply', TID, [TA]}}, V) ->
+ {661, el(TID, V), e(TA, V)};
+e({addReply, {'AmmsReply', TID, TA}}, V) when is_list(TA) ->
+ {662, el(TID, V), el(TA, V)};
+e({addReply, R}, V) ->
+ {663, e(R, V)};
+
+e({subtractReply, {'AmmsReply', TID, asn1_NOVALUE}}, V) ->
+ {670, el(TID, V)};
+e({subtractReply, {'AmmsReply', TID, [TA]}}, V) ->
+ {671, el(TID, V), e(TA, V)};
+e({subtractReply, {'AmmsReply', TID, TA}}, V) when is_list(TA) ->
+ {672, el(TID, V), el(TA, V)};
+e({subtractReply, R}, V) ->
+ {673, e(R, V)};
+
+e({'AmmsReply', TID, asn1_NOVALUE}, V) ->
+ {680, el(TID, V)};
+e({'AmmsReply', TID, [TA]}, V) ->
+ {681, el(TID, V), e(TA, V)};
+e({'AmmsReply', TID, TA}, V) when is_list(TA) ->
+ {682, el(TID, V), el(TA, V)};
+
+e({notifyReply, {'NotifyReply', TID, asn1_NOVALUE}}, V) ->
+ {690, el(TID, V)};
+e({notifyReply, {'NotifyReply', TID, ED}}, V) ->
+ {691, el(TID, V), e(ED, V)};
+e({notifyReply, R}, V) ->
+ {692, e(R, V)};
+e({'NotifyReply', TID, asn1_NOVALUE}, V) ->
+ {693, el(TID, V)};
+e({'NotifyReply', TID, ED}, V) ->
+ {694, el(TID, V), e(ED, V)};
+
+e({auditValueReply, AVR}, V) ->
+ {700, e(AVR, V)};
+
+e({contextAuditResult, TIDs}, V) ->
+ {705, el(TIDs, V)};
+
+e({auditResult, {'AuditResult', TID, [TAR]}}, V) ->
+ {710, e(TID, V), e(TAR, V)};
+e({auditResult, {'AuditResult', TID, TAR}}, V) ->
+ {711, e(TID, V), el(TAR, V)};
+e({auditResult, AR}, V) ->
+ {712, e(AR, V)};
+e({'AuditResult', TID, [TAR]}, V) ->
+ {713, e(TID, V), e(TAR, V)};
+e({'AuditResult', TID, TAR}, V) ->
+ {714, e(TID, V), el(TAR, V)};
+
+e({auditResultTermList, {'TermListAuditResult', TIDs, [TAR]}}, V) ->
+ {715, el(TIDs, V), e(TAR, V)};
+e({auditResultTermList, {'TermListAuditResult', TIDs, TAR}}, V) ->
+ {716, el(TIDs, V), el(TAR, V)};
+
+e({packagesDescriptor, PsD}, V) ->
+ {720, el(PsD, V)};
+
+e({'PackagesItem', "g", 1}, _V) ->
+ {730};
+e({'PackagesItem', "tonegen", 1}, _V) ->
+ {731};
+e({'PackagesItem', "tonedet", 1}, _V) ->
+ {732};
+e({'PackagesItem', "tg", 1}, _V) ->
+ {733};
+e({'PackagesItem', "dd", 1}, _V) ->
+ {734};
+e({'PackagesItem', "cg", 1}, _V) ->
+ {735};
+e({'PackagesItem', "cd", 1}, _V) ->
+ {736};
+e({'PackagesItem', "al", 1}, _V) ->
+ {737};
+e({'PackagesItem', "ct", 1}, _V) ->
+ {738};
+e({'PackagesItem', "nt", 1}, _V) ->
+ {739};
+e({'PackagesItem', "rtp", 1}, _V) ->
+ {740};
+e({'PackagesItem', "tdmc", 1}, _V) ->
+ {741};
+e({'PackagesItem', Name, Ver}, _V) ->
+ {742, Name, Ver};
+
+e({emptyDescriptors, AD}, V) ->
+ {760, e(AD, V)};
+
+e({statisticsDescriptor, [SD]}, V) ->
+ {770, e(SD, V)};
+e({statisticsDescriptor, SsD}, V) ->
+ {771, el(SsD, V)};
+
+e({'StatisticsParameter', Name, asn1_NOVALUE}, _V) ->
+ {780, Name};
+e({'StatisticsParameter', Name, Value}, _V) ->
+ {781, Name, Value};
+
+e({'MuxDescriptor', MT, TL, asn1_NOVALUE}, V) ->
+ {800, e(MT, V), el(TL, V)};
+e({'MuxDescriptor', MT, TL, NSD}, V) ->
+ {801, e(MT, V), el(TL, V), NSD};
+
+e({indAudPackagesDescriptor, {'IndAudPackagesDescriptor', N, Ver}}, V)
+ when (V >= 2) ->
+ {900, N, Ver};
+e({indAudPackagesDescriptor, IAPD}, V)
+ when (V >= 2) ->
+ {900, e(IAPD, V)};
+e({'IndAudPackagesDescriptor', N, Ver}, V)
+ when (V >= 2) ->
+ {901, N, Ver};
+
+e({indAudStatisticsDescriptor, {'IndAudStatisticsDescriptor', N}}, V)
+ when (V >= 2) ->
+ {910, N};
+e({indAudStatisticsDescriptor, IASD}, V)
+ when (V >= 2) ->
+ {911, e(IASD, V)};
+e({'IndAudStatisticsDescriptor', N}, V)
+ when (V >= 2) ->
+ {912, N};
+
+e({indAudDigitMapDescriptor, {'IndAudDigitMapDescriptor', DMN}}, V)
+ when (V >= 2) ->
+ {920, DMN};
+e({indAudDigitMapDescriptor, IADMD}, V)
+ when (V >= 2) ->
+ {921, e(IADMD, V)};
+e({'IndAudDigitMapDescriptor', DMN}, V)
+ when (V >= 2) ->
+ {922, DMN};
+
+e({indAudSignalsDescriptor, {seqSigList, IASD}}, V)
+ when (V >= 2) ->
+ {930, e(IASD, V)};
+e({indAudSignalsDescriptor, {signal, IAS}}, V)
+ when (V >= 2) ->
+ {931, e(IAS, V)};
+
+e({'IndAudSeqSigList', Id, SL}, V)
+ when (V >= 2) ->
+ {940, Id, e(SL, V)};
+
+e({'IndAudSignal', N, SID}, 2 = V) ->
+ {950, N, e(SID, V)};
+e({'IndAudSignal', N, SID, asn1_NOVALUE}, V)
+ when (V >= 3) ->
+ {951, N, e(SID, V)};
+e({'IndAudSignal', N, SID, RID}, V)
+ when (V >= 3) ->
+ {952, N, e(SID, V), e(RID, V)};
+
+e({indAudEventBufferDescriptor, {'IndAudEventBufferDescriptor', EN, SID}}, V)
+ when (V >= 2) ->
+ {960, EN, e(SID, V)};
+e({indAudEventBufferDescriptor, IAEBD}, V)
+ when (V >= 2) ->
+ {961, e(IAEBD, V)};
+e({'IndAudEventBufferDescriptor', EN, SID}, V)
+ when (V >= 2) ->
+ {962, EN, e(SID, V)};
+
+e({indAudEventsDescriptor, {'IndAudEventsDescriptor', RID, N, SID}}, V)
+ when (V >= 2) ->
+ {970, e(RID, V), N, e(SID, V)};
+e({indAudEventsDescriptor, IAED}, V)
+ when (V >= 2) ->
+ {971, e(IAED, V)};
+e({'IndAudEventsDescriptor', RID, N, SID}, V)
+ when (V >= 2) ->
+ {972, e(RID, V), N, e(SID, V)};
+
+e({indAudMediaDescriptor, {'IndAudMediaDescriptor', TSD, S}}, V) when V >= 2 ->
+ {980, e(TSD, V), e(S, V)};
+e({indAudMediaDescriptor, IAMD}, V) when V >= 2 ->
+ {981, e(IAMD, V)};
+e({'IndAudMediaDescriptor', TSD, S}, V) when V >= 2 ->
+ {982, e(TSD, V), e(S, V)};
+
+e({'IndAudTerminationStateDescriptor', PP, EBC, SS}, 2 = V) ->
+ {990, el(PP, V), e(EBC, V), e(SS, V)};
+e({'IndAudTerminationStateDescriptor', PP, EBC, SS, asn1_NOVALUE}, V)
+ when V >= 3 ->
+ {991, el(PP, V), e(EBC, V), e(SS, V)};
+e({'IndAudTerminationStateDescriptor', PP, EBC, SS, SSS}, V)
+ when V >= 3 ->
+ {992, el(PP, V), e(EBC, V), e(SS, V), e(SSS, V)};
+
+e({'IndAudStreamDescriptor', SID, SP}, V) ->
+ {1000, e(SID, V), e(SP, V)};
+
+e({'IndAudStreamParms', LCD, asn1_NOVALUE, asn1_NOVALUE}, 2 = V) ->
+ {1010, e(LCD, V)};
+e({'IndAudStreamParms', LCD, LD, RD}, 2 = V) ->
+ {1011, e(LCD, V), e(LD, V), e(RD, V)};
+e({'IndAudStreamParms', LCD, asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE}, V)
+ when V >= 3 ->
+ {1012, e(LCD, V)};
+e({'IndAudStreamParms', LCD, LD, asn1_NOVALUE, asn1_NOVALUE}, V)
+ when V >= 3 ->
+ {1013, e(LCD, V), e(LD, V)};
+e({'IndAudStreamParms', LCD, LD, RD, asn1_NOVALUE}, V)
+ when V >= 3 ->
+ {1014, e(LCD, V), e(LD, V), e(RD, V)};
+e({'IndAudStreamParms', LCD, LD, RD, SD}, V)
+ when V >= 3 ->
+ {1015, e(LCD, V), e(LD, V), e(RD, V), e(SD, V)};
+
+e({'IndAudLocalControlDescriptor', SM, RV, RG, asn1_NOVALUE}, 2 = V) ->
+ {1020, e(SM, V), e(RV, V), e(RG, V)};
+e({'IndAudLocalControlDescriptor', SM, RV, RG, PP}, 2 = V) when is_list(PP) ->
+ {1021, e(SM, V), e(RV, V), e(RG, V), el(PP, V)};
+e({'IndAudLocalControlDescriptor', SM, RV, RG, asn1_NOVALUE, asn1_NOVALUE}, V)
+ when V >= 3 ->
+ {1022, e(SM, V), e(RV, V), e(RG, V)};
+e({'IndAudLocalControlDescriptor', SM, RV, RG, PP, asn1_NOVALUE}, V)
+ when is_list(PP) andalso (V >= 3) ->
+ {1023, e(SM, V), e(RV, V), e(RG, V), el(PP, V)};
+e({'IndAudLocalControlDescriptor', SM, RV, RG, PP, SMS}, V)
+ when is_list(PP) andalso (V >= 3) ->
+ {1024, e(SM, V), e(RV, V), e(RG, V), el(PP, V), e(SMS, V)};
+
+e({'IndAudPropertyParm', N}, 2 = _V) ->
+ {1030, N};
+e({'IndAudPropertyParm', N, asn1_NOVALUE}, V) when V >= 3 ->
+ {1031, N};
+e({'IndAudPropertyParm', N, PP}, V) when V >= 3 ->
+ {1032, N, e(PP, V)};
+
+e(oneway, _V) ->
+ {1100};
+e(bothway, _V) ->
+ {1101};
+e(isolate, _V) ->
+ {1102};
+e(onewayexternal, _V) ->
+ {1103};
+e(onewayboth, _V) ->
+ {1104};
+
+e(T, _V) ->
+ %% io:format("e(~w) -> ~nT: ~w~n", [_V, T]),
+ T.
+
+
+d({1}, _) ->
+ asn1_NOVALUE;
+d({2}, _V) ->
+ 'NULL';
+d({3}, _V) ->
+ sendRecv;
+d({4}, _V) ->
+ recvOnly;
+d({5}, _V) ->
+ restart;
+d({6}, _) ->
+ mediaToken;
+d({7}, _) ->
+ eventsToken;
+d({8}, _) ->
+ signalsToken;
+d({9}, _) ->
+ digitMapToken;
+d({10}, _) ->
+ statsToken;
+d({11}, _) ->
+ packagesToken;
+d({12}, _V) ->
+ h221;
+d({13}, _V) ->
+ h223;
+d({14}, _V) ->
+ h226;
+d({15}, _V) ->
+ v76;
+
+d({20, Mid, Body}, _) ->
+ {'MegacoMessage', asn1_NOVALUE, {'Message', 1, d(Mid, 1), d(Body, 1)}};
+d({21, Mid, Body}, _) ->
+ {'MegacoMessage', asn1_NOVALUE, {'Message', 2, d(Mid, 2), d(Body, 2)}};
+d({22, V, Mid, Body}, _) ->
+ {'MegacoMessage', asn1_NOVALUE, {'Message', V, d(Mid, V), d(Body, V)}};
+d({23, AuthHeader, Mid, Body}, _) ->
+ {'MegacoMessage', d(AuthHeader, 1), {'Message', 1, d(Mid, 1), d(Body, 1)}};
+d({24, AuthHeader, Mid, Body}, _) ->
+ {'MegacoMessage', d(AuthHeader, 2), {'Message', 2, d(Mid, 2), d(Body, 2)}};
+d({25, V, AuthHeader, Mid, Body}, _) ->
+ {'MegacoMessage', d(AuthHeader, V), {'Message', V, d(Mid, V), d(Body, V)}};
+d({26, AuthHeader, Mess}, V) ->
+ {'MegacoMessage', d(AuthHeader, V), d(Mess, V)};
+d({27, V, Mid, Body}, _) ->
+ {'Message', V, d(Mid, V), d(Body, V)};
+
+d({30, Name}, _V) ->
+ {domainName, {'DomainName', Name, asn1_NOVALUE}};
+d({31, Name, PortNumber}, _V) ->
+ {domainName, {'DomainName', Name, PortNumber}};
+d({32, N}, V) ->
+ {domainName, d(N, V)};
+d({33, Name}, _V) ->
+ {'DomainName', Name, asn1_NOVALUE};
+d({34, Name, PortNumber}, _V) ->
+ {'DomainName', Name, PortNumber};
+d({35, Addr}, _V) ->
+ {ip4Address, {'IP4Address', Addr, asn1_NOVALUE}};
+d({36, Addr, PortNumber}, _V) ->
+ {ip4Address, {'IP4Address', Addr, PortNumber}};
+d({37, A}, V) ->
+ {ip4Address, d(A, V)};
+d({38, Addr}, _V) ->
+ {'IP4Address', Addr, asn1_NOVALUE};
+d({39, Addr, PortNumber}, _V) ->
+ {'IP4Address', Addr, PortNumber};
+d({40, Addr}, _V) ->
+ {ip6Address, {'IP6Address', Addr, asn1_NOVALUE}};
+d({41, Addr, PortNumber}, _V) ->
+ {ip6Address, {'IP6Address', Addr, PortNumber}};
+d({42, A}, V) ->
+ {ip6Address, d(A, V)};
+d({43, Addr}, _V) ->
+ {'IP6Address', Addr, asn1_NOVALUE};
+d({44, Addr, PortNumber}, _V) ->
+ {'IP6Address', Addr, PortNumber};
+
+d({50, Transaction}, V) ->
+ {transactions, [d(Transaction, V)]};
+d({51, Transactions}, V) ->
+ {transactions, dl(Transactions, V)};
+d({52, EC}, _V) ->
+ {messageError, {'ErrorDescriptor', EC, asn1_NOVALUE}};
+d({53, EC, ET}, _V) ->
+ {messageError, {'ErrorDescriptor', EC, ET}};
+d({54, Error}, V) ->
+ {messageError, d(Error, V)};
+d({55, TransId, Actions}, V) ->
+ {transactionRequest, {'TransactionRequest', TransId, dl(Actions, V)}};
+d({56, TransId}, _V) ->
+ {transactionPending, {'TransactionPending', TransId}};
+d({57, TransId, TransRes}, V) ->
+ {transactionReply, {'TransactionReply', TransId, asn1_NOVALUE, d(TransRes, V)}};
+d({58, TransId, TransRes}, V) ->
+ {transactionReply, {'TransactionReply', TransId, 'NULL', d(TransRes, V)}};
+d({59, TransId, ImmAckReq, TransRes}, V) ->
+ {transactionReply, {'TransactionReply', TransId, d(ImmAckReq, V), d(TransRes, V)}};
+d({60, T}, V) ->
+ {transactionResponseAck, dl(T, V)};
+d({61, FirstAck}, _V) ->
+ {'TransactionAck', FirstAck, asn1_NOVALUE};
+d({62, FirstAck, LastAck}, _V) ->
+ {'TransactionAck', FirstAck, LastAck};
+
+d({70, EC}, _V) ->
+ {'ErrorDescriptor', EC, asn1_NOVALUE};
+d({71, EC, ET}, _V) ->
+ {'ErrorDescriptor', EC, ET};
+
+d({80, Cid, CtxReq, CtxAAR, CmdReq}, V) ->
+ {'ActionRequest', Cid, d(CtxReq, V), d(CtxAAR, V), [d(CmdReq, V)]};
+d({81, Cid, CtxReq, CtxAAR, CmdReqs}, V) ->
+ {'ActionRequest', Cid, d(CtxReq, V), d(CtxAAR, V), dl(CmdReqs, V)};
+
+d({90, P, E, T}, V) ->
+ {'ContextRequest', d(P, V), d(E, V), dl(T, V)};
+d({91, P, E, T}, V) ->
+ {'ContextRequest', d(P, V), d(E, V), dl(T, V),
+ asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE};
+d({92, P, E, T, IC}, V) ->
+ {'ContextRequest', d(P, V), d(E, V), dl(T, V),
+ d(IC, V), asn1_NOVALUE, asn1_NOVALUE};
+d({93, P, E, T, IC, CP}, V) ->
+ {'ContextRequest', d(P, V), d(E, V), dl(T, V),
+ d(IC, V), dl(CP, V), asn1_NOVALUE};
+d({94, P, E, T, IC, CP, CL}, V) ->
+ {'ContextRequest', d(P, V), d(E, V), dl(T, V),
+ d(IC, V), dl(CP, V), dl(CL, V)};
+
+d({100, P, E, T}, V) ->
+ {'ContextAttrAuditRequest', d(P, V), d(E, V), d(T, V)};
+d({101, P, E, T}, V) ->
+ {'ContextAttrAuditRequest', d(P, V), d(E, V), d(T, V),
+ asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE};
+d({102, P, E, T, IC}, V) ->
+ {'ContextAttrAuditRequest', d(P, V), d(E, V), d(T, V),
+ d(IC, V), asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE};
+d({103, P, E, T, IC, CPA}, V) ->
+ {'ContextAttrAuditRequest', d(P, V), d(E, V), d(T, V),
+ d(IC, V), dl(CPA, V), asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE};
+d({104, P, E, T, IC, CPA, SP}, V) ->
+ {'ContextAttrAuditRequest', d(P, V), d(E, V), d(T, V),
+ d(IC, V), dl(CPA, V), d(SP, V), asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE};
+d({105, P, E, T, IC, CPA, SP, SE}, V) ->
+ {'ContextAttrAuditRequest', d(P, V), d(E, V), d(T, V),
+ d(IC, V), dl(CPA, V), d(SP, V), d(SE, V), asn1_NOVALUE, asn1_NOVALUE};
+d({106, P, E, T, IC, CPA, SP, SE, SIC}, V) ->
+ {'ContextAttrAuditRequest', d(P, V), d(E, V), d(T, V),
+ d(IC, V), dl(CPA, V), d(SP, V), d(SE, V), d(SIC, V), asn1_NOVALUE};
+d({107, P, E, T, IC, CPA, SP, SE, SIC, SL}, V) ->
+ {'ContextAttrAuditRequest', d(P, V), d(E, V), d(T, V),
+ d(IC, V), dl(CPA, V), d(SP, V), d(SE, V), d(SIC, V), d(SL, V)};
+
+d({110, Cmd}, V) ->
+ {'CommandRequest', d(Cmd, V), asn1_NOVALUE, asn1_NOVALUE};
+d({111, Cmd}, V) ->
+ {'CommandRequest', d(Cmd, V), 'NULL', asn1_NOVALUE};
+d({112, Cmd}, V) ->
+ {'CommandRequest', d(Cmd, V), asn1_NOVALUE, 'NULL'};
+d({113, Cmd}, V) ->
+ {'CommandRequest', d(Cmd, V), 'NULL', 'NULL'};
+d({114, Cmd, Opt, WR}, V) ->
+ {'CommandRequest', d(Cmd, V), d(Opt, V), d(WR, V)};
+
+d({120, From, To, Dir}, 1 = V) ->
+ {'TopologyRequest', d(From, V), d(To, V), d(Dir, V)};
+d({121, From, To, Dir, SID}, 2 = V) ->
+ {'TopologyRequest', d(From, V), d(To, V), d(Dir, V), d(SID, V)};
+d({122, From, To, Dir, SID}, V) when (V >= 3) ->
+ {'TopologyRequest', d(From, V), d(To, V), d(Dir, V), d(SID, V), asn1_NOVALUE};
+d({123, From, To, Dir, SID, TDE}, V) when (V >= 3) ->
+ {'TopologyRequest', d(From, V), d(To, V), d(Dir, V), d(SID, V), d(TDE, V)};
+
+d({130, TID}, V) ->
+ {modReq, {'AmmRequest', dl(TID, V), []}};
+d({131, TID, Desc}, V) ->
+ {modReq, {'AmmRequest', dl(TID, V), [d(Desc, V)]}};
+d({132, TID, Descs}, V) ->
+ {modReq, {'AmmRequest', dl(TID, V), dl(Descs, V)}};
+d({133, TID}, V) ->
+ {addReq, {'AmmRequest', dl(TID, V), []}};
+d({134, TID, Desc}, V) ->
+ {addReq, {'AmmRequest', dl(TID, V), [d(Desc, V)]}};
+d({135, TID, Descs}, V) ->
+ {addReq, {'AmmRequest', dl(TID, V), dl(Descs, V)}};
+d({136, TID, Descs}, V) ->
+ {'AmmRequest', dl(TID, V), dl(Descs, V)};
+
+d({140, TID}, V) ->
+ {subtractReq, {'SubtractRequest', dl(TID, V), asn1_NOVALUE}};
+d({141, TID, AudDesc}, V) ->
+ {subtractReq, {'SubtractRequest', dl(TID, V), d(AudDesc, V)}};
+d({142, TID}, V) ->
+ {'SubtractRequest', dl(TID, V), asn1_NOVALUE};
+d({143, TID, AudDesc}, V) ->
+ {'SubtractRequest', dl(TID, V), d(AudDesc, V)};
+
+d({150, AR}, V) ->
+ {auditValueRequest, d(AR, V)};
+
+d({160, TID, AudDesc}, V) when V < 3 ->
+ {'AuditRequest', d(TID, V), d(AudDesc, V)};
+d({161, TID, AudDesc}, V) when V >= 3 ->
+ {'AuditRequest', d(TID, V), d(AudDesc, V), asn1_NOVALUE};
+d({162, TID, AudDesc, TIDs}, V) when V >= 3 ->
+ {'AuditRequest', d(TID, V), d(AudDesc, V), dl(TIDs, V)};
+
+d({170, AR}, V) ->
+ {actionReplies, [d(AR, V)]};
+d({171, ARs}, V) ->
+ {actionReplies, dl(ARs, V)};
+
+d({180, CID, CmdRep}, V) ->
+ {'ActionReply', CID, asn1_NOVALUE, asn1_NOVALUE, [d(CmdRep, V)]};
+d({181, CID, CmdRep}, V) ->
+ {'ActionReply', CID, asn1_NOVALUE, asn1_NOVALUE, dl(CmdRep, V)};
+d({182, CID, CtxRep, CmdRep}, V) ->
+ {'ActionReply', CID, asn1_NOVALUE, d(CtxRep, V), [d(CmdRep, V)]};
+d({183, CID, CtxRep, CmdRep}, V) ->
+ {'ActionReply', CID, asn1_NOVALUE, d(CtxRep, V), dl(CmdRep, V)};
+d({184, CID, ED, CmdRep}, V) ->
+ {'ActionReply', CID, d(ED, V), asn1_NOVALUE, [d(CmdRep, V)]};
+d({185, CID, ED, CmdRep}, V) ->
+ {'ActionReply', CID, d(ED, V), asn1_NOVALUE, dl(CmdRep, V)};
+d({186, CID, ED, CtxRep, CmdRep}, V) ->
+ {'ActionReply', CID, d(ED, V), d(CtxRep, V), [d(CmdRep, V)]};
+d({187, CID, ED, CtxRep, CmdRep}, V) ->
+ {'ActionReply', CID, d(ED, V), d(CtxRep, V), dl(CmdRep, V)};
+
+d({190}, 1 = _V) ->
+ {'AuditDescriptor', asn1_NOVALUE};
+d({191, AT}, 1 = V) ->
+ {'AuditDescriptor', dl(AT, V)};
+d({192}, V) when (V >= 2) ->
+ {'AuditDescriptor', asn1_NOVALUE, asn1_NOVALUE};
+d({193, AT, APT}, V) when is_list(AT) andalso is_list(APT) andalso (V >= 2) ->
+ {'AuditDescriptor', dl(AT, V), dl(APT, V)};
+d({194, AT, APT}, V) when is_list(APT) andalso (V >= 2) ->
+ {'AuditDescriptor', d(AT, V), dl(APT, V)};
+d({195, AT, APT}, V) when is_list(AT) andalso (V >= 2) ->
+ {'AuditDescriptor', dl(AT, V), d(APT, V)};
+d({196, AT, APT}, V) when (V >= 2) ->
+ {'AuditDescriptor', d(AT, V), d(APT, V)};
+
+d({200, TID, OED}, V) ->
+ {notifyReq, {'NotifyRequest', dl(TID, V), d(OED, V), asn1_NOVALUE}};
+d({201, TID, OED, ED}, V) ->
+ {notifyReq, {'NotifyRequest', dl(TID, V), d(OED, V), d(ED, V)}};
+d({202, TID, OED}, V) ->
+ {'NotifyRequest', dl(TID, V), d(OED, V), asn1_NOVALUE};
+d({203, TID, OED, ED}, V) ->
+ {'NotifyRequest', dl(TID, V), d(OED, V), d(ED, V)};
+
+d({210, RID, OEL}, V) ->
+ {'ObservedEventsDescriptor', RID, dl(OEL, V)};
+
+d({220, EN, SID, EPL, TN}, V) ->
+ {'ObservedEvent', EN, d(SID, V), dl(EPL, V), d(TN, V)};
+
+d({230}, _V) ->
+ {'EventParameter', "type", ["est"], asn1_NOVALUE};
+d({231, Val}, _V) ->
+ {'EventParameter', "type", [Val], asn1_NOVALUE};
+d({232, Val}, _V) ->
+ {'EventParameter', "type", Val, asn1_NOVALUE};
+d({233}, _V) ->
+ {'EventParameter', "Generalcause", ["NR"], asn1_NOVALUE};
+d({234}, _V) ->
+ {'EventParameter', "Generalcause", ["UR"], asn1_NOVALUE};
+d({235}, _V) ->
+ {'EventParameter', "Generalcause", ["FT"], asn1_NOVALUE};
+d({236}, _V) ->
+ {'EventParameter', "Generalcause", ["FP"], asn1_NOVALUE};
+d({237}, _V) ->
+ {'EventParameter', "Generalcause", ["IW"], asn1_NOVALUE};
+d({238}, _V) ->
+ {'EventParameter', "Generalcause", ["UN"], asn1_NOVALUE};
+d({239, Val}, _V) ->
+ {'EventParameter', "Generalcause", [Val], asn1_NOVALUE};
+d({240, Val}, _V) ->
+ {'EventParameter', "Generalcause", Val, asn1_NOVALUE};
+d({241, Val}, _V) ->
+ {'EventParameter', "Failurecause", [Val], asn1_NOVALUE};
+d({242, Val}, _V) ->
+ {'EventParameter', "Failurecause", Val, asn1_NOVALUE};
+d({243, EPN, Val}, _V) ->
+ {'EventParameter', EPN, Val, asn1_NOVALUE};
+d({244, EPN, Val, EI}, _V) ->
+ {'EventParameter', EPN, Val, EI};
+
+d({260, TID, SCPs}, V) ->
+ {serviceChangeReq, {'ServiceChangeRequest', dl(TID, V), d(SCPs, V)}};
+d({261, SCR}, V) ->
+ {serviceChangeReq, d(SCR, V)};
+d({262, TID, SCPs}, V) ->
+ {'ServiceChangeRequest', dl(TID, V), d(SCPs, V)};
+
+d({270, TID, SCR}, V) ->
+ {serviceChangeReply, {'ServiceChangeReply', dl(TID, V), d(SCR, V)}};
+d({271, SCR}, V) ->
+ {serviceChangeReply, d(SCR, V)};
+d({272, TID, SCR}, V) -> %% KOLLA
+ {'ServiceChangeReply', dl(TID, V), d(SCR, V)};
+
+d({280, TSD, S}, V) ->
+ {mediaDescriptor, {'MediaDescriptor', d(TSD, V), d(S, V)}};
+d({281, MD}, V) ->
+ {mediaDescriptor, d(MD, V)};
+d({282, TSD, S}, V) ->
+ {'MediaDescriptor', d(TSD, V), d(S, V)};
+
+d({290, S}, V) ->
+ {oneStream, d(S, V)};
+d({291, S}, V) ->
+ {multiStream, dl(S, V)};
+d({292, SID, SP}, V) ->
+ {'StreamDescriptor', d(SID, V), d(SP, V)};
+
+d({300, LCD}, V) ->
+ {'StreamParms', d(LCD, V), asn1_NOVALUE, asn1_NOVALUE};
+d({301, LCD, LD}, V) ->
+ {'StreamParms', d(LCD, V), d(LD, V), asn1_NOVALUE};
+d({302, LCD, LD, RD}, V) ->
+ {'StreamParms', d(LCD, V), d(LD, V), d(RD, V)};
+
+d({303, LCD}, V)
+ when V >= 3 ->
+ {'StreamParms', d(LCD, V), asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE};
+d({304, LCD, LD}, V)
+ when V >= 3 ->
+ {'StreamParms', d(LCD, V), d(LD, V), asn1_NOVALUE, asn1_NOVALUE};
+d({305, LCD, LD, RD}, V)
+ when V >= 3 ->
+ {'StreamParms', d(LCD, V), d(LD, V), d(RD, V), asn1_NOVALUE};
+d({306, LCD, LD, RD, SD}, V)
+ when V >= 3 ->
+ {'StreamParms', d(LCD, V), d(LD, V), d(RD, V), dl(SD, V)};
+
+d({310, SM, RV, RG, PP}, V) ->
+ {'LocalControlDescriptor', d(SM, V), d(RV, V), d(RG, V), dl(PP, V)};
+
+d({320, Val}, _V) ->
+ {'PropertyParm', "v", [Val], asn1_NOVALUE};
+d({321, Val}, _V) ->
+ {'PropertyParm', "v", Val, asn1_NOVALUE};
+d({332, Val}, _V) ->
+ {'PropertyParm', "o", [Val], asn1_NOVALUE};
+d({333, Val}, _V) ->
+ {'PropertyParm', "o", Val, asn1_NOVALUE};
+d({334, Val}, _V) ->
+ {'PropertyParm', "s", [Val], asn1_NOVALUE};
+d({335, Val}, _V) ->
+ {'PropertyParm', "s", Val, asn1_NOVALUE};
+d({336, Val}, _V) ->
+ {'PropertyParm', "i", [Val], asn1_NOVALUE};
+d({337, Val}, _V) ->
+ {'PropertyParm', "i", Val, asn1_NOVALUE};
+d({338, Val}, _V) ->
+ {'PropertyParm', "u", [Val], asn1_NOVALUE};
+d({339, Val}, _V) ->
+ {'PropertyParm', "u", Val, asn1_NOVALUE};
+d({340, Val}, _V) ->
+ {'PropertyParm', "e", [Val], asn1_NOVALUE};
+d({341, Val}, _V) ->
+ {'PropertyParm', "e", Val, asn1_NOVALUE};
+d({342, Val}, _V) ->
+ {'PropertyParm', "p", [Val], asn1_NOVALUE};
+d({343, Val}, _V) ->
+ {'PropertyParm', "p", Val, asn1_NOVALUE};
+d({344, Val}, _V) ->
+ {'PropertyParm', "c", [Val], asn1_NOVALUE};
+d({345, Val}, _V) ->
+ {'PropertyParm', "c", Val, asn1_NOVALUE};
+d({346, Val}, _V) ->
+ {'PropertyParm', "b", [Val], asn1_NOVALUE};
+d({347, Val}, _V) ->
+ {'PropertyParm', "b", Val, asn1_NOVALUE};
+d({348, Val}, _V) ->
+ {'PropertyParm', "z", [Val], asn1_NOVALUE};
+d({349, Val}, _V) ->
+ {'PropertyParm', "z", Val, asn1_NOVALUE};
+d({350, Val}, _V) ->
+ {'PropertyParm', "k", [Val], asn1_NOVALUE};
+d({351, Val}, _V) ->
+ {'PropertyParm', "k", Val, asn1_NOVALUE};
+d({352, Val}, _V) ->
+ {'PropertyParm', "a", [Val], asn1_NOVALUE};
+d({353, Val}, _V) ->
+ {'PropertyParm', "a", Val, asn1_NOVALUE};
+d({354, Val}, _V) ->
+ {'PropertyParm', "t", [Val], asn1_NOVALUE};
+d({355, Val}, _V) ->
+ {'PropertyParm', "t", Val, asn1_NOVALUE};
+d({356, Val}, _V) ->
+ {'PropertyParm', "r", [Val], asn1_NOVALUE};
+d({357, Val}, _V) ->
+ {'PropertyParm', "r", Val, asn1_NOVALUE};
+d({358, Val}, _V) ->
+ {'PropertyParm', "m", [Val], asn1_NOVALUE};
+d({359, Val}, _V) ->
+ {'PropertyParm', "m", Val, asn1_NOVALUE};
+d({360, Val}, _V) ->
+ {'PropertyParm', "nt/jit", [Val], asn1_NOVALUE};
+d({361, Val}, _V) ->
+ {'PropertyParm', "nt/jit", Val, asn1_NOVALUE};
+d({362}, _V) ->
+ {'PropertyParm', "tdmc/ec", ["on"], asn1_NOVALUE};
+d({363}, _V) ->
+ {'PropertyParm', "tdmc/ec", ["off"], asn1_NOVALUE};
+d({364}, _V) ->
+ {'PropertyParm', "tdmc/gain", ["automatic"], asn1_NOVALUE};
+d({365, Val}, _V) ->
+ {'PropertyParm', "tdmc/gain", [Val], asn1_NOVALUE};
+d({366, Val}, _V) ->
+ {'PropertyParm', "tdmc/gain", Val, asn1_NOVALUE};
+d({367, Val}, _V) ->
+ {'PropertyParm', "maxNumberOfContexts", [Val], asn1_NOVALUE};
+d({368, Val}, _V) ->
+ {'PropertyParm', "maxNumberOfContexts", Val, asn1_NOVALUE};
+d({369, Val}, _V) ->
+ {'PropertyParm', "maxTerminationsPerContext", [Val], asn1_NOVALUE};
+d({370, Val}, _V) ->
+ {'PropertyParm', "maxTerminationsPerContext", Val, asn1_NOVALUE};
+d({371, Val}, _V) ->
+ {'PropertyParm', "normalMGExecutionTime", [Val], asn1_NOVALUE};
+d({372, Val}, _V) ->
+ {'PropertyParm', "normalMGExecutionTime", Val, asn1_NOVALUE};
+d({373, Val}, _V) ->
+ {'PropertyParm', "normalMGCExecutionTime", [Val], asn1_NOVALUE};
+d({374, Val}, _V) ->
+ {'PropertyParm', "normalMGCExecutionTime", Val, asn1_NOVALUE};
+d({375, Val}, _V) ->
+ {'PropertyParm', "MGProvisionalResponseTimerValue", [Val], asn1_NOVALUE};
+d({376, Val}, _V) ->
+ {'PropertyParm', "MGProvisionalResponseTimerValue", Val, asn1_NOVALUE};
+d({377, Val}, _V) ->
+ {'PropertyParm', "MGCProvisionalResponseTimerValue", [Val], asn1_NOVALUE};
+d({378, Val}, _V) ->
+ {'PropertyParm', "MGCProvisionalResponseTimerValue", Val, asn1_NOVALUE};
+d({379, N, Val}, _V) ->
+ {'PropertyParm', N, [Val], asn1_NOVALUE};
+d({380, N, Val}, _V) ->
+ {'PropertyParm', N, Val, asn1_NOVALUE};
+d({381, N, Val, EI}, _V) ->
+ {'PropertyParm', N, Val, EI};
+
+d({400, PG}, V) ->
+ {'LocalRemoteDescriptor', [[d(PG, V)]]};
+d({401, PG}, V) ->
+ {'LocalRemoteDescriptor', [dl(PG, V)]};
+d({402, PG}, V) ->
+ {'LocalRemoteDescriptor', dll(PG, V)};
+
+d({410, PP, EBC, SS}, V) ->
+ {'TerminationStateDescriptor', dl(PP, V), d(EBC, V), d(SS, V)};
+
+d({420, RID, E}, V) ->
+ {eventsDescriptor, {'EventsDescriptor', d(RID, V), [d(E, V)]}};
+d({421, RID, EL}, V) ->
+ {eventsDescriptor, {'EventsDescriptor', d(RID, V), dl(EL, V)}};
+d({422, ED}, V) ->
+ {eventsDescriptor, d(ED, V)};
+d({423, RID, E}, V) ->
+ {'EventsDescriptor', d(RID, V), [d(E, V)]};
+d({424, RID, EL}, V) ->
+ {'EventsDescriptor', d(RID, V), dl(EL, V)};
+
+d({425, PN, SID, EA, EPL}, V) ->
+ {'RequestedEvent', PN, d(SID, V), d(EA, V), dl(EPL, V)};
+
+d({430, SED, SD}, V) ->
+ {'RegulatedEmbeddedDescriptor', d(SED, V), dl(SD, V)};
+
+d({435, NI}, V) ->
+ {notifyImmediate, d(NI, V)};
+d({436, NR}, V) ->
+ {notifyRegulated, d(NR, V)};
+d({437, NN}, V) ->
+ {neverNotify, d(NN, V)};
+
+d({440, KA, EDM, SE, SD}, V) ->
+ {'RequestedActions', d(KA, V), d(EDM, V), d(SE, V), d(SD, V)};
+d({441, KA, EDM, SE, SD}, V)
+ when V >= 3 ->
+ {'RequestedActions', d(KA, V), d(EDM, V), d(SE, V), d(SD, V),
+ asn1_NOVALUE, asn1_NOVALUE};
+d({442, KA, EDM, SE, SD, NB}, V)
+ when V >= 3 ->
+ {'RequestedActions', d(KA, V), d(EDM, V), d(SE, V), d(SD, V),
+ d(NB, V), asn1_NOVALUE};
+d({443, KA, EDM, SE, SD, NB, RED}, V)
+ when V >= 3 ->
+ {'RequestedActions', d(KA, V), d(EDM, V), d(SE, V), d(SD, V),
+ d(NB, V), d(RED, V)};
+
+d({450, RID, E}, V) ->
+ {'SecondEventsDescriptor', d(RID, V), [d(E, V)]};
+d({451, RID, EL}, V) ->
+ {'SecondEventsDescriptor', d(RID, V), dl(EL, V)};
+
+d({460, PN, SID, EA, EPL}, V) ->
+ {'SecondRequestedEvent', PN, d(SID, V), d(EA, V), d(EPL, V)};
+
+d({470, KA, EDM, SD}, V) ->
+ {'SecondRequestedActions', d(KA, V), d(EDM, V), d(SD, V)};
+d({471, KA, EDM, SD}, V)
+ when V >= 3 ->
+ {'SecondRequestedActions', d(KA, V), d(EDM, V), d(SD, V),
+ asn1_NOVALUE, asn1_NOVALUE};
+d({472, KA, EDM, SD, NB}, V)
+ when V >= 3 ->
+ {'SecondRequestedActions', d(KA, V), d(EDM, V), d(SD, V),
+ d(NB, V), asn1_NOVALUE};
+d({473, KA, EDM, SD, NB, RED}, V)
+ when V >= 3 ->
+ {'SecondRequestedActions', d(KA, V), d(EDM, V), d(SD, V),
+ d(NB, V), d(RED, V)};
+
+d({480, EN, SID, EPL}, V) ->
+ {'EventSpec', EN, d(SID, V), dl(EPL, V)};
+
+d({490, ID, SL}, V) ->
+ {'SeqSigList', ID, dl(SL, V)};
+
+d({500, S}, V) ->
+ {signalsDescriptor, dl(S, V)};
+
+d({510, S}, V) ->
+ {signal, d(S, V)};
+
+d({520, SN, SID, ST, D, NC, KA, SPL}, V) ->
+ {'Signal',
+ SN, d(SID, V), d(ST, V), d(D, V), d(NC, V), d(KA, V), dl(SPL, V)};
+d({521, SN, SID, ST, D, NC, KA, SPL}, V)
+ when V >= 3 ->
+ {'Signal',
+ SN, d(SID, V), d(ST, V), d(D, V), d(NC, V), d(KA, V), dl(SPL, V),
+ asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE};
+d({522, SN, SID, ST, D, NC, KA, SPL, SD}, V)
+ when V >= 3 ->
+ {'Signal',
+ SN, d(SID, V), d(ST, V), d(D, V), d(NC, V), d(KA, V), dl(SPL, V),
+ d(SD, V), asn1_NOVALUE, asn1_NOVALUE};
+d({523, SN, SID, ST, D, NC, KA, SPL, SD, RID}, V)
+ when V >= 3 ->
+ {'Signal',
+ SN, d(SID, V), d(ST, V), d(D, V), d(NC, V), d(KA, V), dl(SPL, V),
+ d(SD, V), d(RID, V), asn1_NOVALUE};
+d({524, SN, SID, ST, D, NC, KA, SPL, SD, RID, IsD}, V)
+ when V >= 3 ->
+ {'Signal',
+ SN, d(SID, V), d(ST, V), d(D, V), d(NC, V), d(KA, V), dl(SPL, V),
+ d(SD, V), d(RID, V), d(IsD, V)};
+
+d({530, SPN, Val}, _V) ->
+ {'SigParameter', SPN, Val, asn1_NOVALUE};
+d({531, SPN, Val, EI}, _V) ->
+ {'SigParameter', SPN, Val, EI};
+
+d({550, MD}, V) ->
+ {modemDescriptor, d(MD, V)};
+d({551, MTL, MPL}, _V) ->
+ {'ModemDescriptor', MTL, MPL, asn1_NOVALUE};
+d({552, MTL, MPL, NSD}, _V) ->
+ {'ModemDescriptor', MTL, MPL, NSD};
+
+d({560, DMN, DMV}, V) ->
+ {digitMapDescriptor, {'DigitMapDescriptor', DMN, d(DMV, V)}};
+d({561, DMD}, V) ->
+ {digitMapDescriptor, d(DMD, V)};
+d({562, DMN, DMV}, V) ->
+ {'DigitMapDescriptor', DMN, d(DMV, V)};
+
+d({570, Start, Stop, Long, DMB}, 1 = V) ->
+ {'DigitMapValue', d(Start, V), d(Stop, V), d(Long, V), DMB};
+d({571, Start, Stop, Long, DMB, Dur}, V) when V >= 2 ->
+ {'DigitMapValue', d(Start, V), d(Stop, V), d(Long, V), DMB, d(Dur, V)};
+
+d({580, M, A, Ver, Prof, R, D, Id}, V) ->
+ {'ServiceChangeParm',
+ d(M, V), d(A, V), d(Ver, V), d(Prof, V), R, d(D, V), d(Id, V),
+ asn1_NOVALUE, asn1_NOVALUE};
+d({581, M, A, Ver, Prof, R, D, Id, TS}, V) ->
+ {'ServiceChangeParm',
+ d(M, V), d(A, V), d(Ver, V), d(Prof, V), R, d(D, V), d(Id, V),
+ d(TS, V), asn1_NOVALUE};
+d({582, M, A, Ver, Prof, R, D, Id, TS, NSD}, V) ->
+ {'ServiceChangeParm',
+ d(M, V), d(A, V), d(Ver, V), d(Prof, V), R, d(D, V), d(Id, V),
+ d(TS, V), NSD};
+
+d({583, M, A, Ver, Prof, R, D, Id, TS, NSD}, V)
+ when V == 2 ->
+ {'ServiceChangeParm',
+ d(M, V), d(A, V), d(Ver, V), d(Prof, V), R, d(D, V), d(Id, V),
+ d(TS, V), NSD, asn1_NOVALUE};
+d({584, M, A, Ver, Prof, R, D, Id, TS, NSD, Info}, V)
+ when V == 2 ->
+ {'ServiceChangeParm',
+ d(M, V), d(A, V), d(Ver, V), d(Prof, V), R, d(D, V), d(Id, V),
+ d(TS, V), NSD, d(Info, V)};
+
+d({585, M, A, Ver, Prof, R, D, Id, TS, NSD}, V)
+ when V >= 3 ->
+ {'ServiceChangeParm',
+ d(M, V), d(A, V), d(Ver, V), d(Prof, V), R, d(D, V), d(Id, V),
+ d(TS, V), NSD, asn1_NOVALUE, asn1_NOVALUE};
+d({586, M, A, Ver, Prof, R, D, Id, TS, NSD, Info}, V)
+ when V >= 3 ->
+ {'ServiceChangeParm',
+ d(M, V), d(A, V), d(Ver, V), d(Prof, V), R, d(D, V), d(Id, V),
+ d(TS, V), NSD, d(Info, V), asn1_NOVALUE};
+d({587, M, A, Ver, Prof, R, D, Id, TS, NSD, Info, Flag}, V)
+ when V >= 3 ->
+ {'ServiceChangeParm',
+ d(M, V), d(A, V), d(Ver, V), d(Prof, V), R, d(D, V), d(Id, V),
+ d(TS, V), NSD, d(Info, V), d(Flag, V)};
+
+d({590, Id, A, Ver, Prof, TS}, V) ->
+ {serviceChangeResParms, {'ServiceChangeResParm', Id, d(A, V), Ver, d(Prof, V), TS}};
+d({591, SCRP}, V) ->
+ {serviceChangeResParms, d(SCRP, V)};
+d({592, Id, A, Ver, Prof, TS}, V) ->
+ {'ServiceChangeResParm', Id, d(A, V), Ver, d(Prof, V), TS};
+
+d({600, N}, _V) ->
+ {portNumber, N};
+
+d({610, D, T}, _V) ->
+ {'TimeNotation', D, T};
+
+d({620, N, Ver}, _V) ->
+ {'ServiceChangeProfile', N, Ver};
+
+d({630, N}, _) ->
+ {digitMapName, N};
+
+d({640, Id}, _V) ->
+ {megaco_term_id, false, Id};
+d({641}, _V) ->
+ {megaco_term_id, true, [[$*]]};
+d({642}, _V) ->
+ {megaco_term_id, true, [[$$]]};
+d({643, Id}, _V) ->
+ {megaco_term_id, true, Id};
+d({644, W, ID}, _V) ->
+ {'TerminationID', W, ID};
+
+d({650, TID}, V) ->
+ {modReply, {'AmmsReply', dl(TID, V), asn1_NOVALUE}};
+d({651, TID, TA}, V) ->
+ {modReply, {'AmmsReply', dl(TID, V), [d(TA, V)]}};
+d({652, TID, TA}, V) ->
+ {modReply, {'AmmsReply', dl(TID, V), dl(TA, V)}};
+d({653, R}, V) ->
+ {modReply, d(R, V)};
+
+d({655, AR}, V) ->
+ {moveReply, d(AR, V)};
+
+d({660, TID}, V) ->
+ {addReply, {'AmmsReply', dl(TID, V), asn1_NOVALUE}};
+d({661, TID, TA}, V) ->
+ {addReply, {'AmmsReply', dl(TID, V), [d(TA, V)]}};
+d({662, TID, TA}, V) ->
+ {addReply, {'AmmsReply', dl(TID, V), dl(TA, V)}};
+d({663, R}, V) ->
+ {addReply, d(R, V)};
+
+d({670, TID}, V) ->
+ {subtractReply, {'AmmsReply', dl(TID, V), asn1_NOVALUE}};
+d({671, TID, TA}, V) ->
+ {subtractReply, {'AmmsReply', dl(TID, V), [d(TA, V)]}};
+d({672, TID, TA}, V) ->
+ {subtractReply, {'AmmsReply', dl(TID, V), dl(TA, V)}};
+d({673, R}, V) ->
+ {subtractReply, d(R, V)};
+
+d({680, TID}, V) ->
+ {'AmmsReply', dl(TID, V), asn1_NOVALUE};
+d({681, TID, TA}, V) ->
+ {'AmmsReply', dl(TID, V), [d(TA, V)]};
+d({682, TID, TA}, V) ->
+ {'AmmsReply', dl(TID, V), dl(TA, V)};
+
+d({690, TID}, V) ->
+ {notifyReply, {'NotifyReply', dl(TID, V), asn1_NOVALUE}};
+d({691, TID, ED}, V) ->
+ {notifyReply, {'NotifyReply', dl(TID, V), d(ED, V)}};
+d({692, R}, V) ->
+ {notifyReply, d(R, V)};
+d({693, TID}, V) ->
+ {'NotifyReply', dl(TID, V), asn1_NOVALUE};
+d({694, TID, ED}, V) ->
+ {'NotifyReply', dl(TID, V), d(ED, V)};
+
+d({700, AVR}, V) ->
+ {auditValueReply, d(AVR, V)};
+
+d({705, TIDs}, V) ->
+ {contextAuditResult, dl(TIDs, V)};
+
+d({710, TID, TAR}, V) ->
+ {auditResult, {'AuditResult', d(TID, V), [d(TAR, V)]}};
+d({711, TID, TAR}, V) ->
+ {auditResult, {'AuditResult', d(TID, V), dl(TAR, V)}};
+d({712, AR}, V) ->
+ {auditResult, d(AR, V)};
+d({713, TID, TAR}, V) ->
+ {'AuditResult', d(TID, V), [d(TAR, V)]};
+d({714, TID, TAR}, V) ->
+ {'AuditResult', d(TID, V), dl(TAR, V)};
+
+d({715, TIDs, [TAR]}, V) ->
+ {auditResultTermList, {'TermListAuditResult', dl(TIDs, V), [d(TAR, V)]}};
+d({716, TIDs, TAR}, V) ->
+ {auditResultTermList, {'TermListAuditResult', dl(TIDs, V), dl(TAR, V)}};
+
+d({720, PsD}, V) ->
+ {packagesDescriptor, dl(PsD, V)};
+
+d({730}, _V) ->
+ {'PackagesItem', "g", 1};
+d({731}, _V) ->
+ {'PackagesItem', "tonegen", 1};
+d({732}, _V) ->
+ {'PackagesItem', "tonedet", 1};
+d({733}, _V) ->
+ {'PackagesItem', "tg", 1};
+d({734}, _V) ->
+ {'PackagesItem', "dd", 1};
+d({735}, _V) ->
+ {'PackagesItem', "cg", 1};
+d({736}, _V) ->
+ {'PackagesItem', "cd", 1};
+d({737}, _V) ->
+ {'PackagesItem', "al", 1};
+d({738}, _V) ->
+ {'PackagesItem', "ct", 1};
+d({739}, _V) ->
+ {'PackagesItem', "nt", 1};
+d({740}, _V) ->
+ {'PackagesItem', "rtp", 1};
+d({741}, _V) ->
+ {'PackagesItem', "tdmc", 1};
+d({742, Name, Ver}, _V) ->
+ {'PackagesItem', Name, Ver};
+
+d({760, AD}, V) ->
+ {emptyDescriptors, d(AD, V)};
+
+d({770, SD}, V) ->
+ {statisticsDescriptor, [d(SD, V)]};
+d({771, SsD}, V) ->
+ {statisticsDescriptor, dl(SsD, V)};
+
+d({780, Name}, _V) ->
+ {'StatisticsParameter', Name, asn1_NOVALUE};
+d({781, Name, Value}, _V) ->
+ {'StatisticsParameter', Name, Value};
+
+d({800, MT, TL}, V) ->
+ {'MuxDescriptor', d(MT, V), dl(TL, V), asn1_NOVALUE};
+d({801, MT, TL, NSD}, V) ->
+ {'MuxDescriptor', d(MT, V), dl(TL, V), NSD};
+
+d({900, N, Ver}, V) when (V >= 2) ->
+ {indAudPackagesDescriptor, {'IndAudPackagesDescriptor', N, Ver}};
+d({900, IAPD}, V) when (V >= 2) ->
+ {indAudPackagesDescriptor, d(IAPD, V)};
+d({901, N, Ver}, V) when (V >= 2) ->
+ {'IndAudPackagesDescriptor', N, Ver};
+
+d({910, N}, V) when (V >= 2) ->
+ {indAudStatisticsDescriptor, {'IndAudStatisticsDescriptor', N}};
+d({911, IASD}, V) when (V >= 2) ->
+ {indAudStatisticsDescriptor, d(IASD, V)};
+d({912, N}, V) when (V >= 2) ->
+ {'IndAudStatisticsDescriptor', N};
+
+d({920, DMN}, V) when (V >= 2) ->
+ {indAudDigitMapDescriptor, {'IndAudDigitMapDescriptor', DMN}};
+d({921, IADMD}, V) when (V >= 2) ->
+ {indAudDigitMapDescriptor, d(IADMD, V)};
+d({922, DMN}, V) when (V >= 2) ->
+ {'IndAudDigitMapDescriptor', DMN};
+
+d({930, IASD}, V) when (V >= 2) ->
+ {indAudSignalsDescriptor, {seqSigList, d(IASD, V)}};
+d({931, IAS}, V) when (V >= 2) ->
+ {indAudSignalsDescriptor, {signal, d(IAS, V)}};
+
+d({940, Id, SL}, V) when (V >= 2) ->
+ {'IndAudSeqSigList', Id, d(SL, V)};
+
+d({950, N, SID}, 2 = V) ->
+ {'IndAudSignal', N, d(SID, V)};
+d({951, N, SID}, V) when (V >= 3) ->
+ {'IndAudSignal', N, d(SID, V), asn1_NOVALUE};
+d({952, N, SID, RID}, V) when (V >= 3) ->
+ {'IndAudSignal', N, d(SID, V), d(RID, V)};
+
+d({960, EN, SID}, V) when (V >= 2) ->
+ {indAudEventBufferDescriptor,
+ {'IndAudEventBufferDescriptor', EN, d(SID, V)}};
+d({961, IAEBD}, V) when (V >= 2) ->
+ {indAudEventBufferDescriptor, d(IAEBD, V)};
+d({962, EN, SID}, V) when (V >= 2) ->
+ {'IndAudEventBufferDescriptor', EN, d(SID, V)};
+
+d({970, RID, N, SID}, V) when (V >= 2) ->
+ {indAudEventsDescriptor,
+ {'IndAudEventsDescriptor', d(RID, V), N, d(SID, V)}};
+d({971, IAED}, V) when (V >= 2) ->
+ {indAudEventsDescriptor, d(IAED, V)};
+d({972, RID, N, SID}, V) when (V >= 2) ->
+ {'IndAudEventsDescriptor', d(RID, V), N, d(SID, V)};
+
+d({980, TSD, S}, V) when (V >= 2) ->
+ {indAudMediaDescriptor, {'IndAudMediaDescriptor', d(TSD, V), d(S, V)}};
+d({981, IAMD}, V) when (V >= 2) ->
+ {indAudMediaDescriptor, d(IAMD, V)};
+d({982, TSD, S}, V) when (V >= 2) ->
+ {'IndAudMediaDescriptor', d(TSD, V), d(S, V)};
+
+d({990, PP, EBC, SS}, 2 = V) ->
+ {'IndAudTerminationStateDescriptor', dl(PP, V), d(EBC, V), d(SS, V)};
+d({991, PP, EBC, SS}, V) when V >= 3 ->
+ {'IndAudTerminationStateDescriptor', dl(PP, V), d(EBC, V), d(SS, V),
+ asn1_NOVALUE};
+d({992, PP, EBC, SS, SSS}, V) when V >= 3 ->
+ {'IndAudTerminationStateDescriptor', dl(PP, V), d(EBC, V), d(SS, V),
+ d(SSS, V)};
+
+d({1000, SID, SP}, V) ->
+ {'IndAudStreamDescriptor', d(SID, V), d(SP, V)};
+
+d({1010, LCD}, 2 = V) ->
+ {'IndAudStreamParms', d(LCD, V), asn1_NOVALUE, asn1_NOVALUE};
+d({1011, LCD, LD, RD}, 2 = V) ->
+ {'IndAudStreamParms', d(LCD, V), d(LD, V), d(RD, V)};
+d({1012, LCD}, V) when V >= 3 ->
+ {'IndAudStreamParms', d(LCD, V), asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE};
+d({1013, LCD, LD}, V) when V >= 3 ->
+ {'IndAudStreamParms', d(LCD, V), d(LD, V), asn1_NOVALUE, asn1_NOVALUE};
+d({1014, LCD, LD, RD}, V) when V >= 3 ->
+ {'IndAudStreamParms', d(LCD, V), d(LD, V), d(RD, V), asn1_NOVALUE};
+d({1015, LCD, LD, RD, SD}, V) when V >= 3 ->
+ {'IndAudStreamParms', d(LCD, V), d(LD, V), d(RD, V), d(SD, V)};
+
+d({1020, SM, RV, RG}, 2 = V) ->
+ {'IndAudLocalControlDescriptor',
+ d(SM, V), d(RV, V), d(RG, V), asn1_NOVALUE};
+d({1021, SM, RV, RG, PP}, 2 = V)
+ when is_list(PP) ->
+ {'IndAudLocalControlDescriptor', d(SM, V), d(RV, V), d(RG, V), dl(PP, V)};
+d({1022, SM, RV, RG}, V) when (V >= 3) ->
+ {'IndAudLocalControlDescriptor',
+ d(SM, V), d(RV, V), d(RG, V), asn1_NOVALUE, asn1_NOVALUE};
+d({1023, SM, RV, RG, PP}, V)
+ when is_list(PP) andalso (V >= 3) ->
+ {'IndAudLocalControlDescriptor', d(SM, V), d(RV, V), d(RG, V), dl(PP, V),
+ asn1_NOVALUE};
+d({1024, SM, RV, RG, PP, SMS}, V)
+ when is_list(PP) andalso (V >= 3) ->
+ {'IndAudLocalControlDescriptor', d(SM, V), d(RV, V), d(RG, V), dl(PP, V),
+ d(SMS, V)};
+
+d({1030, N}, 2 = _V) ->
+ {'IndAudPropertyParm', N};
+d({1031, N}, V) when V >= 3 ->
+ {'IndAudPropertyParm', N, asn1_NOVALUE};
+d({1032, N, PP}, V) when V >= 3 ->
+ {'IndAudPropertyParm', N, d(PP, V)};
+
+d({1100}, _V) ->
+ oneway;
+d({1101}, _V) ->
+ bothway;
+d({1102}, _V) ->
+ isolate;
+d({1103}, _V) ->
+ onewayexternal;
+d({1104}, _V) ->
+ onewayboth;
+
+d(T, _V) ->
+ %% io:format("d(~w) -> ~nT: ~w~n", [_V, T]),
+ T.
+
+
+%% i(F, A) ->
+%% %% i(get(dbg), F, A).
+%% i(true, F, A).
+
+%% i(true, F, A) ->
+%% io:format("DBG:" ++ F ++ "~n", A);
+%% i(_, _, _) ->
+%% ok.
+
diff --git a/lib/megaco/src/engine/megaco_filter.erl b/lib/megaco/src/engine/megaco_filter.erl
new file mode 100644
index 0000000000..23a91b1f1d
--- /dev/null
+++ b/lib/megaco/src/engine/megaco_filter.erl
@@ -0,0 +1,350 @@
+%%
+%% %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 : megaco/H.248 customization of generic event tracer
+%%----------------------------------------------------------------------
+
+-module(megaco_filter).
+
+-export([start/0, start/1, filter/1,
+ pretty_error/1, string_to_term/1]).
+
+-include_lib("megaco/include/megaco.hrl").
+-include_lib("megaco/include/megaco_message_v1.hrl").
+-include_lib("megaco/src/app/megaco_internal.hrl").
+-include_lib("et/include/et.hrl").
+
+start() ->
+ start([]).
+
+start(ExtraOptions) ->
+ Options =
+ [{event_order, event_ts},
+ {scale, 3},
+ {max_actors, infinity},
+ {trace_pattern, {megaco, max}},
+ {trace_global, true},
+ {dict_insert, {filter, ?MODULE}, fun filter/1},
+ {active_filter, ?MODULE},
+ {title, "Megaco tracer - Erlang/OTP"} | ExtraOptions],
+ et_viewer:start(Options).
+
+filter(E) when is_record(E, event) ->
+ From = filter_actor(E#event.from),
+ To = filter_actor(E#event.to),
+ E2 = E#event{from = From, to = To},
+ E3 = filter_contents(E#event.contents, E2, []),
+ {true, E3}.
+
+filter_actors(From, To, E)
+ when (E#event.from =:= ?APPLICATION) andalso (E#event.to =:= ?APPLICATION) ->
+ Label = E#event.label,
+ case lists:prefix("callback:", Label) of
+ true ->
+ E#event{from = filter_actor(From),
+ to = filter_user_actor(From)};
+ false ->
+ case lists:prefix("return:", Label) of
+ true ->
+ E#event{from = filter_user_actor(From),
+ to = filter_actor(From)};
+ false ->
+ case lists:prefix("receive bytes", Label) of
+ true ->
+ E#event{from = filter_actor(To),
+ to = filter_actor(From)};
+ false ->
+ E#event{from = filter_actor(From),
+ to = filter_actor(To)}
+ end
+ end
+ end;
+filter_actors(_From, _To, E) ->
+ E.
+
+filter_actor(Actor) ->
+ String = do_filter_actor(Actor),
+ if
+ length(String) > 21 ->
+ string:substr(String, 1, 21) ++ [$*];
+ true ->
+ String
+ end.
+
+filter_user_actor(Actor) ->
+ String = do_filter_actor(Actor) ++ "@user",
+ if
+ length(String) > 21 ->
+ string:substr(String, 1, 21) ++ [$*];
+ true ->
+ String
+ end.
+
+do_filter_actor(CH) when is_record(CH, megaco_conn_handle) ->
+ Mid = CH#megaco_conn_handle.local_mid,
+ do_filter_actor(Mid);
+do_filter_actor(Actor) ->
+ case Actor of
+ {ip4Address, {'IP4Address', [A1,A2,A3,A4], asn1_NOVALUE}} ->
+ integer_to_list(A1) ++ [$.] ++
+ integer_to_list(A2) ++ [$.] ++
+ integer_to_list(A3) ++ [$.] ++
+ integer_to_list(A4);
+ {ip4Address, {'IP4Address', [A1,A2,A3,A4], Port}} ->
+ integer_to_list(A1) ++ [$.] ++
+ integer_to_list(A2) ++ [$.] ++
+ integer_to_list(A3) ++ [$.] ++
+ integer_to_list(A4) ++ [$:] ++
+ integer_to_list(Port);
+ {domainName, {'DomainName', Name, asn1_NOVALUE}} ->
+ Name;
+ {domainName, {'DomainName', Name, Port}} ->
+ Name ++ [$:] ++ integer_to_list(Port);
+ {deviceName, Name} ->
+ Name;
+ unknown_remote_mid ->
+ "preliminary_mid";
+ preliminary_mid ->
+ "preliminary_mid";
+ megaco ->
+ megaco;
+ _Other ->
+ "UNKNOWN"
+ end.
+
+filter_contents([], E, Contents) ->
+ E#event{contents = lists:flatten(lists:reverse(Contents))};
+filter_contents([H | T], E, Contents) ->
+ case H of
+ {line, _Mod, _Line} ->
+ filter_contents(T, E, Contents);
+ CD when is_record(CD, conn_data) ->
+ CH = CD#conn_data.conn_handle,
+ From = CH#megaco_conn_handle.local_mid,
+ To = CH#megaco_conn_handle.remote_mid,
+ E2 = filter_actors(From, To, E),
+ Serial = CD#conn_data.serial,
+ E3 = append_serial(Serial, E2),
+ filter_contents(T, E3, Contents);
+ CH when is_record(CH, megaco_conn_handle) ->
+ From = CH#megaco_conn_handle.local_mid,
+ To = CH#megaco_conn_handle.remote_mid,
+ E2 = filter_actors(From, To, E),
+ filter_contents(T, E2, Contents);
+ {orig_conn_handle, _CH} ->
+ filter_contents(T, E, Contents);
+ RH when is_record(RH, megaco_receive_handle) ->
+ Actor = RH#megaco_receive_handle.local_mid,
+ E2 = filter_actors(Actor, Actor, E),
+ filter_contents(T, E2, Contents);
+ {pid, Pid} when is_pid(Pid) ->
+ filter_contents(T, E, Contents);
+ pending ->
+ filter_contents(T, E, Contents);
+ reply ->
+ filter_contents(T, E, Contents);
+ {error, Reason} ->
+ Pretty = pretty_error({error, Reason}),
+ E2 = prepend_error(E),
+ filter_contents(T, E2, [[Pretty, "\n"], Contents]);
+ {'EXIT', Reason} ->
+ Pretty = pretty_error({'EXIT', Reason}),
+ E2 = prepend_error(E),
+ filter_contents(T, E2, [[Pretty, "\n"], Contents]);
+ ED when is_record(ED, 'ErrorDescriptor') ->
+ Pretty = pretty_error(ED),
+ E2 = prepend_error(E),
+ filter_contents(T, E2, [[Pretty, "\n"], Contents]);
+ Trans when is_record(Trans, 'TransactionRequest') ->
+ Pretty = pretty({trans, {transactionRequest, Trans}}),
+ filter_contents([], E, [[Pretty, "\n"], Contents]);
+ Trans when is_record(Trans, 'TransactionReply') ->
+ Pretty = pretty({trans, {transactionReply, Trans}}),
+ filter_contents([], E, [[Pretty, "\n"], Contents]);
+ Trans when is_record(Trans, 'TransactionPending') ->
+ Pretty = pretty({trans, {transactionPending, Trans}}),
+ filter_contents([], E, [[Pretty, "\n"], Contents]);
+ Trans when is_record(Trans, 'TransactionAck') ->
+ Pretty = pretty({trans, {transactionResponseAck, [Trans]}}),
+ case Trans#'TransactionAck'.lastAck of
+ asn1_NOVALUE ->
+ filter_contents([], E, [[Pretty, "\n"], Contents]);
+ Last ->
+ Label = term_to_string(E#event.label),
+ E2 = E#event{label = Label ++ ".." ++ integer_to_list(Last)},
+ filter_contents([], E2, [[Pretty, "\n"], Contents])
+ end;
+ {context_id, _ContextId} ->
+ Pretty = pretty(H),
+ filter_contents(T, E, [[Pretty, "\n"], Contents]);
+ {command_request, CmdReq} ->
+ Pretty = pretty(CmdReq),
+ filter_contents(T, E, [[Pretty, "\n"], Contents]);
+ {user_reply, {ok, ARS}} ->
+ Pretty = [[pretty(AR), "\n"] || AR <- ARS],
+ filter_contents(T, E, [["REPLY: \n", Pretty, "\n"], Contents]);
+ {user_reply, Error} ->
+ Pretty = pretty_error(Error),
+ filter_contents(T, E, [["REPLY: \n", Pretty, "\n"], Contents]);
+ {actionReplies, ARS} ->
+ Pretty = [[pretty(AR), "\n"] || AR <- ARS],
+ filter_contents(T, E, [["REPLY: \n", Pretty, "\n"], Contents]);
+ MegaMsg when is_record(MegaMsg, 'MegacoMessage') ->
+ Pretty = pretty(MegaMsg),
+ filter_contents(T, E, [["MESSAGE: \n", Pretty, "\n"], Contents]);
+ {bytes, Bin} when is_binary(Bin) ->
+ E2 =
+ case E#event.label of
+ [$s, $e, $n, $d, $ , $b, $y, $t, $e, $s | Tail] ->
+ L = lists:concat(["send ", size(Bin), " bytes", Tail]),
+ E#event{label = L};
+ [$r, $e, $c, $e, $i, $v, $e, $ , $b, $y, $t, $e, $s | Tail] ->
+ L = lists:concat(["receive ", size(Bin), " bytes", Tail]),
+ E#event{label = L};
+ _ ->
+ E
+ end,
+ CharList = erlang:binary_to_list(Bin),
+ filter_contents(T, E2, [[CharList , "\n"], Contents]);
+ [] ->
+ filter_contents(T, E, Contents);
+ {test_lib, _Mod, _Fun} ->
+ filter_contents(T, E, Contents);
+ Other ->
+ Pretty = pretty(Other),
+ filter_contents(T, E, [[Pretty, "\n"], Contents])
+ end.
+
+append_serial(Serial, E) when is_integer(Serial) ->
+ Label = term_to_string(E#event.label),
+ E#event{label = Label ++ " #" ++ integer_to_list(Serial)};
+append_serial(_Serial, E) ->
+ E.
+
+prepend_error(E) ->
+ Label = term_to_string(E#event.label),
+ E#event{label = "<ERROR> " ++ Label}.
+
+pretty({context_id, ContextId}) ->
+ if
+ ContextId =:= ?megaco_null_context_id ->
+ ["CONTEXT ID: -\n"];
+ ContextId =:= ?megaco_choose_context_id ->
+ ["CONTEXT ID: $\n"];
+ ContextId =:= ?megaco_all_context_id ->
+ ["CONTEXT ID: *\n"];
+ is_integer(ContextId) ->
+ ["CONTEXT ID: ",integer_to_list(ContextId), "\n"]
+ end;
+pretty(MegaMsg) when is_record(MegaMsg, 'MegacoMessage') ->
+ case catch megaco_pretty_text_encoder:encode_message([], MegaMsg) of
+ {ok, Bin} ->
+ term_to_string(Bin);
+ _Bad ->
+ term_to_string(MegaMsg)
+ end;
+pretty(CmdReq) when is_record(CmdReq, 'CommandRequest') ->
+ case catch megaco_pretty_text_encoder:encode_command_request(CmdReq) of
+ {ok, IoList} ->
+ IoList2 = lists:flatten(IoList),
+ term_to_string(IoList2);
+ _Bad ->
+ term_to_string(CmdReq)
+ end;
+pretty({complete_success, ContextId, RepList} = Res) ->
+ ActRep = #'ActionReply'{contextId = ContextId,
+ commandReply = RepList},
+ case catch megaco_pretty_text_encoder:encode_action_reply(ActRep) of
+ {ok, IoList} ->
+ IoList2 = lists:flatten(IoList),
+ term_to_string(IoList2);
+ _Bad ->
+ term_to_string(Res)
+ end;
+pretty(AR) when is_record(AR, 'ActionReply') ->
+ case catch megaco_pretty_text_encoder:encode_action_reply(AR) of
+ {ok, IoList} ->
+ IoList2 = lists:flatten(IoList),
+ term_to_string(IoList2);
+ _Bad ->
+ term_to_string(AR)
+ end;
+pretty({partial_failure, ContextId, RepList} = Res) ->
+ ActRep = #'ActionReply'{contextId = ContextId,
+ commandReply = RepList},
+ case catch megaco_pretty_text_encoder:encode_action_reply(ActRep) of
+ {ok, IoList} ->
+ IoList2 = lists:flatten(IoList),
+ term_to_string(IoList2);
+ _Bad ->
+ term_to_string(Res)
+ end;
+pretty({trans, Trans}) ->
+ case catch megaco_pretty_text_encoder:encode_transaction(Trans) of
+ {ok, Bin} when is_binary(Bin) ->
+ IoList2 = lists:flatten(binary_to_list(Bin)),
+ term_to_string(IoList2);
+ {ok, IoList} ->
+ IoList2 = lists:flatten(IoList),
+ term_to_string(IoList2);
+ _Bad ->
+ term_to_string(Trans)
+ end;
+pretty(Other) ->
+ term_to_string(Other).
+
+pretty_error({error, Reason}) ->
+ ["ERROR: ", pretty_error(Reason)];
+pretty_error({'EXIT', Reason}) ->
+ ["EXIT: ", pretty_error(Reason)];
+pretty_error({'ErrorDescriptor', Code, Reason}) ->
+ ["CODE: ", integer_to_list(Code), " TEXT: ", pretty_error(Reason)];
+pretty_error(Ugly) ->
+ case string_to_term(Ugly) of
+ {ok, Pretty} -> ["\n", Pretty];
+ _ -> ["\n", term_to_string(Ugly)]
+ end.
+
+string_to_term(Chars) ->
+ do_string_to_term([], Chars, 1).
+
+do_string_to_term(Cont, Chars, Line) ->
+ case catch erl_scan:tokens(Cont, Chars, Line) of
+ {done, {ok, Tokens, _EndLine}, _Rest} ->
+ case erl_parse:parse_term(Tokens) of
+ {ok, Term} ->
+ {ok, Term};
+ {error, Reason} ->
+ {error, Reason}
+ end;
+ {more, Cont2} ->
+ do_string_to_term(Cont2, ". ", Line);
+ Other ->
+ {error, Other}
+ end.
+
+term_to_string(Bin) when is_binary(Bin) ->
+ binary_to_list(Bin);
+term_to_string(Term) ->
+ case catch io_lib:format("~s", [Term]) of
+ {'EXIT', _} -> lists:flatten(io_lib:format("~p", [Term]));
+ GoodString -> lists:flatten(GoodString)
+ end.
diff --git a/lib/megaco/src/engine/megaco_message_internal.hrl b/lib/megaco/src/engine/megaco_message_internal.hrl
new file mode 100644
index 0000000000..44f38752a9
--- /dev/null
+++ b/lib/megaco/src/engine/megaco_message_internal.hrl
@@ -0,0 +1,159 @@
+%%
+%% %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%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Generated by the Erlang ASN.1 compiler version:1.2.7
+%% Purpose: Erlang record definitions for each named and unnamed
+%% SEQUENCE and SET in module MEDIA-GATEWAY-CONTROL
+%%----------------------------------------------------------------------
+
+-record('MegacoMessage',
+ {
+ authHeader = asn1_NOVALUE,
+ mess
+ }).
+
+-record('AuthenticationHeader',
+ {
+ secParmIndex,
+ seqNum,
+ ad
+ }).
+
+-record('Message',
+ {
+ version,
+ mId,
+ messageBody
+ }). % with extension mark
+
+-record('DomainName',
+ {
+ name,
+ portNumber = asn1_NOVALUE
+ }).
+
+-record('IP4Address',
+ {
+ address,
+ portNumber = asn1_NOVALUE
+ }).
+
+-record('IP6Address',
+ {
+ address,
+ portNumber = asn1_NOVALUE
+ }).
+
+-record('TransactionRequest',
+ {
+ transactionId,
+ actions
+ }). % with extension mark
+
+-record('TransactionPending',
+ {
+ transactionId
+ }). % with extension mark
+
+
+%% --- TransactionReply ---
+
+-record('megaco_transaction_reply',
+ {
+ transactionId,
+ immAckRequired = asn1_NOVALUE,
+ transactionResult,
+ segmentNumber = asn1_NOVALUE,
+ segmentationComplete = asn1_NOVALUE
+ }).
+
+
+%% %% Pre v3 record def:
+%% -record('TransactionReply',
+%% {
+%% transactionId,
+%% immAckRequired = asn1_NOVALUE,
+%% transactionResult
+%% }). %% with extension mark
+
+%% %% v3 record def:
+%% -record('TransactionReply',
+%% {
+%% transactionId,
+%% immAckRequired = asn1_NOVALUE,
+%% transactionResult,
+%% %% with extension mark -- v3 --
+%% segmentNumber = asn1_NOVALUE,
+%% segmentationComplete = asn1_NOVALUE
+%% }).
+
+
+%% -- v3 --
+-record('SegmentReply',
+ {
+ transactionId,
+ segmentNumber,
+ segmentationComplete = asn1_NOVALUE
+ }). % with extension mark
+
+
+-record('TransactionAck',
+ {
+ firstAck,
+ lastAck = asn1_NOVALUE
+ }).
+
+-record('ErrorDescriptor',
+ {
+ errorCode,
+ errorText = asn1_NOVALUE
+ }).
+
+-record('DigitMapDescriptor',
+ {
+ digitMapName = asn1_NOVALUE,
+ digitMapValue = asn1_NOVALUE
+ }).
+
+-record('DigitMapValue',
+ {
+ startTimer = asn1_NOVALUE,
+ shortTimer = asn1_NOVALUE,
+ longTimer = asn1_NOVALUE,
+ %% BUGBUG BUGBUG
+ %% Note that there should not really be a default value
+ %% for this item, but a problem with the flex scanner
+ %% makes it neccessary to swap the values of digitMapBody
+ %% and durationTimer. The same is done in the (erl) scanner
+ %% just so they behave the same. The values are later
+ %% swapped back by the parser...
+ digitMapBody = asn1_NOVALUE,
+ %% with extensions
+ durationTimer = asn1_NOVALUE
+ }).
+
+
+-record('TerminationID',
+ {
+ wildcard,
+ id
+ }). % with extension mark
+
diff --git a/lib/megaco/src/engine/megaco_messenger.erl b/lib/megaco/src/engine/megaco_messenger.erl
new file mode 100644
index 0000000000..a9e4fd67b2
--- /dev/null
+++ b/lib/megaco/src/engine/megaco_messenger.erl
@@ -0,0 +1,5158 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1999-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: Send and process a (sequence of) Megaco/H.248 transactions
+%%----------------------------------------------------------------------
+
+-module(megaco_messenger).
+
+%% Application internal export
+-export([
+ process_received_message/4, process_received_message/5,
+ receive_message/4, receive_message/5,
+ connect/4, connect/5,
+ disconnect/2,
+ encode_actions/3,
+ call/3,
+ cast/3,
+ cancel/2,
+ request_timeout/2,
+ request_keep_alive_timeout/2,
+ pending_timeout/3,
+ reply_timeout/3,
+ segment_timeout/3,
+ %% segment_reply_timeout/4,
+
+ test_request/5,
+ test_reply/5
+ ]).
+
+%% MIB stat functions
+-export([
+ get_stats/0, get_stats/1, get_stats/2,
+ reset_stats/0, reset_stats/1
+ ]).
+
+%% Misc functions
+-export([
+ cleanup/2,
+ which_requests/1, which_replies/1
+ ]).
+
+%% Module internal export
+-export([
+ process_received_message/6,
+ handle_request/2,
+ handle_long_request/2,
+ connect_remote/3,
+ disconnect_local/2,
+ disconnect_remote/3,
+ send_request_remote/4,
+ receive_reply_remote/2, receive_reply_remote/3
+ ]).
+
+-include_lib("megaco/include/megaco.hrl").
+-include("megaco_message_internal.hrl").
+-include_lib("megaco/src/app/megaco_internal.hrl").
+
+%% N.B. Update cancel/1 with '_' when a new field is added
+-record(request,
+ {trans_id,
+ remote_mid,
+ timer_ref, % {short, Ref} | {long, Ref}
+ init_timer,
+ init_long_timer,
+ curr_timer,
+ version,
+ bytes, % {send, Data} | {no_send, Data}, Data = binary() | tuple()
+ send_handle,
+ user_mod,
+ user_args,
+ reply_action, % call | cast
+ reply_data,
+ seg_recv = [], % [integer()] (received segments)
+ init_seg_timer,
+ seg_timer_ref,
+ keep_alive_timer, % plain | integer() >= 0
+ keep_alive_ref % undefined | ref()
+ }).
+
+
+%% N.B. Update cancel/1 with '_' when a new field is added
+-record(reply,
+ {
+ trans_id,
+ local_mid,
+ state = prepare, % prepare | eval_request | waiting_for_ack | aborted
+ pending_timer_ref,
+ handler = undefined, % pid of the proc executing the callback func
+ timer_ref,
+ version,
+ %% bytes: Sent reply data: not acknowledged
+ bytes, % binary() | [{integer(), binary(), timer_ref()}]
+ ack_action, % discard_ack | {handle_ack, Data}
+ send_handle,
+ %% segments: Not sent reply data (segments)
+ segments = [] % [{integer(), binary()}]
+ }).
+
+-record(trans_id,
+ {
+ mid,
+ serial
+ }).
+
+
+-ifdef(MEGACO_TEST_CODE).
+-define(SIM(Other,Where),
+ fun(Afun,Bfun) ->
+ Kfun = {?MODULE,Bfun},
+ case (catch ets:lookup(megaco_test_data, Kfun)) of
+ [{Kfun,Cfun}] ->
+ Cfun(Afun);
+ _ ->
+ Afun
+ end
+ end(Other,Where)).
+-define(TC_AWAIT_CANCEL_EVENT(),
+ case megaco_tc_controller:lookup(block_on_cancel) of
+ {value, {Tag, Pid}} when is_pid(Pid) ->
+ Pid ! {Tag, self()},
+ receive
+ {Tag, Pid} ->
+ ok
+ end;
+ {value, {sleep, To}} when is_integer(To) andalso (To > 0) ->
+ receive after To -> ok end;
+ _ ->
+ ok
+ end).
+-define(TC_AWAIT_REPLY_EVENT(Info),
+ case megaco_tc_controller:lookup(block_on_reply) of
+ {value, {Tag, Pid}} when is_pid(Pid) ->
+ Pid ! {Tag, self(), Info},
+ receive
+ {Tag, Pid} ->
+ ok
+ end;
+ _Whatever ->
+ %% io:format("Whatever: ~p~n", [Whatever]),
+ ok
+ end).
+-else.
+-define(SIM(Other,Where),Other).
+-define(TC_AWAIT_CANCEL_EVENT(),ok).
+-define(TC_AWAIT_REPLY_EVENT(_),ok).
+-endif.
+
+
+-define(report_pending_limit_exceeded(ConnData),
+ ?report_important(ConnData, "<ERROR> pending limit exceeded", [])).
+
+-ifdef(megaco_extended_trace).
+-define(rt1(T,F,A),?report_trace(T,F,A)).
+-define(rt2(F,A), ?rt1(ignore,F,A)).
+-define(rt3(F), ?rt2(F,[])).
+-else.
+-define(rt1(T,F,A),ok).
+-define(rt2(F,A), ok).
+-define(rt3(F), ok).
+-endif.
+
+
+%%----------------------------------------------------------------------
+%% SNMP statistics handling functions
+%%----------------------------------------------------------------------
+
+%%-----------------------------------------------------------------
+%% Func: get_stats/0, get_stats/1, get_stats/2
+%% Description: Retreive statistics (counters) for TCP
+%%-----------------------------------------------------------------
+
+get_stats() ->
+ megaco_stats:get_stats(megaco_stats).
+
+get_stats(ConnHandleOrCounter) ->
+ megaco_stats:get_stats(megaco_stats, ConnHandleOrCounter).
+
+get_stats(ConnHandle, Counter) ->
+ megaco_stats:get_stats(megaco_stats, ConnHandle, Counter).
+
+
+%%-----------------------------------------------------------------
+%% Func: reset_stats/0, reaet_stats/1
+%% Description: Reset statistics (counters)
+%%-----------------------------------------------------------------
+
+reset_stats() ->
+ megaco_stats:reset_stats(megaco_stats).
+
+reset_stats(ConnHandleOrCounter) ->
+ megaco_stats:reset_stats(megaco_stats, ConnHandleOrCounter).
+
+
+
+%%----------------------------------------------------------------------
+%% cleanup utility functions
+%%----------------------------------------------------------------------
+
+cleanup(#megaco_conn_handle{local_mid = LocalMid}, Force)
+ when (Force =:= true) orelse (Force =:= false) ->
+ Pat = #reply{trans_id = '$1',
+ local_mid = LocalMid,
+ state = '$2',
+ _ = '_'},
+ do_cleanup(Pat, Force);
+cleanup(LocalMid, Force)
+ when (Force =:= true) orelse (Force =:= false) ->
+ Pat = #reply{trans_id = '$1',
+ local_mid = LocalMid,
+ state = '$2',
+ _ = '_'},
+ do_cleanup(Pat, Force).
+
+do_cleanup(Pat, Force) ->
+ Match = megaco_monitor:which_replies(Pat),
+ Reps = [{V1, V2} || [V1, V2] <- Match],
+ do_cleanup2(Reps, Force).
+
+do_cleanup2([], _) ->
+ ok;
+do_cleanup2([{TransId, aborted}|T], Force = false) ->
+ megaco_monitor:delete_reply(TransId),
+ do_cleanup2(T, Force);
+do_cleanup2([_|T], Force = false) ->
+ do_cleanup2(T, Force);
+do_cleanup2([{TransId, _State}|T], Force = true) ->
+ megaco_monitor:delete_reply(TransId),
+ do_cleanup2(T, Force).
+
+
+%%----------------------------------------------------------------------
+%% which_requests and which_replies utility functions
+%%----------------------------------------------------------------------
+
+which_requests(#megaco_conn_handle{local_mid = LocalMid,
+ remote_mid = RemoteMid}) ->
+ Pat1 = #trans_id{mid = LocalMid,
+ serial = '$1', _ = '_'},
+ Pat2 = #request{trans_id = Pat1,
+ remote_mid = RemoteMid,
+ _ = '_'},
+ Match = megaco_monitor:which_requests(Pat2),
+ [S || [S] <- Match];
+which_requests(LocalMid) ->
+ Pat1 = #trans_id{mid = LocalMid,
+ serial = '$1', _ = '_'},
+ Pat2 = #request{trans_id = Pat1,
+ remote_mid = '$2', _ = '_'},
+ Match0 = megaco_monitor:which_requests(Pat2),
+ Match1 = [{mk_ch(LocalMid, V2), V1} || [V1, V2] <- Match0],
+ which_requests1(lists:sort(Match1)).
+
+which_requests1([]) ->
+ [];
+which_requests1([{CH, S}|T]) ->
+ which_requests2(T, CH, [S], []).
+
+which_requests2([], CH, Serials, Reqs) ->
+ lists:reverse([{CH, Serials}|Reqs]);
+which_requests2([{CH, S}|T], CH, Serials, Reqs) ->
+ which_requests2(T, CH, [S|Serials], Reqs);
+which_requests2([{CH1, S}|T], CH2, Serials, Reqs) ->
+ which_requests2(T, CH1, [S], [{CH2, lists:reverse(Serials)}| Reqs]).
+
+
+which_replies(#megaco_conn_handle{local_mid = LocalMid,
+ remote_mid = RemoteMid}) ->
+ Pat1 = #trans_id{mid = RemoteMid,
+ serial = '$1', _ = '_'},
+ Pat2 = #reply{trans_id = Pat1,
+ local_mid = LocalMid,
+ state = '$2',
+ handler = '$3', _ = '_'},
+ Match = megaco_monitor:which_replies(Pat2),
+ [{V1, V2, V3} || [V1, V2, V3] <- Match];
+which_replies(LocalMid) ->
+ Pat1 = #trans_id{mid = '$1',
+ serial = '$2', _ = '_'},
+ Pat2 = #reply{trans_id = Pat1,
+ local_mid = LocalMid,
+ state = '$3',
+ handler = '$4', _ = '_'},
+ Match0 = megaco_monitor:which_replies(Pat2),
+ Match1 = [{mk_ch(LocalMid,V1),{V2,V3,V4}} || [V1, V2, V3, V4] <- Match0],
+ which_replies1(lists:sort(Match1)).
+
+which_replies1([]) ->
+ [];
+which_replies1([{CH, Data}|T]) ->
+ which_replies2(T, CH, [Data], []).
+
+which_replies2([], CH, Data, Reps) ->
+ lists:reverse([{CH, Data}|Reps]);
+which_replies2([{CH, Data}|T], CH, Datas, Reps) ->
+ which_replies2(T, CH, [Data|Datas], Reps);
+which_replies2([{CH1, Data}|T], CH2, Datas, Reps) ->
+ which_replies2(T, CH1, [Data], [{CH2, lists:reverse(Datas)}| Reps]).
+
+
+mk_ch(LM, RM) ->
+ #megaco_conn_handle{local_mid = LM, remote_mid = RM}.
+
+
+%%----------------------------------------------------------------------
+%% Register/unreister connections
+%%----------------------------------------------------------------------
+
+%% Returns {ok, ConnHandle} | {error, Reason}
+autoconnect(RH, RemoteMid, SendHandle, ControlPid, Extra)
+ when is_record(RH, megaco_receive_handle) ->
+ ?rt2("autoconnect", [RH, RemoteMid, SendHandle, ControlPid]),
+ case megaco_config:autoconnect(RH, RemoteMid, SendHandle, ControlPid) of
+ {ok, ConnData} ->
+ do_connect(ConnData, Extra);
+ {error, Reason} ->
+ {error, Reason}
+ end;
+autoconnect(BadHandle, _CH, _SendHandle, _ControlPid, _Extra) ->
+ {error, {bad_receive_handle, BadHandle}}.
+
+connect(RH, RemoteMid, SendHandle, ControlPid) ->
+ Extra = ?default_user_callback_extra,
+ connect(RH, RemoteMid, SendHandle, ControlPid, Extra).
+connect(RH, RemoteMid, SendHandle, ControlPid, Extra)
+ when is_record(RH, megaco_receive_handle) ->
+ ?rt2("connect", [RH, RemoteMid, SendHandle, ControlPid, Extra]),
+
+ %% The purpose of this is to have a temoporary process, to
+ %% which one can set up a monitor or link and get a
+ %% notification when process exits. The entire connect is
+ %% done in the temporary worker process.
+ %% When it exits, the connect is either successfully done
+ %% or it failed.
+
+ ConnectorFun =
+ fun() ->
+
+ ConnectResult =
+ case megaco_config:connect(RH, RemoteMid,
+ SendHandle, ControlPid) of
+ {ok, ConnData} ->
+ do_connect(ConnData, Extra);
+ {error, Reason} ->
+ {error, Reason}
+ end,
+ ?rt2("connector: connected", [self(), ConnectResult]),
+ exit({result, ConnectResult})
+ end,
+ Flag = process_flag(trap_exit, true),
+ Connector = erlang:spawn_link(ConnectorFun),
+ receive
+ {'EXIT', Connector, {result, ConnectResult}} ->
+ ?rt2("connect result: received expected connector exit signal",
+ [Connector, ConnectResult]),
+ process_flag(trap_exit, Flag),
+ ConnectResult;
+ {'EXIT', Connector, OtherReason} ->
+ ?rt2("connect exit: received unexpected connector exit signal",
+ [Connector, OtherReason]),
+ process_flag(trap_exit, Flag),
+ {error, OtherReason}
+ end;
+connect(BadHandle, _CH, _SendHandle, _ControlPid, _Extra) ->
+ {error, {bad_receive_handle, BadHandle}}.
+
+do_connect(CD, Extra) ->
+ CH = CD#conn_data.conn_handle,
+ Version = CD#conn_data.protocol_version,
+ UserMod = CD#conn_data.user_mod,
+ UserArgs = CD#conn_data.user_args,
+ Args =
+ case Extra of
+ ?default_user_callback_extra ->
+ [CH, Version | UserArgs];
+ _ ->
+ [CH, Version, Extra | UserArgs]
+ end,
+ ?report_trace(CD, "callback: connect", [Args]),
+ Res = (catch apply(UserMod, handle_connect, Args)),
+ ?report_debug(CD, "return: connect", [{return, Res}]),
+ case Res of
+ ok ->
+ ?SIM(ok, do_connect), % do_encode),
+ monitor_process(CH, CD#conn_data.control_pid);
+ error ->
+ megaco_config:disconnect(CH),
+ {error, {connection_refused, CD, error}};
+ {error, ED} when is_record(ED,'ErrorDescriptor') ->
+ megaco_config:disconnect(CH),
+ {error, {connection_refused, CD, ED}};
+ _Error ->
+ warning_msg("connect callback failed: ~w", [Res]),
+ megaco_config:disconnect(CH),
+ {error, {connection_refused, CD, Res}}
+ end.
+
+finish_connect(#conn_data{control_pid = ControlPid} = CD)
+ when is_pid(ControlPid) andalso (node(ControlPid) =:= node()) ->
+ ?rt1(CD, "finish local connect", [ControlPid]),
+ do_finish_connect(CD);
+finish_connect(#conn_data{conn_handle = CH,
+ control_pid = ControlPid} = CD)
+ when is_pid(ControlPid) andalso (node(ControlPid) =/= node()) ->
+ ?rt1(CD, "finish remote connect", [ControlPid]),
+ RemoteNode = node(ControlPid),
+ UserMonitorPid = whereis(megaco_monitor),
+ Args = [CH, ControlPid, UserMonitorPid],
+ case rpc:call(RemoteNode, ?MODULE, connect_remote, Args) of
+ {ok, ControlMonitorPid} ->
+ do_finish_connect(CD#conn_data{control_pid = ControlMonitorPid});
+ {error, Reason} ->
+ disconnect(CH, {connect_remote, Reason}),
+ {error, Reason};
+ {badrpc, Reason} ->
+ Reason2 = {'EXIT', Reason},
+ disconnect(CH, {connect_remote, Reason2}),
+ {error, Reason2}
+ end.
+
+do_finish_connect(#conn_data{conn_handle = CH,
+ send_handle = SendHandle,
+ control_pid = ControlPid} = CD) ->
+ M = ?MODULE,
+ F = disconnect_local,
+ A = [CH],
+ MFA = {M, F, A},
+ case megaco_config:finish_connect(CH, SendHandle, ControlPid, MFA) of
+ {ok, Ref} ->
+ {ok, CD#conn_data{monitor_ref = Ref}};
+ {error, Reason} ->
+ {error, {config_update, Reason}}
+ end.
+
+
+monitor_process(CH, ControlPid)
+ when is_pid(ControlPid) andalso (node(ControlPid) =:= node()) ->
+ M = ?MODULE,
+ F = disconnect_local,
+ A = [CH],
+ Ref = megaco_monitor:apply_at_exit(M, F, A, ControlPid),
+ case megaco_config:update_conn_info(CH, monitor_ref, Ref) of
+ ok ->
+ ?SIM({ok, CH}, monitor_process_local);
+ {error, Reason} ->
+ disconnect(CH, {config_update, Reason}),
+ {error, Reason}
+ end;
+monitor_process(CH, ControlPid)
+ when is_pid(ControlPid) andalso (node(ControlPid) =/= node()) ->
+ RemoteNode = node(ControlPid),
+ UserMonitorPid = whereis(megaco_monitor),
+ Args = [CH, ControlPid, UserMonitorPid],
+ case rpc:call(RemoteNode, ?MODULE, connect_remote, Args) of
+ {ok, ControlMonitorPid} ->
+ M = ?MODULE,
+ F = disconnect_local,
+ A = [CH],
+ Ref = megaco_monitor:apply_at_exit(M, F, A, ControlMonitorPid),
+ case megaco_config:update_conn_info(CH, monitor_ref, Ref) of
+ ok ->
+ ?SIM({ok, CH}, monitor_process_remote);
+ {error, Reason} ->
+ disconnect(CH, {config_update, Reason}),
+ {error, Reason}
+ end;
+ {error, Reason} ->
+ disconnect(CH, {connect_remote, Reason}),
+ {error, Reason};
+ {badrpc, Reason} ->
+ Reason2 = {'EXIT', Reason},
+ disconnect(CH, {connect_remote, Reason2}),
+ {error, Reason2}
+ end;
+monitor_process(CH, undefined = _ControlPid) ->
+ %% We have to do this later (setting up the monitor),
+ %% when the first message arrives. The 'connected' atom is
+ %% the indication for the first arriving message to finish
+ %% the connect.
+ %% This may be the case when an MGC performs a pre-connect
+ %% in order to speed up the handling of an (expected) connecting
+ %% MG.
+ case megaco_config:update_conn_info(CH, monitor_ref, connected) of
+ ok ->
+ ?SIM({ok, CH}, monitor_process_local);
+ {error, Reason} ->
+ disconnect(CH, {config_update, Reason}),
+ {error, Reason}
+ end.
+
+connect_remote(CH, ControlPid, UserMonitorPid)
+ when node(ControlPid) =:= node() andalso node(UserMonitorPid) =/= node() ->
+ case megaco_config:lookup_local_conn(CH) of
+ [_ConnData] ->
+ UserNode = node(UserMonitorPid),
+ M = ?MODULE,
+ F = disconnect_remote,
+ A = [CH, UserNode],
+ Ref = megaco_monitor:apply_at_exit(M, F, A, UserMonitorPid),
+ case megaco_config:connect_remote(CH, UserNode, Ref) of
+ ok ->
+ ControlMonitorPid = whereis(megaco_monitor),
+ ?SIM({ok, ControlMonitorPid}, connect_remote);
+ {error, Reason} ->
+ {error, Reason}
+ end;
+ [] ->
+ {error, {no_connection, CH}}
+ end.
+
+cancel_apply_at_exit({connecting, _ConnectorPid}) ->
+ ok;
+cancel_apply_at_exit(connected) ->
+ ok;
+cancel_apply_at_exit(ControlRef) ->
+ megaco_monitor:cancel_apply_at_exit(ControlRef).
+
+node_of_control_pid(Pid) when is_pid(Pid) ->
+ node(Pid);
+node_of_control_pid(_) ->
+ node().
+
+disconnect(ConnHandle, DiscoReason)
+ when is_record(ConnHandle, megaco_conn_handle) ->
+ case megaco_config:disconnect(ConnHandle) of
+ {ok, ConnData, RemoteConnData} ->
+ ControlRef = ConnData#conn_data.monitor_ref,
+ cancel_apply_at_exit(ControlRef),
+ handle_disconnect_callback(ConnData, DiscoReason),
+ ControlNode = node_of_control_pid(ConnData#conn_data.control_pid),
+ case ControlNode =:= node() of
+ true ->
+ %% Propagate to remote users
+ CancelFun =
+ fun(RCD) ->
+ UserRef = RCD#remote_conn_data.monitor_ref,
+ cancel_apply_at_exit(UserRef),
+ RCD#remote_conn_data.user_node
+ end,
+ Nodes = lists:map(CancelFun, RemoteConnData),
+ %% io:format("NODES: ~p~n", [Nodes]),
+ M = ?MODULE,
+ F = disconnect,
+ A = [ConnHandle, DiscoReason],
+ case rpc:multicall(Nodes, M, F, A) of
+ {Res, []} ->
+ Check = fun(ok) -> false;
+ ({error, {no_connection, _CH}}) -> false;
+ (_) -> true
+ end,
+ case lists:filter(Check, Res) of
+ [] ->
+ ok;
+ Bad ->
+ {error, {remote_disconnect_error, ConnHandle, Bad}}
+ end;
+ {_Res, Bad} ->
+ {error, {remote_disconnect_crash, ConnHandle, Bad}}
+ end;
+ false when (RemoteConnData =:= []) ->
+ %% Propagate to remote control node
+ M = ?MODULE,
+ F = disconnect_remote,
+ A = [DiscoReason, ConnHandle, node()],
+ case rpc:call(ControlNode, M, F, A) of
+ {badrpc, Reason} ->
+ {error, {'EXIT', Reason}};
+ Other ->
+ Other
+ end
+ end;
+ {error, Reason} ->
+ {error, Reason}
+ end;
+disconnect(BadHandle, Reason) ->
+ {error, {bad_conn_handle, BadHandle, Reason}}.
+
+disconnect_local(Reason, ConnHandle) ->
+ disconnect(ConnHandle, {no_controlling_process, Reason}).
+
+disconnect_remote(_Reason, ConnHandle, UserNode) ->
+ case megaco_config:disconnect_remote(ConnHandle, UserNode) of
+ [RCD] ->
+ Ref = RCD#remote_conn_data.monitor_ref,
+ cancel_apply_at_exit(Ref),
+ ok;
+ [] ->
+ {error, {no_connection, ConnHandle}}
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Handle incoming message
+%%----------------------------------------------------------------------
+
+receive_message(ReceiveHandle, ControlPid, SendHandle, Bin) ->
+ Extra = ?default_user_callback_extra,
+ receive_message(ReceiveHandle, ControlPid, SendHandle, Bin, Extra).
+
+receive_message(ReceiveHandle, ControlPid, SendHandle, Bin, Extra) ->
+ Opts = [link , {min_heap_size, 5000}],
+ spawn_opt(?MODULE,
+ process_received_message,
+ [ReceiveHandle, ControlPid, SendHandle, Bin, self(), Extra], Opts),
+ ok.
+
+%% This function is called via the spawn_opt function with the link
+%% option, therefor the unlink before the exit.
+process_received_message(ReceiveHandle, ControlPid, SendHandle, Bin, Receiver,
+ Extra) ->
+ process_received_message(ReceiveHandle, ControlPid, SendHandle, Bin, Extra),
+ unlink(Receiver),
+ exit(normal).
+
+process_received_message(ReceiveHandle, ControlPid, SendHandle, Bin) ->
+ Extra = ?default_user_callback_extra,
+ process_received_message(ReceiveHandle, ControlPid, SendHandle, Bin, Extra).
+
+process_received_message(ReceiveHandle, ControlPid, SendHandle, Bin, Extra) ->
+ Flag = process_flag(trap_exit, true),
+ case prepare_message(ReceiveHandle, SendHandle, Bin, ControlPid, Extra) of
+ {ok, ConnData, MegaMsg} when is_record(MegaMsg, 'MegacoMessage') ->
+ ?rt1(ConnData, "message prepared", [MegaMsg]),
+ Mess = MegaMsg#'MegacoMessage'.mess,
+ case Mess#'Message'.messageBody of
+ {transactions, Transactions} ->
+ {AckList, ReqList} =
+ prepare_trans(ConnData, Transactions, [], [], Extra),
+ handle_acks(AckList, Extra),
+ case ReqList of
+ [] ->
+ ?rt3("no transaction requests"),
+ ignore;
+ [Req|Reqs] when (ConnData#conn_data.threaded =:= true) ->
+ ?rt3("handle requests (spawned)"),
+ lists:foreach(
+ fun(R) ->
+ spawn(?MODULE, handle_request, [R, Extra])
+ end,
+ Reqs),
+ handle_request(Req, Extra);
+ _ ->
+ ?rt3("handle requests"),
+ case handle_requests(ReqList, [], Extra) of
+ [] ->
+ ignore;
+ [LongRequest | More] ->
+ lists:foreach(
+ fun(LR) ->
+ spawn(?MODULE, handle_long_request, [LR, Extra])
+ end,
+ More),
+ handle_long_request(LongRequest, Extra)
+ end
+ end;
+ {messageError, Error} ->
+ handle_message_error(ConnData, Error, Extra)
+ end;
+ {silent_fail, ConnData, {_Code, Reason, Error}} ->
+ ?report_debug(ConnData, Reason, [no_reply, Error]),
+ ignore;
+ {verbose_fail, ConnData, {Code, Reason, Error}} ->
+ ?report_debug(ConnData, Reason, [Error]),
+ send_message_error(ConnData, Code, Reason)
+ end,
+ process_flag(trap_exit, Flag),
+ ok.
+
+prepare_message(RH, SH, Bin, Pid, Extra)
+ when is_record(RH, megaco_receive_handle) andalso is_pid(Pid) ->
+ ?report_trace(RH, "receive bytes", [{bytes, Bin}]),
+ EncodingMod = RH#megaco_receive_handle.encoding_mod,
+ EncodingConfig = RH#megaco_receive_handle.encoding_config,
+ ProtVersion = RH#megaco_receive_handle.protocol_version,
+ case (catch EncodingMod:decode_message(EncodingConfig, ProtVersion, Bin)) of
+ {ok, MegaMsg} when is_record(MegaMsg, 'MegacoMessage') ->
+ ?report_trace(RH, "receive message", [{message, MegaMsg}]),
+ Mess = MegaMsg#'MegacoMessage'.mess,
+ RemoteMid = Mess#'Message'.mId,
+ Version = Mess#'Message'.version,
+ LocalMid = RH#megaco_receive_handle.local_mid,
+ CH = #megaco_conn_handle{local_mid = LocalMid,
+ remote_mid = RemoteMid},
+ case megaco_config:lookup_local_conn(CH) of
+
+ %%
+ %% Message is not of the negotiated version
+ %%
+
+ [#conn_data{protocol_version = NegVersion,
+ strict_version = true} = ConnData]
+ when NegVersion =/= Version ->
+ %% Use already established connection,
+ %% but incorrect version
+ ?rt1(ConnData, "not negotiated version", [Version]),
+ Error = {error, {not_negotiated_version,
+ NegVersion, Version}},
+ handle_syntax_error_callback(RH, ConnData,
+ prepare_error(Error),
+ Extra);
+
+
+ [ConnData] ->
+
+ %%
+ %% Use an already established connection
+ %%
+ %% This *may* have been set up in the
+ %% "non-official" way, so we may need to
+ %% create the monitor to the control process
+ %% and store the SendHandle (which is normally
+ %% done when creating the "temporary" connection).
+ %%
+
+ ?rt1(ConnData, "use already established connection", []),
+ ConnData2 = ConnData#conn_data{send_handle = SH,
+ control_pid = Pid,
+ protocol_version = Version},
+ check_message_auth(CH, ConnData2, MegaMsg, Bin);
+
+ [] ->
+ %% Setup a temporary connection
+ ?rt3("setup a temporary connection"),
+ case autoconnect(RH, RemoteMid, SH, Pid, Extra) of
+ {ok, _} ->
+ do_prepare_message(RH, CH, SH, MegaMsg, Pid, Bin);
+ {error, {already_connected, _ConnHandle}} ->
+ do_prepare_message(RH, CH, SH, MegaMsg, Pid, Bin);
+ {error, {connection_refused, ConnData, Reason}} ->
+ Error = prepare_error({error, {connection_refused, Reason}}),
+ {verbose_fail, ConnData, Error};
+ {error, Reason} ->
+ ConnData = fake_conn_data(RH, RemoteMid, SH, Pid),
+ ConnData2 = ConnData#conn_data{protocol_version = Version},
+ Error = prepare_error({error, Reason}),
+ {verbose_fail, ConnData2, Error}
+ end
+ end;
+ Error ->
+ ?rt2("decode error", [Error]),
+ ConnData = handle_decode_error(Error,
+ RH, SH, Bin, Pid,
+ EncodingMod,
+ EncodingConfig,
+ ProtVersion),
+ handle_syntax_error_callback(RH, ConnData, prepare_error(Error), Extra)
+ end;
+prepare_message(RH, SendHandle, _Bin, ControlPid, _Extra) ->
+ ConnData = fake_conn_data(RH, SendHandle, ControlPid),
+ Error = prepare_error({'EXIT', {bad_receive_handle, RH}}),
+ {verbose_fail, ConnData, Error}.
+
+
+handle_decode_error({error, {unsupported_version, _}},
+ #megaco_receive_handle{local_mid = LocalMid} = RH, SH,
+ Bin, Pid,
+ EM, EC, V) ->
+ case (catch EM:decode_mini_message(EC, V, Bin)) of
+ {ok, #'MegacoMessage'{mess = #'Message'{version = _Ver,
+ mId = RemoteMid}}} ->
+ ?rt2("erroneous message received", [SH, RemoteMid, _Ver]),
+ CH = #megaco_conn_handle{local_mid = LocalMid,
+ remote_mid = RemoteMid},
+ incNumErrors(CH),
+ %% We cannot put the version into conn-data, that will
+ %% make the resulting error message impossible to sent
+ %% (unsupported version)
+ case megaco_config:lookup_local_conn(CH) of
+ [ConnData] ->
+ ?rt3("known to us"),
+ ConnData#conn_data{send_handle = SH};
+ [] ->
+ ?rt3("unknown to us"),
+ ConnData = fake_conn_data(RH, SH, Pid),
+ ConnData#conn_data{conn_handle = CH}
+ end;
+
+ _ ->
+ ?rt2("erroneous message received", [SH]),
+ incNumErrors(),
+ fake_conn_data(RH, SH, Pid)
+ end;
+
+handle_decode_error(_,
+ #megaco_receive_handle{local_mid = LocalMid} = RH, SH,
+ Bin, Pid,
+ EM, EC, V) ->
+ case (catch EM:decode_mini_message(EC, V, Bin)) of
+ {ok, #'MegacoMessage'{mess = #'Message'{version = Ver,
+ mId = RemoteMid}}} ->
+ ?rt2("erroneous message received", [SH, Ver, RemoteMid]),
+ CH = #megaco_conn_handle{local_mid = LocalMid,
+ remote_mid = RemoteMid},
+ incNumErrors(CH),
+ case megaco_config:lookup_local_conn(CH) of
+ [ConnData] ->
+ ?rt3("known to us"),
+ ConnData#conn_data{send_handle = SH,
+ protocol_version = Ver};
+ [] ->
+ ?rt3("unknown to us"),
+ ConnData = fake_conn_data(RH, SH, Pid),
+ ConnData#conn_data{conn_handle = CH,
+ protocol_version = Ver}
+ end;
+
+ _ ->
+ ?rt2("erroneous message received", [SH]),
+ incNumErrors(),
+ fake_conn_data(RH, SH, Pid)
+ end.
+
+
+do_prepare_message(RH, CH, SendHandle, MegaMsg, ControlPid, Bin) ->
+ case megaco_config:lookup_local_conn(CH) of
+ [ConnData] ->
+ case check_message_auth(CH, ConnData, MegaMsg, Bin) of
+ {ok, ConnData2, MegaMsg} ->
+ %% Let the connection be permanent
+ {ok, ConnData2, MegaMsg};
+ {ReplyTag, ConnData, Reason} ->
+ %% Remove the temporary connection
+ disconnect(CH, {bad_auth, Reason}),
+ {ReplyTag, ConnData, Reason}
+ end;
+ [] ->
+ Reason = no_connection,
+ disconnect(CH, Reason),
+ RemoteMid = CH#megaco_conn_handle.remote_mid,
+ ConnData = fake_conn_data(RH, RemoteMid, SendHandle, ControlPid),
+ Error = prepare_error({error, Reason}),
+ {silent_fail, ConnData, Error}
+ end.
+
+check_message_auth(_ConnHandle, ConnData, MegaMsg, Bin) ->
+ MsgAuth = MegaMsg#'MegacoMessage'.authHeader,
+ Mess = MegaMsg#'MegacoMessage'.mess,
+ Version = Mess#'Message'.version,
+ ConnData2 = ConnData#conn_data{protocol_version = Version},
+ ConnAuth = ConnData2#conn_data.auth_data,
+ ?report_trace(ConnData2, "check message auth", [{bytes, Bin}]),
+ if
+ (MsgAuth =:= asn1_NOVALUE) andalso (ConnAuth =:= asn1_NOVALUE) ->
+ ?SIM({ok, ConnData2, MegaMsg}, check_message_auth);
+ true ->
+ ED = #'ErrorDescriptor'{errorCode = ?megaco_unauthorized,
+ errorText = "Autentication is not supported"},
+ {verbose_fail, ConnData2, prepare_error({error, ED})}
+ end.
+
+handle_syntax_error_callback(ReceiveHandle, ConnData, PrepError, Extra) ->
+ {Code, Reason, Error} = PrepError,
+ ErrorDesc = #'ErrorDescriptor'{errorCode = Code, errorText = Reason},
+ Version =
+ case Error of
+ {error, {unsupported_version, UV}} ->
+ UV;
+ _ ->
+ ConnData#conn_data.protocol_version
+ end,
+ UserMod = ConnData#conn_data.user_mod,
+ UserArgs = ConnData#conn_data.user_args,
+ ?report_trace(ReceiveHandle, "callback: syntax error", [ErrorDesc, Error]),
+ Args =
+ case Extra of
+ ?default_user_callback_extra ->
+ [ReceiveHandle, Version, ErrorDesc | UserArgs];
+ _ ->
+ [ReceiveHandle, Version, ErrorDesc, Extra | UserArgs]
+ end,
+ Res = (catch apply(UserMod, handle_syntax_error, Args)),
+ ?report_debug(ReceiveHandle, "return: syntax error",
+ [{return, Res}, ErrorDesc, Error]),
+ case Res of
+ reply ->
+ {verbose_fail, ConnData, PrepError};
+ {reply,#'ErrorDescriptor'{errorCode = Code1, errorText = Reason1}} ->
+ {verbose_fail, ConnData, {Code1,Reason1,Error}};
+ no_reply ->
+ {silent_fail, ConnData, PrepError};
+ {no_reply,#'ErrorDescriptor'{errorCode=Code2,errorText=Reason2}} ->
+ {silent_fail, ConnData, {Code2,Reason2,Error}}; %%% OTP-????
+ _ ->
+ warning_msg("syntax error callback failed: ~w", [Res]),
+ {verbose_fail, ConnData, PrepError}
+ end.
+
+fake_conn_data(CH) when is_record(CH, megaco_conn_handle) ->
+ case (catch megaco_config:conn_info(CH, receive_handle)) of
+ RH when is_record(RH, megaco_receive_handle) ->
+ RemoteMid = CH#megaco_conn_handle.remote_mid,
+ ConnData =
+ fake_conn_data(RH, RemoteMid, no_send_handle, no_control_pid),
+ ConnData#conn_data{conn_handle = CH};
+ {'EXIT', _} ->
+ UserMid = CH#megaco_conn_handle.local_mid,
+ case catch megaco_config:user_info(UserMid, receive_handle) of
+ {'EXIT', _} -> % No such user
+ #conn_data{conn_handle = CH,
+ serial = undefined_serial,
+ control_pid = no_control_pid,
+ monitor_ref = undefined_monitor_ref,
+ send_mod = no_send_mod,
+ send_handle = no_send_handle,
+ encoding_mod = no_encoding_mod,
+ encoding_config = no_encoding_config,
+ reply_action = undefined,
+ sent_pending_limit = infinity,
+ recv_pending_limit = infinity};
+ RH ->
+ ConnData =
+ fake_conn_data(RH, no_send_handle, no_control_pid),
+ ConnData#conn_data{conn_handle = CH}
+ end
+ end.
+
+fake_conn_data(RH, SendHandle, ControlPid) ->
+ fake_conn_data(RH, unknown_remote_mid, SendHandle, ControlPid).
+
+fake_conn_data(RH, RemoteMid, SendHandle, ControlPid) ->
+ case catch megaco_config:init_conn_data(RH, RemoteMid, SendHandle, ControlPid) of
+ {'EXIT', _} -> % No such user
+ fake_user_data(RH, RemoteMid, SendHandle, ControlPid);
+ ConnData ->
+ ConnData
+ end.
+
+fake_user_data(RH, RemoteMid, SendHandle, ControlPid) ->
+ LocalMid = RH#megaco_receive_handle.local_mid,
+ RH2 = RH#megaco_receive_handle{local_mid = default},
+ case catch megaco_config:init_conn_data(RH2, RemoteMid, SendHandle, ControlPid) of
+ {'EXIT', _} -> % Application stopped?
+ ConnHandle = #megaco_conn_handle{local_mid = LocalMid,
+ remote_mid = RemoteMid},
+ EncodingMod = RH#megaco_receive_handle.encoding_mod,
+ EncodingConfig = RH#megaco_receive_handle.encoding_config,
+ SendMod = RH#megaco_receive_handle.send_mod,
+ #conn_data{conn_handle = ConnHandle,
+ serial = undefined_serial,
+ control_pid = ControlPid,
+ monitor_ref = undefined_monitor_ref,
+ send_mod = SendMod,
+ send_handle = SendHandle,
+ encoding_mod = EncodingMod,
+ encoding_config = EncodingConfig,
+ reply_action = undefined,
+ sent_pending_limit = infinity,
+ recv_pending_limit = infinity};
+ ConnData ->
+ ConnData
+ end.
+
+prepare_error(Error) ->
+ case Error of
+ {error, ED} when is_record(ED, 'ErrorDescriptor') ->
+ Code = ED#'ErrorDescriptor'.errorCode,
+ Reason = ED#'ErrorDescriptor'.errorText,
+ {Code, Reason, Error};
+ {error, [{reason, {bad_token, [BadToken, _Acc]}, Line}]} when is_integer(Line) ->
+ Reason =
+ lists:flatten(
+ io_lib:format("Illegal token (~p) on line ~w", [BadToken, Line])),
+ Code = ?megaco_bad_request,
+ {Code, Reason, Error};
+ {error, [{reason, {bad_token, _}, Line}]} when is_integer(Line) ->
+ Reason = lists:concat(["Illegal token on line ", Line]),
+ Code = ?megaco_bad_request,
+ {Code, Reason, Error};
+ {error, [{reason, {Line, _ParserMod, RawReasonString}} | _]} when is_integer(Line) andalso is_list(RawReasonString) ->
+ Reason =
+ case RawReasonString of
+ [[$s, $y, $n, $t, $a, $x | _], TokenString] ->
+ lists:flatten(
+ io_lib:format("Syntax error on line ~w before token ~s", [Line, TokenString]));
+ _ ->
+ lists:flatten(io_lib:format("Syntax error on line ~w", [Line]))
+ end,
+ Code = ?megaco_bad_request,
+ {Code, Reason, Error};
+ {error, [{reason, {Line, _, _}} | _]} when is_integer(Line) ->
+ Reason = lists:concat(["Syntax error on line ", Line]),
+ Code = ?megaco_bad_request,
+ {Code, Reason, Error};
+ {error, {connection_refused, ED}} when is_record(ED,'ErrorDescriptor') ->
+ Code = ED#'ErrorDescriptor'.errorCode,
+ Reason = ED#'ErrorDescriptor'.errorText,
+ {Code, Reason, Error};
+ {error, {connection_refused, _}} ->
+ Reason = "Connection refused by user",
+ Code = ?megaco_unauthorized,
+ {Code, Reason, Error};
+ {error, {unsupported_version, V}} ->
+ Reason =
+ lists:flatten(io_lib:format("Unsupported version: ~w",[V])),
+ Code = ?megaco_version_not_supported,
+ {Code, Reason, Error};
+ {error, {not_negotiated_version, NegV, MsgV}} ->
+ Reason =
+ lists:flatten(
+ io_lib:format("Not negotiated version: ~w [negotiated ~w]",
+ [MsgV, NegV])),
+ Code = ?megaco_version_not_supported,
+ {Code, Reason, Error};
+ {error, _} ->
+ Reason = "Syntax error",
+ Code = ?megaco_bad_request,
+ {Code, Reason, Error};
+ {ok, MegaMsg} when is_record(MegaMsg, 'MegacoMessage') ->
+ Reason = "MID does not match config",
+ Code = ?megaco_incorrect_identifier,
+ {Code, Reason, Error};
+ _ ->
+ Reason = "Fatal syntax error",
+ Code = ?megaco_internal_gateway_error,
+ {Code, Reason, Error}
+ end.
+
+prepare_trans(_ConnData, [], AckList, ReqList, _Extra) ->
+ ?SIM({AckList, ReqList}, prepare_trans_done);
+
+prepare_trans(ConnData, Trans, AckList, ReqList, Extra)
+ when ConnData#conn_data.monitor_ref =:= undefined_auto_monitor_ref ->
+
+ ?rt3("prepare_trans - autoconnect"),
+
+ %% <BUGBUG>
+ %% Do we need something here, if we send more then one
+ %% trans per message?
+ %% </BUGBUG>
+
+ %% May occur if another process has already setup a
+ %% temporary connection, but the handle_connect callback
+ %% function has not yet returned before the eager MG
+ %% re-sends its initial service change message.
+
+ prepare_autoconnecting_trans(ConnData, Trans, AckList, ReqList, Extra);
+
+prepare_trans(#conn_data{monitor_ref = connected} = ConnData,
+ Trans, AckList, ReqList, Extra) ->
+
+ ?rt3("prepare_trans - connected"),
+
+ %%
+ %% This will happen when the "MGC" user performs a "pre" connect,
+ %% instead of waiting for the auto-connect (which normally
+ %% happen when the MGC receives the first message from the
+ %% MG).
+ %%
+
+ %%
+ %% The monitor_ref will have this value when the pre-connect
+ %% is complete, so we finish it here and then continue with the
+ %% normal transaction prepare.
+ %%
+
+ case finish_connect(ConnData) of
+ {ok, CD} ->
+ prepare_normal_trans(CD, Trans, AckList, ReqList, Extra);
+ {error, Reason} ->
+ disconnect(ConnData#conn_data.conn_handle, Reason),
+ {[], []}
+ end;
+
+prepare_trans(#conn_data{monitor_ref = {connecting, _}} = _ConnData,
+ _Trans, _AckList, _ReqList, _Extra) ->
+
+ ?rt3("prepare_trans - connecting"),
+
+ %%
+ %% This will happen when the "MGC" user performs a "pre" connect,
+ %% instead of waiting for the auto-connect (which normally
+ %% happen when the MGC receives the first message from the
+ %% MG).
+ %%
+
+ %%
+ %% The monitor_ref will have this value when the pre-connect
+ %% is in progress. We drop (ignore) this message and hope the
+ %% other side (MG) will resend.
+ %%
+
+ %% prepare_connecting_trans(ConnData, Trans, AckList, ReqList, Extra);
+ {[], []};
+
+prepare_trans(ConnData, Trans, AckList, ReqList, Extra) ->
+
+ ?rt3("prepare_trans - normal"),
+
+ %% Handle transaction in the normal case
+
+ prepare_normal_trans(ConnData, Trans, AckList, ReqList, Extra).
+
+
+prepare_autoconnecting_trans(_ConnData, [], AckList, ReqList, _Extra) ->
+ ?SIM({AckList, ReqList}, prepare_autoconnecting_trans_done);
+
+prepare_autoconnecting_trans(ConnData, [Trans | Rest], AckList, ReqList, Extra) ->
+ ?rt1(ConnData, "[autoconnecting] prepare trans", [Trans]),
+ case Trans of
+ {transactionRequest, T} when is_record(T, 'TransactionRequest') ->
+
+ Serial = T#'TransactionRequest'.transactionId,
+ ConnData2 = ConnData#conn_data{serial = Serial},
+ ?report_trace(ConnData2, "Pending handle_connect", [T]),
+
+ %% ------------------------------------------
+ %%
+ %% Check pending limit
+ %%
+ %% ------------------------------------------
+
+ Limit = ConnData#conn_data.sent_pending_limit,
+ TransId = to_remote_trans_id(ConnData2),
+ case check_and_maybe_incr_pending_limit(Limit, sent, TransId) of
+ ok ->
+ send_pending(ConnData2);
+ error ->
+ %% Pending limit:
+ %% In this (granted, highly hypothetical case)
+ %% we would make the user very confused if we
+ %% called the abort callback function, since
+ %% the request callback function has not yet
+ %% been called. Alas, we skip this call here.
+ send_pending_limit_error(ConnData);
+ aborted ->
+ ignore
+ end,
+ prepare_autoconnecting_trans(ConnData2, Rest, AckList, ReqList,
+ Extra);
+ _ ->
+ prepare_autoconnecting_trans(ConnData, Rest, AckList, ReqList,
+ Extra)
+ end.
+
+
+%% =================================================================
+%%
+%% Note that the TransactionReply record was changed i v3 (two
+%% new fields where added), and since we don't know which version,
+%% we cannot use the record definition of TransactionReply.
+%% Instead we transform the record into our own internal format
+%% #megaco_transaction_reply{}
+%%
+%% =================================================================
+
+prepare_normal_trans(_ConnData, [], AckList, ReqList, _Extra) ->
+ ?SIM({AckList, ReqList}, prepare_normal_trans_done);
+
+prepare_normal_trans(ConnData, [Trans | Rest], AckList, ReqList, Extra) ->
+ ?rt1(ConnData, "prepare [normal] trans", [Trans]),
+ case Trans of
+ {transactionRequest, #'TransactionRequest'{transactionId = asn1_NOVALUE}} ->
+ ConnData2 = ConnData#conn_data{serial = 0},
+ Code = ?megaco_bad_request,
+ Reason = "Syntax error in message: transaction id missing",
+ send_trans_error(ConnData2, Code, Reason),
+ prepare_normal_trans(ConnData2, Rest, AckList, ReqList, Extra);
+ {transactionRequest, T} when is_record(T, 'TransactionRequest') ->
+ Serial = T#'TransactionRequest'.transactionId,
+ ConnData2 = ConnData#conn_data{serial = Serial},
+ prepare_request(ConnData2, T, Rest, AckList, ReqList, Extra);
+ {transactionPending, T} when is_record(T, 'TransactionPending') ->
+ Serial = T#'TransactionPending'.transactionId,
+ ConnData2 = ConnData#conn_data{serial = Serial},
+ handle_pending(ConnData2, T, Extra),
+ prepare_normal_trans(ConnData2, Rest, AckList, ReqList, Extra);
+ {transactionReply, T} when is_tuple(T) andalso
+ (element(1, T) == 'TransactionReply') ->
+ T2 = transform_transaction_reply_dec(T),
+ Serial = T2#megaco_transaction_reply.transactionId,
+ ConnData2 = ConnData#conn_data{serial = Serial},
+ handle_reply(ConnData2, T2, Extra),
+ prepare_normal_trans(ConnData2, Rest, AckList, ReqList, Extra);
+ {transactionResponseAck, List} when is_list(List) ->
+ prepare_ack(ConnData, List, Rest, AckList, ReqList, Extra);
+ {segmentReply, SR} when is_record(SR, 'SegmentReply') ->
+ handle_segment_reply(ConnData, SR, Extra),
+ prepare_normal_trans(ConnData, Rest, AckList, ReqList, Extra)
+
+ end.
+
+
+prepare_request(ConnData, T, Rest, AckList, ReqList, Extra) ->
+ ?rt2("prepare request", [T]),
+ ConnHandle = ConnData#conn_data.conn_handle,
+ LocalMid = ConnHandle#megaco_conn_handle.local_mid,
+ TransId = to_remote_trans_id(ConnData),
+ ?rt2("prepare request", [LocalMid, TransId]),
+ case megaco_monitor:lookup_reply(TransId) of
+ [] ->
+ ?rt3("brand new request"),
+
+ %% Brand new request
+
+ %% Check pending limit:
+ %%
+ %% We should actually check the pending limit here
+ %% but since we have to do it later in the
+ %% handle_request function (just before we call
+ %% the handle_trans_request callback function) we
+ %% can just as well wait (this is after all a very
+ %% unlikely case: see function prepare_trans when
+ %% monitor_ref == undefined_auto_monitor_ref).
+ %%
+
+ #conn_data{send_handle = SendHandle,
+ pending_timer = InitTimer,
+ protocol_version = Version} = ConnData,
+ {WaitFor, CurrTimer} = megaco_timer:init(InitTimer),
+ M = ?MODULE,
+ F = pending_timeout,
+ A = [ConnHandle, TransId, CurrTimer],
+ PendingRef = megaco_monitor:apply_after(M, F, A, WaitFor),
+ Rep = #reply{send_handle = SendHandle,
+ trans_id = TransId,
+ local_mid = LocalMid,
+ pending_timer_ref = PendingRef,
+ handler = self(),
+ version = Version},
+ case megaco_monitor:insert_reply_new(Rep) of
+ true ->
+ prepare_normal_trans(ConnData, Rest, AckList,
+ [{ConnData, TransId, T} | ReqList],
+ Extra);
+ false ->
+ %% Oups - someone got there before we did...
+ ?report_debug(ConnData,
+ "prepare request: conflicting requests",
+ [TransId]),
+ send_pending(ConnData),
+ megaco_monitor:cancel_apply_after(PendingRef),
+ prepare_normal_trans(ConnData, Rest, AckList, ReqList,
+ Extra)
+ end;
+
+ [#reply{state = State,
+ handler = Pid,
+ pending_timer_ref = Ref} = Rep]
+ when (State =:= prepare) orelse (State =:= eval_request) ->
+
+ ?rt2("request resend", [State, Pid, Ref]),
+
+ %% Pending limit:
+ %% We are still preparing/evaluating the request
+ %% Check if the pending limit has been exceeded...
+ %% If the pending limit is _not_ exceeded then
+ %% we shall send a pending (and actually restart
+ %% the pending timer, but that we cannot do).
+ %% Don't care about Msg and Rep version diff
+
+ #conn_data{sent_pending_limit = Limit} = ConnData,
+
+ case check_and_maybe_incr_pending_limit(Limit, sent, TransId) of
+ ok ->
+
+ %% ------------------------------------------
+ %%
+ %% Pending limit not exceeded
+ %%
+ %% 1) Increment number of pendings sent
+ %% (done in the check function above)
+ %% 2) Send pending message
+ %% (We should really restart the pending
+ %% timer, but we have no way of doing that).
+ %%
+ %% ------------------------------------------
+
+ send_pending(ConnData),
+ prepare_normal_trans(ConnData, Rest, AckList, ReqList,
+ Extra);
+
+
+ error ->
+
+ %% -------------------------------------------
+ %%
+ %% Pending limit exceeded
+ %%
+ %% 1) Cancel pending timer
+ %% 2) Send 506 error message to other side
+ %% 3) Inform user (depends on state)
+ %% 4) Set reply in aborted state
+ %%
+ %% -------------------------------------------
+
+ %%
+ %% State == eval_request:
+ %% This means that the request is currently beeing
+ %% evaluated by the user, and the reply timer has
+ %% not yet been started.
+ %% Either:
+ %% a) The "other side" will resend (which will
+ %% trigger a pending message send) until we pass the
+ %% pending limit
+ %% b) We will send pending messages (when the pending
+ %% timer expire) until we pass the pending limit.
+ %% In any event, we cannot delete the reply record
+ %% or the pending counter in this case. Is there
+ %% a risk we accumulate aborted reply records?
+ %%
+ %% State == prepare:
+ %% The user does not know about this request
+ %% so we can safely perform cleanup.
+ %%
+ megaco_monitor:cancel_apply_after(Ref),
+ send_pending_limit_error(ConnData),
+ if
+ State == eval_request ->
+ %%
+ %% What if the user never replies?
+ %% In that case we will have a record
+ %% (and counters) that is never cleaned up...
+ NewFields =
+ [{#reply.state, aborted},
+ {#reply.pending_timer_ref, undefined}],
+ megaco_monitor:update_reply_fields(TransId,
+ NewFields),
+ handle_request_abort_callback(ConnData,
+ TransId, Pid, Extra);
+ true ->
+ %% Since the user does not know about
+ %% this call yet, it is safe to cleanup.
+ %% Should we inform?
+ Rep2 = Rep#reply{state = aborted},
+ cancel_reply(ConnData, Rep2, aborted),
+ ok
+ end,
+ prepare_normal_trans(ConnData, Rest, AckList, ReqList,
+ Extra);
+
+
+ aborted ->
+
+ %% -------------------------------------------
+ %%
+ %% Pending limit already exceeded
+ %%
+ %% Cleanup, just to make sure:
+ %% reply record & pending counter
+ %%
+ %% -------------------------------------------
+
+ Rep2 = Rep#reply{state = aborted},
+ cancel_reply(ConnData, Rep2, aborted),
+ prepare_normal_trans(ConnData, Rest, AckList, ReqList,
+ Extra)
+
+ end;
+
+ [#reply{state = waiting_for_ack,
+ bytes = Bin,
+ version = Version} = Rep] ->
+ ?rt3("request resend when waiting for ack"),
+
+ %% We have already sent a reply, but the receiver
+ %% has obviously not got it. Resend the reply but
+ %% don't restart the reply_timer.
+ ConnData2 = ConnData#conn_data{protocol_version = Version},
+ ?report_trace(ConnData2,
+ "re-send trans reply", [T | {bytes, Bin}]),
+ case megaco_messenger_misc:send_message(ConnData2, true, Bin) of
+ {ok, _} ->
+ ok;
+ {error, Reason} ->
+ %% Pass it on to the user (via handle_ack)
+ cancel_reply(ConnData2, Rep, Reason)
+ end,
+ prepare_normal_trans(ConnData2, Rest, AckList, ReqList, Extra);
+
+ [#reply{state = aborted} = Rep] ->
+ ?rt3("request resend when already in aborted state"),
+
+ %% OTP-4956:
+ %% Already aborted so ignore.
+ %% This furthermore means that the abnoxious user at the
+ %% other end has already been informed (pending-limit
+ %% passed => error descriptor sent), but keeps sending...
+ %%
+ %% Shall we perform a cleanup?
+ cancel_reply(ConnData, Rep, aborted),
+ prepare_normal_trans(ConnData, Rest, AckList, ReqList, Extra)
+ end.
+
+prepare_ack(ConnData, [TA | T], Rest, AckList, ReqList, Extra)
+ when is_record(TA, 'TransactionAck') ->
+ First = TA#'TransactionAck'.firstAck,
+ Last = TA#'TransactionAck'.lastAck,
+ TA2 = TA#'TransactionAck'{lastAck = asn1_NOVALUE},
+ ConnData2 = ConnData#conn_data{serial = First},
+ AckList2 = do_prepare_ack(ConnData2, TA2, AckList),
+ if
+ Last =:= asn1_NOVALUE ->
+ prepare_ack(ConnData, T, Rest, AckList2, ReqList, Extra);
+ First < Last ->
+ TA3 = TA#'TransactionAck'{firstAck = First + 1},
+ prepare_ack(ConnData, [TA3 | T], Rest, AckList2, ReqList, Extra);
+ First =:= Last ->
+ prepare_ack(ConnData, T, Rest, AckList2, ReqList, Extra);
+ First > Last ->
+ %% Protocol violation from the sender of this ack
+ ?report_important(ConnData, "<ERROR> discard trans",
+ [TA, {error, "firstAck > lastAck"}]),
+ prepare_ack(ConnData, T, Rest, AckList2, ReqList, Extra)
+ end;
+prepare_ack(ConnData, [], Rest, AckList, ReqList, Extra) ->
+ prepare_normal_trans(ConnData, Rest, AckList, ReqList, Extra).
+
+do_prepare_ack(ConnData, T, AckList) ->
+ TransId = to_remote_trans_id(ConnData),
+ case megaco_monitor:lookup_reply(TransId) of
+ [] ->
+ %% The reply has already been garbage collected. Ignore.
+ ?report_trace(ConnData, "discard ack (no receiver)", [T]),
+ AckList;
+ [Rep] when Rep#reply.state =:= waiting_for_ack ->
+ %% Don't care about Msg and Rep version diff
+ [{ConnData, Rep, T} | AckList];
+ [_Rep] ->
+ %% Protocol violation from the sender of this ack
+ ?report_important(ConnData, "<ERROR> discard trans",
+ [T, {error, "got ack before reply was sent"}]),
+ AckList
+ end.
+
+
+increment_request_keep_alive_counter(#conn_data{conn_handle = CH}, TransId) ->
+ ?rt1(CH, "increment request keep alive counter", [TransId]),
+ megaco_config:incr_reply_counter(CH, TransId).
+
+create_or_maybe_increment_request_keep_alive_counter(
+ #conn_data{conn_handle = CH}, TransId) ->
+ ?rt1(CH, "create or maybe increment request keep alive counter",
+ [TransId]),
+ try
+ begin
+ megaco_config:cre_reply_counter(CH, TransId)
+ end
+ catch
+ _:_ ->
+ megaco_config:incr_reply_counter(CH, TransId)
+ end.
+
+
+check_and_maybe_create_pending_limit(infinity, _, _) ->
+ ok;
+check_and_maybe_create_pending_limit(Limit, Direction, TransId) ->
+ ?rt2("check and maybe create pending limit counter",
+ [Limit, Direction, TransId]),
+ try megaco_config:get_pending_counter(Direction, TransId) of
+ Val when Val =< Limit ->
+ %% Since we have no intention to increment here, it
+ %% is ok to be _at_ the limit
+ ok;
+ _ ->
+ aborted
+ catch
+ _:_ ->
+ %% Has not been created yet (connect).
+ megaco_config:cre_pending_counter(Direction, TransId, 0),
+ ok
+ end.
+
+%% check_and_maybe_create_pending_limit(infinity, _, _) ->
+%% ok;
+%% check_and_maybe_create_pending_limit(Limit, Direction, TransId) ->
+%% case (catch megaco_config:get_pending_counter(Direction, TransId)) of
+%% {'EXIT', _} ->
+%% %% Has not been created yet (connect).
+%% megaco_config:cre_pending_counter(Direction, TransId, 0),
+%% ok;
+%% Val when Val =< Limit ->
+%% %% Since we have no intention to increment here, it
+%% %% is ok to be _at_ the limit
+%% ok;
+%% _ ->
+%% aborted
+%% end.
+
+
+check_pending_limit(infinity, _, _) ->
+ {ok, 0};
+check_pending_limit(Limit, Direction, TransId) ->
+ ?rt2("check pending limit", [Direction, Limit, TransId]),
+ try megaco_config:get_pending_counter(Direction, TransId) of
+ Val when Val =< Limit ->
+ %% Since we have no intention to increment here, it
+ %% is ok to be _at_ the limit
+ ?rt2("check pending limit - ok", [Val]),
+ {ok, Val};
+ _Val ->
+ ?rt2("check pending limit - aborted", [_Val]),
+ aborted
+ catch
+ _:_ ->
+ %% This function is only called when we "know" the
+ %% counter to exist. So, the only reason that this
+ %% would happen is of the counter has been removed.
+ %% This only happen if the pending limit has been
+ %% reached. In any case, this is basically the same
+ %% as aborted!
+ ?rt2("check pending limit - exit", []),
+ aborted
+ end.
+
+%% check_pending_limit(infinity, _, _) ->
+%% {ok, 0};
+%% check_pending_limit(Limit, Direction, TransId) ->
+%% ?rt2("check pending limit", [Direction, Limit, TransId]),
+%% case (catch megaco_config:get_pending_counter(Direction, TransId)) of
+%% {'EXIT', _} ->
+%% %% This function is only called when we "know" the
+%% %% counter to exist. So, the only reason that this
+%% %% would happen is of the counter has been removed.
+%% %% This only happen if the pending limit has been
+%% %% reached. In any case, this is basically the same
+%% %% as aborted!
+%% ?rt2("check pending limit - exit", []),
+%% aborted;
+%% Val when Val =< Limit ->
+%% %% Since we have no intention to increment here, it
+%% %% is ok to be _at_ the limit
+%% ?rt2("check pending limit - ok", [Val]),
+%% {ok, Val};
+%% _Val ->
+%% ?rt2("check pending limit - aborted", [_Val]),
+%% aborted
+%% end.
+
+
+check_and_maybe_incr_pending_limit(infinity, _, _) ->
+ ok;
+check_and_maybe_incr_pending_limit(Limit, Direction, TransId) ->
+ %%
+ %% We need this kind of test to detect when we _pass_ the limit
+ %%
+ ?rt2("check and maybe incr pending limit", [Direction, Limit, TransId]),
+ try megaco_config:get_pending_counter(Direction, TransId) of
+ Val when Val > Limit ->
+ ?rt2("check and maybe incr - aborted", [Direction, Val, Limit]),
+ aborted; % Already passed the limit
+ Val ->
+ ?rt2("check and maybe incr - incr", [Direction, Val, Limit]),
+ megaco_config:incr_pending_counter(Direction, TransId),
+ if
+ Val < Limit ->
+ ok; % Still within the limit
+ true ->
+ ?rt2("check and maybe incr - error",
+ [Direction, Val, Limit]),
+ error % Passed the limit
+ end
+ catch
+ _:_ ->
+ %% Has not been created yet (connect).
+ megaco_config:cre_pending_counter(Direction, TransId, 1),
+ ok
+ end.
+
+
+%% check_and_maybe_incr_pending_limit(infinity, _, _) ->
+%% ok;
+%% check_and_maybe_incr_pending_limit(Limit, Direction, TransId) ->
+%% %%
+%% %% We need this kind of test to detect when we _pass_ the limit
+%% %%
+%% ?rt2("check and maybe incr pending limit", [Direction, Limit, TransId]),
+%% case (catch megaco_config:get_pending_counter(Direction, TransId)) of
+%% {'EXIT', _} ->
+%% %% Has not been created yet (connect).
+%% megaco_config:cre_pending_counter(Direction, TransId, 1),
+%% ok;
+%% Val when Val > Limit ->
+%% ?rt2("check and maybe incr - aborted", [Direction, Val, Limit]),
+%% aborted; % Already passed the limit
+%% Val ->
+%% ?rt2("check and maybe incr - incr", [Direction, Val, Limit]),
+%% megaco_config:incr_pending_counter(Direction, TransId),
+%% if
+%% Val < Limit ->
+%% ok; % Still within the limit
+%% true ->
+%% ?rt2("check and maybe incr - error",
+%% [Direction, Val, Limit]),
+%% error % Passed the limit
+%% end
+%% end.
+
+
+%% BUGBUG BUGBUG BUGBUG
+%%
+%% Do we know that the Rep is still valid? A previous transaction
+%% could have taken a lot of time.
+%%
+handle_request({ConnData, TransId, T}, Extra) ->
+ case handle_request(ConnData, TransId, T, Extra) of
+ {pending, _RequestData} ->
+ handle_long_request(ConnData, TransId, T, Extra);
+ Else ->
+ Else
+ end.
+
+handle_request(ConnData, TransId, T, Extra) ->
+ ?report_trace(ConnData, "handle request", [TransId, T]),
+
+ %% Pending limit:
+ %% Ok, before we begin, lets check that this request
+ %% has not been aborted. I.e. exceeded the pending
+ %% limit, so go check it...
+
+ #conn_data{sent_pending_limit = Limit} = ConnData,
+
+ case check_and_maybe_create_pending_limit(Limit, sent, TransId) of
+ ok ->
+ %% Ok so far, now update state
+ case megaco_monitor:update_reply_field(TransId,
+ #reply.state,
+ eval_request) of
+ true ->
+ Actions = T#'TransactionRequest'.actions,
+ {AckAction, SendReply} =
+ handle_request_callback(ConnData, TransId, Actions,
+ T, Extra),
+
+ %% Next step, while we where in the callback function,
+ %% the pending limit could have been exceeded, so check
+ %% it again...
+ do_handle_request(AckAction, SendReply,
+ ConnData, TransId);
+
+ false ->
+ %% Ugh?
+ ignore
+ end;
+
+ aborted ->
+ %% Pending limit
+ %% Already exceeded the limit
+ %% The user does not yet know about this request, so
+ %% don't bother telling that it has been aborted...
+ %% Furthermore, the reply timer has not been started,
+ %% so do the cleanup now
+ ?rt1(ConnData, "pending limit already passed", [TransId]),
+ case megaco_monitor:lookup_reply(TransId) of
+ [Rep] ->
+ cancel_reply(ConnData, Rep, aborted);
+ _ ->
+ ok
+ end,
+ ignore
+ end.
+
+do_handle_request(_, ignore, _ConnData, _TransId) ->
+ ?rt1(_ConnData, "ignore: don't reply", [_TransId]),
+ ignore;
+do_handle_request(_, ignore_trans_request, ConnData, TransId) ->
+ ?rt1(ConnData, "ignore trans request: don't reply", [TransId]),
+ case megaco_monitor:lookup_reply(TransId) of
+ [#reply{} = Rep] ->
+ cancel_reply(ConnData, Rep, ignore);
+ _ ->
+ ignore
+ end;
+do_handle_request({pending, _RequestData}, {aborted, ignore}, _, _) ->
+ ?rt2("handle request: pending - aborted - ignore => don't reply", []),
+ ignore;
+do_handle_request({pending, _RequestData}, {aborted, _SendReply}, _, _) ->
+ ?rt2("handle request: pending - aborted => don't reply", []),
+ ignore;
+do_handle_request({pending, RequestData}, _SendReply, _ConnData, _) ->
+ ?rt2("handle request: pending", [RequestData]),
+ {pending, RequestData};
+do_handle_request(AckAction, {ok, Bin}, ConnData, TransId)
+ when is_binary(Bin) ->
+ ?rt1(ConnData, "handle request - ok", [AckAction, TransId]),
+ case megaco_monitor:lookup_reply(TransId) of
+ [#reply{pending_timer_ref = PendingRef} = Rep] ->
+
+ #conn_data{reply_timer = InitTimer,
+ conn_handle = ConnHandle} = ConnData,
+
+ %% Pending limit update:
+ %% - Cancel the pending timer, if running
+ %% - Delete the pending counter
+ %%
+
+ megaco_monitor:cancel_apply_after(PendingRef),
+ megaco_config:del_pending_counter(sent, TransId),
+
+ Method = timer_method(AckAction),
+ {WaitFor, CurrTimer} = megaco_timer:init(InitTimer),
+ OptBin = opt_garb_binary(CurrTimer, Bin),
+ M = ?MODULE,
+ F = reply_timeout,
+ A = [ConnHandle, TransId, CurrTimer],
+ Ref = megaco_monitor:apply_after(Method, M, F, A,
+ WaitFor),
+ Rep2 = Rep#reply{pending_timer_ref = undefined,
+ handler = undefined,
+ bytes = OptBin,
+ state = waiting_for_ack,
+ timer_ref = Ref,
+ ack_action = AckAction},
+ megaco_monitor:insert_reply(Rep2), % Timing problem?
+ ignore;
+
+ _ ->
+ %% Been removed already?
+ ignore
+ end;
+do_handle_request(AckAction, {ok, {Sent, NotSent}}, ConnData, TransId)
+ when is_list(Sent) andalso is_list(NotSent) ->
+ ?rt1(ConnData, "handle request - ok [segmented reply]",
+ [AckAction, TransId]),
+
+ case megaco_monitor:lookup_reply(TransId) of
+ [#reply{pending_timer_ref = PendingRef} = Rep] ->
+
+ %% d("do_handle_request -> found reply record:"
+ %% "~n Rep: ~p", [Rep]),
+
+ #conn_data{reply_timer = InitTimer,
+ conn_handle = ConnHandle} = ConnData,
+
+ %% Pending limit update:
+ %% - Cancel the pending timer, if running
+ %% - Delete the pending counter
+ %%
+
+ megaco_monitor:cancel_apply_after(PendingRef),
+ megaco_config:del_pending_counter(sent, TransId),
+
+ Method = timer_method(AckAction),
+ {WaitFor, CurrTimer} = megaco_timer:init(InitTimer),
+ Garb = fun(Bin) -> opt_garb_binary(CurrTimer, Bin) end,
+ OptBins = [{SN, Garb(Bin), undefined} || {SN, Bin} <- Sent],
+
+ M = ?MODULE,
+ F = reply_timeout,
+ A = [ConnHandle, TransId, CurrTimer],
+ Ref = megaco_monitor:apply_after(Method, M, F, A, WaitFor),
+
+ Rep2 = Rep#reply{pending_timer_ref = undefined,
+ handler = undefined,
+ bytes = OptBins,
+ state = waiting_for_ack,
+ timer_ref = Ref,
+ ack_action = AckAction,
+ segments = NotSent},
+ megaco_monitor:insert_reply(Rep2), % Timing problem?
+
+ ignore;
+ _ ->
+ %% Been removed already?
+ ignore
+ end;
+do_handle_request(_, {error, aborted}, ConnData, TransId) ->
+ ?report_trace(ConnData, "aborted during our absence", [TransId]),
+ case megaco_monitor:lookup_reply(TransId) of
+ [Rep] ->
+ cancel_reply(ConnData, Rep, aborted);
+ _ ->
+ ok
+ end,
+ ignore;
+do_handle_request(AckAction, {error, Reason}, ConnData, TransId) ->
+ ?report_trace(ConnData, "error", [TransId, Reason]),
+ case megaco_monitor:lookup_reply(TransId) of
+ [Rep] ->
+ Rep2 = Rep#reply{state = waiting_for_ack,
+ ack_action = AckAction},
+ cancel_reply(ConnData, Rep2, Reason);
+ _ ->
+ ok
+ end,
+ ignore;
+do_handle_request(AckAction, SendReply, ConnData, TransId) ->
+ ?report_trace(ConnData, "unknown send trans reply result",
+ [TransId, AckAction, SendReply]),
+ ignore.
+
+
+handle_requests([{ConnData, TransId, T} | Rest], Pending, Extra) ->
+ ?rt2("handle requests", [TransId]),
+ case handle_request(ConnData, TransId, T, Extra) of
+ {pending, RequestData} ->
+ handle_requests(Rest, [{ConnData,TransId,RequestData} | Pending], Extra);
+ _ ->
+ handle_requests(Rest, Pending, Extra)
+ end;
+handle_requests([], Pending, _Extra) ->
+ ?rt2("handle requests - done", [Pending]),
+ Pending.
+
+%% opt_garb_binary(timeout, _Bin) -> garb_binary; % Need msg at restart of timer
+opt_garb_binary(_Timer, Bin) -> Bin.
+
+timer_method(discard_ack) ->
+ apply_method;
+timer_method(_) ->
+ spawn_method.
+
+
+handle_long_request({ConnData, TransId, RequestData}, Extra) ->
+
+ ?rt2("handle long request", [TransId, RequestData]),
+
+ %% Pending limit:
+ %% We need to check the pending limit, in case it was
+ %% exceeded before we got this far...
+ %% We dont need to be able to create the counter here,
+ %% since that was done in the handle_request function.
+
+ #conn_data{sent_pending_limit = Limit} = ConnData,
+
+ case check_pending_limit(Limit, sent, TransId) of
+ {ok, _} ->
+ handle_long_request(ConnData, TransId, RequestData, Extra);
+ _ ->
+ %% Already exceeded the limit
+ ignore
+ end.
+
+handle_long_request(ConnData, TransId, RequestData, Extra) ->
+ ?report_trace(ConnData, "callback: trans long request",
+ [TransId, {request_data, RequestData}]),
+
+ %% Attempt to update the handler field for this reply record
+ %% (if there is one).
+ case megaco_monitor:update_reply_field(TransId, #reply.handler, self()) of
+ true ->
+ {AckAction, Res} =
+ handle_long_request_callback(ConnData, TransId,
+ RequestData, Extra),
+ do_handle_long_request(AckAction, Res, ConnData, TransId);
+ false ->
+ %% Been removed already?
+ ignore
+ end.
+
+
+do_handle_long_request(AckAction, {ok, Bin}, ConnData, TransId) ->
+ case megaco_monitor:lookup_reply_field(TransId, #reply.trans_id) of
+ {ok, _} ->
+ Method = timer_method(AckAction),
+ InitTimer = ConnData#conn_data.reply_timer,
+ {WaitFor, CurrTimer} = megaco_timer:init(InitTimer),
+ OptBin = opt_garb_binary(CurrTimer, Bin),
+ ConnHandle = ConnData#conn_data.conn_handle,
+ M = ?MODULE,
+ F = reply_timeout,
+ A = [ConnHandle, TransId, CurrTimer],
+ Ref = megaco_monitor:apply_after(Method, M, F, A, WaitFor),
+ NewFields =
+ [{#reply.bytes, OptBin},
+ {#reply.state, waiting_for_ack},
+ {#reply.timer_ref, Ref},
+ {#reply.ack_action, AckAction}],
+ megaco_monitor:update_reply_fields(TransId, NewFields); % Timing problem?
+ _ ->
+ %% Been removed already?
+ ignore
+ end;
+do_handle_long_request(_, {error, Reason}, ConnData, TransId) ->
+ ?report_trace(ConnData, "send trans reply", [TransId, {error, Reason}]),
+ ignore.
+
+handle_request_abort_callback(ConnData, TransId, Pid) ->
+ Extra = ?default_user_callback_extra,
+ handle_request_abort_callback(ConnData, TransId, Pid, Extra).
+
+handle_request_abort_callback(ConnData, TransId, Pid, Extra) ->
+ ?report_trace(ConnData, "callback: trans request aborted", [TransId, Pid]),
+ ConnHandle = ConnData#conn_data.conn_handle,
+ Version = ConnData#conn_data.protocol_version,
+ UserMod = ConnData#conn_data.user_mod,
+ UserArgs = ConnData#conn_data.user_args,
+ Serial = TransId#trans_id.serial,
+ Args =
+ case Extra of
+ ?default_user_callback_extra ->
+ [ConnHandle, Version, Serial, Pid | UserArgs];
+ _ ->
+ [ConnHandle, Version, Serial, Pid, Extra | UserArgs]
+ end,
+ Res = (catch apply(UserMod, handle_trans_request_abort, Args)),
+ ?report_debug(ConnData, "return: trans request aborted",
+ [TransId, {return, Res}]),
+ case Res of
+ ok ->
+ ok;
+ _ ->
+ warning_msg("transaction request abort callback failed: ~w",
+ [Res]),
+ ok
+ end.
+
+handle_request_callback(ConnData, TransId, Actions, T, Extra) ->
+ ?report_trace(ConnData, "callback: trans request", [T]),
+ ConnHandle = ConnData#conn_data.conn_handle,
+ Version = ConnData#conn_data.protocol_version,
+ UserMod = ConnData#conn_data.user_mod,
+ UserArgs = ConnData#conn_data.user_args,
+ Args =
+ case Extra of
+ ?default_user_callback_extra ->
+ [ConnHandle, Version, Actions | UserArgs];
+ _ ->
+ [ConnHandle, Version, Actions, Extra | UserArgs]
+ end,
+ Res = (catch apply(UserMod, handle_trans_request, Args)),
+ ?report_debug(ConnData, "return: trans request", [T, {return, Res}]),
+ case Res of
+ ignore -> %% NOTE: Only used for testing!!
+ {discard_ack, ignore};
+
+ ignore_trans_request ->
+ {discard_ack, ignore_trans_request};
+
+ {discard_ack, Replies} when is_list(Replies) ->
+ Reply = {actionReplies, Replies},
+ SendReply = maybe_send_reply(ConnData, TransId, Reply,
+ [], asn1_NOVALUE),
+ {discard_ack, SendReply};
+ {discard_ack, Error} when is_record(Error, 'ErrorDescriptor') ->
+ Reply = {transactionError, Error},
+ SendReply = maybe_send_reply(ConnData, TransId, Reply,
+ [], asn1_NOVALUE),
+ {discard_ack, SendReply};
+ {discard_ack, Replies, SendOpts} when is_list(Replies) andalso
+ is_list(SendOpts) ->
+ Reply = {actionReplies, Replies},
+ SendReply = maybe_send_reply(ConnData, TransId, Reply,
+ SendOpts, asn1_NOVALUE),
+ {discard_ack, SendReply};
+ {discard_ack, Error, SendOpts}
+ when is_record(Error, 'ErrorDescriptor') andalso
+ is_list(SendOpts) ->
+ Reply = {transactionError, Error},
+ SendReply = maybe_send_reply(ConnData, TransId, Reply,
+ SendOpts, asn1_NOVALUE),
+ {discard_ack, SendReply};
+
+ {{handle_pending_ack, AckData}, Replies} when is_list(Replies) ->
+ Reply = {actionReplies, Replies},
+ SendReply = maybe_send_reply(ConnData, TransId, Reply,
+ [], when_pending_sent),
+ {{handle_ack, AckData}, SendReply};
+ {{handle_pending_ack, AckData}, Error}
+ when is_record(Error, 'ErrorDescriptor') ->
+ Reply = {transactionError, Error},
+ SendReply = maybe_send_reply(ConnData, TransId, Reply,
+ [], when_pending_sent),
+ {{handle_ack, AckData}, SendReply};
+ {{handle_pending_ack, AckData}, Replies, SendOpts}
+ when is_list(Replies) andalso
+ is_list(SendOpts) ->
+ Reply = {actionReplies, Replies},
+ SendReply = maybe_send_reply(ConnData, TransId, Reply,
+ SendOpts, when_pending_sent),
+ {{handle_ack, AckData}, SendReply};
+ {{handle_pending_ack, AckData}, Error, SendOpts}
+ when is_record(Error, 'ErrorDescriptor') andalso
+ is_list(SendOpts) ->
+ Reply = {transactionError, Error},
+ SendReply = maybe_send_reply(ConnData, TransId, Reply,
+ SendOpts, when_pending_sent),
+ {{handle_ack, AckData}, SendReply};
+
+ {{handle_ack, AckData}, Replies} when is_list(Replies) ->
+ Reply = {actionReplies, Replies},
+ SendReply = maybe_send_reply(ConnData, TransId, Reply,
+ [], 'NULL'),
+ {{handle_ack, AckData}, SendReply};
+ {{handle_ack, AckData}, Error}
+ when is_record(Error, 'ErrorDescriptor') ->
+ Reply = {transactionError, Error},
+ SendReply = maybe_send_reply(ConnData, TransId, Reply,
+ [], 'NULL'),
+ {{handle_ack, AckData}, SendReply};
+ {{handle_ack, AckData}, Replies, SendOpts}
+ when is_list(Replies) andalso
+ is_list(SendOpts) ->
+ Reply = {actionReplies, Replies},
+ SendReply = maybe_send_reply(ConnData, TransId, Reply,
+ SendOpts, 'NULL'),
+ {{handle_ack, AckData}, SendReply};
+ {{handle_ack, AckData}, Error, SendOpts}
+ when is_record(Error, 'ErrorDescriptor') andalso
+ is_list(SendOpts) ->
+ Reply = {transactionError, Error},
+ SendReply = maybe_send_reply(ConnData, TransId, Reply,
+ SendOpts, 'NULL'),
+ {{handle_ack, AckData}, SendReply};
+
+ {{handle_sloppy_ack, AckData}, Replies} when is_list(Replies) ->
+ Reply = {actionReplies, Replies},
+ SendReply = maybe_send_reply(ConnData, TransId, Reply,
+ [], asn1_NOVALUE),
+ {{handle_ack, AckData}, SendReply};
+ {{handle_sloppy_ack, AckData}, Error}
+ when is_record(Error, 'ErrorDescriptor') ->
+ Reply = {transactionError, Error},
+ SendReply = maybe_send_reply(ConnData, TransId, Reply,
+ [], asn1_NOVALUE),
+ {{handle_ack, AckData}, SendReply};
+ {{handle_sloppy_ack, AckData}, Replies, SendOpts}
+ when is_list(Replies) andalso
+ is_list(SendOpts) ->
+ Reply = {actionReplies, Replies},
+ SendReply = maybe_send_reply(ConnData, TransId, Reply,
+ SendOpts, asn1_NOVALUE),
+ {{handle_ack, AckData}, SendReply};
+ {{handle_sloppy_ack, AckData}, Error, SendOpts}
+ when is_record(Error, 'ErrorDescriptor') andalso
+ is_list(SendOpts) ->
+ Reply = {transactionError, Error},
+ SendReply = maybe_send_reply(ConnData, TransId, Reply,
+ SendOpts, asn1_NOVALUE),
+ {{handle_ack, AckData}, SendReply};
+
+ {pending, RequestData} ->
+ %% The user thinks that this request will take
+ %% quite a while to evaluate. Maybe respond with
+ %% a pending trans (depends on the pending limit)
+ SendReply = maybe_send_pending(ConnData, TransId),
+ {{pending, RequestData}, SendReply};
+
+ Error ->
+ ErrorText = atom_to_list(UserMod),
+ ED = #'ErrorDescriptor'{
+ errorCode = ?megaco_internal_gateway_error,
+ errorText = ErrorText},
+ ?report_important(ConnData,
+ "callback: <ERROR> trans request",
+ [ED, {error, Error}]),
+ error_msg("transaction request callback failed: ~w", [Error]),
+ Reply = {transactionError, ED},
+ SendReply = maybe_send_reply(ConnData, TransId, Reply,
+ [], asn1_NOVALUE),
+ {discard_ack, SendReply}
+ end.
+
+handle_long_request_callback(ConnData, TransId, RequestData, Extra) ->
+ ?report_trace(ConnData, "callback: trans long request", [RequestData]),
+ ConnHandle = ConnData#conn_data.conn_handle,
+ Version = ConnData#conn_data.protocol_version,
+ UserMod = ConnData#conn_data.user_mod,
+ UserArgs = ConnData#conn_data.user_args,
+ Args =
+ case Extra of
+ ?default_user_callback_extra ->
+ [ConnHandle, Version, RequestData | UserArgs];
+ _ ->
+ [ConnHandle, Version, RequestData, Extra | UserArgs]
+ end,
+ Res = (catch apply(UserMod, handle_trans_long_request, Args)),
+ ?report_debug(ConnData, "return: trans long request",
+ [{request_data, RequestData}, {return, Res}]),
+ case Res of
+ ignore ->
+ {discard_ack, ignore};
+
+ {discard_ack, Replies} when is_list(Replies) ->
+ Reply = {actionReplies, Replies},
+ SendReply = maybe_send_reply(ConnData, TransId, Reply,
+ [], asn1_NOVALUE),
+ {discard_ack, SendReply};
+ {discard_ack, Replies, SendOpts} when is_list(Replies) andalso
+ is_list(SendOpts) ->
+ Reply = {actionReplies, Replies},
+ SendReply = maybe_send_reply(ConnData, TransId, Reply,
+ SendOpts, asn1_NOVALUE),
+ {discard_ack, SendReply};
+
+ {{handle_ack, AckData}, Replies} when is_list(Replies) ->
+ Reply = {actionReplies, Replies},
+ SendReply = maybe_send_reply(ConnData, TransId, Reply,
+ [], 'NULL'),
+ {{handle_ack, AckData}, SendReply};
+ {{handle_ack, AckData}, Replies, SendOpts} when is_list(Replies)
+ andalso
+ is_list(SendOpts) ->
+ Reply = {actionReplies, Replies},
+ SendReply = maybe_send_reply(ConnData, TransId, Reply,
+ SendOpts, 'NULL'),
+ {{handle_ack, AckData}, SendReply};
+
+ Error ->
+ ErrorText = atom_to_list(UserMod),
+ ED = #'ErrorDescriptor'{errorCode = ?megaco_internal_gateway_error,
+ errorText = ErrorText},
+ ?report_important(ConnData, "callback: <ERROR> trans long request",
+ [ED, {error, Error}]),
+ error_msg("long transaction request callback failed: ~w", [Error]),
+ Reply = {transactionError, ED},
+ SendReply = maybe_send_reply(ConnData, TransId, Reply,
+ [], asn1_NOVALUE),
+ {discard_ack, SendReply}
+ end.
+
+handle_pending(ConnData, T, Extra) ->
+ TransId = to_local_trans_id(ConnData),
+ ?rt2("handle pending", [T, TransId]),
+ case megaco_monitor:lookup_request(TransId) of
+ [Req] ->
+
+ %% ------------------------------------------
+ %%
+ %% Check received pending limit
+ %%
+ %% ------------------------------------------
+
+ Limit = ConnData#conn_data.recv_pending_limit,
+ case check_and_maybe_incr_pending_limit(Limit,
+ recv, TransId) of
+
+ ok ->
+ %% ----------------------------------------------------
+ %%
+ %% Received pending limit not exceeded
+ %%
+ %% ----------------------------------------------------
+
+ handle_recv_pending(ConnData, TransId, Req, T);
+
+ error ->
+ %% ----------------------------------------------------
+ %%
+ %% Received pending limit exceeded
+ %%
+ %% Time to give up on this transaction
+ %% 1) Delete request record
+ %% 2) Cancel timers
+ %% 3) Delete the (receive) pending counter
+ %% 4) Inform the user (handle_trans_reply)
+ %%
+ %% ----------------------------------------------------
+
+ handle_recv_pending_error(ConnData, TransId, Req, T, Extra);
+
+
+ aborted ->
+ %% ----------------------------------------------------
+ %%
+ %% Received pending limit already exceeded
+ %%
+ %% BMK BMK BMK -- can this really happen?
+ %%
+ %% The user has already been notified about this
+ %% (see error above)
+ %%
+ %% ----------------------------------------------------
+
+ ok
+
+ end;
+
+ [] ->
+ ?report_trace(ConnData, "remote pending (no receiver)", [T]),
+ return_unexpected_trans(ConnData, T, Extra)
+ end.
+
+handle_recv_pending(#conn_data{long_request_resend = LRR,
+ conn_handle = ConnHandle} = ConnData,
+ TransId,
+ #request{timer_ref = {short, Ref},
+ init_long_timer = InitTimer}, T) ->
+
+ ?rt2("handle pending - long request", [LRR, InitTimer]),
+
+ %% The request seems to take a while,
+ %% let's reset our transmission timer.
+ %% We now know the other side has got
+ %% the request and is working on it,
+ %% so there is no need to keep the binary
+ %% message for re-transmission.
+
+ %% Start using the long timer.
+ %% We can now drop the "bytes", since we will
+ %% not resend from now on.
+
+ megaco_monitor:cancel_apply_after(Ref),
+ {WaitFor, CurrTimer} = megaco_timer:init(InitTimer),
+ ConnHandle = ConnData#conn_data.conn_handle,
+ M = ?MODULE,
+ F = request_timeout,
+ A = [ConnHandle, TransId],
+ Ref2 = megaco_monitor:apply_after(M, F, A, WaitFor),
+ NewFields =
+ case LRR of
+ true ->
+ [{#request.timer_ref, {long, Ref2}},
+ {#request.curr_timer, CurrTimer}];
+ false ->
+ [{#request.bytes, {no_send, garb_binary}},
+ {#request.timer_ref, {long, Ref2}},
+ {#request.curr_timer, CurrTimer}]
+ end,
+ ?report_trace(ConnData, "trans pending (timer restarted)", [T]),
+ megaco_monitor:update_request_fields(TransId, NewFields); % Timing problem?
+
+handle_recv_pending(_ConnData, _TransId,
+ #request{timer_ref = {long, _Ref},
+ curr_timer = timeout}, _T) ->
+
+ ?rt3("handle pending - timeout"),
+
+ %% The request seems to take a while,
+ %% let's reset our transmission timer.
+ %% We now know the other side has got
+ %% the request and is working on it,
+ %% so there is no need to keep the binary
+ %% message for re-transmission.
+
+ %% This can happen if the timer is running for the last
+ %% time. I.e. next time it expires, will be the last.
+ %% Therefor we really do not need to do anything here.
+ %% The cleanup will be done in request_timeout.
+
+ ok;
+
+handle_recv_pending(#conn_data{conn_handle = ConnHandle} = ConnData, TransId,
+ #request{timer_ref = {long, Ref},
+ curr_timer = CurrTimer}, T) ->
+
+ ?rt2("handle pending - still waiting", [CurrTimer]),
+
+ %% The request seems to take a while,
+ %% let's reset our transmission timer.
+ %% We now know the other side has got
+ %% the request and is working on it,
+ %% so there is no need to keep the binary
+ %% message for re-transmission.
+
+ %% We just need to recalculate the timer, i.e.
+ %% increment the timer (one "slot" has been consumed).
+
+ megaco_monitor:cancel_apply_after(Ref),
+ {WaitFor, Timer2} = megaco_timer:restart(CurrTimer),
+ ConnHandle = ConnData#conn_data.conn_handle,
+ M = ?MODULE,
+ F = request_timeout,
+ A = [ConnHandle, TransId],
+ Ref2 = megaco_monitor:apply_after(M, F, A, WaitFor),
+ NewFields =
+ [{#request.timer_ref, {long, Ref2}},
+ {#request.curr_timer, Timer2}],
+ ?report_trace(ConnData,
+ "long trans pending"
+ " (timer restarted)", [T]),
+ %% Timing problem?
+ megaco_monitor:update_request_fields(TransId, NewFields).
+
+
+handle_recv_pending_error(ConnData, TransId, Req, T, Extra) ->
+ %% 1) Delete the request record
+ megaco_monitor:delete_request(TransId),
+
+ %% 2) Possibly cancel the timer
+ case Req#request.timer_ref of
+ {_, Ref} ->
+ megaco_monitor:cancel_apply_after(Ref);
+ _ ->
+ ok
+ end,
+
+ %% 3) Delete the (receive) pending counter
+ megaco_config:del_pending_counter(recv, TransId),
+
+ %% 4) Inform the user that his/her request reached
+ %% the receive pending limit
+ UserMod = Req#request.user_mod,
+ UserArgs = Req#request.user_args,
+ Action = Req#request.reply_action,
+ UserData = Req#request.reply_data,
+ UserReply = {error, exceeded_recv_pending_limit},
+ ConnData2 = ConnData#conn_data{user_mod = UserMod,
+ user_args = UserArgs,
+ reply_action = Action,
+ reply_data = UserData},
+
+ ?report_trace(ConnData, "receive pending limit reached", [T]),
+ return_reply(ConnData2, TransId, UserReply, Extra).
+
+
+%%
+%% This _is_ a segmented message.
+%%
+%% Since this is not the last segment, we shall not send any ack.
+%% (even if three-way-handshake has been configured).
+%%
+handle_reply(
+ ConnData,
+ #megaco_transaction_reply{segmentNumber = SN,
+ segmentationComplete = asn1_NOVALUE} = T, Extra)
+ when is_integer(SN) ->
+ TransId = to_local_trans_id(ConnData),
+ ?rt2("handle segmented reply", [T, TransId, SN]),
+ case megaco_monitor:lookup_request(TransId) of
+
+ %% ---------------------------------------------------------
+ %% The first segment, so stop the request timer. No longer
+ %% needed when the segment(s) start to arrive.
+
+ [#request{timer_ref = {_Type, Ref},
+ seg_recv = [],
+ seg_timer_ref = undefined} = Req] ->
+
+ %% Don't care about Req and Rep version diff
+ ?report_trace(ConnData, "[segmented] trans reply - first seg",
+ [T]),
+
+ %% Stop the request timer
+ megaco_monitor:cancel_apply_after(Ref), %% OTP-4843
+
+ %% Acknowledge the segment
+ send_segment_reply(ConnData, SN),
+
+ %% First segment for this reply
+ NewFields =
+ [{#request.timer_ref, undefined},
+ {#request.seg_recv, [SN]}],
+ megaco_monitor:update_request_fields(TransId, NewFields),
+
+ %% Handle the reply
+ UserMod = Req#request.user_mod,
+ UserArgs = Req#request.user_args,
+ Action = Req#request.reply_action,
+ UserData = Req#request.reply_data,
+ UserReply =
+ case T#megaco_transaction_reply.transactionResult of
+ {transactionError, Reason} ->
+ {error, {SN, false, Reason}};
+ {actionReplies, Replies} ->
+ {ok, {SN, false, Replies}}
+ end,
+ ConnData2 = ConnData#conn_data{user_mod = UserMod,
+ user_args = UserArgs,
+ reply_action = Action,
+ reply_data = UserData},
+ return_reply(ConnData2, TransId, UserReply, Extra);
+
+
+ %% ---------------------------------------------------------
+ %% This is not the first segment.
+ %% The segment timer has not been started, so the last
+ %% segment have been received.
+ %% We must check that this is not a re-transmission!
+
+ [#request{seg_recv = Segs,
+ seg_timer_ref = undefined} = Req] ->
+ %% Don't care about Req and Rep version diff
+ ?report_trace(ConnData, "[segmented] trans reply - no seg acc",
+ [T]),
+
+ %% Acknowledge the segment
+ send_segment_reply(ConnData, SN),
+
+ %% Updated/handle received segment
+ case lists:member(SN, Segs) of
+ true ->
+ %% This is a re-transmission, so we shall not pass
+ %% it on to the user (or update the request record).
+ ok;
+ false ->
+ %% First time for this segment
+ megaco_monitor:update_request_field(TransId,
+ #request.seg_recv,
+ [ SN | Segs ]),
+
+ %% Handle the reply
+ UserMod = Req#request.user_mod,
+ UserArgs = Req#request.user_args,
+ Action = Req#request.reply_action,
+ UserData = Req#request.reply_data,
+ UserReply =
+ case T#megaco_transaction_reply.transactionResult of
+ {transactionError, Reason} ->
+ {error, {SN, false, Reason}};
+ {actionReplies, Replies} ->
+ {ok, {SN, false, Replies}}
+ end,
+ ConnData2 = ConnData#conn_data{user_mod = UserMod,
+ user_args = UserArgs,
+ reply_action = Action,
+ reply_data = UserData},
+ return_reply(ConnData2, TransId, UserReply, Extra)
+
+ end;
+
+
+ %% ---------------------------------------------------------
+ %% The segment timer is running!
+ %% This could be the last (out-of-order) segment!
+ %% We must check that this is not a re-transmission!
+
+ [#request{seg_recv = Segs,
+ seg_timer_ref = SegRef} = Req] ->
+ %% Don't care about Req and Rep version diff
+ ?report_trace(ConnData, "[segmented] trans reply - no seg acc",
+ [T]),
+
+ %% Acknowledge the segment
+ send_segment_reply(ConnData, SN),
+
+ %% Updated received segments
+ case lists:member(SN, Segs) of
+ true ->
+ %% This is a re-transmission
+ ok;
+ false ->
+ %% First time for this segment,
+ %% we may now have a complete set
+ Last =
+ case is_all_segments([SN | Segs]) of
+ {true, _Sorted} ->
+ megaco_monitor:cancel_apply_after(SegRef),
+ megaco_monitor:delete_request(TransId),
+ send_ack(ConnData),
+ true;
+ {false, Sorted} ->
+ megaco_monitor:update_request_field(TransId,
+ #request.seg_recv,
+ Sorted),
+ false
+ end,
+
+ %% Handle the reply
+ UserMod = Req#request.user_mod,
+ UserArgs = Req#request.user_args,
+ Action = Req#request.reply_action,
+ UserData = Req#request.reply_data,
+ UserReply =
+ case T#megaco_transaction_reply.transactionResult of
+ {transactionError, Reason} ->
+ {error, {SN, Last, Reason}};
+ {actionReplies, Replies} ->
+ {ok, {SN, Last, Replies}}
+ end,
+ ConnData2 = ConnData#conn_data{user_mod = UserMod,
+ user_args = UserArgs,
+ reply_action = Action,
+ reply_data = UserData},
+ return_reply(ConnData2, TransId, UserReply, Extra)
+
+ end;
+
+
+ [] ->
+ ?report_trace(ConnData, "trans reply (no receiver)", [T]),
+ return_unexpected_trans(ConnData, T, Extra)
+ end;
+
+
+%%
+%% This _is_ a segmented message and it's the last segment of the
+%% message.
+%%
+handle_reply(
+ ConnData,
+ #megaco_transaction_reply{segmentNumber = SN,
+ segmentationComplete = 'NULL'} = T, Extra)
+ when is_integer(SN) ->
+ TransId = to_local_trans_id(ConnData),
+ ?rt2("handle (last) segmented reply", [T, TransId, SN]),
+ case megaco_monitor:lookup_request(TransId) of
+
+ %% ---------------------------------------------------------
+ %% The first segment, so stop the request timer. No longer
+ %% needed when the segment(s) start to arrive.
+
+ [#request{timer_ref = {_Type, Ref},
+ seg_recv = [],
+ seg_timer_ref = undefined} = Req] ->
+
+ %% Don't care about Req and Rep version diff
+ ?report_trace(ConnData, "[segmented] trans reply - "
+ "first/complete seg", [T]),
+
+ %% Stop the request timer
+ megaco_monitor:cancel_apply_after(Ref), %% OTP-4843
+
+ %% Acknowledge the ("last") segment
+ send_segment_reply_complete(ConnData, SN),
+
+ %% It is ofcourse pointless to split
+ %% a transaction into just one segment,
+ %% but just to be sure, we handle that
+ %% case also
+ Last =
+ if
+ SN > 1 ->
+ %% More then one segment
+ %% First time for this segment
+ ConnHandle = ConnData#conn_data.conn_handle,
+ InitSegTmr = Req#request.init_seg_timer,
+ {WaitFor, CurrTimer} = megaco_timer:init(InitSegTmr),
+ M = ?MODULE,
+ F = segment_timeout,
+ A = [ConnHandle, TransId, CurrTimer],
+ SegRef =
+ megaco_monitor:apply_after(M, F, A, WaitFor),
+ NewFields =
+ [{#request.timer_ref, undefined},
+ {#request.seg_recv, [SN]},
+ {#request.seg_timer_ref, SegRef}],
+ megaco_monitor:update_request_fields(TransId, NewFields),
+ false;
+ true ->
+ %% Just one segment!
+ megaco_monitor:delete_request(TransId),
+ send_ack(ConnData),
+ true
+ end,
+
+ %% Handle the reply
+ UserMod = Req#request.user_mod,
+ UserArgs = Req#request.user_args,
+ Action = Req#request.reply_action,
+ UserData = Req#request.reply_data,
+ UserReply =
+ case T#megaco_transaction_reply.transactionResult of
+ {transactionError, Reason} ->
+ {error, {SN, Last, Reason}};
+ {actionReplies, Replies} ->
+ {ok, {SN, Last, Replies}}
+ end,
+ ConnData2 = ConnData#conn_data{user_mod = UserMod,
+ user_args = UserArgs,
+ reply_action = Action,
+ reply_data = UserData},
+ return_reply(ConnData2, TransId, UserReply, Extra);
+
+
+ [#request{seg_recv = Segs} = Req] ->
+ %% Don't care about Req and Rep version diff
+ ?report_trace(ConnData, "[segmented] trans reply - no seg acc",
+ [T]),
+
+ %% Acknowledge the ("last") segment
+ send_segment_reply_complete(ConnData, SN),
+
+ %% Updated received segments
+ %% This is _probably_ the last segment, but some of
+ %% the previous segments may have been lost, so we
+ %% may not have a complete set!
+ case lists:member(SN, Segs) of
+ true ->
+ %% This is a re-transmission
+ ok;
+ false ->
+ Last =
+ case is_all_segments([SN | Segs]) of
+ {true, _Sorted} ->
+ ?report_trace(ConnData,
+ "[segmented] trans reply - "
+ "complete set", [T]),
+ megaco_monitor:delete_request(TransId),
+ send_ack(ConnData),
+ true;
+ {false, Sorted} ->
+ ConnHandle = ConnData#conn_data.conn_handle,
+ InitSegTmr = Req#request.init_seg_timer,
+ {WaitFor, CurrTimer} =
+ megaco_timer:init(InitSegTmr),
+ M = ?MODULE,
+ F = segment_timeout,
+ A = [ConnHandle, TransId, CurrTimer],
+ SegRef =
+ megaco_monitor:apply_after(M, F, A,
+ WaitFor),
+ NewFields =
+ [{#request.seg_recv, Sorted},
+ {#request.seg_timer_ref, SegRef}],
+ megaco_monitor:update_request_fields(TransId, NewFields),
+ false
+ end,
+
+ %% Handle the reply
+ UserMod = Req#request.user_mod,
+ UserArgs = Req#request.user_args,
+ Action = Req#request.reply_action,
+ UserData = Req#request.reply_data,
+ UserReply =
+ case T#megaco_transaction_reply.transactionResult of
+ {transactionError, Reason} ->
+ {error, {SN, Last, Reason}};
+ {actionReplies, Replies} ->
+ {ok, {SN, Last, Replies}}
+ end,
+ ConnData2 = ConnData#conn_data{user_mod = UserMod,
+ user_args = UserArgs,
+ reply_action = Action,
+ reply_data = UserData},
+ return_reply(ConnData2, TransId, UserReply, Extra)
+
+ end;
+
+ [] ->
+ ?report_trace(ConnData, "trans reply (no receiver)", [T]),
+ return_unexpected_trans(ConnData, T, Extra)
+ end;
+
+
+%%
+%% This is _not_ a segmented message,
+%% i.e. it's an ordinary transaction reply
+%%
+handle_reply(#conn_data{conn_handle = CH} = CD, T, Extra) ->
+ TransId = to_local_trans_id(CD),
+ ?rt2("handle reply", [T, TransId]),
+ case megaco_monitor:lookup_request(TransId) of
+ [Req] when (is_record(Req, request) andalso
+ (CD#conn_data.cancel =:= true)) ->
+ ?TC_AWAIT_REPLY_EVENT(true),
+ do_handle_reply_cancel(CD, Req, T);
+
+ [#request{remote_mid = RMid} = Req] when ((RMid =:= preliminary_mid) orelse
+ (RMid =:= CH#megaco_conn_handle.remote_mid)) ->
+ ?TC_AWAIT_REPLY_EVENT(false),
+ %% Just in case conn_data got update after our lookup
+ %% but before we looked up the request record, we
+ %% check the cancel field again.
+ case megaco_config:conn_info(CD, cancel) of
+ true ->
+ do_handle_reply_cancel(CD, Req, T);
+ false ->
+ do_handle_reply(CD, Req, TransId, T, Extra)
+ end;
+
+ [#request{user_mod = UserMod,
+ user_args = UserArgs,
+ reply_action = Action,
+ reply_data = UserData,
+ remote_mid = RMid}] ->
+ ?report_trace(CD,
+ "received trans reply with invalid remote mid",
+ [T, RMid]),
+ WrongMid = CH#megaco_conn_handle.remote_mid,
+ T2 = transform_transaction_reply_enc(CD#conn_data.protocol_version,
+ T),
+ UserReply = {error, {wrong_mid, WrongMid, RMid, T2}},
+ CD2 = CD#conn_data{user_mod = UserMod,
+ user_args = UserArgs,
+ reply_action = Action,
+ reply_data = UserData},
+ return_reply(CD2, TransId, UserReply, Extra);
+
+ [] ->
+ ?TC_AWAIT_REPLY_EVENT(undefined),
+ ?report_trace(CD, "trans reply (no receiver)", [T]),
+ return_unexpected_trans(CD, T, Extra)
+ end.
+
+do_handle_reply_cancel(CD, #request{user_mod = UserMod,
+ user_args = UserArgs,
+ reply_action = Action,
+ reply_data = UserData}, T) ->
+ CD2 = CD#conn_data{user_mod = UserMod,
+ user_args = UserArgs,
+ reply_action = Action,
+ reply_data = UserData},
+ return_unexpected_trans(CD2, T).
+
+%% Plain old handling of incomming replies
+do_handle_reply(CD,
+ #request{timer_ref = {_Type, Ref}, % OTP-4843
+ user_mod = UserMod,
+ user_args = UserArgs,
+ reply_action = Action,
+ reply_data = UserData,
+ keep_alive_timer = RKAT},
+ TransId, T, Extra)
+ when ((RKAT =:= plain) orelse (Action =:= call)) ->
+ %% Don't care about Req and Rep version diff
+ ?report_trace(CD, "trans reply", [T]),
+
+ %% This is the first reply (maybe of many)
+ megaco_monitor:delete_request(TransId),
+ megaco_monitor:cancel_apply_after(Ref), % OTP-4843
+ megaco_config:del_pending_counter(recv, TransId), % OTP-7189
+
+ %% Send acknowledgement
+ maybe_send_ack(T#megaco_transaction_reply.immAckRequired, CD),
+
+ UserReply =
+ case T#megaco_transaction_reply.transactionResult of
+ {transactionError, Reason} ->
+ {error, Reason};
+ {actionReplies, Replies} ->
+ {ok, Replies}
+ end,
+ CD2 = CD#conn_data{user_mod = UserMod,
+ user_args = UserArgs,
+ reply_action = Action,
+ reply_data = UserData},
+ return_reply(CD2, TransId, UserReply, Extra);
+
+%% This may be the first reply (of maybe many)
+do_handle_reply(CD,
+ #request{user_mod = UserMod,
+ user_args = UserArgs,
+ reply_action = Action,
+ reply_data = UserData,
+ keep_alive_ref = undefined} = Req,
+ TransId, T, Extra) ->
+ %% Don't care about Req and Rep version diff
+ ?report_trace(CD, "trans reply", [T]),
+
+ %% Could be the first reply, in which case we shall start the
+ %% Request Keep Alive timer...
+ %% This could happen for more than one (1) reply though, so
+ %% we need to check if the counter value actually equals one (1)!
+
+ ReplyNo =
+ create_or_maybe_increment_request_keep_alive_counter(CD, TransId),
+ if
+ (ReplyNo =:= 1) ->
+ %% This *is* the first reply!!
+ %% 1) Stop resend timer
+ {_Type, Ref} = Req#request.timer_ref, % OTP-4843
+ megaco_monitor:cancel_apply_after(Ref), % OTP-4843
+
+ %% 2) Delete pending counter
+ megaco_config:del_pending_counter(recv, TransId), % OTP-7189
+
+ %% 3) Start request keep alive timer
+ ConnHandle = CD#conn_data.conn_handle,
+ RKATimer = Req#request.keep_alive_timer,
+ {RKAWaitFor, _} = megaco_timer:init(RKATimer),
+ RKARef = megaco_monitor:apply_after(?MODULE,
+ request_keep_alive_timeout,
+ [ConnHandle, TransId],
+ RKAWaitFor),
+
+ %% 4) Maybe send acknowledgement (three-way-handshake)
+ maybe_send_ack(T#megaco_transaction_reply.immAckRequired, CD),
+
+ %% 5) And finally store the updated request record
+ Req2 = Req#request{keep_alive_ref = RKARef},
+ megaco_monitor:insert_request(Req2);
+
+ true ->
+ ok
+ end,
+
+ UserReply =
+ case T#megaco_transaction_reply.transactionResult of
+ {transactionError, Reason} ->
+ {error, ReplyNo, Reason};
+ {actionReplies, Replies} ->
+ {ok, ReplyNo, Replies}
+ end,
+ CD2 = CD#conn_data{user_mod = UserMod,
+ user_args = UserArgs,
+ reply_action = Action,
+ reply_data = UserData},
+ return_reply(CD2, TransId, UserReply, Extra);
+
+%% This is *not* the first reply (of many)
+do_handle_reply(CD, #request{user_mod = UserMod,
+ user_args = UserArgs,
+ reply_action = Action,
+ reply_data = UserData}, TransId, T, Extra) ->
+ %% Don't care about Req and Rep version diff
+ ?report_trace(CD, "trans reply (first reply already delivered)", [T]),
+
+ ReplyNo = increment_request_keep_alive_counter(CD, TransId),
+
+ UserReply =
+ case T#megaco_transaction_reply.transactionResult of
+ {transactionError, Reason} ->
+ {error, ReplyNo, Reason};
+ {actionReplies, Replies} ->
+ {ok, ReplyNo, Replies}
+ end,
+ CD2 = CD#conn_data{user_mod = UserMod,
+ user_args = UserArgs,
+ reply_action = Action,
+ reply_data = UserData},
+ return_reply(CD2, TransId, UserReply, Extra).
+
+is_all_segments(Segs) ->
+ Sorted = lists:sort(Segs),
+ {is_all_segments(Sorted, 1, lists:last(Sorted)), Sorted}.
+
+is_all_segments([Last], Last, Last) ->
+ true;
+is_all_segments([_], _, _) ->
+ false;
+is_all_segments([SN|Segs], SN, Last) when (SN < Last) ->
+ is_all_segments(Segs, SN+1, Last);
+is_all_segments([SN1|_], SN2, _Last) when SN1 =/= SN2 ->
+ false.
+
+
+handle_segment_reply(CD,
+ #'SegmentReply'{transactionId = TransId,
+ segmentNumber = SN,
+ segmentationComplete = SC}, Extra) ->
+ ?rt2("handle segment reply", [{trans_id, TransId},
+ {segment_no, SN},
+ {segmentation_complete, SC}]),
+ TransId2 = to_remote_trans_id(CD#conn_data{serial = TransId}),
+ case megaco_monitor:lookup_reply(TransId2) of
+ [#reply{bytes = Sent,
+ segments = []} = Rep] when is_list(Sent) ->
+ ?rt2("no unsent segments", [Sent]),
+ handle_segment_reply_callback(CD, TransId, SN, SC, Extra),
+ case lists:keysearch(SN, 1, Sent) of
+ {value, {SN, _Bin, SegTmr}} ->
+ megaco_monitor:cancel_apply_after(SegTmr), %% BMK BMK
+ case lists:keydelete(SN, 1, Sent) of
+ [] -> %% We are done
+ Ref = Rep#reply.timer_ref,
+ megaco_monitor:cancel_apply_after(Ref),
+ megaco_monitor:update_reply_field(TransId2,
+ #reply.bytes,
+ []),
+ ok;
+ NewSent ->
+ megaco_monitor:update_reply_field(TransId2,
+ #reply.bytes,
+ NewSent),
+ ok
+ end;
+ _ ->
+ ok
+ end;
+
+ [#reply{bytes = Sent,
+ segments = NotSent}] when is_list(Sent) andalso
+ is_list(NotSent) ->
+ ?rt2("unsent segments", [Sent, NotSent]),
+ handle_segment_reply_callback(CD, TransId, SN, SC, Extra),
+ case lists:keysearch(SN, 1, Sent) of
+ {value, {SN, _Bin, SegTmr}} ->
+ megaco_monitor:cancel_apply_after(SegTmr), %% BMK BMK
+ NewSent = lists:keydelete(SN, 1, Sent),
+ [{SN2, Bin2}|NewNotSent] = NotSent,
+ case send_reply_segment(CD, "send trans reply segment",
+ SN2, Bin2) of
+ {ok, Bin3} ->
+ ?rt2("another segment sent", [Bin3]),
+ NewSent2 = [{SN2, Bin3, undefined}|NewSent],
+ NewFields =
+ [{#reply.bytes, NewSent2},
+ {#reply.segments, NewNotSent}],
+ megaco_monitor:update_reply_fields(TransId2,
+ NewFields),
+ ok;
+ Error ->
+ incNumErrors(CD#conn_data.conn_handle),
+ ?report_important(CD, "failed sending segment",
+ [{segment_no, SN2},
+ {error, Error}]),
+ error_msg("failed sending transaction reply [~w] "
+ "segment [~w]: ~w",
+ [TransId, SN2, Error]),
+ megaco_monitor:update_reply_field(TransId2,
+ #reply.bytes,
+ NewSent),
+ ok
+ end;
+ _ ->
+ ok
+ end;
+
+ [#reply{state = State}] ->
+ %% We received a segment reply for a segmented reply we have
+ %% not yet sent? This is either some sort of race condition
+ %% or the "the other side" is really confused.
+ %% Ignore the message but issue a warning just in case...
+ warning_msg("received unexpected segment reply: "
+ "~n Transaction Id: ~p"
+ "~n Segment Number: ~p"
+ "~n Segmentation Complete: ~p"
+ "~n Reply state: ~p",
+ [TransId2, SN, SC, State]),
+ ignore;
+
+ [] ->
+ ignore
+
+ end.
+
+
+%%
+%% This should be passed on to the user only if the user wish it
+%% (sri = segment reply indication)
+%%
+handle_segment_reply_callback(#conn_data{segment_reply_ind = true,
+ conn_handle = ConnHandle,
+ protocol_version = Version,
+ user_mod = UserMod,
+ user_args = UserArgs},
+ TransId, SN, SC, Extra) ->
+ Args =
+ case Extra of
+ ?default_user_callback_extra ->
+ [ConnHandle, Version, TransId, SN, SC | UserArgs];
+ _ ->
+ [ConnHandle, Version, TransId, SN, SC, Extra | UserArgs]
+ end,
+ (catch apply(UserMod, handle_segment_reply, Args));
+handle_segment_reply_callback(_CD, _TransId, _SN, _SC, _Extra) ->
+ ok.
+
+
+handle_acks([{ConnData, Rep, T} | Rest], Extra)
+ when Rep#reply.state == waiting_for_ack ->
+ handle_ack(ConnData, ok, Rep, T, Extra),
+ handle_acks(Rest, Extra);
+handle_acks([], _Extra) ->
+ ok.
+
+%% If the reply to which this is the ack was segmented,
+%% then we also need to check that we have received all
+%% the segment-replies. If not, an error callback call
+%% shall be made instead.
+handle_ack(ConnData, AckStatus,
+ #reply{trans_id = TransId,
+ bytes = Bytes,
+ timer_ref = ReplyRef,
+ pending_timer_ref = PendingRef, %% BMK Still running?
+ ack_action = AckAction}, T, Extra)
+ when is_binary(Bytes) orelse (Bytes =:= undefined) ->
+ handle_ack_cleanup(TransId, ReplyRef, PendingRef),
+ handle_ack_callback(ConnData, AckStatus, AckAction, T, Extra);
+
+handle_ack(ConnData, AckStatus,
+ #reply{trans_id = TransId,
+ bytes = [],
+ segments = [],
+ timer_ref = ReplyRef,
+ pending_timer_ref = PendingRef, %% BMK Still running?
+ ack_action = AckAction}, T, Extra) ->
+ handle_ack_cleanup(TransId, ReplyRef, PendingRef),
+ handle_ack_callback(ConnData, AckStatus, AckAction, T, Extra);
+
+handle_ack(ConnData, OrigAckStatus,
+ #reply{trans_id = TransId,
+ bytes = SegSent,
+ segments = NotSent,
+ timer_ref = ReplyRef,
+ pending_timer_ref = PendingRef, %% BMK Still running?
+ ack_action = OrigAckAction}, T, Extra)
+ when is_list(SegSent) andalso is_list(NotSent) ->
+ SN_NotAcked = [SN || {SN, _, _} <- SegSent],
+ SN_NotSent = [SN || {SN, _} <- NotSent],
+ AckStatus = {error, {segment_failure,
+ [{original_ack_status, OrigAckStatus},
+ {segments_not_acked, SN_NotAcked},
+ {segments_not_sent, SN_NotSent}]}},
+ AckAction =
+ case OrigAckAction of
+ {handle_ack, _} ->
+ OrigAckAction;
+ _ ->
+ {handle_ack, segmented_reply}
+ end,
+ cancel_segment_timers(SegSent),
+ handle_ack_cleanup(TransId, ReplyRef, PendingRef),
+ handle_ack_callback(ConnData, AckStatus, AckAction, T, Extra).
+
+handle_ack_cleanup(TransId, ReplyRef, PendingRef) ->
+ megaco_monitor:cancel_apply_after(ReplyRef),
+ megaco_monitor:cancel_apply_after(PendingRef),
+ megaco_monitor:delete_reply(TransId),
+ megaco_config:del_pending_counter(sent, TransId). %% BMK: Still existing?
+
+cancel_segment_timers(SegSent) when is_list(SegSent) ->
+ Cancel = fun({_, _, Ref}) ->
+ megaco_monitor:cancel_apply_after(Ref)
+ end,
+ lists:foreach(Cancel, SegSent);
+cancel_segment_timers(_) ->
+ ok.
+
+handle_ack_callback(_CD, ok = _AS, discard_ack = _AA, _T, _Extra) ->
+ ok;
+handle_ack_callback(ConnData, {error, Reason}, discard_ack = AckAction, T, Extra) ->
+ ?report_trace(ConnData, "handle ack (no callback)",
+ [T, AckAction, {error, Reason}, Extra]);
+handle_ack_callback(ConnData, AckStatus, {handle_ack, AckData}, T, Extra) ->
+ ?report_trace(ConnData, "callback: trans ack", [{ack_data, AckData}]),
+ ConnHandle = ConnData#conn_data.conn_handle,
+ Version = ConnData#conn_data.protocol_version,
+ UserMod = ConnData#conn_data.user_mod,
+ UserArgs = ConnData#conn_data.user_args,
+ Args =
+ case Extra of
+ ?default_user_callback_extra ->
+ [ConnHandle, Version, AckStatus, AckData | UserArgs];
+ _ ->
+ [ConnHandle, Version, AckStatus, AckData, Extra | UserArgs]
+ end,
+ Res = (catch apply(UserMod, handle_trans_ack, Args)),
+ ?report_debug(ConnData, "return: trans ack", [T, AckData, {return, Res}]),
+ case Res of
+ ok ->
+ ok;
+ _ ->
+ warning_msg("transaction ack callback failed: ~w", [Res]),
+ ok
+ end,
+ Res.
+
+
+handle_message_error(ConnData, _Error, _Extra)
+ when ConnData#conn_data.monitor_ref == undefined_monitor_ref ->
+ %% May occur if another process already has setup a
+ %% temporary connection, but the handle_connect callback
+ %% function has not yet returned before the eager MG
+ %% re-sends its initial service change message.
+ ignore;
+handle_message_error(ConnData, Error, Extra) ->
+ ?report_trace(ConnData, "callback: message error", [Error]),
+ ConnHandle = ConnData#conn_data.conn_handle,
+ Version = ConnData#conn_data.protocol_version,
+ UserMod = ConnData#conn_data.user_mod,
+ UserArgs = ConnData#conn_data.user_args,
+ Args =
+ case Extra of
+ ?default_user_callback_extra ->
+ [ConnHandle, Version, Error | UserArgs];
+ _ ->
+ [ConnHandle, Version, Error, Extra | UserArgs]
+ end,
+ Res = (catch apply(UserMod, handle_message_error, Args)),
+ ?report_debug(ConnData, "return: message error", [Error, {return, Res}]),
+ case Res of
+ ok ->
+ ok;
+ _ ->
+ warning_msg("message error callback failed: ~w", [Res]),
+ ok
+ end,
+ Res.
+
+handle_disconnect_callback(ConnData, UserReason)
+ when is_record(ConnData, conn_data) ->
+ ?report_trace(ConnData, "callback: disconnect", [{reason, UserReason}]),
+ ConnHandle = ConnData#conn_data.conn_handle,
+ Version = ConnData#conn_data.protocol_version,
+ UserMod = ConnData#conn_data.user_mod,
+ UserArgs = ConnData#conn_data.user_args,
+ Args = [ConnHandle, Version, UserReason | UserArgs],
+ Res = (catch apply(UserMod, handle_disconnect, Args)),
+ ?report_debug(ConnData, "return: disconnect", [{reason, UserReason}, {return, Res}]),
+ case Res of
+ ok ->
+ ok;
+ _ ->
+ warning_msg("disconnect callback failed: ~w", [Res]),
+ ok
+ end,
+ Res.
+
+
+%%----------------------------------------------------------------------
+%% Test "outgoing" messages
+%%----------------------------------------------------------------------
+
+%% test_request/5 -> {MegacoMessage, EncodingRes}
+%%
+%% This function is only intended for testing
+%% (e.g. answer the question: have I constructed a valid action request?)
+%%
+%% It's not exactly the same code as a call to 'call'
+%% or 'cast' but close enough.
+%%
+test_request(ConnHandle, Actions,
+ Version, EncodingMod, EncodingConfig)
+ when is_record(ConnHandle, megaco_conn_handle) and
+ is_integer(Version) andalso is_atom(EncodingMod) ->
+ %% Create a fake conn_data structure
+ ConnData = #conn_data{serial = 1,
+ protocol_version = Version,
+ conn_handle = ConnHandle,
+ auth_data = asn1_NOVALUE,
+ encoding_mod = EncodingMod,
+ encoding_config = EncodingConfig},
+
+ TRs = test_req_compose_transactions(ConnData, Actions),
+ Body = {transactions, TRs},
+ MegaMsg = megaco_messenger_misc:compose_message(ConnData, Version, Body),
+ EncodeRes = megaco_messenger_misc:encode_message(ConnData, MegaMsg),
+ {MegaMsg, EncodeRes}.
+
+
+test_req_compose_transactions(ConnData, [A|_] = ActionsList) when is_list(A) ->
+ LastSerial = ConnData#conn_data.serial,
+ test_req_compose_transactions(LastSerial, lists:reverse(ActionsList), []);
+test_req_compose_transactions(#conn_data{serial = Serial}, Actions) ->
+ TR = #'TransactionRequest'{transactionId = Serial,
+ actions = Actions},
+ [{transactionRequest, TR}].
+
+test_req_compose_transactions(_Serial, [], Acc) ->
+ lists:reverse(Acc);
+test_req_compose_transactions(Serial, [A|As], Acc) ->
+ TR = #'TransactionRequest'{transactionId = Serial,
+ actions = A},
+ test_req_compose_transactions(Serial, As, [{transactionRequest, TR}|Acc]).
+
+
+test_reply(ConnHandle, Version, EncodingMod, EncodingConfig, Error)
+ when is_record(Error, 'ErrorDescriptor') ->
+ Reply = {transactionError, Error},
+ test_reply_encode(ConnHandle, Version, EncodingMod, EncodingConfig, Reply);
+test_reply(ConnHandle, Version, EncodingMod, EncodingConfig, Replies)
+ when is_list(Replies) ->
+ Reply = {actionReplies, Replies},
+ test_reply_encode(ConnHandle, Version, EncodingMod, EncodingConfig, Reply).
+
+test_reply_encode(ConnHandle, Version, EncodingMod, EncodingConfig, Reply) ->
+ ImmAck = asn1_NOVALUE,
+ Serial = 1,
+ %% Create a fake conn_data structure
+ CD = #conn_data{serial = Serial,
+ protocol_version = Version,
+ conn_handle = ConnHandle,
+ auth_data = asn1_NOVALUE,
+ encoding_mod = EncodingMod,
+ encoding_config = EncodingConfig},
+ TR0 = #megaco_transaction_reply{transactionId = Serial,
+ immAckRequired = ImmAck,
+ transactionResult = Reply},
+ TR = megaco_messenger_misc:transform_transaction_reply(CD, TR0),
+ Body = {transactions, [{transactionReply, TR}]},
+ MegaMsg = megaco_messenger_misc:compose_message(CD, Version, Body),
+ EncodeRes = megaco_messenger_misc:encode_message(CD, MegaMsg),
+ {MegaMsg, EncodeRes}.
+
+
+%%----------------------------------------------------------------------
+%% Send (or prepare) outgoing messages
+%%----------------------------------------------------------------------
+
+%% Description:
+%% Encode a list of actions or a list of list of actions for
+%% later sending (using call or cast).
+%%
+%% encode_actions(CH, Acts, Opts) -> {ok, encoded_actions()} | {error, Reason}
+%% CH -> connection_handle()
+%% Acts -> action_reqs() | [action_reqs()]
+%% action_reqs() -> [action_req()]
+%% action_req() -> #'ActionRequest'{}
+%% Opts -> [option()]
+%% option() -> {Tab, Val}
+%% Tag -> atom()
+%% Val -> term()
+%% encoded_actions() -> binary() | [binary()]
+%% Reason -> term()
+encode_actions(CH, [A|_] = ActionsList, Opts)
+ when is_record(CH, megaco_conn_handle) andalso is_list(A) ->
+ (catch encode_multi_actions(CH, ActionsList, Opts));
+
+encode_actions(CH, [A|_] = Actions, Opts)
+ when is_record(CH, megaco_conn_handle) andalso is_tuple(A) ->
+ do_encode_actions(CH, Actions, Opts).
+
+encode_multi_actions(CH, ActionsList, Opts) ->
+ case prepare_req_send_options(CH, Opts) of
+ {ok, CD} ->
+ ActsList = [encode_multi_actions(CD, Acts) || Acts <- ActionsList],
+ {ok, ActsList};
+ Error ->
+ Error
+ end.
+
+encode_multi_actions(CD, Actions) ->
+ case megaco_messenger_misc:encode_actions(CD,
+ "encode multi actions",
+ Actions) of
+ {ok, Bin} ->
+ Bin;
+ Error ->
+ throw(Error)
+ end.
+
+do_encode_actions(CH, Actions, Opts)
+ when is_record(CH, megaco_conn_handle) ->
+ case prepare_req_send_options(CH, Opts) of
+ {ok, CD} ->
+ megaco_messenger_misc:encode_actions(CD,
+ "encode actions",
+ Actions);
+ Error ->
+ Error
+ end.
+
+prepare_req_send_options(CH, Opts) ->
+ case megaco_config:lookup_local_conn(CH) of
+ [CD] ->
+ override_req_send_options(any, CD, Opts);
+ [] ->
+ {error, {not_found, conn_data}}
+ end.
+
+
+call(ConnHandle, Actions, Options) ->
+ case lists:keymember(reply_data, 1, Options) of
+ true ->
+ {error, {bad_option, reply_data}};
+ false ->
+ Self = self(),
+ ProxyFun = fun() -> call_proxy(Self) end,
+ {Proxy, MRef} = erlang:spawn_monitor(ProxyFun),
+ Options2 = [{reply_data, Proxy} | Options],
+ call_or_cast(call, ConnHandle, Actions, Options2, MRef)
+ end.
+
+cast(ConnHandle, Actions, Options) ->
+ call_or_cast(cast, ConnHandle, Actions, Options, undefined).
+
+%% In a transaction there can be several actions, so if the
+%% First element of the Actions list is an ''ActionRequest''
+%% record this a list of ActionRequest's for one Transaction
+%% request. If on the other hand this is not the case, then
+%% the Actions list is assumed to be a list of list of
+%% ActionRequest. That is, action requests for several transactions.
+%% It could also be a binary or a list of binaries (if
+%% the actions has already been encoded).
+call_or_cast(CallOrCast, ConnHandle, [A|_] = Actions, Options, ProxyMon)
+ when is_tuple(A) ->
+ %% Just one transaction
+ case call_or_cast(CallOrCast, ConnHandle, [Actions], Options, ProxyMon) of
+ ok ->
+ ok;
+ {error, Reason} ->
+ {error, Reason};
+ {Version, [Reply]} when is_integer(Version) ->
+ {Version, Reply};
+ {Version, Error} when is_integer(Version) ->
+ {Version, Error}
+ end;
+
+call_or_cast(CallOrCast, ConnHandle, Actions, Options, ProxyMon)
+ when is_binary(Actions) ->
+ %% Just one transaction (although the actions has already been encoded)
+ case call_or_cast(CallOrCast, ConnHandle, [Actions], Options, ProxyMon) of
+ ok ->
+ ok;
+ {error, Reason} ->
+ {error, Reason};
+ {Version, [Reply]} when is_integer(Version) ->
+ {Version, Reply};
+ {Version, Error} when is_integer(Version) ->
+ {Version, Error}
+ end;
+
+call_or_cast(CallOrCast, ConnHandle, ActionsList, Options, ProxyMon)
+ when is_record(ConnHandle, megaco_conn_handle) ->
+ case prepare_req_send_options(CallOrCast,
+ ConnHandle, Options, ActionsList) of
+ {ok, ConnData} ->
+ ?report_trace(ConnData, "call_or_cast - options prepared", []),
+ case encode_requests(ConnData, ActionsList) of
+ {ok, TRs, BinOrBins} ->
+ ?report_trace(ConnData,
+ "call_or_cast - request encoded", []),
+ send_request(ConnData, ConnHandle,
+ TRs, CallOrCast, BinOrBins),
+ case CallOrCast of
+ call ->
+ TransIds = to_local_trans_id(ConnData, TRs),
+ wait_for_reply(ConnData, TransIds, ProxyMon);
+ cast ->
+ ok
+ end;
+ {error, Reason} ->
+ call_proxy_cleanup(ConnData, ProxyMon),
+ Version = ConnData#conn_data.protocol_version,
+ return_error(CallOrCast, Version, {error, Reason})
+ end;
+ {error, Reason} ->
+ call_proxy_cleanup(Options, ProxyMon),
+ return_error(CallOrCast, 1, {error, Reason})
+ end;
+call_or_cast(CallOrCast, ConnHandle, _Actions, Options, ProxyMon) ->
+ call_proxy_cleanup(Options, ProxyMon),
+ return_error(CallOrCast, 1, {error, {bad_megaco_conn_handle, ConnHandle}}).
+
+
+return_error(Action, Version, Error) ->
+ case Action of
+ call -> {Version, Error};
+ cast -> Error
+ end.
+
+wait_for_reply(CD, TransIds, ProxyMon) ->
+ ProxyPid = CD#conn_data.reply_data,
+ ProxyPid ! {go, self(), CD, TransIds},
+ receive
+ {reply, ProxyPid, Reply} ->
+ erlang:demonitor(ProxyMon, [flush]),
+ Reply;
+ {'DOWN', ProxyMon, process, ProxyPid, Info} ->
+ UserReply = {error, {call_proxy_crash, Info}},
+ {CD#conn_data.protocol_version, UserReply}
+ end.
+
+
+call_proxy_cleanup(#conn_data{reply_data = ProxyPid}, ProxyMon) ->
+ do_call_proxy_cleanup(ProxyPid, ProxyMon);
+call_proxy_cleanup(Options, ProxyMon) when is_list(Options) ->
+ ProxyPid =
+ case lists:keysearch(reply_data, 1, Options) of
+ {value, {reply_data, Data}} ->
+ Data;
+ _ ->
+ undefined
+ end,
+ do_call_proxy_cleanup(ProxyPid, ProxyMon);
+call_proxy_cleanup(ProxyPid, ProxyMon) ->
+ do_call_proxy_cleanup(ProxyPid, ProxyMon).
+
+do_call_proxy_cleanup(ProxyPid, ProxyMon) ->
+ maybe_demonitor(ProxyMon),
+ maybe_stop_proxy(ProxyPid),
+ ok.
+
+maybe_demonitor(undefined) ->
+ ok;
+maybe_demonitor(Mon) ->
+ (catch erlang:demonitor(Mon, [flush])),
+ ok.
+
+maybe_stop_proxy(Pid) when is_pid(Pid) ->
+ Pid ! {stop, self()},
+ ok;
+maybe_stop_proxy(_) ->
+ ok.
+
+
+call_proxy(Parent) ->
+ receive
+ {go, Parent, CD, TransIds} ->
+ call_proxy(Parent, CD, TransIds);
+ {stop, Parent} ->
+ exit(normal)
+ end.
+
+call_proxy(Parent, CD, TransIds) ->
+ Reply = proxy_wait_for_reply(CD, TransIds, []),
+ Parent ! {reply, self(), Reply},
+ call_proxy_gc(CD, CD#conn_data.call_proxy_gc_timeout).
+
+call_proxy_gc(CD, Timeout) when (Timeout > 0) ->
+ T = t(),
+ receive
+ {?MODULE, TransId, Version, Result} -> % Old format
+ CD2 = CD#conn_data{protocol_version = Version},
+ Extra = ?default_user_callback_extra,
+ return_unexpected_trans_reply(CD2, TransId, Result, Extra),
+ call_proxy_gc(CD, Timeout - (t() - T));
+
+ {?MODULE, TransId, Version, Result, Extra} ->
+ CD2 = CD#conn_data{protocol_version = Version},
+ return_unexpected_trans_reply(CD2, TransId, Result, Extra),
+ call_proxy_gc(CD, Timeout - (t() - T))
+
+ after Timeout ->
+ exit(normal)
+ end;
+call_proxy_gc(_CD, _Timeout) ->
+ exit(normal).
+
+proxy_wait_for_reply(_CD, [], Replies0) ->
+ % Make sure they come in the same order as the requests where sent
+ Replies1 = lists:keysort(2, Replies0),
+ %% Must all be the same version
+ [{Version, _, _}|_] = Replies1,
+ Replies2 = [Result || {_Version, _TransId, Result} <- Replies1],
+ {Version, Replies2};
+proxy_wait_for_reply(CD, TransIds, Replies) ->
+ receive
+ {?MODULE, TransId, Version, Reply} -> % Old format
+ {TransIds2, Replies2} =
+ wfr_handle_reply(CD,
+ TransIds, TransId,
+ Version, Replies, Reply),
+ proxy_wait_for_reply(CD, TransIds2, Replies2);
+
+ {?MODULE, TransId, Version, Reply, Extra} ->
+ {TransIds2, Replies2} =
+ wfr_handle_reply(CD,
+ TransIds, TransId,
+ Version, Replies, Reply, Extra),
+ proxy_wait_for_reply(CD, TransIds2, Replies2)
+ end.
+
+wfr_handle_reply(CD, TransIds, TransId, Version, Replies, Reply) ->
+ Extra = ?default_user_callback_extra,
+ wfr_handle_reply(CD, TransIds, TransId, Version, Replies, Reply, Extra).
+
+wfr_handle_reply(CD, TransIds, TransId, Version, Replies, Reply, Extra) ->
+ %% Is this meant for us?
+ case lists:member(TransId, TransIds) of
+ true -> % Yep
+ wfr_update(TransIds, TransId, Version, Replies, Reply, Extra);
+ false -> % Nop
+ CD2 = CD#conn_data{protocol_version = Version},
+ return_unexpected_trans_reply(CD2, TransId, Reply, Extra),
+ {TransIds, Replies}
+ end.
+
+wfr_mk_reply(Version, TransId, Result, ?default_user_callback_extra = _Extra) ->
+ {Version, TransId, Result};
+wfr_mk_reply(Version, TransId, Result0, Extra) ->
+ Result = list_to_tuple(lists:append(tuple_to_list(Result0), [Extra])),
+ {Version, TransId, Result}.
+
+%% Last segment of a reply
+%% transactionResult "=" actionReplies
+wfr_update(TransIds, TransId, Version, Results, {ok, {SegNo, Last, ARs}}, Extra)
+ when is_integer(SegNo) andalso (Last == true) ->
+ TransIds2 = lists:delete(TransId, TransIds),
+ case lists:keysearch(TransId, 2, Results) of
+
+ %% All segments ok (actionReplies)
+ {value, {V, TransId, {ok, SegReps}}} ->
+ SegReps2 = lists:keysort(1, [{SegNo, ARs}|SegReps]),
+ Rep = wfr_mk_reply(V, TransId, {ok, SegReps2}, Extra),
+ Results2 = lists:keyreplace(TransId, 2, Results, Rep),
+ {TransIds2, Results2};
+
+ %% Atleast one segment error (transactionError)
+ {value, {V, TransId, {error, {segment, OkSegs, ErrSegs}}}} ->
+ OkSegs2 = lists:keysort(1, [{SegNo, ARs}|OkSegs]),
+ ErrSegs2 = lists:keysort(1, ErrSegs),
+ Error = {error, {segment, OkSegs2, ErrSegs2}},
+ Rep = wfr_mk_reply(V, TransId, Error, Extra),
+ Results2 = lists:keyreplace(TransId, 2, Results, Rep),
+ {TransIds2, Results2};
+
+ false ->
+ %% First and only segment
+ Rep = wfr_mk_reply(Version, TransId, {ok, [{SegNo, ARs}]}, Extra),
+ {TransIds2, [Rep | Results]}
+
+ end;
+
+%% Last segment of a reply
+%% transactionResult "=" transactionError
+wfr_update(TransIds, TransId, Version, Results, {error, {SegNo, Last, ED}}, Extra)
+ when is_integer(SegNo) andalso (Last == true) ->
+ TransIds2 = lists:delete(TransId, TransIds),
+ case lists:keysearch(TransId, 2, Results) of
+
+ %% First segment with error (transactionError)
+ {value, {V, TransId, {ok, SegReps}}} ->
+ OkSegs = lists:keysort(1, [{SegNo, ED}|SegReps]),
+ ErrSegs = [{SegNo, ED}],
+ Error = {error, {segment, OkSegs, ErrSegs}},
+ Rep = wfr_mk_reply(V, TransId, Error, Extra),
+ Results2 = lists:keyreplace(TransId, 2, Results, Rep),
+ {TransIds2, Results2};
+
+ %% Another segment with error (transactionError)
+ {value, {V, TransId, {error, {segment, OkSegs, ErrSegs}}}} ->
+ OkSegs2 = lists:keysort(1, OkSegs),
+ ErrSegs2 = lists:keysort(1, [{SegNo, ED}|ErrSegs]),
+ Error = {error, {segment, OkSegs2, ErrSegs2}},
+ Rep = wfr_mk_reply(V, TransId, Error, Extra),
+ Results2 = lists:keyreplace(TransId, 2, Results, Rep),
+ {TransIds2, Results2};
+
+ false ->
+ %% First and only segment
+ OkSegs = [],
+ ErrSegs = [{SegNo, ED}],
+ Error = {error, {segment, OkSegs, ErrSegs}},
+ Rep = wfr_mk_reply(Version, TransId, Error, Extra),
+ {TransIds2, [Rep]}
+
+ end;
+
+%% One segment of a reply
+%% transactionResult "=" actionReplies
+wfr_update(TransIds, TransId, Version, Results, {ok, {SegNo, _Last, ARs}}, Extra)
+ when is_integer(SegNo) ->
+ case lists:keysearch(TransId, 2, Results) of
+
+ %% All segments ok (actionReplies)
+ {value, {V, TransId, {ok, SegReps}}} ->
+ SegReps2 = [{SegNo, ARs}|SegReps],
+ Rep = wfr_mk_reply(V, TransId, {ok, SegReps2}, Extra),
+ Results2 = lists:keyreplace(TransId, 2, Results, Rep),
+ {TransIds, Results2};
+
+ %% Atleast one segment error (transactionError)
+ {value, {V, TransId, {error, {segment, OkSegs, ErrSegs}}}} ->
+ OkSegs2 = [{SegNo, ARs}|OkSegs],
+ Error = {error, {segment, OkSegs2, ErrSegs}},
+ Rep = wfr_mk_reply(V, TransId, Error, Extra),
+ Results2 = lists:keyreplace(TransId, 2, Results, Rep),
+ {TransIds, Results2};
+
+ false ->
+ %% First and only segment
+ Rep = wfr_mk_reply(Version, TransId, {ok, [{SegNo, ARs}]}, Extra),
+ {TransIds, [Rep | Results]}
+
+ end;
+
+%% One segment of a reply
+%% transactionResult "=" transactionError
+wfr_update(TransIds, TransId, Version, Results, {error, {SegNo, _Last, ED}}, Extra)
+ when is_integer(SegNo) ->
+ case lists:keysearch(TransId, 2, Results) of
+
+ %% First segment with error (transactionError)
+ {value, {V, TransId, {ok, OkSegs}}} ->
+ ErrSegs = [{SegNo, ED}],
+ Error = {error, {segment, OkSegs, ErrSegs}},
+ Rep = wfr_mk_reply(V, TransId, Error, Extra),
+ Results2 = lists:keyreplace(TransId, 2, Results, Rep),
+ {TransIds, Results2};
+
+ %% Another segment with error (transactionError)
+ {value, {V, TransId, {error, {OkSegs, ErrSegs}}}} ->
+ ErrSegs2 = [{SegNo, ED}|ErrSegs],
+ Error = {error, {segment, OkSegs, ErrSegs2}},
+ Rep = wfr_mk_reply(V, TransId, Error, Extra),
+ Results2 = lists:keyreplace(TransId, 2, Results, Rep),
+ {TransIds, Results2};
+
+ false ->
+ %% First segment
+ OkSegs = [],
+ ErrSegs = [{SegNo, ED}],
+ Error = {error, {segment, OkSegs, ErrSegs}},
+ Rep = wfr_mk_reply(Version, TransId, Error, Extra),
+ {TransIds, [Rep]}
+
+ end;
+
+%% This means that some segments did not make it in time
+wfr_update(TransIds, TransId, Version, Results,
+ {error, {segment_timeout, Missing}}, Extra) ->
+ TransIds2 = lists:delete(TransId, TransIds),
+ case lists:keysearch(TransId, 2, Results) of
+
+ %% First segment with error (transactionError)
+ {value, {V, TransId, {ok, OkSegs}}} ->
+ Error = {error, {segment_timeout, Missing, OkSegs, []}},
+ Rep = wfr_mk_reply(V, TransId, Error, Extra),
+ Results2 = lists:keyreplace(TransId, 2, Results, Rep),
+ {TransIds2, Results2};
+
+ %% Another segment with error (transactionError)
+ {value, {V, TransId, {error, {segment, OkSegs, ErrSegs}}}} ->
+ Error = {error, {segment_timeout, Missing, OkSegs, ErrSegs}},
+ Rep = wfr_mk_reply(V, TransId, Error, Extra),
+ Results2 = lists:keyreplace(TransId, 2, Results, Rep),
+ {TransIds2, Results2};
+
+ false ->
+ %% First segment
+ Error = {error, {segment_timeout, Missing, [], []}},
+ Rep = wfr_mk_reply(Version, TransId, Error, Extra),
+ {TransIds2, [Rep]}
+
+ end;
+
+%% And all other results (presumably results without segments).
+wfr_update(TransIds, TransId, Version, Results, Result, Extra) ->
+ TransIds2 = lists:delete(TransId, TransIds),
+ Results2 = [wfr_mk_reply(Version, TransId, Result, Extra)|Results],
+ {TransIds2, Results2}.
+
+
+%% TransInfo is either [trans_id()] or a [trans_req()]
+
+%% This is the normal case where we have just one
+%% transaction to be sent (using call or cast) using
+%% the transaction sender process.
+send_request(#conn_data{control_pid = CP,
+ trans_req = true,
+ trans_sender = Pid} = CD,
+ CH, [Serial], Action, [Bin])
+ when is_pid(Pid) andalso
+ is_integer(Serial) andalso
+ (node(CP) =:= node()) ->
+
+ ?report_trace(CD,
+ "send_request - one transaction via trans-sender",
+ [Serial]),
+
+ #conn_data{request_timer = InitTimer,
+ long_request_timer = LongTimer} = CD,
+ TransId = to_local_trans_id(CH, Serial),
+ insert_request(CD, CH, TransId, Action, {Serial, Bin},
+ InitTimer, LongTimer),
+ megaco_trans_sender:send_req(Pid, Serial, Bin);
+
+%% This is the general case where we have several transactions
+%% beeing sent (using call or cast) at once using
+%% the transaction sender process.
+send_request(#conn_data{control_pid = CP,
+ trans_req = true,
+ trans_sender = Pid} = CD,
+ CH, TransInfo, Action, Bins)
+ when is_pid(Pid) andalso
+ is_list(Bins) andalso
+ (node(CP) =:= node()) ->
+
+ ?report_trace(CD,
+ "send_request - multi transactions via trans_sender",
+ [TransInfo, Pid]),
+
+ #conn_data{request_timer = InitTimer,
+ long_request_timer = LongTimer} = CD,
+ insert_requests(CD, CH, TransInfo, Action, Bins,
+ InitTimer, LongTimer),
+ megaco_trans_sender:send_reqs(Pid, TransInfo, Bins);
+
+%% This is the case when one or more transactions is
+%% beeing sent in one message immediatelly (not using
+%% the transaction sender process. E.g. the binary is
+%% this encoded message.
+send_request(#conn_data{control_pid = CP} = CD,
+ CH, TRs, Action, Bin)
+ when is_list(TRs) andalso
+ is_binary(Bin) andalso
+ (node(CP) =:= node()) ->
+
+ %% d("send_request -> entry with"
+ %% "~n TRs: ~p", [TRs]),
+
+ ?report_trace(CD, "send_request - multi transaction", [TRs]),
+
+ #conn_data{request_timer = InitTimer,
+ long_request_timer = LongTimer} = CD,
+ insert_requests(CD, CH, TRs, Action, Bin,
+ InitTimer, LongTimer),
+ case megaco_messenger_misc:send_message(CD, false, Bin) of
+ {error, Reason} ->
+ cancel_requests(CD, TRs, Reason);
+ {ok, _} ->
+ ignore
+ end;
+
+%% This is the case where we are not on the node where the
+%% transport process run.
+send_request(#conn_data{control_pid = CP} = CD,
+ CH, TransInfo, Action, Bin)
+ when node(CP) =/= node() ->
+
+ ?report_trace(CD, "send_request - remote", [TransInfo]),
+
+ InitTimer = infinity,
+ LongTimer = infinity,
+ insert_requests(CD, CH, TransInfo, Action, Bin,
+ InitTimer, LongTimer),
+ Node = node(CP),
+ Args = [node(), CD, TransInfo, Bin],
+ rpc:cast(Node, ?MODULE, send_request_remote, Args).
+
+
+insert_requests(_, _, [], _, _, _, _) ->
+ ok;
+
+insert_requests(ConnData, ConnHandle, [Serial|Serials],
+ Action, [Bin|Bins], InitTimer, LongTimer)
+ when is_integer(Serial) andalso is_binary(Bin) ->
+ TransId = to_local_trans_id(ConnHandle, Serial),
+ insert_request(ConnData, ConnHandle,
+ TransId, Action, Bin, InitTimer, LongTimer),
+
+ insert_requests(ConnData, ConnHandle, Serials, Action, Bins,
+ InitTimer, LongTimer);
+
+insert_requests(ConnData, ConnHandle,
+ [{transactionRequest, TR}|TRs],
+ Action, Bin, InitTimer, LongTimer)
+ when is_record(TR, 'TransactionRequest') andalso is_binary(Bin) ->
+ #'TransactionRequest'{transactionId = Serial} = TR,
+ TransId = to_local_trans_id(ConnHandle, Serial),
+ insert_request(ConnData, ConnHandle,
+ TransId, Action, TR, InitTimer, LongTimer),
+
+ insert_requests(ConnData, ConnHandle, TRs, Action, Bin,
+ InitTimer, LongTimer).
+
+
+insert_request(ConnData, ConnHandle, TransId,
+ Action, Data, InitTimer, LongTimer) ->
+ #megaco_conn_handle{remote_mid = RemoteMid} = ConnHandle,
+ #conn_data{protocol_version = Version,
+ user_mod = UserMod,
+ user_args = UserArgs,
+ send_handle = SendHandle,
+ reply_data = ReplyData,
+ segment_recv_timer = InitSegTimer,
+ request_keep_alive_timeout = RKATimer} = ConnData,
+ {WaitFor, CurrTimer} = megaco_timer:init(InitTimer),
+ M = ?MODULE,
+ F = request_timeout,
+ A = [ConnHandle, TransId],
+ Ref = megaco_monitor:apply_after(M, F, A, WaitFor),
+ Req = #request{trans_id = TransId,
+ remote_mid = RemoteMid,
+ timer_ref = ?SIM({short, Ref}, init_request_timer),
+ init_timer = InitTimer,
+ init_long_timer = LongTimer,
+ curr_timer = CurrTimer,
+ version = Version,
+ bytes = {send, Data},
+ send_handle = SendHandle,
+ user_mod = UserMod,
+ user_args = UserArgs,
+ reply_action = Action,
+ reply_data = ReplyData,
+ init_seg_timer = InitSegTimer,
+ keep_alive_timer = RKATimer},
+ megaco_monitor:insert_request(Req). % Timing problem?
+
+
+send_request_remote(ReplyNode, ConnData, TransInfo, Bin) ->
+ Action = remote,
+ ConnHandle = ConnData#conn_data.conn_handle,
+ ConnData2 = ConnData#conn_data{reply_data = ReplyNode},
+ send_request(ConnData2, ConnHandle, TransInfo, Action, Bin).
+
+prepare_req_send_options(CallOrCast, ConnHandle, Options, Actions) ->
+ %% Ensures that two processes cannot get same transaction id.
+ %% Bad send options may cause spurious transaction id to be consumed.
+ Incr = number_of_transactions(Actions),
+ case megaco_config:incr_trans_id_counter(ConnHandle, Incr) of
+ {ok, ConnData} ->
+ override_req_send_options(CallOrCast, ConnData, Options);
+ {error, Reason} ->
+ {error, Reason}
+ end.
+
+number_of_transactions([Action|_]) when is_tuple(Action) ->
+ 1;
+number_of_transactions(ActionsList) ->
+ length(ActionsList).
+
+override_req_send_options(ReplyAction, ConnData, [{Key, Val} | Tail]) ->
+ case Key of
+ protocol_version ->
+ ConnData2 = ConnData#conn_data{protocol_version = Val},
+ override_req_send_options(ReplyAction, ConnData2, Tail);
+ send_handle ->
+ ConnData2 = ConnData#conn_data{send_handle = Val},
+ override_req_send_options(ReplyAction, ConnData2, Tail);
+ request_timer ->
+ case megaco_config:verify_val(Key, Val) of
+ true ->
+ ConnData2 = ConnData#conn_data{request_timer = Val},
+ override_req_send_options(ReplyAction, ConnData2, Tail);
+ false ->
+ {error, {bad_send_option, {Key, Val}}}
+ end;
+ long_request_timer ->
+ case megaco_config:verify_val(Key, Val) of
+ true ->
+ ConnData2 = ConnData#conn_data{long_request_timer = Val},
+ override_req_send_options(ReplyAction, ConnData2, Tail);
+ false ->
+ {error, {bad_send_option, {Key, Val}}}
+ end;
+ call_proxy_gc_timeout when (ReplyAction =:= call) orelse
+ (ReplyAction =:= any) ->
+ case megaco_config:verify_val(Key, Val) of
+ true ->
+ ConnData2 =
+ ConnData#conn_data{call_proxy_gc_timeout = Val},
+ override_req_send_options(ReplyAction, ConnData2, Tail);
+ false ->
+ {error, {bad_send_option, {Key, Val}}}
+ end;
+ request_keep_alive_timeout when (ReplyAction =:= cast) orelse
+ (ReplyAction =:= any) ->
+ case megaco_config:verify_val(Key, Val) of
+ true ->
+ ConnData2 =
+ ConnData#conn_data{request_keep_alive_timeout = Val},
+ override_req_send_options(ReplyAction, ConnData2, Tail);
+ false ->
+ {error, {bad_send_option, {Key, Val}}}
+ end;
+ reply_data ->
+ ConnData2 = ConnData#conn_data{reply_data = Val},
+ override_req_send_options(ReplyAction, ConnData2, Tail);
+ user_mod when is_atom(Val) ->
+ ConnData2 = ConnData#conn_data{user_mod = Val},
+ override_req_send_options(ReplyAction, ConnData2, Tail);
+ user_args when is_list(Val) ->
+ ConnData2 = ConnData#conn_data{user_args = Val},
+ override_req_send_options(ReplyAction, ConnData2, Tail);
+ trans_req when Val =:= false ->
+ %% We only allow turning the transaction-sender off, since
+ %% the opposite (turning it on) would causing to much headake...
+ %% This will allow not using the transaction sender for
+ %% occasional messages
+ ConnData2 = ConnData#conn_data{trans_req = Val,
+ trans_sender = undefined},
+ override_req_send_options(ReplyAction, ConnData2, Tail);
+ _Bad ->
+ {error, {bad_send_option, {Key, Val}}}
+ end;
+override_req_send_options(_ReplyAction, ConnData, []) ->
+ {ok, ConnData}.
+
+override_rep_send_options(ConnData, [{Key, Val} | Tail]) ->
+ case Key of
+ protocol_version ->
+ ConnData2 = ConnData#conn_data{protocol_version = Val},
+ override_rep_send_options(ConnData2, Tail);
+ send_handle ->
+ ConnData2 = ConnData#conn_data{send_handle = Val},
+ override_rep_send_options(ConnData2, Tail);
+ reply_timer ->
+ case megaco_config:verify_val(Key, Val) of
+ true ->
+ ConnData2 = ConnData#conn_data{reply_timer = Val},
+ override_rep_send_options(ConnData2, Tail);
+ false ->
+ {error, {bad_send_option, {Key, Val}}}
+ end;
+ trans_req when Val =:= false ->
+ %% We only allow turning the transaction-sender off, since
+ %% the opposite (turning it on) would causing to much headake...
+ %% This will allow not using the transaction sender for
+ %% occasional messages
+ ConnData2 = ConnData#conn_data{trans_req = Val,
+ trans_sender = undefined},
+ override_rep_send_options(ConnData2, Tail);
+ _Bad ->
+ {error, {bad_send_option, {Key, Val}}}
+ end;
+override_rep_send_options(ConnData, []) ->
+ {ok, ConnData}.
+
+
+%% ----
+%% This list is allways atleast one (list of actions) long.
+%% ----
+%% The proper number of transaction id numbers has already
+%% been "allocated", and the connection data record is
+%% updated accordingly.
+encode_requests(#conn_data{trans_req = true,
+ trans_sender = Pid,
+ serial = LastSerial} = CD, ActionsList)
+ when is_pid(Pid) ->
+ (catch encode_requests(CD, LastSerial,
+ lists:reverse(ActionsList), [], []));
+encode_requests(#conn_data{serial = LastSerial} = CD, ActionsList) ->
+ %% We shall not accumulate transactions.
+ %% This means that we shall not encode
+ %% the transactions individually (and send
+ %% them to the sender process, which
+ %% accumulate transactions for later sending),
+ %% Instead we encode the entire message directly.
+ %% => We shall return one binary, containing,
+ %% possibly, many transactions
+ encode_requests_in_msg(CD, LastSerial, lists:reverse(ActionsList)).
+
+
+%% This means that we shall compose and encode one complete
+%% megaco message, containing one or more transactions.
+encode_requests_in_msg(CD, LastSerial, ActionsList) ->
+ TRs = compose_requests_in_msg(LastSerial, ActionsList, []),
+ Body = {transactions, TRs},
+ Res = megaco_messenger_misc:encode_body(CD,
+ "encode trans request(s) msg",
+ Body),
+ case Res of
+ {ok, Bin} ->
+ {ok, TRs, Bin};
+ Error ->
+ Error
+ end.
+
+compose_requests_in_msg(_S, [], TRs) ->
+ TRs;
+compose_requests_in_msg(Serial, [A|As], Acc) ->
+ TR = #'TransactionRequest'{transactionId = Serial,
+ actions = A},
+ compose_requests_in_msg(Serial - 1, As, [{transactionRequest, TR}|Acc]).
+
+
+%% We have done the encoding in reverse order, so there
+%% is no need to reverse now.
+encode_requests(_, _, [], Serials, EncodedTRs) ->
+ {ok, Serials, EncodedTRs};
+encode_requests(CD, Serial, [Actions|ActionsList], Serials, EncodedTRs) ->
+ case do_encode_request(CD, Serial, Actions) of
+ {ok, Bin} ->
+ encode_requests(CD, Serial - 1, ActionsList,
+ [Serial|Serials], [Bin|EncodedTRs]);
+ Error ->
+ throw(Error)
+ end.
+
+
+do_encode_request(CD, Serial, Actions) ->
+ TR = #'TransactionRequest'{transactionId = Serial,
+ actions = Actions},
+ megaco_messenger_misc:encode_trans_request(CD, TR).
+
+
+imm_ack_req(Counter, when_pending_sent) when (Counter > 0) -> 'NULL';
+imm_ack_req(_Counter, when_pending_sent) -> asn1_NOVALUE;
+imm_ack_req(_Counter, ImmAck) -> ImmAck.
+
+maybe_send_reply(#conn_data{sent_pending_limit = Limit} = ConnData,
+ TransId, Result, SendOpts, ImmAck) ->
+
+ %% d("maybe_send_reply -> entry with"
+ %% "~n Limit: ~p"
+ %% "~n TransId: ~p"
+ %% "~n Result: ~p"
+ %% "~n SendOpts: ~p"
+ %% "~n ImmAck: ~p", [Limit, TransId, Result, SendOpts, ImmAck]),
+
+ %% Pending limit
+ %% Before we can send the reply we must check that we have
+ %% not passed the pending limit (and sent an error message).
+ case check_pending_limit(Limit, sent, TransId) of
+ {ok, Counter} ->
+ case override_rep_send_options(ConnData, SendOpts) of
+ {ok, ConnData2} ->
+ send_reply(ConnData2, Result,
+ imm_ack_req(Counter, ImmAck));
+ Error ->
+ Error
+ end;
+ aborted ->
+ {error, aborted}
+ end.
+
+encode_reply(CD, TR) ->
+ megaco_messenger_misc:encode_trans_reply(CD, TR).
+
+send_reply(#conn_data{serial = Serial,
+ trans_req = TransReq,
+ trans_sender = TransSnd} = CD, TransRes, ImmAck) ->
+
+ %% Encapsule the transaction result into a reply message
+
+ %% d("send_reply -> entry with"
+ %% "~n Serial: ~p"
+ %% "~n TransRes: ~p"
+ %% "~n ImmAck: ~p", [Serial, TransRes, ImmAck]),
+
+ TR = #megaco_transaction_reply{transactionId = Serial,
+ immAckRequired = ImmAck,
+ transactionResult = TransRes},
+ case encode_reply(CD, TR) of
+ {ok, Bin} when is_binary(Bin) andalso (TransReq =:= true) ->
+ ?rt2("send_reply - pass it on to the transaction sender",
+ [size(Bin)]),
+ megaco_trans_sender:send_reply(TransSnd, Bin),
+ {ok, Bin};
+
+ {ok, Bin} when is_binary(Bin) ->
+ ?rt2("send_reply - encoded", [size(Bin)]),
+ TraceLabel = "send trans reply",
+ Body = {transactions, [Bin]},
+ megaco_messenger_misc:send_body(CD, TraceLabel, Body);
+
+ {ok, Bins} when is_list(Bins) ->
+ ?rt2("send_reply - encoded (segmented)", [length(Bins)]),
+ Res = send_reply_segments(CD, Bins),
+ {ok, Res};
+
+ {error, not_implemented} ->
+ %% Oups, we cannot segment regardless the config,
+ %% so pack it all into one message and hope for
+ %% the best...
+ ?rt2("send_reply - cannot encode separate transactions", []),
+ TR2 = megaco_messenger_misc:transform_transaction_reply(CD, TR),
+ Body = {transactions, [{transactionReply, TR2}]},
+ megaco_messenger_misc:send_body(CD, "encode trans reply", Body);
+
+ {error, Reason} = Error ->
+ Code = ?megaco_internal_gateway_error,
+ Text = "encode transaction reply",
+ ED = #'ErrorDescriptor'{errorCode = Code,
+ errorText = Text},
+ Res = {transactionError, ED},
+ TR2 = #megaco_transaction_reply{transactionId = Serial,
+ transactionResult = Res},
+ TR3 = megaco_messenger_misc:transform_transaction_reply(CD, TR2),
+ TraceLabel = "<ERROR> encode trans reply body failed",
+ ?report_important(CD, TraceLabel, [TR, TR3, ED, Error]),
+ error_msg("failed encoding transaction reply body: ~s",
+ [format_encode_error_reason(Reason)]),
+ Body = {transactions, [{transactionReply, TR3}]},
+ megaco_messenger_misc:send_body(CD, TraceLabel, Body),
+ Error
+ end.
+
+send_reply_segments(CD, Bins) ->
+ TraceLabelPre = "send segmented trans reply",
+ (catch send_reply_segments(CD, TraceLabelPre, Bins)).
+
+send_reply_segments(#conn_data{segment_send = infinity} = CD, Label, Bins) ->
+ send_reply_segments(CD, Label, length(Bins), Bins);
+
+send_reply_segments(#conn_data{segment_send = K} = CD, Label, Bins)
+ when is_integer(K) andalso (K =< length(Bins)) ->
+ send_reply_segments(CD, Label, K, Bins);
+
+send_reply_segments(#conn_data{segment_send = K} = CD, Label, Bins)
+ when is_integer(K) ->
+ send_reply_segments(CD, Label, length(Bins), Bins).
+
+send_reply_segments(CD, Label, K, Bins) ->
+ send_reply_segments(CD, Label, K, Bins, []).
+
+send_reply_segments(_CD, _Label, 0, Bins, Sent) ->
+ ?rt2("send_reply_segments - done", [Sent, Bins]),
+ {Sent, Bins};
+send_reply_segments(CD, TraceLabelPre, K, [{SN, Bin}|Bins], Sent) ->
+ case send_reply_segment(CD, TraceLabelPre, SN, Bin) of
+ {ok, Bin2} ->
+ ?rt2("send_reply_segments - send", [K, SN]),
+ send_reply_segments(CD, TraceLabelPre, K-1,
+ Bins, [{SN, Bin2}|Sent]);
+ Error ->
+ throw(Error)
+ end.
+
+send_reply_segment(CD, TraceLabelPre, SN, Bin) ->
+ Label = lists:flatten(io_lib:format("~s[~w]", [TraceLabelPre, SN])),
+ Body = {transactions, [Bin]},
+ megaco_messenger_misc:send_body(CD, Label, Body).
+
+
+format_encode_error_reason(Reason) ->
+ FS =
+ case Reason of
+ {Mod, Func, [EC, Msg], {AE, CS}} when is_atom(Mod) andalso
+ is_atom(Func) andalso
+ is_list(EC) and
+ is_tuple(Msg) and
+ is_list(CS) ->
+ io_lib:format("~n Encode module: ~w"
+ "~n Func: ~w"
+ "~n Encode config: ~w"
+ "~n Message part: ~p"
+ "~n Actual error: ~p"
+ "~n Call stack: ~w",
+ [Mod, Func, EC, Msg, AE, CS]);
+
+ {Mod, Func, [EC, Msg], AE} when is_atom(Mod) andalso
+ is_atom(Func) andalso
+ is_list(EC) andalso
+ is_tuple(Msg) ->
+ io_lib:format("~n Encode module: ~w"
+ "~n Func: ~w"
+ "~n Encode config: ~w"
+ "~n Message part: ~p"
+ "~n Actual error: ~p",
+ [Mod, Func, EC, Msg, AE]);
+
+ {Mod, [EC, Msg], {AE, CS}} when is_atom(Mod) andalso
+ is_list(EC) andalso
+ is_tuple(Msg) andalso
+ is_list(CS) ->
+ io_lib:format("~n Encode module: ~w"
+ "~n Encode config: ~w"
+ "~n Message part: ~p"
+ "~n Actual error: ~p"
+ "~n Call stack: ~w",
+ [Mod, EC, Msg, AE, CS]);
+
+ {Mod, [EC, Msg], AE} when is_atom(Mod) andalso
+ is_list(EC) andalso
+ is_tuple(Msg) ->
+ io_lib:format("~n Encode module: ~w"
+ "~n Encode config: ~w"
+ "~n Message part: ~p"
+ "~n Actual error: ~p",
+ [Mod, EC, Msg, AE]);
+
+ Error ->
+ io_lib:format("~n ~w", [Error])
+ end,
+ lists:flatten(FS).
+
+
+%% Presumably the user would return immediately (with {pending, Data}) if it
+%% knows or suspects a request to take a long time to process.
+%% For this reason we assume that handling a resent request
+%% could not have caused an update of the pending limit counter.
+maybe_send_pending(#conn_data{sent_pending_limit = Limit} = ConnData,
+ TransId) ->
+ case check_and_maybe_incr_pending_limit(Limit, sent, TransId) of
+ ok ->
+ send_pending(ConnData);
+ error ->
+ SendReply = send_pending_limit_error(ConnData),
+ {aborted, SendReply};
+ aborted ->
+ {aborted, ignore}
+ end.
+
+
+send_pending(#conn_data{serial = Serial,
+ trans_req = true,
+ trans_sender = Pid}) ->
+ megaco_trans_sender:send_pending(Pid, Serial);
+send_pending(#conn_data{serial = Serial} = CD) ->
+ %% Encapsule the transaction result into a pending message
+ TP = #'TransactionPending'{transactionId = Serial},
+ Body = {transactions, [{transactionPending, TP}]},
+ megaco_messenger_misc:send_body(CD, "send trans pending", Body).
+
+
+maybe_send_ack('NULL', #conn_data{serial = Serial,
+ trans_ack = true,
+ trans_sender = Pid}) ->
+ megaco_trans_sender:send_ack_now(Pid, Serial);
+maybe_send_ack('NULL', CD) ->
+ send_ack(CD);
+maybe_send_ack(_, #conn_data{auto_ack = false}) ->
+ ignore;
+maybe_send_ack(_, #conn_data{serial = Serial,
+ trans_ack = true,
+ trans_sender = Pid})
+ when is_pid(Pid) ->
+ %% Send (later) via the transaction sender
+ megaco_trans_sender:send_ack(Pid, Serial),
+ ok;
+maybe_send_ack(_, CD) ->
+ %% Send now
+ send_ack(CD).
+
+
+send_ack(#conn_data{serial = Serial} = CD) ->
+ %% Encapsule the transaction result into a ack message
+ TRA = #'TransactionAck'{firstAck = Serial},
+ Body = {transactions, [{transactionResponseAck, [TRA]}]},
+ megaco_messenger_misc:send_body(CD, "send trans ack", Body).
+
+
+send_segment_reply(#conn_data{serial = Serial} = CD, SegNo) ->
+ SR = #'SegmentReply'{transactionId = Serial,
+ segmentNumber = SegNo},
+ Body = {transactions, [{segmentReply, SR}]},
+ megaco_messenger_misc:send_body(CD, "send segment reply", Body).
+
+send_segment_reply(#conn_data{serial = Serial} = CD, SegNo, Complete) ->
+ SR = #'SegmentReply'{transactionId = Serial,
+ segmentNumber = SegNo,
+ segmentationComplete = Complete},
+ Body = {transactions, [{segmentReply, SR}]},
+ megaco_messenger_misc:send_body(CD, "send segment reply", Body).
+
+send_segment_reply_complete(CD, SegNo) ->
+ send_segment_reply(CD, SegNo, 'NULL').
+
+
+send_pending_limit_error(ConnData) ->
+ ?report_pending_limit_exceeded(ConnData),
+ Code = ?megaco_number_of_transactionpending_exceeded,
+ Reason = "Pending limit exceeded",
+ send_trans_error(ConnData, Code, Reason).
+
+send_trans_error(ConnData, Code, Reason) ->
+ %% Encapsulate the transaction error into a reply message
+ ED = #'ErrorDescriptor'{errorCode = Code, errorText = Reason},
+ Serial = ConnData#conn_data.serial,
+ %% Version = ConnData#conn_data.protocol_version,
+ TransRes = {transactionError, ED},
+ TR = #megaco_transaction_reply{transactionId = Serial,
+ transactionResult = TransRes},
+ TR2 = megaco_messenger_misc:transform_transaction_reply(ConnData, TR),
+ Body = {transactions, [{transactionReply, TR2}]},
+ case megaco_messenger_misc:send_body(ConnData, "send trans error", Body) of
+ {error, Reason2} ->
+ ?report_important(ConnData,
+ "<ERROR> failed sending transaction error",
+ [Body, {error, Reason2}]),
+ error;
+ _ ->
+ ok
+ end.
+
+
+send_message_error(ConnData, Code, Reason) ->
+ ED = #'ErrorDescriptor'{errorCode = Code, errorText = Reason},
+ Body = {messageError, ED},
+ case megaco_messenger_misc:send_body(ConnData, "send trans error", Body) of
+ {error, Reason2} ->
+ ?report_important(ConnData,
+ "<ERROR> failed sending message error",
+ [Body, {error, Reason2}]),
+ error;
+ _ ->
+ ok
+ end.
+
+
+cancel(ConnHandle, Reason) when is_record(ConnHandle, megaco_conn_handle) ->
+ case megaco_config:lookup_local_conn(ConnHandle) of
+ [CD] ->
+ megaco_config:update_conn_info(CD, cancel, true),
+ do_cancel(ConnHandle, Reason, CD#conn_data{cancel = true}),
+ megaco_config:update_conn_info(CD, cancel, false),
+ ok;
+ [] ->
+ ConnData = fake_conn_data(ConnHandle),
+ do_cancel(ConnHandle, Reason, ConnData)
+ end.
+
+do_cancel(ConnHandle, Reason, ConnData) ->
+ ?report_trace(ConnData, "cancel", [ConnHandle, Reason]),
+ LocalMid = ConnHandle#megaco_conn_handle.local_mid,
+ RemoteMid = ConnHandle#megaco_conn_handle.remote_mid,
+ ReqTransIdPat = #trans_id{mid = LocalMid, _ = '_'},
+ ReqPat = #request{trans_id = ReqTransIdPat,
+ remote_mid = RemoteMid,
+ _ = '_'},
+ CancelReq = fun(Req) ->
+ cancel_request(ConnData, Req, Reason),
+ {_Type, Ref} = Req#request.timer_ref, %% OTP-4843
+ megaco_monitor:cancel_apply_after(Ref)
+ end,
+ Requests = megaco_monitor:match_requests(ReqPat),
+ lists:foreach(CancelReq, Requests),
+ RemoteMid = ConnHandle#megaco_conn_handle.remote_mid,
+ RepTransIdPat = #trans_id{mid = RemoteMid, _ = '_'}, % BUGBUG List here?
+ RepPat = #reply{trans_id = RepTransIdPat,
+ local_mid = LocalMid,
+ _ = '_'},
+ CancelRep = fun(Rep) ->
+ cancel_reply(ConnData, Rep, Reason)
+ end,
+ Replies = megaco_monitor:match_replies(RepPat),
+ lists:foreach(CancelRep, Replies),
+ ok.
+
+cancel_requests(_ConnData, [], _Reason) ->
+ ok;
+cancel_requests(ConnData, [{transactionRequest,TR}|TRs], Reason) ->
+ #'TransactionRequest'{transactionId = TransId0} = TR,
+ TransId = to_local_trans_id(ConnData#conn_data.conn_handle, TransId0),
+ case megaco_monitor:lookup_request(TransId) of
+ [] ->
+ ignore;
+ [Req] when is_record(Req, request) ->
+ cancel_request(ConnData, Req, Reason)
+ end,
+ cancel_requests(ConnData, TRs, Reason).
+
+cancel_request(ConnData, Req, Reason) ->
+ ?report_trace(ignore, "cancel request", [Req]),
+ ?TC_AWAIT_CANCEL_EVENT(),
+ TransId = Req#request.trans_id,
+ Version = Req#request.version,
+ UserMod = Req#request.user_mod,
+ UserArgs = Req#request.user_args,
+ Action = Req#request.reply_action,
+ UserData = Req#request.reply_data,
+ UserReply = {error, Reason},
+ ConnData2 = ConnData#conn_data{protocol_version = Version,
+ user_mod = UserMod,
+ user_args = UserArgs,
+ reply_action = Action,
+ reply_data = UserData},
+ cancel_request2(ConnData2, TransId, UserReply).
+
+cancel_request2(ConnData, TransId, UserReply) ->
+ megaco_monitor:delete_request(TransId),
+ megaco_config:del_pending_counter(recv, TransId), % OTP-7189
+ Serial = TransId#trans_id.serial,
+ ConnData2 = ConnData#conn_data{serial = Serial},
+ return_reply(ConnData2, TransId, UserReply).
+
+
+return_reply(ConnData, TransId, UserReply) ->
+ Extra = ?default_user_callback_extra,
+ return_reply(ConnData, TransId, UserReply, Extra).
+
+return_reply(ConnData, TransId, UserReply, Extra) ->
+ ?report_trace(ConnData, "callback: trans reply", [UserReply]),
+ Version = ConnData#conn_data.protocol_version,
+ UserData = ConnData#conn_data.reply_data,
+ case ConnData#conn_data.reply_action of
+ call when is_pid(UserData) ->
+ ?report_trace(ConnData, "callback: (call) trans reply",
+ [UserReply]),
+ Pid = UserData,
+ Pid ! {?MODULE, TransId, Version, UserReply, Extra};
+ cast ->
+ ?report_trace(ConnData, "callback: (cast) trans reply", [UserReply]),
+ UserMod = ConnData#conn_data.user_mod,
+ UserArgs = ConnData#conn_data.user_args,
+ ConnHandle = ConnData#conn_data.conn_handle,
+ Args =
+ case Extra of
+ ?default_user_callback_extra ->
+ [ConnHandle, Version, UserReply, UserData | UserArgs];
+ _ ->
+ [ConnHandle, Version, UserReply, UserData, Extra | UserArgs]
+ end,
+ Res = (catch apply(UserMod, handle_trans_reply, Args)),
+ ?report_debug(ConnData, "return: (cast) trans reply",
+ [UserReply, {return, Res}]),
+ case Res of
+ ok ->
+ ok;
+ _ ->
+ warning_msg("transaction reply callback failed: ~w",
+ [Res]),
+ ok
+ end,
+ Res;
+ remote ->
+ ?report_trace(ConnData, "callback: (remote) trans reply", [UserReply]),
+ Node = UserData,
+ Args = [ConnData, UserReply, Extra],
+ rpc:cast(Node, ?MODULE, receive_reply_remote, Args)
+ end.
+
+receive_reply_remote(ConnData, UserReply) ->
+ Extra = ?default_user_callback_extra,
+ receive_reply_remote(ConnData, UserReply, Extra).
+
+receive_reply_remote(ConnData, UserReply, Extra) ->
+ TransId = to_local_trans_id(ConnData),
+ case (catch megaco_monitor:lookup_request(TransId)) of
+ [#request{timer_ref = {_Type, Ref}} = Req] -> %% OTP-4843
+ %% Don't care about Req and Rep version diff
+ megaco_monitor:delete_request(TransId),
+ megaco_monitor:cancel_apply_after(Ref), % OTP-4843
+ megaco_config:del_pending_counter(recv, TransId), % OTP-7189
+
+ UserMod = Req#request.user_mod,
+ UserArgs = Req#request.user_args,
+ Action = Req#request.reply_action,
+ UserData = Req#request.reply_data,
+ ConnData2 = ConnData#conn_data{user_mod = UserMod,
+ user_args = UserArgs,
+ reply_action = Action,
+ reply_data = UserData},
+ return_reply(ConnData2, TransId, UserReply, Extra);
+
+ _ ->
+ ?report_trace(ConnData, "remote reply (no receiver)",
+ [UserReply]),
+ return_unexpected_trans_reply(ConnData, TransId, UserReply, Extra)
+ end.
+
+cancel_reply(ConnData, #reply{state = waiting_for_ack} = Rep, Reason) ->
+ ?report_trace(ignore, "cancel reply [waiting_for_ack]", [Rep]),
+ megaco_monitor:cancel_apply_after(Rep#reply.pending_timer_ref),
+ Serial = (Rep#reply.trans_id)#trans_id.serial,
+ ConnData2 = ConnData#conn_data{serial = Serial},
+ T = #'TransactionAck'{firstAck = Serial},
+ Extra = ?default_user_callback_extra,
+ handle_ack(ConnData2, {error, Reason}, Rep, T, Extra);
+
+cancel_reply(_ConnData, #reply{state = aborted} = Rep, _Reason) ->
+ ?report_trace(ignore, "cancel reply [aborted]", [Rep]),
+ #reply{trans_id = TransId,
+ timer_ref = ReplyRef,
+ pending_timer_ref = PendingRef} = Rep,
+ megaco_monitor:delete_reply(TransId),
+ megaco_monitor:cancel_apply_after(ReplyRef),
+ megaco_monitor:cancel_apply_after(PendingRef), % Still running?
+ megaco_config:del_pending_counter(sent, TransId), % Still existing?
+ ok;
+
+cancel_reply(_ConnData, Rep, ignore) ->
+ ?report_trace(ignore, "cancel reply [ignore]", [Rep]),
+ #reply{trans_id = TransId,
+ timer_ref = ReplyRef,
+ pending_timer_ref = PendingRef} = Rep,
+ megaco_monitor:delete_reply(TransId),
+ megaco_monitor:cancel_apply_after(ReplyRef),
+ megaco_monitor:cancel_apply_after(PendingRef), % Still running?
+ megaco_config:del_pending_counter(sent, TransId), % Still existing?
+ ok;
+
+cancel_reply(_CD, _Rep, _Reason) ->
+ ok.
+
+
+request_keep_alive_timeout(ConnHandle, TransId) ->
+ megaco_config:del_pending_counter(ConnHandle, TransId),
+ megaco_monitor:lookup_request(TransId),
+ ok.
+
+
+request_timeout(ConnHandle, TransId) ->
+ ?rt1(ConnHandle, "request timeout", [TransId]),
+ case megaco_monitor:lookup_request(TransId) of
+ [] ->
+ request_not_found_ignore;
+ [Req] when is_record(Req, request) ->
+ case megaco_config:lookup_local_conn(ConnHandle) of
+ [CD] when (CD#conn_data.cancel =:= true) ->
+ cancel_in_progress_ignore;
+ [CD] ->
+ incNumTimerRecovery(ConnHandle),
+ do_request_timeout(ConnHandle, TransId, CD, Req);
+ [] when ConnHandle#megaco_conn_handle.remote_mid =:= preliminary_mid ->
+ %% There are two possibillities:
+ %% 1) The connection has just been upgraded from a
+ %% preliminary to a real connection. So this timeout
+ %% is just a glitch. E.g. between the removel of this
+ %% ConnHandle and the timer.
+ %% 2) The first message sent, the service-change, got no
+ %% reply (UDP without three-way-handshake).
+ %% And then the other side (MGC) sends a request,
+ %% which causes an auto-upgrade
+ request_timeout_upgraded(ConnHandle, Req);
+ [] ->
+ incNumTimerRecovery(ConnHandle),
+ ConnData = fake_conn_data(ConnHandle),
+ do_request_timeout(ConnHandle, TransId, ConnData, Req)
+ end
+ end.
+
+request_timeout_upgraded(ConnHandle, Req) ->
+ CD = fake_conn_data(ConnHandle),
+ cancel_request(CD, Req, timeout).
+
+do_request_timeout(ConnHandle, TransId, ConnData,
+ #request{curr_timer = CurrTimer} = Req) ->
+
+ ?rt1(ConnHandle, "process request timeout", [TransId, CurrTimer]),
+
+ SendHandle = Req#request.send_handle,
+ Version = Req#request.version,
+ ConnData2 = ConnData#conn_data{send_handle = SendHandle,
+ protocol_version = Version},
+ case CurrTimer of
+ timeout -> %%%%%%%
+ cancel_request(ConnData2, Req, timeout),
+ timeout1;
+
+ %% Restartable timer
+ %% (max_retries = infinity_restartable)
+ {_, timeout} ->
+ cancel_request(ConnData2, Req, timeout),
+ timeout2;
+
+ Timer ->
+ {SendOrNoSend, Data} = Req#request.bytes,
+ case SendOrNoSend of
+ send ->
+ case maybe_encode(ConnData2, Data) of
+ {ok, Bin} ->
+ ?report_trace(ConnData2, "re-send trans request",
+ [{bytes, Bin}]),
+ case maybe_send_message(ConnData2, true, Bin) of
+ ok ->
+ sent1_ignore;
+ {ok, _} ->
+ sent2_ignore;
+ {error, Reason} ->
+ ?report_important(ConnData2,
+ "<ERROR> "
+ "re-send trans "
+ "request failed",
+ [{bytes, Bin},
+ {error, Reason}])
+ end;
+
+ {error, Reason} ->
+ %% Since it was possible to encode the original
+ %% message this should really never happen...
+ ?report_important(ConnData2,
+ "<ERROR> "
+ "re-send trans request failed",
+ [{transaction,
+ Req#request.bytes},
+ {error, Reason}])
+ end;
+ no_send ->
+ not_sent_ok
+ end,
+ {WaitFor, Timer2} = megaco_timer:restart(Timer),
+ OptBin = opt_garb_binary(Timer2, Data),
+ {Type, _} = Req#request.timer_ref,
+ M = ?MODULE,
+ F = request_timeout,
+ A = [ConnHandle, TransId],
+ Ref2 = megaco_monitor:apply_after(M, F, A, WaitFor),
+ NewFields =
+ [{#request.bytes, {SendOrNoSend, OptBin}},
+ {#request.timer_ref, {Type, Ref2}},
+ {#request.curr_timer, Timer2}],
+ megaco_monitor:update_request_fields(TransId, NewFields), % Timing problem
+ {restarted, WaitFor, Timer2}
+
+ end.
+
+maybe_encode(#conn_data{trans_req = false} = CD, {_Serial, Bin})
+ when is_binary(Bin) ->
+ Body = {transactions, [{transactionRequest, Bin}]},
+ megaco_messenger_misc:encode_body(CD, "encode trans request msg", Body);
+maybe_encode(_CD, {_Serial, Bin} = D) when is_binary(Bin) ->
+ {ok, D};
+maybe_encode(#conn_data{trans_req = true,
+ trans_sender = Pid} = CD,
+ #'TransactionRequest'{transactionId = Serial} = TR)
+ when is_pid(Pid) ->
+ case megaco_messenger_misc:encode_trans_request(CD, TR) of
+ {ok, Bin} ->
+ {ok, {Serial, Bin}};
+ Error ->
+ Error
+ end;
+maybe_encode(CD, TR)
+ when is_record(TR, 'TransactionRequest') ->
+ Body = {transactions, [{transactionRequest, TR}]},
+ megaco_messenger_misc:encode_body(CD, "encode trans request msg", Body);
+maybe_encode(_CD, Trash) ->
+ {error, {invalid_bin, Trash}}.
+
+maybe_send_message(CD, Resend, Bin) when is_binary(Bin) ->
+ megaco_messenger_misc:send_message(CD, Resend, Bin);
+maybe_send_message(#conn_data{trans_sender = Pid}, _Resend, {Serial, Bin})
+ when is_pid(Pid) andalso is_integer(Serial) andalso is_binary(Bin) ->
+ megaco_trans_sender:send_req(Pid, Serial, Bin).
+
+
+reply_timeout(ConnHandle, TransId, timeout) ->
+ handle_reply_timer_timeout(ConnHandle, TransId);
+
+%% This means that infinity_restartable was used for max_retries.
+%% There is currently no reason to use this for the reply_timeout,
+%% since there is no external event to restart the timer!
+reply_timeout(ConnHandle, TransId, {_, timeout}) ->
+ handle_reply_timer_timeout(ConnHandle, TransId);
+
+reply_timeout(ConnHandle, TransId, Timer) ->
+ ?report_trace(ConnHandle, "reply timeout", [Timer, TransId]),
+
+ case megaco_monitor:lookup_reply(TransId) of
+ [] ->
+ reply_not_found_ignore;
+
+ [#reply{state = waiting_for_ack,
+ ack_action = {handle_ack, _}} = Rep] ->
+ case megaco_config:lookup_local_conn(ConnHandle) of
+ [CD] when (CD#conn_data.cancel =:= true) ->
+ cancel_in_progress_ignore;
+ [CD] ->
+ incNumTimerRecovery(ConnHandle),
+ do_reply_timeout(ConnHandle, TransId, CD, Timer, Rep);
+ [] ->
+ incNumTimerRecovery(ConnHandle),
+ CD = fake_conn_data(ConnHandle),
+ do_reply_timeout(ConnHandle, TransId, CD, Timer, Rep)
+ end;
+
+ [#reply{state = waiting_for_ack,
+ bytes = Sent} = Rep] when is_list(Sent) ->
+ case megaco_config:lookup_local_conn(ConnHandle) of
+ [ConnData] ->
+ incNumTimerRecovery(ConnHandle),
+ do_reply_timeout(ConnHandle, TransId, ConnData,
+ Timer, Rep);
+ [] ->
+ incNumTimerRecovery(ConnHandle),
+ ConnData = fake_conn_data(ConnHandle),
+ do_reply_timeout(ConnHandle, TransId, ConnData,
+ Timer, Rep)
+ end;
+
+ [#reply{state = waiting_for_ack} = Rep] ->
+ do_reply_timeout(ConnHandle, TransId, Timer, Rep);
+
+ [#reply{state = aborted} = Rep] ->
+ do_reply_timeout(ConnHandle, TransId, Timer, Rep);
+
+ _ ->
+ ignore
+
+ end.
+
+do_reply_timeout(ConnHandle, TransId, ConnData, Timer,
+ #reply{send_handle = SH,
+ version = V,
+ bytes = Bytes} = Rep) when is_binary(Bytes) ->
+
+%% d("do_reply_timeout -> entry with"
+%% "~n ConnHandle: ~p"
+%% "~n TransId: ~p"
+%% "~n Timer: ~p"
+%% "~n Rep: ~p"
+%% "~n", [ConnHandle, TransId, Timer, Rep]),
+
+ CD = ConnData#conn_data{send_handle = SH,
+ protocol_version = V},
+
+ ?rt1(CD, "re-send trans reply", [{bytes, Bytes}]),
+ case megaco_messenger_misc:send_message(CD, true, Bytes) of
+ {ok, _} ->
+ ignore;
+ {error, Reason} ->
+ ?report_important(CD, "<ERROR> re-send trans reply failed",
+ [{bytes, Bytes}, {error, Reason}])
+ end,
+ do_reply_timeout(ConnHandle, TransId, Timer, Rep);
+
+do_reply_timeout(ConnHandle, TransId, ConnData, Timer,
+ #reply{send_handle = SH,
+ version = V,
+ bytes = Sent} = Rep) when is_list(Sent) ->
+
+%% d("do_reply_timeout -> entry with"
+%% "~n ConnHandle: ~p"
+%% "~n TransId: ~p"
+%% "~n Timer: ~p"
+%% "~n Rep: ~p"
+%% "~n", [ConnHandle, TransId, Timer, Rep]),
+
+ CD = ConnData#conn_data{send_handle = SH,
+ protocol_version = V},
+
+ ReSend =
+ fun({SN, Bytes}) ->
+ ?rt1(CD, "re-send segmented trans reply",
+ [{segment_no, SN}, {bytes, Bytes}]),
+ case megaco_messenger_misc:send_message(CD, true, Bytes) of
+%% ok ->
+%% ignore;
+ {ok, _} ->
+ ignore;
+ {error, Reason} ->
+ ?report_important(CD,
+ "<ERROR> re-send segmented "
+ "trans reply failed",
+ [{segment_no, SN},
+ {bytes, Bytes},
+ {error, Reason}])
+ end
+ end,
+ lists:foreach(ReSend, Sent),
+ do_reply_timeout(ConnHandle, TransId, Timer, Rep).
+
+do_reply_timeout(ConnHandle, TransId, Timer, #reply{bytes = Bytes}) ->
+ {WaitFor, Timer2} = megaco_timer:restart(Timer),
+ OptBin = case Bytes of
+ Bin when is_binary(Bin) ->
+ opt_garb_binary(Timer2, Bin);
+ Sent when is_list(Sent) ->
+ Garb = fun(Bin) -> opt_garb_binary(Timer2, Bin) end,
+ [{SN, Garb(Bin)} || {SN, Bin} <- Sent]
+ end,
+ M = ?MODULE,
+ F = reply_timeout,
+ A = [ConnHandle, TransId, Timer2],
+ Ref2 = megaco_monitor:apply_after(M, F, A, WaitFor),
+ NewFields =
+ [{#reply.bytes, OptBin},
+ {#reply.timer_ref, Ref2}],
+ megaco_monitor:update_reply_fields(TransId, NewFields), % Timing problem?
+ {restarted, WaitFor, Timer2}.
+
+
+handle_reply_timer_timeout(ConnHandle, TransId) ->
+ ?report_trace(ConnHandle, "handle reply timeout", [timeout, TransId]),
+ incNumTimerRecovery(ConnHandle),
+ %% OTP-4378
+ case megaco_monitor:lookup_reply(TransId) of
+ [#reply{state = waiting_for_ack} = Rep] ->
+ Serial = (Rep#reply.trans_id)#trans_id.serial,
+ ConnData =
+ case megaco_config:lookup_local_conn(ConnHandle) of
+ [ConnData0] ->
+ ConnData0;
+ [] ->
+ fake_conn_data(ConnHandle)
+ end,
+ ConnData2 = ConnData#conn_data{serial = Serial},
+ T = #'TransactionAck'{firstAck = Serial},
+ Extra = ?default_user_callback_extra,
+ handle_ack(ConnData2, {error, timeout}, Rep, T, Extra);
+ [#reply{pending_timer_ref = Ref, % aborted?
+ bytes = SegSent}] -> % may be a binary
+ megaco_monitor:cancel_apply_after(Ref),
+ cancel_segment_timers(SegSent),
+ megaco_monitor:delete_reply(TransId),
+ megaco_config:del_pending_counter(sent, TransId);
+ [] ->
+ ignore_reply_removed
+ end.
+
+%% segment_reply_timeout(ConnHandle, TransId, SN, timeout) ->
+%% ?report_trace(ConnHandle, "segment reply timeout", [timeout, SN, TransId]),
+%% D = fun({_, _, SegRef}) ->
+%% megaco_monitor:cancel_apply_after(SegRef)
+%% end,
+%% incNumTimerRecovery(ConnHandle),
+%% %% OTP-4378
+%% case megaco_monitor:lookup_reply(TransId) of
+%% [#reply{state = waiting_for_ack,
+%% bytes = Sent} = Rep] ->
+%% Serial = (Rep#reply.trans_id)#trans_id.serial,
+%% ConnData =
+%% case megaco_config:lookup_local_conn(ConnHandle) of
+%% [ConnData0] ->
+%% ConnData0;
+%% [] ->
+%% fake_conn_data(ConnHandle)
+%% end,
+%% ConnData2 = ConnData#conn_data{serial = Serial},
+%% T = #'TransactionAck'{firstAck = Serial},
+%% lists:foreach(D, Sent),
+%% Extra = ?default_user_callback_extra,
+%% handle_ack(ConnData2, {error, timeout}, Rep, T, Extra);
+%% [#reply{pending_timer_ref = Ref,
+%% bytes = Sent}] -> % aborted?
+%% lists:foreach(D, Sent),
+%% megaco_monitor:cancel_apply_after(Ref),
+%% megaco_monitor:delete_reply(TransId),
+%% megaco_config:del_pending_counter(sent, TransId);
+
+%% [] ->
+%% ignore
+
+%% end.
+
+%% segment_reply_timeout(ConnHandle, TransId, SN, Timer) ->
+%% ?report_trace(ConnHandle, "reply timeout", [Timer, SN, TransId]),
+
+%% %% d("reply_timeout -> entry with"
+%% %% "~n ConnHandle: ~p"
+%% %% "~n TransId: ~p"
+%% %% "~n Timer: ~p", [ConnHandle, TransId, Timer]),
+
+%% case megaco_monitor:lookup_reply(TransId) of
+%% [] ->
+%% ignore; % Trace ??
+
+%% [#reply{state = waiting_for_ack,
+%% bytes = ack_action = {handle_ack, _}} = Rep] ->
+%% case megaco_config:lookup_local_conn(ConnHandle) of
+%% [ConnData] ->
+%% incNumTimerRecovery(ConnHandle),
+%% do_reply_timeout(ConnHandle, TransId, ConnData,
+%% Timer, Rep);
+%% [] ->
+%% incNumTimerRecovery(ConnHandle),
+%% ConnData = fake_conn_data(ConnHandle),
+%% do_reply_timeout(ConnHandle, TransId, ConnData,
+%% Timer, Rep)
+%% end;
+
+%% [#reply{state = waiting_for_ack} = Rep] ->
+%% do_reply_timeout(ConnHandle, TransId, Timer, Rep);
+
+%% [#reply{state = aborted} = Rep] ->
+%% do_reply_timeout(ConnHandle, TransId, Timer, Rep);
+
+%% _ ->
+%% ignore
+
+%% end.
+
+
+%% This clause is to catch the timers started prior to the code-upgrade
+pending_timeout(#conn_data{conn_handle = CH}, TransId, Timer) ->
+ ?report_trace(CH, "pending timeout(1)", [Timer, TransId]),
+ pending_timeout(CH, TransId, Timer);
+
+pending_timeout(ConnHandle, TransId, Timer) ->
+ ?report_trace(ConnHandle, "pending timeout(2)", [Timer, TransId]),
+ case megaco_config:lookup_local_conn(ConnHandle) of
+ [CD] when (CD#conn_data.cancel == true) ->
+ cancel_in_progress_ignore;
+ [CD] ->
+ Serial = TransId#trans_id.serial,
+ handle_pending_timeout(CD#conn_data{serial = Serial},
+ TransId, Timer);
+ [] ->
+ no_such_connection_ignore
+ end.
+
+handle_pending_timeout(CD, TransId, Timer) ->
+ ?report_trace(CD, "handle pending timeout", []),
+ case megaco_monitor:lookup_reply(TransId) of
+ [#reply{state = State,
+ handler = Pid} = Rep] when (State =:= prepare) orelse
+ (State =:= eval_request) ->
+
+ #conn_data{sent_pending_limit = Limit,
+ conn_handle = ConnHandle} = CD,
+
+ %% ------------------------------------------
+ %%
+ %% Check pending limit
+ %%
+ %% ------------------------------------------
+
+ case check_and_maybe_incr_pending_limit(Limit, sent, TransId) of
+ ok ->
+
+ %% ---------------------------------------------
+ %%
+ %% 1) Send pending message
+ %% 2) Possibly restart the pending timer
+ %%
+ %% ---------------------------------------------
+
+ send_pending(CD),
+ case Timer of
+ timeout ->
+ %% We are done
+ incNumTimerRecovery(ConnHandle),
+ timeout1;
+ {_, timeout} ->
+ %% We are done
+ incNumTimerRecovery(ConnHandle),
+ timeout2;
+ _ ->
+ {WaitFor, Timer2} = megaco_timer:restart(Timer),
+ M = ?MODULE,
+ F = pending_timeout,
+ A = [ConnHandle, TransId, Timer2],
+ PendingRef =
+ megaco_monitor:apply_after(M, F, A, WaitFor),
+ %% Timing problem?
+ megaco_monitor:update_reply_field(TransId,
+ #reply.pending_timer_ref,
+ PendingRef),
+ {restarted, WaitFor, Timer2}
+ end;
+
+
+ error ->
+
+ %% ------------------------------------------
+ %%
+ %% 1) Send 506 error message to other side
+ %% 2) Notify user
+ %% 3) Set reply data in aborted state
+ %%
+ %% -------------------------------------------
+
+ send_pending_limit_error(CD),
+ handle_request_abort_callback(CD, TransId, Pid),
+ %% Timing problem?
+ Rep2 = Rep#reply{state = aborted},
+ cancel_reply(CD, Rep2, aborted),
+ pending_limit_error;
+
+
+ aborted ->
+
+ %% ------------------------------------------
+ %%
+ %% Pending limit already passed
+ %%
+ %% -------------------------------------------
+ Rep2 = Rep#reply{state = aborted},
+ cancel_reply(CD, Rep2, aborted),
+ pending_limit_aborted
+
+ end;
+ [] ->
+ reply_not_found; % Trace ??
+
+ [#reply{state = waiting_for_ack}] ->
+ %% The reply has already been sent
+ %% No need for any pending trans reply
+ reply_has_been_sent;
+
+ [#reply{state = aborted} = Rep] ->
+ %% glitch, but cleanup just the same
+ cancel_reply(CD, Rep, aborted),
+ reply_aborted_state
+
+ end.
+
+
+segment_timeout(ConnHandle, TransId, timeout = Timer) ->
+ ?report_trace(ConnHandle, "segment timeout", [TransId, Timer]),
+ incNumTimerRecovery(ConnHandle),
+ case megaco_monitor:lookup_request(TransId) of
+ [] ->
+ timeout_not_found_ignore;
+
+ [#request{seg_recv = Segs} = Req] ->
+ ConnData =
+ case megaco_config:lookup_local_conn(ConnHandle) of
+ [ConnData0] ->
+ ConnData0;
+ [] ->
+ fake_conn_data(ConnHandle)
+ end,
+ Last = lists:last(lists:sort(Segs)),
+ All = lists:seq(1,Last),
+ case All -- Segs of
+ [] ->
+ %% The last segment has just arrived, ignore
+ ok;
+ Missing ->
+ %% Send the error message
+ Code = ?megaco_segments_not_received,
+ Reason = missing_to_str(Missing),
+ send_message_error(ConnData, Code, Reason),
+
+ %% Report to the user
+ UserMod = Req#request.user_mod,
+ UserArgs = Req#request.user_args,
+ Action = Req#request.reply_action,
+ UserData = Req#request.reply_data,
+ UserReply = {error, {segment_timeout, Missing}},
+ ConnData2 = ConnData#conn_data{user_mod = UserMod,
+ user_args = UserArgs,
+ reply_action = Action,
+ reply_data = UserData},
+ return_reply(ConnData2, TransId, UserReply)
+ end
+ end;
+
+segment_timeout(ConnHandle, TransId, Timer) ->
+ ?report_trace(ConnHandle, "segment timeout", [TransId, Timer]),
+ case megaco_monitor:lookup_request_field(TransId, #request.trans_id) of
+ {ok, _} ->
+ {WaitFor, Timer2} = megaco_timer:restart(Timer),
+ M = ?MODULE,
+ F = segment_timeout,
+ A = [ConnHandle, TransId, Timer2],
+ Ref = megaco_monitor:apply_after(M, F, A, WaitFor),
+ %% Timing problem?
+ megaco_monitor:update_request_field(TransId,
+ #request.seg_timer_ref,
+ Ref),
+ {restarted, WaitFor, Timer2};
+ _ ->
+ not_found_ignore
+ end.
+
+%% segment_reply_timeout() ->
+%% ok.
+
+missing_to_str(Missing) ->
+ lists:flatten(missing_to_str2(Missing)).
+
+missing_to_str2([X]) ->
+ [integer_to_list(X)];
+missing_to_str2([H|T]) ->
+ [integer_to_list(H) , "," | missing_to_str2(T)].
+
+return_unexpected_trans_reply(ConnData, TransId,
+ {actionReplies, _} = UserReply, Extra) ->
+ Trans = make_transaction_reply(ConnData, TransId, UserReply),
+ return_unexpected_trans(ConnData, Trans, Extra);
+return_unexpected_trans_reply(ConnData, TransId,
+ {transactionError, _} = UserReply, Extra) ->
+ Trans = make_transaction_reply(ConnData, TransId, UserReply),
+ return_unexpected_trans(ConnData, Trans, Extra);
+return_unexpected_trans_reply(CD, TransId, {error, Reason}, Extra) ->
+ ?report_important(CD, "unexpected trans reply with error",
+ [TransId, Reason, Extra]),
+ ok;
+return_unexpected_trans_reply(CD, TransId, Crap, Extra) ->
+ ?report_important(CD, "unexpected trans reply with crap",
+ [TransId, Crap, Extra]),
+ ok.
+
+return_unexpected_trans(ConnData, Trans) ->
+ Extra = ?default_user_callback_extra,
+ return_unexpected_trans(ConnData, Trans, Extra).
+
+return_unexpected_trans(ConnData, Trans0, Extra) ->
+ UserMod = ConnData#conn_data.user_mod,
+ UserArgs = ConnData#conn_data.user_args,
+ ConnHandle = ConnData#conn_data.conn_handle,
+ Version = ConnData#conn_data.protocol_version,
+ Trans = transform_transaction_reply_enc(Version, Trans0),
+ Args =
+ case Extra of
+ ?default_user_callback_extra ->
+ [ConnHandle, Version, Trans | UserArgs];
+ _ ->
+ [ConnHandle, Version, Trans, Extra | UserArgs]
+ end,
+ Res = (catch apply(UserMod, handle_unexpected_trans, Args)),
+ ?report_debug(ConnData, "return: unexpected trans",
+ [Trans, {return, Res}]),
+ case Res of
+ ok ->
+ ok;
+ _ ->
+ warning_msg("unexpected transaction callback failed: ~w", [Res]),
+ ok
+ end,
+ Res.
+
+
+%%-----------------------------------------------------------------
+
+to_remote_trans_id(#conn_data{conn_handle = CH, serial = Serial}) ->
+ Mid = CH#megaco_conn_handle.remote_mid,
+ #trans_id{mid = Mid, serial = Serial}.
+
+to_local_trans_id(#conn_data{conn_handle = CH, serial = Serial}) ->
+ Mid = CH#megaco_conn_handle.local_mid,
+ #trans_id{mid = Mid, serial = Serial}.
+
+to_local_trans_id(#conn_data{conn_handle = CH}, [S|_] = Serials)
+ when is_integer(S) ->
+ Mid = CH#megaco_conn_handle.local_mid,
+ [#trans_id{mid = Mid, serial = Serial} || Serial <- Serials];
+to_local_trans_id(#conn_data{conn_handle = CH},
+ [{transactionRequest, TR}|_] = TRs)
+ when is_record(TR, 'TransactionRequest') ->
+ Mid = CH#megaco_conn_handle.local_mid,
+ [#trans_id{mid = Mid, serial = Serial} ||
+ {transactionRequest,
+ #'TransactionRequest'{transactionId = Serial}} <- TRs];
+
+to_local_trans_id(#megaco_conn_handle{local_mid = Mid}, Serial)
+ when is_integer(Serial) ->
+ #trans_id{mid = Mid, serial = Serial};
+to_local_trans_id(#conn_data{conn_handle = CH}, Serial)
+ when is_integer(Serial) ->
+ Mid = CH#megaco_conn_handle.local_mid,
+ #trans_id{mid = Mid, serial = Serial}.
+
+
+%%-----------------------------------------------------------------
+
+transform_transaction_reply_dec({'TransactionReply',
+ TransId, IAR, TransRes}) ->
+ #megaco_transaction_reply{transactionId = TransId,
+ immAckRequired = IAR,
+ transactionResult = TransRes};
+transform_transaction_reply_dec({'TransactionReply',
+ TransId, IAR, TransRes,
+ SegNo, SegComplete}) ->
+ #megaco_transaction_reply{transactionId = TransId,
+ immAckRequired = IAR,
+ transactionResult = TransRes,
+ segmentNumber = SegNo,
+ segmentationComplete = SegComplete}.
+
+transform_transaction_reply_enc(
+ 3,
+ #megaco_transaction_reply{transactionId = TransId,
+ immAckRequired = IAR,
+ transactionResult = TransRes,
+ segmentNumber = SegNo,
+ segmentationComplete = SegComplete}) ->
+ {'TransactionReply', TransId, IAR, TransRes, SegNo, SegComplete};
+transform_transaction_reply_enc(
+ Version,
+ #megaco_transaction_reply{transactionId = TransId,
+ immAckRequired = IAR,
+ transactionResult = TransRes})
+ when (Version < 3) ->
+ {'TransactionReply', TransId, IAR, TransRes};
+transform_transaction_reply_enc(_, TR) ->
+ TR.
+
+make_transaction_reply(#conn_data{protocol_version = Version},
+ TransId, TransRes) ->
+ make_transaction_reply(Version, TransId, asn1_NOVALUE, TransRes).
+
+%% make_transaction_reply(#conn_data{protocol_version = Version},
+%% TransId, IAR, TransRes) ->
+%% make_transaction_reply(Version, TransId, IAR, TransRes);
+
+make_transaction_reply(3, TransId, IAR, TransRes) ->
+ {'TransactionReply', TransId, IAR, TransRes, asn1_NOVALUE, asn1_NOVALUE};
+make_transaction_reply(_, TransId, IAR, TransRes) ->
+ {'TransactionReply', TransId, IAR, TransRes}.
+
+
+%%-----------------------------------------------------------------
+
+%%-----------------------------------------------------------------
+warning_msg(F, A) ->
+ ?megaco_warning(F, A).
+
+error_msg(F, A) ->
+ ?megaco_error(F, A).
+
+
+%%-----------------------------------------------------------------
+
+%% d(F) ->
+%% d(F,[]).
+%%
+%% d(F,A) ->
+%% d(true,F,A).
+%% %% d(get(dbg),F,A).
+%%
+%% d(true,F,A) ->
+%% io:format("*** [~s] ~p:~p ***"
+%% "~n " ++ F ++ "~n",
+%% [format_timestamp(now()), self(),?MODULE|A]);
+%% d(_, _, _) ->
+%% ok.
+%%
+%% 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).
+
+%% Time in milli seconds
+t() ->
+ {A,B,C} = erlang:now(),
+ A*1000000000+B*1000+(C div 1000).
+
+
+%%-----------------------------------------------------------------
+%% Func: incNumErrors/0, incNumErrors/1, incNumTimerRecovery/1
+%% Description: SNMP counter increment functions
+%%-----------------------------------------------------------------
+incNumErrors() ->
+ incNum(medGwyGatewayNumErrors).
+
+incNumErrors(CH) ->
+ incNum({CH, medGwyGatewayNumErrors}).
+
+incNumTimerRecovery(CH) ->
+ incNum({CH, medGwyGatewayNumTimerRecovery}).
+
+incNum(Cnt) ->
+ case (catch ets:update_counter(megaco_stats, Cnt, 1)) of
+ {'EXIT', {badarg, _Reason}} ->
+ ets:insert(megaco_stats, {Cnt, 1});
+ Old ->
+ Old
+ end.
+
diff --git a/lib/megaco/src/engine/megaco_messenger_misc.erl b/lib/megaco/src/engine/megaco_messenger_misc.erl
new file mode 100644
index 0000000000..3c340a8484
--- /dev/null
+++ b/lib/megaco/src/engine/megaco_messenger_misc.erl
@@ -0,0 +1,409 @@
+%%
+%% %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: Misc functions used both from the megaco_messenger module
+%% and the megaco_ack_sender module.
+%%
+%%----------------------------------------------------------------------
+
+-module(megaco_messenger_misc).
+
+%% Application internal export
+-export([encode_body/3,
+ encode_trans_request/2,
+ encode_trans_reply/2,
+ encode_actions/3,
+ send_body/3,
+ send_message/3,
+
+ transform_transaction_reply/2
+ ]).
+
+%% Test functions
+-export([compose_message/3, encode_message/2]).
+
+
+-include_lib("megaco/include/megaco.hrl").
+-include("megaco_message_internal.hrl").
+-include_lib("megaco/src/app/megaco_internal.hrl").
+
+-define(MSG_HDR_SZ, 128). % This is just a guess...
+
+-ifdef(MEGACO_TEST_CODE).
+-define(SIM(Other,Where),
+ fun(Afun,Bfun) ->
+ Kfun = {?MODULE,Bfun},
+ case (catch ets:lookup(megaco_test_data, Kfun)) of
+ [{Kfun,Cfun}] ->
+ Cfun(Afun);
+ _ ->
+ Afun
+ end
+ end(Other,Where)).
+-define(TC_AWAIT_SEND_EVENT(SendFunction),
+ case megaco_tc_controller:lookup(send_function) of
+ {value, {Tag, Pid}} when is_pid(Pid) ->
+ Pid ! {Tag, self(), SendFuncion},
+ receive
+ {Tag, Pid} ->
+ ok
+ end;
+ _ ->
+ ok
+ end).
+-else.
+-define(SIM(Other,Where),Other).
+-define(TC_AWAIT_SEND_EVENT(_),ok).
+-endif.
+
+
+%%----------------------------------------------------------------------
+%% Encode the transaction request
+%%----------------------------------------------------------------------
+
+encode_trans_request(CD, TR) when is_record(TR, 'TransactionRequest') ->
+ ?report_debug(CD, "encode trans request", [TR]),
+ Trans = {transactionRequest, TR},
+ encode_transaction(CD, Trans).
+
+encode_trans_reply(#conn_data{segment_send = SegSend,
+ max_pdu_size = Max,
+ protocol_version = V} = CD, Reply)
+ when (SegSend == infinity) or (is_integer(SegSend) and (SegSend > 0)) and
+ is_integer(V) and (V >= 3) and
+ is_integer(Max) and (Max >= ?MSG_HDR_SZ) ->
+ (catch encode_segmented_trans_reply(CD, Reply));
+encode_trans_reply(CD, TR) when is_record(TR, megaco_transaction_reply) ->
+ ?report_debug(CD, "encode trans reply", [TR]),
+ Trans = {transactionReply, transform_transaction_reply(CD, TR)},
+ encode_transaction(CD, Trans);
+encode_trans_reply(CD, TR) when is_tuple(TR) and
+ (element(1, TR) == 'TransactionReply') ->
+ ?report_debug(CD, "encode trans reply", [TR]),
+ Trans = {transactionReply, TR},
+ encode_transaction(CD, Trans).
+
+
+encode_segmented_trans_reply(#conn_data{max_pdu_size = Max} = CD, Rep) ->
+ #megaco_transaction_reply{transactionResult = Res1} = Rep,
+ case Res1 of
+ {actionReplies, AR} when is_list(AR) andalso (length(AR) >= 1) ->
+ case encode_action_replies(CD, AR) of
+ {Size, EncodedARs} when Size =< (Max - ?MSG_HDR_SZ) ->
+ ?report_debug(CD, "action replies encoded size ok",
+ [Size, Max]),
+ %% No need to segment message: within size limit
+ Res2 = {actionReplies, EncodedARs},
+ TR = Rep#megaco_transaction_reply{transactionResult = Res2},
+ TR2 = transform_transaction_reply(CD, TR),
+ Trans = {transactionReply, TR2},
+ encode_transaction(CD, Trans);
+
+ {Size, EncodecARs} ->
+ ?report_debug(CD,
+ "action replies encoded size to large - "
+ "segment",
+ [Size, Max]),
+ %% Over size limit, so go segment the message
+ encode_segments(CD, Rep, EncodecARs)
+ end;
+ _ ->
+ TR = transform_transaction_reply(CD, Rep),
+ Trans = {transactionReply, TR},
+ encode_transaction(CD, Trans)
+ end.
+
+encode_segments(CD, Reply, EncodecARs) ->
+ encode_segments(CD, Reply, EncodecARs, 1, []).
+
+encode_segments(CD, Reply, [EncodedAR], SN, EncodedSegs) ->
+ Bin = encode_segment(CD, Reply, EncodedAR, SN, 'NULL'),
+ {ok, lists:reverse([{SN, Bin}|EncodedSegs])};
+encode_segments(CD, Reply, [EncodedAR|EncodedARs], SN, EncodedSegs) ->
+ Bin = encode_segment(CD, Reply, EncodedAR, SN, asn1_NOVALUE),
+ encode_segments(CD, Reply, EncodedARs, SN + 1, [{SN, Bin}|EncodedSegs]).
+
+encode_segment(CD, Reply, EncodedAR, SN, SC) ->
+ Res = {actionReplies, [EncodedAR]},
+ TR0 = Reply#megaco_transaction_reply{transactionResult = Res,
+ segmentNumber = SN,
+ segmentationComplete = SC},
+ TR = transform_transaction_reply(CD, TR0),
+ Trans = {transactionReply, TR},
+ case encode_transaction(CD, Trans) of
+ {ok, Bin} ->
+ Bin;
+ Error ->
+ throw(Error)
+ end.
+
+
+encode_transaction(#conn_data{protocol_version = V,
+ encoding_mod = EM,
+ encoding_config = EC} = CD, Trans) ->
+ case (catch EM:encode_transaction(EC, V, Trans)) of
+ {ok, Bin} ->
+ ?SIM({ok, Bin}, encode_trans);
+ {'EXIT', {undef, _}} ->
+ {error, not_implemented};
+ {error, not_implemented} = Error1 ->
+ Error1;
+ {error, Reason} ->
+ incNumErrors(CD#conn_data.conn_handle),
+ {error, {EM, encode_transaction, [EC, V, Trans], Reason}};
+ Error2 ->
+ incNumErrors(CD#conn_data.conn_handle),
+ {error, {EM, encode_transaction, [EC, V, Trans], Error2}}
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Encode the action request's
+%%----------------------------------------------------------------------
+
+encode_actions(#conn_data{protocol_version = V} = CD, TraceLabel, ARs) ->
+ ?report_debug(CD, TraceLabel, [ARs]),
+
+ %% Encode the actions
+ EM = CD#conn_data.encoding_mod,
+ EC = CD#conn_data.encoding_config,
+ case (catch EM:encode_action_requests(EC, V, ARs)) of
+ {ok, Bin} when is_binary(Bin) ->
+ ?SIM({ok, Bin}, encode_actions);
+ {'EXIT', {undef, _}} ->
+ incNumErrors(CD#conn_data.conn_handle),
+ Reason = not_implemented,
+ {error, {EM, encode_action_requests, [EC, ARs], Reason}};
+ {error, Reason} ->
+ incNumErrors(CD#conn_data.conn_handle),
+ {error, {EM, encode_action_requests, [EC, ARs], Reason}};
+ Error ->
+ incNumErrors(CD#conn_data.conn_handle),
+ {error, {EM, encode_action_requests, [EC, ARs], Error}}
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Encode the action reply's
+%%----------------------------------------------------------------------
+
+encode_action_replies(CD, AR) ->
+ encode_action_replies(CD, AR, 0, []).
+
+encode_action_replies(_, [], Size, Acc) ->
+ {Size, lists:reverse(Acc)};
+encode_action_replies(#conn_data{protocol_version = V,
+ encoding_mod = Mod,
+ encoding_config = Conf} = CD,
+ [AR|ARs], Size, Acc) ->
+ case (catch Mod:encode_action_reply(Conf, V, AR)) of
+ {ok, Bin} when is_binary(Bin) ->
+ encode_action_replies(CD, ARs, Size + size(Bin), [Bin|Acc]);
+ {'EXIT', {undef, _}} ->
+ throw({error, not_implemented});
+ {error, not_implemented} = Error1 ->
+ throw(Error1);
+ {error, Reason} ->
+ incNumErrors(CD#conn_data.conn_handle),
+ throw({error, {Mod, encode_action_reply, [Conf, AR], Reason}});
+ Error ->
+ incNumErrors(CD#conn_data.conn_handle),
+ throw({error, {Mod, encode_action_reply, [Conf, AR], Error}})
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Encode the message body
+%%----------------------------------------------------------------------
+
+encode_body(#conn_data{protocol_version = V} = ConnData,
+ TraceLabel, Body) ->
+ %% Create the message envelope
+ MegaMsg = compose_message(ConnData, V, Body),
+
+ ?report_debug(ConnData, TraceLabel, [MegaMsg]),
+
+ %% Encode the message
+ EM = ConnData#conn_data.encoding_mod,
+ EC = ConnData#conn_data.encoding_config,
+ case (catch EM:encode_message(EC, V, MegaMsg)) of
+ {ok, Bin} when is_binary(Bin) ->
+ ?SIM({ok, Bin}, encode_body);
+ {error, Reason} ->
+ incNumErrors(ConnData#conn_data.conn_handle),
+ {error, {EM, [EC, MegaMsg], Reason}};
+ Error ->
+ incNumErrors(ConnData#conn_data.conn_handle),
+ {error, {EM, [EC, MegaMsg], Error}}
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Compose and encode a message
+%%----------------------------------------------------------------------
+compose_message(#conn_data{conn_handle = CH,
+ auth_data = MsgAuth}, V, Body) ->
+ LocalMid = CH#megaco_conn_handle.local_mid,
+ Msg = #'Message'{version = V,
+ mId = LocalMid,
+ messageBody = Body},
+ MegaMsg = #'MegacoMessage'{authHeader = MsgAuth, % BUGBUG: Compute?
+ mess = Msg},
+ MegaMsg.
+
+
+encode_message(#conn_data{protocol_version = Version,
+ encoding_mod = EncodingMod,
+ encoding_config = EncodingConfig}, MegaMsg) ->
+ (catch EncodingMod:encode_message(EncodingConfig, Version, MegaMsg)).
+
+
+%%----------------------------------------------------------------------
+%% Send the message body
+%%----------------------------------------------------------------------
+
+send_body(ConnData, TraceLabel, Body) ->
+ case encode_body(ConnData, TraceLabel, Body) of
+ {ok, Bin} ->
+ send_message(ConnData, false, Bin);
+ {error, Reason} ->
+ {error, Reason}
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Send the (encoded) message
+%%----------------------------------------------------------------------
+
+send_message(#conn_data{resend_indication = flag} = ConnData,
+ Resend, Bin) ->
+ do_send_message(ConnData, send_message, Bin, [Resend]);
+
+send_message(#conn_data{resend_indication = true} = ConnData,
+ true, Bin) ->
+ do_send_message(ConnData, resend_message, Bin, []);
+
+send_message(ConnData, _Resend, Bin) ->
+ do_send_message(ConnData, send_message, Bin, []).
+
+do_send_message(ConnData, SendFunc, Bin, Extra) ->
+ %% Send the message
+ #conn_data{send_mod = SendMod,
+ send_handle = SendHandle} = ConnData,
+
+ ?TC_AWAIT_SEND_EVENT(SendFunc),
+
+ ?report_trace(ConnData, "send bytes", [{bytes, Bin},
+ {send_func, SendFunc}]),
+
+ Args = [SendHandle, Bin | Extra],
+ case (catch apply(SendMod, SendFunc, Args)) of
+ ok ->
+ ?SIM({ok, Bin}, send_message);
+ {cancel, Reason} ->
+ ?report_trace(ConnData, "<CANCEL> send_message callback",
+ [{bytes, Bin}, {cancel, Reason}]),
+ {error, {send_message_cancelled, Reason}};
+ {error, Reason} ->
+ incNumErrors(ConnData#conn_data.conn_handle),
+ ?report_important(ConnData, "<ERROR> send_message callback",
+ [{bytes, Bin}, {error, Reason}]),
+ error_msg("failed (error) sending message [using ~w] (~p):"
+ "~n~w", [SendFunc, SendHandle, Reason]),
+ {error, {send_message_failed, Reason}};
+ {'EXIT', Reason} = Error ->
+ incNumErrors(ConnData#conn_data.conn_handle),
+ ?report_important(ConnData, "<ERROR> send_message callback",
+ [{bytes, Bin}, {exit, Reason}]),
+ error_msg("failed (exit) sending message [using ~w] (~p):"
+ "~n~w", [SendFunc, SendHandle, Reason]),
+ {error, {send_message_failed, Error}};
+ Reason ->
+ incNumErrors(ConnData#conn_data.conn_handle),
+ ?report_important(ConnData, "<ERROR> send_message callback",
+ [{bytes, Bin}, {error, Reason}]),
+ error_msg("failed sending message [using ~w] on (~p): "
+ "~n~w", [SendFunc, SendHandle, Reason]),
+ {error, {send_message_failed, Reason}}
+ end.
+
+
+%%%-----------------------------------------------------------------
+%%% Misc internal util functions
+%%%-----------------------------------------------------------------
+
+transform_transaction_reply(#conn_data{protocol_version = V}, TR)
+ when is_integer(V) and (V >= 3) ->
+ #megaco_transaction_reply{transactionId = TransId,
+ immAckRequired = IAR,
+ transactionResult = TransRes,
+ segmentNumber = SegNo,
+ segmentationComplete = SegComplete} = TR,
+ {'TransactionReply', TransId, IAR, TransRes, SegNo, SegComplete};
+transform_transaction_reply(_, TR) ->
+ #megaco_transaction_reply{transactionId = TransId,
+ immAckRequired = IAR,
+ transactionResult = TransRes} = TR,
+ {'TransactionReply', TransId, IAR, TransRes}.
+
+
+%%-----------------------------------------------------------------
+%% Func: error_msg/2
+%% Description: Send an error message
+%%-----------------------------------------------------------------
+
+error_msg(F, A) ->
+ ?megaco_error(F, A).
+
+
+%%-----------------------------------------------------------------
+%% Func: incNumErrors/0, incNumErrors/1, incNumTimerRecovery/1
+%% Description: SNMP counter increment functions
+%%-----------------------------------------------------------------
+
+incNumErrors(CH) ->
+ incNum({CH, medGwyGatewayNumErrors}).
+
+incNum(Cnt) ->
+ case (catch ets:update_counter(megaco_stats, Cnt, 1)) of
+ {'EXIT', {badarg, _R}} ->
+ ets:insert(megaco_stats, {Cnt, 1});
+ Old ->
+ Old
+ end.
+
+%% p(F, A) ->
+%% print(now(), F, A).
+
+%% print(Ts, F, A) ->
+%% io:format("*** [~s] ~p ***"
+%% "~n " ++ F ++ "~n",
+%% [format_timestamp(Ts), self() | A]).
+
+%% format_timestamp(Now) ->
+%% {_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/engine/megaco_misc_sup.erl b/lib/megaco/src/engine/megaco_misc_sup.erl
new file mode 100644
index 0000000000..07fe96871d
--- /dev/null
+++ b/lib/megaco/src/engine/megaco_misc_sup.erl
@@ -0,0 +1,77 @@
+%%
+%% %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%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: The top supervisor for the Megaco/H.248 application
+%%----------------------------------------------------------------------
+
+-module(megaco_misc_sup).
+
+-behaviour(supervisor).
+
+%% public
+-export([start/0, start/2, stop/1, init/1]).
+-export([start_permanent_worker/4]).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% application and supervisor callback functions
+
+start(normal, Args) ->
+ SupName = {local,?MODULE},
+ case supervisor:start_link(SupName, ?MODULE, [Args]) of
+ {ok, Pid} ->
+ {ok, Pid, {normal, Args}};
+ Error ->
+ Error
+ end;
+start(_, _) ->
+ {error, badarg}.
+
+start() ->
+ SupName = {local,?MODULE},
+ supervisor:start_link(SupName, ?MODULE, []).
+
+stop(_StartArgs) ->
+ ok.
+
+init([]) -> % Supervisor
+ init();
+init(BadArg) ->
+ {error, {badarg, BadArg}}.
+
+init() ->
+ Flags = {one_for_one, 0, 1},
+ Workers = [],
+ {ok, {Flags, Workers}}.
+
+
+%%----------------------------------------------------------------------
+%% Function: start_permanent_worker/3
+%% Description: Starts a permanent worker (child) process
+%%----------------------------------------------------------------------
+
+start_permanent_worker(M, F, A, Modules) ->
+ Spec = {M, {M,F,A}, permanent, timer:seconds(1), worker, [M] ++ Modules},
+ supervisor:start_child(?MODULE, Spec).
+
+
+
+
diff --git a/lib/megaco/src/engine/megaco_monitor.erl b/lib/megaco/src/engine/megaco_monitor.erl
new file mode 100644
index 0000000000..f95a20cf58
--- /dev/null
+++ b/lib/megaco/src/engine/megaco_monitor.erl
@@ -0,0 +1,365 @@
+%%
+%% %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: Monitor connections and timers
+%%----------------------------------------------------------------------
+
+-module(megaco_monitor).
+
+-behaviour(gen_server).
+
+
+%%-----------------------------------------------------------------
+%% Include files
+%%-----------------------------------------------------------------
+
+-include_lib("megaco/src/app/megaco_internal.hrl").
+
+
+%% Application internal exports
+-export([
+ start_link/0,
+ stop/0,
+
+ apply_after/4,
+ apply_after/5,
+ cancel_apply_after/1,
+
+ lookup_request/1,
+ lookup_request_field/2,
+ match_requests/1,
+ which_requests/1,
+ insert_request/1,
+ update_request_field/3, update_request_fields/2,
+ delete_request/1,
+
+ lookup_reply/1,
+ lookup_reply_field/2,
+ match_replies/1,
+ which_replies/1,
+ insert_reply/1, insert_reply_new/1,
+ update_reply_field/3, update_reply_fields/2,
+ delete_reply/1,
+
+ apply_at_exit/4,
+ cancel_apply_at_exit/1
+ ]).
+
+%% gen_server callbacks
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
+ terminate/2, code_change/3]).
+
+-define(SERVER, ?MODULE).
+-record(state, {parent_pid}).
+-record(apply_at_exit, {ref, pid, module, function, arguments}).
+
+
+
+%%%----------------------------------------------------------------------
+%%% API
+%%%----------------------------------------------------------------------
+start_link() ->
+ ?d("start -> entry", []),
+ gen_server:start_link({local, ?SERVER}, ?MODULE, [self()], []).
+
+stop() ->
+ call(stop).
+
+lookup_request(Key) ->
+ ets:lookup(megaco_requests, Key).
+
+lookup_request_field(Key, Field) ->
+ try
+ begin
+ {ok, ets:lookup_element(megaco_requests, Key, Field)}
+ end
+ catch
+ error:badarg ->
+ {error, not_found}
+ end.
+
+match_requests(Pat) ->
+ ets:match_object(megaco_requests, Pat).
+
+which_requests(Pat) ->
+ Spec = [{Pat, [], ['$$']}],
+ ets:select(megaco_requests, Spec).
+
+insert_request(Rec) ->
+ ets:insert(megaco_requests, Rec).
+
+update_request_field(Key, Field, NewValue) ->
+ ets:update_element(megaco_requests, Key, {Field, NewValue}).
+
+update_request_fields(Key, NewFields) when is_list(NewFields) ->
+ ets:update_element(megaco_requests, Key, NewFields).
+
+delete_request(Key) ->
+ ets:delete(megaco_requests, Key).
+
+lookup_reply(Key) ->
+ ets:lookup(megaco_replies, Key).
+
+lookup_reply_field(Key, Field) ->
+ try
+ begin
+ {ok, ets:lookup_element(megaco_replies, Key, Field)}
+ end
+ catch
+ error:badarg ->
+ {error, not_found}
+ end.
+
+match_replies(Pat) ->
+ ets:match_object(megaco_replies, Pat).
+
+which_replies(Pat) ->
+ Spec = [{Pat, [], ['$$']}],
+ ets:select(megaco_replies, Spec).
+
+insert_reply(Rec) ->
+ ets:insert(megaco_replies, Rec).
+
+insert_reply_new(Rec) ->
+ ets:insert_new(megaco_replies, Rec).
+
+update_reply_field(Key, Field, NewValue) ->
+ ets:update_element(megaco_replies, Key, {Field, NewValue}).
+
+update_reply_fields(Key, NewFields) when is_list(NewFields) ->
+ ets:update_element(megaco_replies, Key, NewFields).
+
+delete_reply(Key) ->
+ ets:delete(megaco_replies, Key).
+
+apply_after(M, F, A, Time) ->
+ apply_after(spawn_method, M, F, A, Time).
+
+apply_after(Method, M, F, A, Time)
+ when is_atom(M) andalso is_atom(F) andalso is_list(A) ->
+ if
+ Time =:= infinity ->
+ apply_after_infinity;
+ is_integer(Time) ->
+ Msg = {apply_after, Method, M, F, A},
+ Ref = erlang:send_after(Time, whereis(?SERVER), Msg),
+ {apply_after, Ref}
+ end.
+
+cancel_apply_after({apply_after, Ref}) ->
+ case erlang:cancel_timer(Ref) of
+ TimeLeft when is_integer(TimeLeft) ->
+ {ok, TimeLeft};
+ _ ->
+ {ok, 0}
+ end;
+cancel_apply_after(apply_after_infinity) ->
+ ok;
+cancel_apply_after(BadRef) ->
+ {error, {bad_ref, BadRef}}.
+
+%% Performs apply(M, F, [Reason | A]) when process Pid dies
+apply_at_exit(M, F, A, Pid)
+ when is_atom(M) andalso is_atom(F) andalso is_list(A) andalso is_pid(Pid) ->
+ Ref = call({apply_at_exit, M, F, A, Pid}),
+ {apply_at_exit, Ref}.
+
+cancel_apply_at_exit({apply_at_exit, Ref}) ->
+ cast({cancel_apply_at_exit, Ref});
+cancel_apply_at_exit(BadRef) ->
+ {error, {bad_ref, BadRef}}.
+
+call(Request) ->
+ gen_server:call(?SERVER, Request, infinity).
+
+cast(Msg) ->
+ ?SERVER ! Msg, ok.
+
+%%%----------------------------------------------------------------------
+%%% Callback functions from gen_server
+%%%----------------------------------------------------------------------
+
+%%----------------------------------------------------------------------
+%% Func: init/1
+%% Returns: {ok, State} |
+%% {ok, State, Timeout} |
+%% ignore |
+%% {stop, Reason}
+%%----------------------------------------------------------------------
+
+init([Parent]) ->
+ ?d("init -> entry", []),
+ process_flag(trap_exit, true),
+ ets:new(megaco_requests, [public, named_table, {keypos, 2}]),
+ ets:new(megaco_replies, [public, named_table, {keypos, 2}]),
+ ?d("init -> done", []),
+ {ok, #state{parent_pid = Parent}}.
+
+
+%%----------------------------------------------------------------------
+%% Func: handle_call/3
+%% Returns: {reply, Reply, State} |
+%% {reply, Reply, State, Timeout} |
+%% {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, Reply, State} | (terminate/2 is called)
+%% {stop, Reason, State} (terminate/2 is called)
+%%----------------------------------------------------------------------
+
+handle_call({apply_at_exit, M, F, A, Pid}, _From, S) ->
+ Ref = erlang:monitor(process, Pid),
+ AAE = #apply_at_exit{ref = Ref,
+ pid = Pid,
+ module = M,
+ function = F,
+ arguments = A},
+ put({?MODULE, Ref}, AAE),
+ Reply = Ref,
+ {reply, Reply, S};
+
+handle_call(stop, {Parent, _} = _From, #state{parent_pid = Parent} = S) ->
+ {stop, normal, ok, S};
+
+handle_call(Req, From, S) ->
+ warning_msg("received unexpected request from ~p: "
+ "~n~w",[From, Req]),
+ {reply, {error, {bad_request, Req}}, S}.
+
+
+%%----------------------------------------------------------------------
+%% Func: handle_cast/2
+%% Returns: {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, State} (terminate/2 is called)
+%%----------------------------------------------------------------------
+handle_cast(Msg, S) ->
+ warning_msg("received unexpected message: "
+ "~n~w", [Msg]),
+ {noreply, S}.
+
+%%----------------------------------------------------------------------
+%% Func: handle_info/2
+%% Returns: {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, State} (terminate/2 is called)
+%%----------------------------------------------------------------------
+
+handle_info({cancel_apply_at_exit, Ref}, S) ->
+ case erase({?MODULE, Ref}) of
+ undefined ->
+ %% Reply = {error, {already_cancelled, {apply_at_exit, Ref}}},
+ {noreply, S};
+ _AAE ->
+ erlang:demonitor(Ref),
+ {noreply, S}
+ end;
+
+handle_info({apply_after, Method, M, F, A}, S) ->
+ handle_apply(Method, M, F, A, apply_after),
+ {noreply, S};
+
+%% Handle the old format also...
+handle_info({apply_after, M, F, A}, S) ->
+ handle_apply(M, F, A, apply_after),
+ {noreply, S};
+
+handle_info({'DOWN', Ref, process, _Pid, Reason}, S) ->
+ case erase({?MODULE, Ref}) of
+ undefined ->
+ {noreply, S};
+ AAE ->
+ M = AAE#apply_at_exit.module,
+ F = AAE#apply_at_exit.function,
+ A = AAE#apply_at_exit.arguments,
+ handle_apply(M, F, [Reason | A], apply_at_exit),
+ {noreply, S}
+ end;
+
+handle_info({'EXIT', Pid, Reason}, S) when Pid == S#state.parent_pid ->
+ %% [megaco_messenger:disconnect(CH, {stopped, Reason})
+ %% || CH <- megaco:lookup_system_info(connections)],
+ {stop, Reason, S};
+
+handle_info(Info, S) ->
+ warning_msg("received unknown info: "
+ "~n~w", [Info]),
+ {noreply, S}.
+
+
+%%----------------------------------------------------------------------
+%% Func: terminate/2
+%% Purpose: Shutdown the server
+%% Returns: any (ignored by gen_server)
+%%----------------------------------------------------------------------
+terminate(_Reason, _State) ->
+ ok.
+
+%%----------------------------------------------------------------------
+%% Func: code_change/3
+%% Purpose: Convert process state when code is changed
+%% Returns: {ok, NewState}
+%%----------------------------------------------------------------------
+code_change(_Vsn, S, _Extra) ->
+ {ok, S}.
+
+
+%%%----------------------------------------------------------------------
+%%% Internal functions
+%%%----------------------------------------------------------------------
+
+handle_apply(M, F, A, _ErrorTag) ->
+ spawn(M, F, A).
+
+handle_apply(spawn_method, M, F, A, _ErrorTag) ->
+ spawn(M, F, A);
+handle_apply(_Method, M, F, A, _ErrorTag) ->
+ (catch apply(M, F, A)).
+
+
+warning_msg(F, A) ->
+ ?megaco_warning("Monitor server: " ++ F, A).
+
+
+% d(F) ->
+% d(F,[]).
+
+% d(F,A) ->
+% %% d(true,F,A).
+% d(get(dbg),F,A).
+
+% d(true,F,A) ->
+% io:format("*** [~s] ~p:~p ***"
+% "~n " ++ F ++ "~n",
+% [format_timestamp(now()), self(),?MODULE|A]);
+% d(_, _, _) ->
+% ok.
+
+% format_timestamp(Now) ->
+% {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/engine/megaco_sdp.erl b/lib/megaco/src/engine/megaco_sdp.erl
new file mode 100644
index 0000000000..90911fe24a
--- /dev/null
+++ b/lib/megaco/src/engine/megaco_sdp.erl
@@ -0,0 +1,1645 @@
+%%
+%% %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%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: RFC 4566
+%%----------------------------------------------------------------------
+
+-module(megaco_sdp).
+
+%%----------------------------------------------------------------------
+%% Include files
+%%----------------------------------------------------------------------
+
+-include_lib("megaco/include/megaco.hrl").
+-include_lib("megaco/src/app/megaco_internal.hrl").
+-include_lib("megaco/include/megaco_message_v1.hrl").
+-include_lib("megaco/include/megaco_sdp.hrl").
+
+
+%%----------------------------------------------------------------------
+%% External exports
+%%----------------------------------------------------------------------
+
+-export([
+ decode/1, encode/1,
+ get_sdp_record_from_PropertyGroup/2
+ ]).
+
+
+%%----------------------------------------------------------------------
+%% Internal exports
+%%----------------------------------------------------------------------
+
+
+%%----------------------------------------------------------------------
+%% Macros
+%%----------------------------------------------------------------------
+
+
+%%----------------------------------------------------------------------
+%% Records
+%%----------------------------------------------------------------------
+
+
+%%======================================================================
+%% External functions
+%%======================================================================
+
+%% ---------------------------------------------------------------------
+%% decode(PP) -> {ok, SDP} | {error, Reason}
+%%
+%% This function performs the following conversion:
+%% property_parm() -> sdp()
+%% property_group() -> sdp_property_group()
+%% property_groups() -> sdp_property_groups()
+%%
+%% ---------------------------------------------------------------------
+
+decode(SDP) ->
+ case (catch do_decode(SDP)) of
+ {ok, _} = OK ->
+ OK;
+ {error, _} = ERR ->
+ ERR;
+ {'EXIT', Reason} ->
+ {error, {exit, Reason}};
+ CRAP ->
+ {error, {crap, CRAP}}
+ end.
+
+do_decode(PP) when is_record(PP, 'PropertyParm') ->
+ decode_PropertyParm(PP);
+do_decode([PP|_] = PG) when is_record(PP, 'PropertyParm') ->
+ decode_PropertyGroup(PG);
+do_decode([H|_] = PGs) when is_list(H) ->
+ decode_PropertyGroups(PGs);
+do_decode(asn1_NOVALUE = V) ->
+ {ok, V};
+do_decode(Bad) ->
+ {error, {bad_sdp, Bad}}.
+
+
+%% ---------------------------------------------------------------------
+%% encode(SDPs) -> {ok, PP} | {error, Reason}
+%%
+%% This function performs the following conversion:
+%% sdp() -> property_parm()
+%% sdp_property_group() -> property_group()
+%% sdp_property_groups() -> property_groups()
+%%
+%% ---------------------------------------------------------------------
+
+encode(SDP) ->
+ case (catch do_encode(SDP)) of
+ {ok, _} = OK ->
+ OK;
+ {error, _} = ERR ->
+ ERR;
+ {'EXIT', Reason} ->
+ {error, {exit, Reason}};
+ CRAP ->
+ {error, {crap, CRAP}}
+ end.
+
+do_encode(SDP) when is_tuple(SDP) ->
+ {ok, encode_PropertyParm(SDP)};
+do_encode([SDP|_] = PG) when is_tuple(SDP) ->
+ encode_PropertyGroup(PG);
+do_encode([H|_] = PGs) when is_list(H) ->
+ encode_PropertyGroups(PGs);
+do_encode(asn1_NOVALUE = V) ->
+ {ok, V}.
+
+
+%%-----------------------------------------------------------------
+%% Generate sdp records from PropertyParm records
+%%-----------------------------------------------------------------
+
+decode_PropertyGroups(PGs) ->
+ decode_PropertyGroups(PGs, []).
+
+decode_PropertyGroups([], DecodedPGs) ->
+ {ok, lists:reverse(DecodedPGs)};
+
+decode_PropertyGroups([PG | PGs], DecodedPGs) ->
+ {ok, DecodedPG} = decode_PropertyGroup(PG),
+ decode_PropertyGroups(PGs, [DecodedPG | DecodedPGs]).
+
+
+decode_PropertyGroup(PG) ->
+ {ok, decode_PropertyGroup(PG, [])}.
+
+decode_PropertyGroup([], Acc) ->
+ lists:reverse(Acc);
+
+decode_PropertyGroup([PP | PG], Acc) ->
+ case (catch decode_PropertyParm(PP)) of
+ {ok, PP2} ->
+ decode_PropertyGroup(PG, [PP2 | Acc]);
+ {error, Reason} ->
+ decode_PropertyGroup(PG, [{PP, Reason} | Acc]);
+ Error ->
+ decode_PropertyGroup(PG, [{PP, Error} | Acc])
+ end.
+
+
+%% ===== Protocol Version =====
+%%
+decode_PropertyParm(#'PropertyParm'{name = "v",
+ value = [V],
+ extraInfo = asn1_NOVALUE}) ->
+ decode_pp_protocol_version(V);
+
+
+%% ===== Origin =====
+%%
+decode_PropertyParm(#'PropertyParm'{name = "o",
+ value = [V],
+ extraInfo = asn1_NOVALUE}) ->
+ decode_pp_origin(V);
+
+
+%% ===== Session Name =====
+%%
+decode_PropertyParm(#'PropertyParm'{name = "s",
+ value = [V],
+ extraInfo = asn1_NOVALUE}) ->
+ decode_pp_session_name(V);
+
+
+%% ===== Session and Media Information =====
+%%
+decode_PropertyParm(#'PropertyParm'{name = "i",
+ value = [V],
+ extraInfo = asn1_NOVALUE}) ->
+ decode_pp_session_media_id(V);
+
+
+%% ===== URI =====
+%%
+decode_PropertyParm(#'PropertyParm'{name = "u",
+ value = [V],
+ extraInfo = asn1_NOVALUE}) ->
+ decode_pp_uri(V);
+
+
+%% ===== Email Address and Phone Number =====
+%%
+decode_PropertyParm(#'PropertyParm'{name = "e",
+ value = [V],
+ extraInfo = asn1_NOVALUE}) ->
+ decode_pp_email(V);
+
+decode_PropertyParm(#'PropertyParm'{name = "p",
+ value = [V],
+ extraInfo = asn1_NOVALUE}) ->
+ decode_pp_phone(V);
+
+
+%% ===== Connection Data =====
+%%
+decode_PropertyParm(#'PropertyParm'{name = "c",
+ value = [V],
+ extraInfo = asn1_NOVALUE}) ->
+ decode_pp_connection_data(V);
+
+
+%% ===== Bandwidth =====
+%%
+decode_PropertyParm(#'PropertyParm'{name = "b",
+ value = [V],
+ extraInfo = asn1_NOVALUE}) ->
+ decode_pp_bandwidth(V);
+
+
+%% ===== Times, Repeat Times and Time Zones =====
+%%
+decode_PropertyParm(#'PropertyParm'{name = "t",
+ value = [V],
+ extraInfo = asn1_NOVALUE }) ->
+ decode_pp_times(V);
+decode_PropertyParm(#'PropertyParm'{name = "r",
+ value = [V],
+ extraInfo = asn1_NOVALUE}) ->
+ decode_pp_rtimes(V);
+decode_PropertyParm(#'PropertyParm'{name = "z",
+ value = [V],
+ extraInfo = asn1_NOVALUE}) ->
+ decode_pp_tzones(V);
+
+
+%% ===== Encryption Keys =====
+%%
+decode_PropertyParm(#'PropertyParm'{name = "k",
+ value = [V],
+ extraInfo = asn1_NOVALUE}) ->
+ decode_pp_encryption_keys(V);
+
+
+%% ===== Attributes =====
+%%
+decode_PropertyParm(#'PropertyParm'{name = "a",
+ value = [V],
+ extraInfo = asn1_NOVALUE}) ->
+ decode_pp_attribute(V);
+
+
+%% ===== Media Announcements =====
+%%
+decode_PropertyParm(#'PropertyParm'{name = "m",
+ value = [V],
+ extraInfo = asn1_NOVALUE}) ->
+ decode_pp_media_announcement(V);
+
+
+decode_PropertyParm(_PP) ->
+ ?d("decode_PropertyParm -> entry with"
+ "~n _PP: ~p", [_PP]),
+ {error, undefined_PropertyParm}.
+
+
+%%-----------------------------------------------------------------
+%% Generate PropertyParm records from sdp records
+%%-----------------------------------------------------------------
+
+encode_PropertyGroups(PGs) ->
+ encode_PropertyGroups(PGs, []).
+
+
+encode_PropertyGroups([], Acc) ->
+ {ok, lists:reverse(Acc)};
+encode_PropertyGroups([PG | PGs], Acc) ->
+ {ok, EncodedPG} = encode_PropertyGroup(PG),
+ encode_PropertyGroups(PGs, [EncodedPG | Acc]).
+
+
+encode_PropertyGroup(PG) ->
+ encode_PropertyGroup(PG, []).
+
+encode_PropertyGroup([], Acc) ->
+ {ok, lists:reverse(Acc)};
+encode_PropertyGroup([PP | PG], Acc) ->
+ EncodedPP = encode_PropertyParm(PP),
+ encode_PropertyGroup(PG, [EncodedPP | Acc]).
+
+
+%% ===== Protocol Version =====
+%%
+encode_PropertyParm(#megaco_sdp_v{version = Version}) ->
+ encode_pp_protocol_version(Version);
+
+
+%% ===== Origin =====
+%%
+encode_PropertyParm(#megaco_sdp_o{user_name = User,
+ session_id = SessionId,
+ version = Version,
+ network_type = Network,
+ address_type = AddrType,
+ address = Addr}) ->
+ encode_pp_origin(User, SessionId, Version, Network, AddrType, Addr);
+
+
+%% ===== Session Name =====
+%%
+encode_PropertyParm(#megaco_sdp_s{name = Name}) ->
+ encode_pp_session_name(Name);
+
+
+%% ===== Session and Media Information =====
+%%
+encode_PropertyParm(#megaco_sdp_i{session_descriptor = SD}) ->
+ encode_pp_session_media_id(SD);
+
+
+%% ===== URI =====
+%%
+encode_PropertyParm(#megaco_sdp_u{uri = URI}) ->
+ encode_pp_uri(URI);
+
+
+%% ===== Email Address and Phone Number =====
+%%
+encode_PropertyParm(#megaco_sdp_e{email = Email}) ->
+ encode_pp_email(Email);
+
+encode_PropertyParm(#megaco_sdp_p{phone_number = Num}) ->
+ encode_pp_phone(Num);
+
+
+%% ===== Connection Data =====
+%%
+encode_PropertyParm(#megaco_sdp_c{network_type = NetType,
+ address_type = AddressType,
+ connection_addr = ConnectionAddr}) ->
+ encode_pp_connection_data(NetType, AddressType, ConnectionAddr);
+
+
+%% ===== Bandwidth =====
+%%
+encode_PropertyParm(#megaco_sdp_b{bwtype = BwType,
+ bandwidth = Bandwidth}) ->
+ encode_pp_bandwidth(BwType, Bandwidth);
+
+
+%% ===== Times, Repeat Times and Time Zones =====
+%%
+encode_PropertyParm(#megaco_sdp_t{start = Start, stop = Stop}) ->
+ encode_pp_times(Start, Stop);
+
+encode_PropertyParm(#megaco_sdp_r{repeat_interval = Repeat,
+ active_duration = Duration,
+ list_of_offsets = ListOfOffsets}) ->
+ encode_pp_rtimes(Repeat, Duration, ListOfOffsets);
+
+encode_PropertyParm(#megaco_sdp_z{list_of_adjustments = LOA}) ->
+ encode_pp_tzones(LOA);
+
+
+%% ===== Encryption Keys =====
+%%
+encode_PropertyParm(#megaco_sdp_k{method = Method,
+ encryption_key = EncryptionKey}) ->
+ encode_pp_encryption_keys(Method, EncryptionKey);
+
+
+%% ===== Attributes =====
+%%
+encode_PropertyParm(#megaco_sdp_a_cat{category = Category}) ->
+ encode_pp_attribute_cat(Category);
+
+encode_PropertyParm(#megaco_sdp_a_keywds{keywords = Keywords}) ->
+ encode_pp_attribute_keywds(Keywords);
+
+encode_PropertyParm(#megaco_sdp_a_tool{name_and_version = NameAndVersion}) ->
+ encode_pp_attribute_tool(NameAndVersion);
+
+encode_PropertyParm(#megaco_sdp_a_ptime{packet_time = PacketTime}) ->
+ encode_pp_attribute_ptime(PacketTime);
+
+encode_PropertyParm(
+ #megaco_sdp_a_maxptime{maximum_packet_time = MaxPacketTime}) ->
+ encode_pp_attribute_maxptime(MaxPacketTime);
+
+encode_PropertyParm(#megaco_sdp_a_rtpmap{payload_type = Payload,
+ encoding_name = EncName,
+ clock_rate = ClockRate,
+ encoding_parms = EncPar}) ->
+ encode_pp_attribute_rtpmap(Payload, EncName, ClockRate, EncPar);
+
+encode_PropertyParm(#megaco_sdp_a_orient{orientation = Orientation}) ->
+ encode_pp_attribute_orient(Orientation);
+
+encode_PropertyParm(#megaco_sdp_a_type{conf_type = CType}) ->
+ encode_pp_attribute_type(CType);
+
+encode_PropertyParm(#megaco_sdp_a_charset{char_set = CharSet}) ->
+ encode_pp_attribute_charset(CharSet);
+
+encode_PropertyParm(#megaco_sdp_a_sdplang{tag = Tag}) ->
+ encode_pp_attribute_sdplang(Tag);
+
+encode_PropertyParm(#megaco_sdp_a_lang{tag = Tag}) ->
+ encode_pp_attribute_lang(Tag);
+
+encode_PropertyParm(#megaco_sdp_a_framerate{frame_rate = FrameRate}) ->
+ encode_pp_attribute_framerate(FrameRate);
+
+encode_PropertyParm(#megaco_sdp_a_quality{quality = Quality}) ->
+ encode_pp_attribute_quality(Quality);
+
+encode_PropertyParm(#megaco_sdp_a_fmtp{format = Fmt, param = Params}) ->
+ encode_pp_attribute_fmtp(Fmt, Params);
+
+encode_PropertyParm(#megaco_sdp_a{attribute = Attr, value = Value}) ->
+ encode_pp_attribute(Attr, Value);
+
+
+%% ===== Media Announcements =====
+%%
+encode_PropertyParm(#megaco_sdp_m{media = Media,
+ port = Port,
+ num_ports = NOP,
+ transport = Transport,
+ fmt_list = FMT}) ->
+ encode_pp_media_announcement(Media, Port, NOP, Transport, FMT);
+
+
+%% This is a "manually" encoded PropertyParm, leave it as is.
+%%
+encode_PropertyParm(PP) when is_record(PP, 'PropertyParm') ->
+ PP;
+
+
+%% Bad data
+encode_PropertyParm(SDP) ->
+ error({unknown_sdp, SDP}).
+
+
+%%-----------------------------------------------------------------
+%% Func: get_sdp_record_from_PropertGroup/2
+%% Description: Get all sdp records of a certain type from a
+%% property group
+%%-----------------------------------------------------------------
+
+get_sdp_record_from_PropertyGroup(Type, PG)
+ when is_atom(Type) and is_list(PG) ->
+ F = fun(R) -> not is_pg_record(Type, R) end,
+ lists:filter(F, PG).
+
+is_pg_record(v, R) when is_record(R, megaco_sdp_v) -> true;
+is_pg_record(c, R) when is_record(R, megaco_sdp_c) -> true;
+is_pg_record(m, R) when is_record(R, megaco_sdp_m) -> true;
+is_pg_record(o, R) when is_record(R, megaco_sdp_o) -> true;
+is_pg_record(a, R) when is_record(R, megaco_sdp_a) -> true;
+is_pg_record(a, R) when is_record(R, megaco_sdp_a_ptime) -> true;
+is_pg_record(a, R) when is_record(R, megaco_sdp_a_rtpmap) -> true;
+is_pg_record(b, R) when is_record(R, megaco_sdp_b) -> true;
+is_pg_record(t, R) when is_record(R, megaco_sdp_t) -> true;
+is_pg_record(r, R) when is_record(R, megaco_sdp_r) -> true;
+is_pg_record(z, R) when is_record(R, megaco_sdp_z) -> true;
+is_pg_record(k, R) when is_record(R, megaco_sdp_k) -> true;
+is_pg_record(s, R) when is_record(R, megaco_sdp_s) -> true;
+is_pg_record(i, R) when is_record(R, megaco_sdp_i) -> true;
+is_pg_record(u, R) when is_record(R, megaco_sdp_u) -> true;
+is_pg_record(e, R) when is_record(R, megaco_sdp_e) -> true;
+is_pg_record(p, R) when is_record(R, megaco_sdp_p) -> true;
+is_pg_record(_, _) -> false.
+
+
+%%======================================================================
+%% Internal functions
+%%======================================================================
+
+%% ===== Protocol Version =====
+%%
+decode_pp_protocol_version(Value) when is_list(Value) ->
+ ?d("decode_pp_protocol_version -> entry with"
+ "~n Value: ~p", [Value]),
+ Version = s2i(Value, invalid_protocol_version),
+ ?d("decode_pp_protocol_version -> entry with"
+ "~n Version: ~w", [Version]),
+ decode_pp_protocol_version(Version);
+decode_pp_protocol_version(Version) when is_integer(Version) ->
+ ?d("decode_pp_protocol_version -> entry with"
+ "~n Version: ~w", [Version]),
+ {ok, #megaco_sdp_v{version = Version}}.
+
+encode_pp_protocol_version(Version) when is_integer(Version) ->
+ ?d("encode_pp_protocol_version -> entry with"
+ "~n Version: ~w", [Version]),
+ #'PropertyParm'{name = "v",
+ value = [integer_to_list(Version)]};
+encode_pp_protocol_version(Version) ->
+ error({invalid_protocol_version, Version}).
+
+
+%% ===== Origin =====
+%%
+decode_pp_origin(Value) ->
+ ?d("decode_pp_origin -> entry with"
+ "~n Value: ~p", [Value]),
+ case string:tokens(Value, " \t") of
+ [User, SessId, SessVersion, NetType, AddrType, UnicastAddress] ->
+ ?d("decode_pp_origin -> entry with"
+ "~n User: ~p"
+ "~n SessionId: ~p"
+ "~n Version: ~p"
+ "~n NetType: ~p"
+ "~n AddrType: ~p"
+ "~n UnicastAddress: ~p",
+ [User, SessId, SessVersion, NetType, AddrType, UnicastAddress]),
+ F = fun(X, R) ->
+ case (catch list_to_integer(X)) of
+ I when is_integer(I) ->
+ I;
+ _ ->
+ error({invalid_origin, {R, X}})
+ end
+ end,
+ SID = F(SessId, sess_id),
+ V = F(SessVersion, sess_version),
+ SDP = #megaco_sdp_o{user_name = User,
+ session_id = SID,
+ version = V,
+ network_type = decode_network_type(NetType),
+ address_type = decode_address_type(AddrType),
+ address = UnicastAddress},
+ {ok, SDP};
+ Err ->
+ ?d("decode_pp_origin -> "
+ "~n Err: ~p", [Err]),
+ invalid_pp(origin, Value, Err)
+ end.
+
+encode_pp_origin(User0, SessionId0, SessVersion0,
+ NetType0, AddrType0, UnicastAddr0) ->
+ ?d("do_encode_pp_origin -> entry with"
+ "~n User0: ~p"
+ "~n SessionId0: ~p"
+ "~n SessVersion0: ~p"
+ "~n NetType0: ~p"
+ "~n AddrType0: ~p"
+ "~n UnicastAddr0: ~p",
+ [User0, SessionId0, SessVersion0, NetType0, AddrType0, UnicastAddr0]),
+ User = encode_origin_user(User0),
+ SessionId = encode_origin_session_id(SessionId0),
+ SessVersion = encode_origin_sess_version(SessVersion0),
+ NetType = encode_origin_network_type(NetType0),
+ AddrType = encode_origin_address_type(AddrType0),
+ UnicastAddr = encode_origin_unicast_address(UnicastAddr0),
+ #'PropertyParm'{name = "o",
+ value = [
+ User ++ " " ++
+ SessionId ++ " " ++
+ SessVersion ++ " " ++
+ NetType ++ " " ++
+ AddrType ++ " " ++
+ UnicastAddr
+ ]}.
+
+encode_origin_user(User) when is_list(User) ->
+ User;
+encode_origin_user(BadUser) ->
+ error({invalid_origin_user, BadUser}).
+
+encode_origin_session_id(SID) when is_integer(SID) ->
+ integer_to_list(SID);
+encode_origin_session_id(BadSID) ->
+ error({invalid_origin_session_id, BadSID}).
+
+encode_origin_sess_version(SessVersion) when is_integer(SessVersion) ->
+ integer_to_list(SessVersion);
+encode_origin_sess_version(BadSessVersion) ->
+ error({invalid_origin_sess_version, BadSessVersion}).
+
+encode_origin_network_type(NT) ->
+ case (catch encode_network_type(NT)) of
+ {error, _} ->
+ error({invalid_origin_network_type, NT});
+ Val ->
+ Val
+ end.
+
+encode_origin_address_type(AT) ->
+ case (catch encode_address_type(AT)) of
+ {error, _} ->
+ error({invalid_origin_address_type, AT});
+ Val ->
+ Val
+ end.
+
+encode_origin_unicast_address(UnicastAddr) when is_list(UnicastAddr) ->
+ UnicastAddr;
+encode_origin_unicast_address(BadUnicastAddr) ->
+ error({invalid_origin_unicast_address, BadUnicastAddr}).
+
+
+%% ===== Session Name =====
+%%
+decode_pp_session_name(Value) ->
+ ?d("decode_pp_session_name -> entry with"
+ "~n Value: ~p", [Value]),
+ {ok, #megaco_sdp_s{name = Value}}.
+
+encode_pp_session_name(Name) when is_list(Name) ->
+ ?d("encode_pp_session_name -> entry with"
+ "~n Name: '~s'", [Name]),
+ #'PropertyParm'{name = "s",
+ value = [Name]};
+encode_pp_session_name(BadName) ->
+ error({invalid_session_name, BadName}).
+
+
+%% ===== Session and Media Information =====
+%%
+decode_pp_session_media_id(Value) ->
+ ?d("decode_pp_session_media_id -> entry with"
+ "~n Value: ~p", [Value]),
+ {ok, #megaco_sdp_i{session_descriptor = Value}}.
+
+encode_pp_session_media_id(SD) when is_list(SD) ->
+ ?d("encode_pp_session_media_id -> entry with"
+ "~n SD: '~s'", [SD]),
+ #'PropertyParm'{name = "i",
+ value = [SD]};
+encode_pp_session_media_id(BadSD) ->
+ error({invalid_session_media_id, BadSD}).
+
+
+%% ===== URI =====
+%%
+decode_pp_uri(Value) ->
+ ?d("decode_pp_uri -> entry with"
+ "~n Value: ~p", [Value]),
+ {ok, #megaco_sdp_u{uri = Value}}.
+
+encode_pp_uri(URI) when is_list(URI) ->
+ ?d("encode_pp_uri -> entry with"
+ "~n URI: ~p", [URI]),
+ #'PropertyParm'{name = "u",
+ value = [URI]};
+encode_pp_uri(BadUri) ->
+ error({invalid_uri, BadUri}).
+
+
+%% ===== Email Address and Phone Number =====
+%%
+decode_pp_email(Value) ->
+ ?d("decode_pp_email -> entry with"
+ "~n Value: ~p", [Value]),
+ {ok, #megaco_sdp_e{email = Value}}.
+
+encode_pp_email(Email) when is_list(Email) ->
+ ?d("encode_pp_email -> entry with"
+ "~n Email: ~p", [Email]),
+ #'PropertyParm'{name = "e",
+ value = [Email]};
+encode_pp_email(BadEmail) ->
+ error({invalid_email, BadEmail}).
+
+decode_pp_phone(Value) ->
+ ?d("decode_pp_phone -> entry with"
+ "~n Value: ~p", [Value]),
+ {ok, #megaco_sdp_p{phone_number = Value}}.
+
+encode_pp_phone(Phone) when is_list(Phone) ->
+ ?d("encode_pp_phone -> entry with"
+ "~n Phone: ~p", [Phone]),
+ #'PropertyParm'{name = "p",
+ value = [Phone]};
+encode_pp_phone(BadPhone) ->
+ error({invalid_phone, BadPhone}).
+
+
+%% ===== Connection Data =====
+%%
+decode_pp_connection_data(Value) ->
+ ?d("decode_pp_connection_data -> entry with"
+ "~n Value: ~p", [Value]),
+ case string:tokens(Value, " \t") of
+ [NetType, AddrType, ConnectionAddr] ->
+ ?d("decode_pp_connection_data -> "
+ "~n NetType: ~p"
+ "~n AddrType: ~p"
+ "~n ConnectionAddr: ~p", [NetType, AddrType, ConnectionAddr]),
+ NT = decode_network_type(NetType),
+ AT = decode_address_type(AddrType),
+ case AT of
+ ip4 ->
+ ?d("decode_pp_connection_data -> ip4", []),
+ ConnAddr =
+ case string:tokens(ConnectionAddr, "\/") of
+ [Base, TtlStr, NumOfAddrs] ->
+ ?d("decode_pp_connection_data -> "
+ "~n Base: ~p"
+ "~n TtlStr: ~p"
+ "~n NumOfAddrs:~p",
+ [Base, TtlStr, NumOfAddrs]),
+ TTL = s2i(TtlStr,
+ invalid_connection_data_ttl),
+ ?d("decode_pp_connection_data -> TTL: ~p",
+ [TTL]),
+ NOA =
+ s2i(NumOfAddrs,
+ invalid_connection_data_conn_addr_num_of),
+ ?d("decode_pp_connection_data -> NOA: ~p",
+ [NOA]),
+ #megaco_sdp_c_conn_addr{base = Base,
+ ttl = TTL,
+ num_of = NOA};
+ [Base, TtlStr] ->
+ ?d("decode_pp_connection_data -> "
+ "~n Base: ~p"
+ "~n TtlStr: ~p",
+ [Base, TtlStr]),
+ TTL =
+ s2i(TtlStr,
+ invalid_connection_data_conn_addr_ttl),
+ ?d("decode_pp_connection_data -> TTL: ~p",
+ [TTL]),
+ #megaco_sdp_c_conn_addr{base = Base,
+ ttl = TTL};
+ [Base] ->
+ Base
+ end,
+ ?d("decode_pp_connection_data -> "
+ "~n ConnAddr: ~p", [ConnAddr]),
+ SDP = #megaco_sdp_c{network_type = NT,
+ address_type = AT,
+ connection_addr = ConnAddr},
+ {ok, SDP};
+ ip6 ->
+ ?d("decode_pp_connection_data -> ip6", []),
+ SDP = #megaco_sdp_c{network_type = NT,
+ address_type = AT,
+ connection_addr = ConnectionAddr},
+ {ok, SDP};
+ _ ->
+ SDP = #megaco_sdp_c{network_type = NT,
+ address_type = AT,
+ connection_addr = ConnectionAddr},
+ {ok, SDP}
+ end;
+ Err ->
+ invalid_pp(connection_data, Value, Err)
+ end.
+
+encode_pp_connection_data(NetType0, AddrType0, ConnAddr0) ->
+ ?d("encode_pp_connection_data -> entry with"
+ "~n NetType0: ~p"
+ "~n AddrType0: ~p"
+ "~n ConnAddr0: ~p", [NetType0, AddrType0, ConnAddr0]),
+ NetType = encode_conn_data_network_type(NetType0),
+ AddrType = encode_conn_data_address_type(AddrType0),
+ ConnAddr = encode_conn_data_conn_addr(AddrType0, ConnAddr0),
+ Val = NetType ++ " " ++ AddrType ++ " " ++ ConnAddr,
+ #'PropertyParm'{name = "c",
+ value = [Val]}.
+
+encode_conn_data_network_type(NT) ->
+ case (catch encode_network_type(NT)) of
+ {error, _} ->
+ error({invalid_connection_data_network_type, NT});
+ Val ->
+ Val
+ end.
+
+encode_conn_data_address_type(AT) ->
+ case (catch encode_address_type(AT)) of
+ {error, _} ->
+ error({invalid_connection_data_address_type, AT});
+ Val ->
+ Val
+ end.
+
+encode_conn_data_conn_addr(_, CA) when is_list(CA) ->
+ CA;
+encode_conn_data_conn_addr(ip4, CA)
+ when is_record(CA, megaco_sdp_c_conn_addr) ->
+ encode_conn_data_conn_addr(CA);
+encode_conn_data_conn_addr(AT, CA)
+ when is_list(AT) and is_record(CA, megaco_sdp_c_conn_addr) ->
+ case tolower(AT) of
+ "ip4" ->
+ encode_conn_data_conn_addr(CA);
+ _ ->
+ error({invalid_connection_data_conn_addr, {AT, CA}})
+ end;
+encode_conn_data_conn_addr(_, BadCA) ->
+ error({invalid_connection_data_conn_addr, BadCA}).
+
+encode_conn_data_conn_addr(#megaco_sdp_c_conn_addr{base = Base0,
+ ttl = TTL0,
+ num_of = undefined}) ->
+ Base = encode_conn_data_conn_addr_base(Base0),
+ TTL = encode_conn_data_conn_addr_ttl(TTL0),
+ Base ++ "/" ++ TTL;
+encode_conn_data_conn_addr(#megaco_sdp_c_conn_addr{base = Base0,
+ ttl = TTL0,
+ num_of = NumOf0}) ->
+ Base = encode_conn_data_conn_addr_base(Base0),
+ TTL = encode_conn_data_conn_addr_ttl(TTL0),
+ NumOf = encode_conn_data_conn_addr_num_of(NumOf0),
+ Base ++ "/" ++ TTL ++ "/" ++ NumOf.
+
+encode_conn_data_conn_addr_base(Base) when is_list(Base) ->
+ Base;
+encode_conn_data_conn_addr_base(BadBase) ->
+ error({invalid_connection_data_conn_addr_base, BadBase}).
+
+encode_conn_data_conn_addr_ttl(TTL) when is_integer(TTL) ->
+ integer_to_list(TTL);
+encode_conn_data_conn_addr_ttl(BadTTL) ->
+ error({invalid_connection_data_conn_addr_ttl, BadTTL}).
+
+encode_conn_data_conn_addr_num_of(NumOf) when is_integer(NumOf) ->
+ integer_to_list(NumOf);
+encode_conn_data_conn_addr_num_of(BadNumOf) ->
+ error({invalid_connection_data_conn_addr_num_of, BadNumOf}).
+
+
+%% ===== Bandwidth =====
+%%
+decode_pp_bandwidth(Value) ->
+ ?d("decode_pp_bandwidth -> entry with"
+ "~n Value: ~p", [Value]),
+ case string:tokens(Value, ":") of
+ [BwTypeStr, BandwidthStr] ->
+ ?d("decode_pp_bandwidth -> "
+ "~n BwTypeStr: ~p"
+ "~n BandwidthStr: ~p", [BwTypeStr, BandwidthStr]),
+ BwType = decode_bandwidth_bwt(BwTypeStr),
+ ?d("decode_pp_bandwidth -> "
+ "~n BwType: ~w", [BwType]),
+ Bandwidth = decode_bandwidth_bw(BandwidthStr),
+ ?d("decode_pp_bandwidth -> "
+ "~n Bandwidth: ~w", [Bandwidth]),
+ SDP = #megaco_sdp_b{bwtype = BwType,
+ bandwidth = Bandwidth},
+ {ok, SDP};
+ Err ->
+ invalid_pp(bandwidth_info, Value, Err)
+ end.
+
+encode_pp_bandwidth(BwType0, Bandwidth0) ->
+ ?d("encode_pp_bandwidth -> entry with"
+ "~n BwType0: ~p"
+ "~n Bandwidth0: ~p", [BwType0, Bandwidth0]),
+ BwType = encode_bandwidth_bwt(BwType0),
+ Bandwidth = encode_bandwidth_bw(Bandwidth0),
+ Val = BwType ++ ":" ++ Bandwidth,
+ #'PropertyParm'{name = "b",
+ value = [Val]}.
+
+decode_bandwidth_bwt("CT") ->
+ ct;
+decode_bandwidth_bwt("AS") ->
+ as;
+decode_bandwidth_bwt(BwType) when is_list(BwType) ->
+ BwType;
+decode_bandwidth_bwt(BadBwType) ->
+ error({invalid_bandwidth_bwtype, BadBwType}).
+
+encode_bandwidth_bwt(ct) ->
+ "CT";
+encode_bandwidth_bwt(as) ->
+ "AS";
+encode_bandwidth_bwt(BwType) when is_list(BwType) ->
+ BwType;
+encode_bandwidth_bwt(BadBwType) ->
+ error({invalid_bandwidth_bwtype, BadBwType}).
+
+decode_bandwidth_bw(Bandwidth) ->
+ s2i(Bandwidth, invalid_bandwidth_bandwidth).
+
+encode_bandwidth_bw(Bandwidth) when is_integer(Bandwidth) ->
+ integer_to_list(Bandwidth);
+encode_bandwidth_bw(BadBandwidth) ->
+ error({invalid_bandwidth_bandwidth, BadBandwidth}).
+
+
+%% ===== Times =====
+%%
+decode_pp_times(Value) ->
+ ?d("decode_pp_times -> entry with"
+ "~n Value: ~p", [Value]),
+ case string:tokens(Value, " \t") of
+ [StartStr, StopStr] ->
+ ?d("decode_pp_times -> "
+ "~n StartStr: ~p"
+ "~n StopStr: ~p", [StartStr, StopStr]),
+ Start = decode_times_start(StartStr),
+ ?d("decode_pp_times -> entry with"
+ "~n Stop: ~w", [Start]),
+ Stop = decode_times_stop(StopStr),
+ ?d("decode_pp_times -> entry with"
+ "~n Stop: ~w", [Stop]),
+ SDP = #megaco_sdp_t{start = Start,
+ stop = Stop},
+ {ok, SDP};
+ Err ->
+ invalid_pp(times, Value, Err)
+ end.
+
+encode_pp_times(Start0, Stop0) ->
+ ?d("encode_pp_times -> entry with"
+ "~n Start0: ~p"
+ "~n Stop0: ~p", [Start0, Stop0]),
+ Start = encode_times_start(Start0),
+ Stop = encode_times_stop(Stop0),
+ Val = Start ++ " " ++ Stop,
+ #'PropertyParm'{name = "t",
+ value = [Val]}.
+
+decode_times_start(Time) ->
+ s2i(Time, invalid_times_start).
+
+encode_times_start(Time) when is_integer(Time) ->
+ integer_to_list(Time);
+encode_times_start(BadTime) ->
+ error({invalid_times_start, BadTime}).
+
+decode_times_stop(Time) ->
+ s2i(Time, invalid_times_stop).
+
+encode_times_stop(Time) when is_integer(Time) ->
+ integer_to_list(Time);
+encode_times_stop(BadTime) ->
+ error({invalid_times_stop, BadTime}).
+
+
+%% ===== Repeat Times =====
+%%
+decode_pp_rtimes(Value) ->
+ ?d("decode_pp_rtimes -> entry with"
+ "~n Value: ~p", [Value]),
+ case string:tokens(Value, " \t") of
+ [Repeat, Duration | ListOfOffsets] ->
+ ?d("decode_pp_rtimes -> "
+ "~n Repeat: ~p"
+ "~n Duration: ~p"
+ "~n ListOfOffsets: ~p", [Repeat, Duration, ListOfOffsets]),
+ SDP = #megaco_sdp_r{repeat_interval = Repeat,
+ active_duration = Duration,
+ list_of_offsets = ListOfOffsets},
+ {ok, SDP};
+ Err ->
+ invalid_pp(repeat_times, Value, Err)
+ end.
+
+encode_pp_rtimes(Repeat0, Duration0, ListOfOffsets0) ->
+ ?d("encode_pp_rtimes -> entry with"
+ "~n Repeat0: ~p"
+ "~n Duration0: ~p"
+ "~n ListOfOffsets0: ~p", [Repeat0, Duration0, ListOfOffsets0]),
+ Repeat = encode_rtimes_repeat(Repeat0),
+ Duration = encode_rtimes_duration(Duration0),
+ ListOfOffsets = encode_rtimes_list_of_offsets(ListOfOffsets0),
+ Val = Repeat ++ " " ++ Duration ++ ListOfOffsets,
+ #'PropertyParm'{name = "r",
+ value = [Val]}.
+
+encode_rtimes_repeat(Repeat) when is_list(Repeat) ->
+ Repeat;
+encode_rtimes_repeat(BadRepeat) ->
+ error({invalid_rtimes_repeat, BadRepeat}).
+
+encode_rtimes_duration(Duration) when is_list(Duration) ->
+ Duration;
+encode_rtimes_duration(BadDuration) ->
+ error({invalid_rtimes_duration, BadDuration}).
+
+encode_rtimes_list_of_offsets(LOO) when is_list(LOO) ->
+ F = fun(Off, Acc) when is_list(Off) ->
+ Acc ++ " " ++ Off;
+ (BadOff, Acc) ->
+ error({invalid_rtimes_list_of_offsets, {BadOff, Acc}})
+ end,
+ lists:foldl(F, [], LOO);
+encode_rtimes_list_of_offsets(BadLoo) ->
+ error({invalid_rtimes_list_of_offsets, BadLoo}).
+
+
+%% ===== Time Zones =====
+%%
+decode_pp_tzones(Value) when is_list(Value) and (length(Value) > 0) ->
+ ?d("decode_pp_ztimes -> entry with"
+ "~n Value: ~p", [Value]),
+ LOA = decode_tzones_list_of_adjustments(string:tokens(Value, " \t"), []),
+ {ok, #megaco_sdp_z{list_of_adjustments = LOA}};
+decode_pp_tzones(BadValue) ->
+ error({invalid_tzones_list_of_adjustments, BadValue}).
+
+encode_pp_tzones(LOA) ->
+ ?d("encode_pp_ztimes -> entry with"
+ "~n LOA: ~p", [LOA]),
+ Val = encode_tzones_list_of_adjustments(LOA),
+ #'PropertyParm'{name = "z",
+ value = [Val]}.
+
+decode_tzones_list_of_adjustments([], Acc) ->
+ lists:reverse(Acc);
+decode_tzones_list_of_adjustments([Adj], Acc) ->
+ error({invalid_tzones_list_of_adjustments, Adj, lists:reverse(Acc)});
+decode_tzones_list_of_adjustments([Time, Offset | LOA], Acc) ->
+ Adj = #megaco_sdp_z_adjustement{time = Time, offset = Offset},
+ decode_tzones_list_of_adjustments(LOA, [Adj | Acc]).
+
+encode_tzones_list_of_adjustments([H|_] = LOA)
+ when is_record(H, megaco_sdp_z_adjustement) ->
+ F = fun(#megaco_sdp_z_adjustement{time = T, offset = O}, Acc) ->
+ Acc ++ " " ++ T ++ " " ++ O;
+ (BadAdjustment, Acc) ->
+ error({invalid_tzones_list_of_adjustments,
+ {BadAdjustment, Acc}})
+ end,
+ lists:foldl(F, [], LOA);
+encode_tzones_list_of_adjustments(LOA) ->
+ error({invalid_tzones_list_of_adjustments, LOA}).
+
+
+%% ===== Encryption Keys =====
+%%
+decode_pp_encryption_keys(Value) ->
+ ?d("decode_pp_encryption_keys -> entry with"
+ "~n Value: ~p", [Value]),
+ {M, E} =
+ case string:tokens(Value, ":") of
+ [Method, EncryptionKey] ->
+ ?d("decode_pp_encryption_keys -> "
+ "~n Method: ~p"
+ "~n EncryptionKey: ~p", [Method, EncryptionKey]),
+ {Method, EncryptionKey};
+ [Method] ->
+ ?d("decode_pp_encryption_keys -> "
+ "~n Method: ~p", [Method]),
+ {Method, undefined};
+ Err ->
+ invalid_pp(encryption_key, Value, Err)
+ end,
+ M2 =
+ case tolower(M) of
+ "clear" ->
+ clear;
+ "base64" ->
+ base64;
+ "uri" ->
+ uri;
+ "prompt" ->
+ prompt;
+ _ ->
+ M
+ end,
+ ?d("decode_pp_encryption_keys -> "
+ "~n M2: ~p", [M2]),
+ SDP = #megaco_sdp_k{method = M2,
+ encryption_key = E},
+ {ok, SDP}.
+
+encode_pp_encryption_keys(prompt = _Method, undefined) ->
+ ?d("encode_pp_encryption_keys(prompt) -> entry", []),
+ #'PropertyParm'{name = "k",
+ value = ["prompt"]};
+encode_pp_encryption_keys(clear = _Method, EncryptionKey)
+ when is_list(EncryptionKey) ->
+ ?d("encode_pp_encryption_keys(clear) -> entry with"
+ "~n EncryptionKey: ~p", [EncryptionKey]),
+ #'PropertyParm'{name = "k",
+ value = ["clear:" ++ EncryptionKey]};
+encode_pp_encryption_keys(base64 = _Method, EncryptionKey)
+ when is_list(EncryptionKey) ->
+ ?d("encode_pp_encryption_keys(base64) -> entry with"
+ "~n EncryptionKey: ~p", [EncryptionKey]),
+ #'PropertyParm'{name = "k",
+ value = ["base64:" ++ EncryptionKey]};
+encode_pp_encryption_keys(uri = _Method, EncryptionKey)
+ when is_list(EncryptionKey) ->
+ ?d("encode_pp_encryption_keys(uri) -> entry with"
+ "~n EncryptionKey: ~p", [EncryptionKey]),
+ #'PropertyParm'{name = "k",
+ value = ["uri:" ++ EncryptionKey]};
+encode_pp_encryption_keys(Method, EncryptionKey)
+ when is_list(Method) and is_list(EncryptionKey) ->
+ ?d("encode_pp_encryption_keys -> entry with"
+ "~n Method: ~p"
+ "~n EncryptionKey: ~p", [Method, EncryptionKey]),
+ #'PropertyParm'{name = "k",
+ value = [Method ++ ":" ++ EncryptionKey]};
+encode_pp_encryption_keys(BadMethod, BadEK) ->
+ error({invalid_encryption_keys, {BadMethod, BadEK}}).
+
+
+%% ===== Attributes =====
+%%
+decode_pp_attribute(Value) ->
+ ?d("decode_pp_attribute -> entry with"
+ "~n Value: ~p", [Value]),
+ First = string:chr(Value, $:),
+ if
+ (First > 0) and (First < length(Value)) ->
+ ?d("decode_pp_attribute -> value attribute", []),
+ Attr = string:substr(Value, 1, First -1),
+ AttrValue = string:substr(Value, First + 1),
+ ?d("decode_pp_attribute -> "
+ "~n Attr: ~p"
+ "~n AttrValue: ~p", [Attr, AttrValue]),
+ decode_pp_attribute_value(Attr, AttrValue);
+
+ First > 0 ->
+ ?d("decode_pp_attribute -> value attribute (empty)", []),
+ Attr = string:substr(Value, 1, First -1),
+ ?d("decode_pp_attribute -> "
+ "~n Attr: ~p", [Attr]),
+ decode_pp_attribute_value(Attr, []);
+
+ true ->
+ ?d("decode_pp_attribute -> binary attribute", []),
+ {ok, #megaco_sdp_a{attribute = Value}}
+
+ end.
+
+decode_pp_attribute_value("cat", AttrValue) ->
+ ?d("decode_pp_attribute -> cat", []),
+ SDP = #megaco_sdp_a_cat{category = AttrValue},
+ {ok, SDP};
+
+decode_pp_attribute_value("keywds", AttrValue) ->
+ ?d("decode_pp_attribute -> keywds", []),
+ SDP = #megaco_sdp_a_keywds{keywords = AttrValue},
+ {ok, SDP};
+
+decode_pp_attribute_value("tool", AttrValue) ->
+ ?d("decode_pp_attribute -> tool", []),
+ SDP = #megaco_sdp_a_tool{name_and_version = AttrValue},
+ {ok, SDP};
+
+decode_pp_attribute_value("ptime", AttrValue) ->
+ ?d("decode_pp_attribute -> ptime", []),
+ PacketTimeStr = string:strip(AttrValue, both, $ ),
+ PacketTime =
+ s2i(PacketTimeStr, invalid_ptime_packet_time),
+ ?d("decode_pp_attribute -> PacketTime: ~w", [PacketTime]),
+ SDP = #megaco_sdp_a_ptime{packet_time = PacketTime},
+ {ok, SDP};
+
+decode_pp_attribute_value("maxptime", AttrValue) ->
+ ?d("decode_pp_attribute -> maxptime", []),
+ MaxPacketTimeStr = string:strip(AttrValue, both, $ ),
+ MaxPacketTime =
+ s2i(MaxPacketTimeStr, invalid_maxptime_maximum_packet_time),
+ ?d("decode_pp_attribute -> MaxPacketTime: ~w", [MaxPacketTime]),
+ SDP = #megaco_sdp_a_maxptime{maximum_packet_time = MaxPacketTime},
+ {ok, SDP};
+
+decode_pp_attribute_value("rtpmap", AttrValue) ->
+ ?d("decode_pp_attribute -> rtpmap", []),
+ case string:tokens(AttrValue, "\/ \t") of
+ [PayloadStr, EncName, ClockRateStr | EncPar] ->
+ ?d("decode_pp_attribute -> "
+ "~n PayloadStr: ~p"
+ "~n EncName: ~p"
+ "~n ClockRateStr: ~p"
+ "~n EncPar: ~p",
+ [PayloadStr, EncName, ClockRateStr, EncPar]),
+ Payload =
+ s2i(PayloadStr, invalid_rtpmap_payload),
+ ?d("decode_pp_attribute -> Payload: ~w",
+ [Payload]),
+ ClockRate =
+ s2i(ClockRateStr, invalid_rtpmap_payload),
+ ?d("decode_pp_attribute -> ClockRate: ~w",
+ [ClockRate]),
+ SDP =
+ #megaco_sdp_a_rtpmap{payload_type = Payload,
+ encoding_name = EncName,
+ clock_rate = ClockRate,
+ encoding_parms = EncPar},
+ {ok, SDP};
+ _ ->
+ error({invalid_rtpmap, AttrValue})
+ end;
+
+decode_pp_attribute_value("orient", AttrValue) ->
+ ?d("decode_pp_attribute -> orient", []),
+ Orientation = decode_attribute_orientation(AttrValue),
+ SDP = #megaco_sdp_a_orient{orientation = Orientation},
+ {ok, SDP};
+
+decode_pp_attribute_value("type", AttrValue) ->
+ ?d("decode_pp_attribute -> type", []),
+ SDP = #megaco_sdp_a_type{conf_type = AttrValue},
+ {ok, SDP};
+
+decode_pp_attribute_value("charset", AttrValue) ->
+ ?d("decode_pp_attribute -> charset", []),
+ SDP = #megaco_sdp_a_charset{char_set = AttrValue},
+ {ok, SDP};
+
+decode_pp_attribute_value("sdplang", AttrValue) ->
+ ?d("decode_pp_attribute -> sdplang", []),
+ SDP = #megaco_sdp_a_sdplang{tag = AttrValue},
+ {ok, SDP};
+
+decode_pp_attribute_value("lang", AttrValue) ->
+ ?d("decode_pp_attribute -> lang", []),
+ SDP = #megaco_sdp_a_lang{tag = AttrValue},
+ {ok, SDP};
+
+decode_pp_attribute_value("framerate", AttrValue) ->
+ ?d("decode_pp_attribute -> framerate", []),
+ SDP = #megaco_sdp_a_framerate{frame_rate = AttrValue},
+ {ok, SDP};
+
+decode_pp_attribute_value("quality", AttrValue) ->
+ ?d("decode_pp_attribute -> quality", []),
+ QualityStr = AttrValue,
+ Quality = s2i(QualityStr, invalid_quality_quality),
+ ?d("decode_pp_attribute -> Quality: ~w", [Quality]),
+ SDP = #megaco_sdp_a_quality{quality = Quality},
+ {ok, SDP};
+
+decode_pp_attribute_value("fmtp", AttrValue) ->
+ ?d("decode_pp_attribute -> fmtp", []),
+ FMTP = AttrValue,
+ First = string:chr(FMTP, $ ),
+ if
+ (First > 0) and (First < length(FMTP)) ->
+ ?d("decode_pp_attribute_value -> valid fmtp with params", []),
+ Format = string:substr(FMTP, 1, First - 1),
+ Params = string:substr(FMTP, First + 1),
+ ?d("decode_pp_attribute_value -> "
+ "~n Format: ~p"
+ "~n Params: ~p", [Format, Params]),
+ SDP = #megaco_sdp_a_fmtp{format = Format,
+ param = Params},
+ {ok, SDP};
+
+ First > 0 ->
+ ?d("decode_pp_attribute -> valid fmtp", []),
+ Format = string:substr(FMTP, 1, First - 1),
+ ?d("decode_pp_attribute -> "
+ "~n Format: ~p", [Format]),
+ {ok, #megaco_sdp_a_fmtp{format = Format, param = []}};
+
+ true ->
+ ?d("decode_pp_attribute_value -> no params", []),
+ {ok, #megaco_sdp_a_fmtp{format = FMTP, param = []}}
+
+ end;
+
+decode_pp_attribute_value(Attr, AttrValue) ->
+ ?d("decode_pp_attribute -> unknown value attribute", []),
+ {ok, #megaco_sdp_a{attribute = Attr, value = AttrValue}}.
+
+decode_attribute_orientation("portrait") ->
+ portrait;
+decode_attribute_orientation("landscape") ->
+ landscape;
+decode_attribute_orientation("seascape") ->
+ seascape;
+decode_attribute_orientation(BadOrientation) ->
+ error({invalid_orient_orientation, BadOrientation}).
+
+encode_attribute_orientation(portrait) ->
+ "portrait";
+encode_attribute_orientation(landscape) ->
+ "landscape";
+encode_attribute_orientation(seascape) ->
+ "seascape";
+encode_attribute_orientation(BadOrientation) ->
+ error({invalid_orient_orientation, BadOrientation}).
+
+
+encode_pp_attribute_cat(Cat) when is_list(Cat) ->
+ ?d("encode_pp_attribute_cat -> entry with"
+ "~n Cat: ~p", [Cat]),
+ #'PropertyParm'{name = "a",
+ value = ["cat:" ++ Cat]};
+encode_pp_attribute_cat(BadCat) ->
+ error({invalid_cat_category, BadCat}).
+
+
+encode_pp_attribute_keywds(Keywords) when is_list(Keywords) ->
+ ?d("encode_pp_attribute_keywds -> entry with"
+ "~n Keywords: ~p", [Keywords]),
+ #'PropertyParm'{name = "a",
+ value = ["keywds:" ++ Keywords]};
+encode_pp_attribute_keywds(BadKeywords) ->
+ error({invalid_keywds_keywords, BadKeywords}).
+
+
+encode_pp_attribute_tool(NameAndVersion) when is_list(NameAndVersion) ->
+ ?d("encode_pp_attribute_tool -> entry with"
+ "~n NameAndVersion: ~p", [NameAndVersion]),
+ #'PropertyParm'{name = "a",
+ value = ["tool:" ++ NameAndVersion]};
+encode_pp_attribute_tool(BadNameAndVersion) ->
+ error({invalid_tool_name_and_version, BadNameAndVersion}).
+
+
+encode_pp_attribute_ptime(PacketTime) when is_integer(PacketTime) ->
+ ?d("encode_pp_attribute_ptime -> entry with"
+ "~n PacketTime: ~w", [PacketTime]),
+ #'PropertyParm'{name = "a",
+ value = ["ptime:" ++ integer_to_list(PacketTime)]};
+encode_pp_attribute_ptime(BadPT) ->
+ error({invalid_ptime_packet_time, BadPT}).
+
+
+encode_pp_attribute_maxptime(MaxPacketTime) when is_integer(MaxPacketTime) ->
+ ?d("encode_pp_attribute_maxptime -> entry with"
+ "~n MaxPacketTime: ~w", [MaxPacketTime]),
+ #'PropertyParm'{name = "a",
+ value = ["maxptime:" ++ integer_to_list(MaxPacketTime)]};
+encode_pp_attribute_maxptime(BadMPT) ->
+ error({invalid_maxptime_maximum_packet_time, BadMPT}).
+
+
+encode_pp_attribute_rtpmap(Payload0, EncName0, ClockRate0, EncPar0) ->
+ ?d("encode_pp_attribute_rtpmap -> entry with"
+ "~n Payload0: ~p"
+ "~n EncName0: ~p"
+ "~n ClockRate0: ~p"
+ "~n EncPar0: ~p", [Payload0, EncName0, ClockRate0, EncPar0]),
+ Payload = encode_rtpmap_payload(Payload0),
+ EncName = encode_rtpmap_encoding_name(EncName0),
+ ClockRate = encode_rtpmap_clockrate(ClockRate0),
+ EncPar = encode_rtpmap_encoding_parms(EncPar0),
+ Val = "rtpmap:" ++ Payload ++ " " ++
+ EncName ++ "/" ++ ClockRate ++ EncPar,
+ #'PropertyParm'{name = "a",
+ value = [Val]}.
+
+encode_rtpmap_payload(Payload) when is_integer(Payload) ->
+ integer_to_list(Payload);
+encode_rtpmap_payload(BadPayload) ->
+ error({invalid_rtpmap_payload, BadPayload}).
+
+encode_rtpmap_encoding_name(EncName) when is_list(EncName) ->
+ EncName;
+encode_rtpmap_encoding_name(BadEncName) ->
+ error({invalid_rtpmap_encoding_name, BadEncName}).
+
+encode_rtpmap_clockrate(ClockRate) when is_integer(ClockRate) ->
+ integer_to_list(ClockRate);
+encode_rtpmap_clockrate(BadClockRate) ->
+ error({invalid_rtpmap_clockrate, BadClockRate}).
+
+encode_rtpmap_encoding_parms(EncPar) when is_list(EncPar) ->
+ F = fun(EP, Acc) when is_list(EP) ->
+ Acc ++ "/" ++ EP;
+ (BadEP, Acc) ->
+ error({invalid_rtpmap_encoding_parms, {BadEP, Acc}})
+ end,
+ lists:foldl(F, [], EncPar);
+encode_rtpmap_encoding_parms(BadEncPar) ->
+ error({invalid_rtpmap_encoding_parms, BadEncPar}).
+
+
+encode_pp_attribute_orient(Orientation0) ->
+ ?d("encode_pp_attribute_orient -> entry with"
+ "~n Orientation0: ~w", [Orientation0]),
+ Orientation = encode_attribute_orientation(Orientation0),
+ #'PropertyParm'{name = "a",
+ value = ["orient:" ++ Orientation]}.
+
+
+encode_pp_attribute_type(CType) when is_list(CType) ->
+ ?d("encode_pp_attribute_type -> entry with"
+ "~n CType: ~p", [CType]),
+ #'PropertyParm'{name = "a",
+ value = ["type:" ++ CType]};
+encode_pp_attribute_type(BadCType) ->
+ error({invalid_type_conf_type, BadCType}).
+
+
+encode_pp_attribute_charset(CharSet) when is_list(CharSet) ->
+ ?d("encode_pp_attribute_charset -> entry with"
+ "~n CharSet: ~p", [CharSet]),
+ #'PropertyParm'{name = "a",
+ value = ["charset:" ++ CharSet]};
+encode_pp_attribute_charset(BadCharSet) ->
+ error({invalid_charset_char_set, BadCharSet}).
+
+
+encode_pp_attribute_sdplang(SdpLang) when is_list(SdpLang) ->
+ ?d("encode_pp_attribute_sdplang -> entry with"
+ "~n SdpLang: ~p", [SdpLang]),
+ #'PropertyParm'{name = "a",
+ value = ["sdplang:" ++ SdpLang]};
+encode_pp_attribute_sdplang(BadSdpLang) ->
+ error({invalid_sdplang_tag, BadSdpLang}).
+
+
+encode_pp_attribute_lang(Lang) when is_list(Lang) ->
+ ?d("encode_pp_attribute_lang -> entry with"
+ "~n Lang: ~p", [Lang]),
+ #'PropertyParm'{name = "a",
+ value = ["lang:" ++ Lang]};
+encode_pp_attribute_lang(BadLang) ->
+ error({invalid_lang_tag, BadLang}).
+
+
+encode_pp_attribute_framerate(FrameRate) when is_list(FrameRate) ->
+ ?d("encode_pp_attribute_framerate -> entry with"
+ "~n FrameRate: ~p", [FrameRate]),
+ #'PropertyParm'{name = "a",
+ value = ["framerate:" ++ FrameRate]};
+encode_pp_attribute_framerate(BadFrameRate) ->
+ error({invalid_framerate_frame_rate, BadFrameRate}).
+
+
+encode_pp_attribute_quality(Quality) when is_integer(Quality) ->
+ ?d("encode_pp_attribute_quality -> entry with"
+ "~n Quality: ~w", [Quality]),
+ #'PropertyParm'{name = "a",
+ value = ["quality:" ++ integer_to_list(Quality)]};
+encode_pp_attribute_quality(BadQ) ->
+ error({invalid_quality_quality, BadQ}).
+
+
+encode_pp_attribute_fmtp(Fmt0, Params0) ->
+ ?d("encode_pp_attribute_rtpmap -> entry with"
+ "~n Fmt0: ~p"
+ "~n Params0: ~p", [Fmt0, Params0]),
+ Fmt = encode_fmtp_format(Fmt0),
+ Params = encode_fmtp_param(Params0),
+ Val = "fmtp:" ++ Fmt ++ " " ++ Params,
+ #'PropertyParm'{name = "a",
+ value = [Val]}.
+
+encode_fmtp_format(Fmt) when is_list(Fmt) ->
+ Fmt;
+encode_fmtp_format(BadFmt) ->
+ error({invalid_fmtp_format, BadFmt}).
+
+encode_fmtp_param(Param) when is_list(Param) ->
+ Param;
+encode_fmtp_param(BadParam) ->
+ error({invalid_fmtp_param, BadParam}).
+
+
+encode_pp_attribute(Attr, undefined) when is_list(Attr) ->
+ ?d("encode_pp_attribute_rtpmap -> entry with"
+ "~n Attr: ~p", [Attr]),
+ #'PropertyParm'{name = "a",
+ value = [Attr]};
+encode_pp_attribute(Attr, Value) when is_list(Attr) and is_list(Value) ->
+ ?d("encode_pp_attribute_rtpmap -> entry with"
+ "~n Attr: ~p"
+ "~n Value: ~p", [Attr, Value]),
+ #'PropertyParm'{name = "a",
+ value = [Attr ++ ":" ++ Value]};
+encode_pp_attribute(BadAttr, BadAttrValue) ->
+ error({invalid_attribute, {BadAttr, BadAttrValue}}).
+
+
+%% ===== Media Announcements =====
+%%
+decode_pp_media_announcement(Value) ->
+ case string:tokens(Value, " \t") of
+ [Media0, PortInfo, Transport | FMT] ->
+ Media =
+ case tolower(Media0) of
+ "audio" -> audio;
+ "video" -> video;
+ "application" -> application;
+ "data" -> data;
+ "control" -> control;
+ _ -> Media0
+ end,
+ {Port, NoOfPorts} =
+ case string:tokens(PortInfo, "/") of
+ [P1, NP] ->
+ {s2i(P1, invalid_media_announcement_port),
+ s2i(NP, invalid_media_announcement_nof_ports)};
+ [P2] ->
+ {s2i(P2, invalid_media_announcement_port),
+ undefined};
+ Err ->
+ invalid_pp(mnta_port_info, Value, Err)
+ end,
+ SDP = #megaco_sdp_m{media = Media,
+ port = Port,
+ num_ports = NoOfPorts,
+ transport = Transport,
+ fmt_list = FMT},
+ {ok, SDP};
+ Err ->
+ invalid_pp(media_name_transp_addr, Value, Err)
+ end.
+
+
+encode_pp_media_announcement(Media0, Port0, undefined, Transport0, FMT0) ->
+ ?d("encode_pp_media_announcement -> entry with"
+ "~n Media0: ~p"
+ "~n Port0: ~p"
+ "~n Transport0: ~p"
+ "~n FMT0: ~p", [Media0, Port0, Transport0, FMT0]),
+ Media = encode_media_announcement_media(Media0),
+ Port = encode_media_announcement_port(Port0),
+ Transport = encode_media_announcement_transport(Transport0),
+ FMT = encode_media_announcement_fmt_list(FMT0),
+ do_encode_pp_media_announcement(Media, Port, "", Transport, FMT);
+encode_pp_media_announcement(Media0, Port0, NumPorts0, Transport0, FMT0) ->
+ ?d("encode_pp_media_announcement -> entry with"
+ "~n Media0: ~p"
+ "~n Port0: ~p"
+ "~n NumPorts0: ~p"
+ "~n Transport0: ~p"
+ "~n FMT0: ~p", [Media0, Port0, NumPorts0, Transport0, FMT0]),
+ Media = encode_media_announcement_media(Media0),
+ Port = encode_media_announcement_port(Port0),
+ NumPorts = encode_media_announcement_num_port(NumPorts0),
+ Transport = encode_media_announcement_transport(Transport0),
+ FMT = encode_media_announcement_fmt_list(FMT0),
+ do_encode_pp_media_announcement(Media, Port, NumPorts, Transport, FMT).
+
+do_encode_pp_media_announcement(Media, Port, NumOfPorts, Transport, FMT) ->
+ Val = Media ++ " " ++ Port ++ NumOfPorts ++ " " ++ Transport ++ FMT,
+ #'PropertyParm'{name = "m",
+ value = [Val]}.
+
+encode_media_announcement_media(Media) when is_atom(Media) ->
+ MaMedia = [audio, video, application, data, control],
+ case lists:member(Media, MaMedia) of
+ true ->
+ atom_to_list(Media);
+ false ->
+ error({invalid_media_announcement_media, Media})
+ end;
+encode_media_announcement_media(Media) when is_list(Media) ->
+ Media;
+encode_media_announcement_media(BadMedia) ->
+ error({invalid_media_announcement_media, BadMedia}).
+
+encode_media_announcement_port(Port) when is_integer(Port) ->
+ integer_to_list(Port);
+encode_media_announcement_port(BadPort) ->
+ error({invalid_media_announcement_port, BadPort}).
+
+encode_media_announcement_num_port(NumPort) when is_integer(NumPort) ->
+ "/" ++ integer_to_list(NumPort);
+encode_media_announcement_num_port(BadNumPort) ->
+ error({invalid_media_announcement_num_port, BadNumPort}).
+
+encode_media_announcement_transport(Transport) when is_list(Transport) ->
+ Transport;
+encode_media_announcement_transport(BadTransport) ->
+ error({invalid_media_announcement_transport, BadTransport}).
+
+encode_media_announcement_fmt_list(FmtList) when is_list(FmtList) ->
+ F = fun(FMT, Acc) when is_list(FMT) ->
+ Acc ++ " " ++ FMT;
+ (BadFMT, Acc) ->
+ error({invalid_media_announcement_fmt_list, {BadFMT, Acc}})
+ end,
+ lists:foldl(F, [], FmtList);
+encode_media_announcement_fmt_list(BadFmtList) ->
+ error({invalid_media_announcement_fmt_list, BadFmtList}).
+
+
+decode_network_type(NT) when is_list(NT) ->
+ case tolower(NT) of
+ "in" -> in;
+ _ -> NT
+ end.
+
+encode_network_type(in) -> "IN";
+encode_network_type(NT) when is_list(NT) -> NT;
+encode_network_type(Bad) ->
+ {error, {invalid_network_type, Bad}}.
+
+
+decode_address_type(AT) when is_list(AT) ->
+ case tolower(AT) of
+ "ip4" -> ip4;
+ "ip6" -> ip6;
+ _ -> AT
+ end.
+
+encode_address_type(ip4) -> "IP4";
+encode_address_type(ip6) -> "IP6";
+encode_address_type(AT) when is_list(AT) ->
+ case toupper(AT) of
+ "IP4" -> "IP4";
+ "IP6" -> "IP6";
+ _ -> AT
+ end;
+encode_address_type(Crap) ->
+ {error, {invalid_address_type, Crap}}.
+
+
+s2i(S, E) ->
+ case (catch list_to_integer(S)) of
+ I when is_integer(I) ->
+ I;
+ _ ->
+ error({E, S})
+ end.
+
+-define(LOWER(Char),
+ if
+ Char >= $A, Char =< $Z ->
+ Char - ($A - $a);
+ true ->
+ Char
+ end).
+tolower(Chars) ->
+ [?LOWER(Char) || Char <- Chars].
+
+-define(UPPER(Char),
+ if
+ Char >= $a, Char =< $z ->
+ Char + ($A - $a);
+ true ->
+ Char
+ end).
+toupper(Chars) ->
+ [?UPPER(Char) || Char <- Chars].
+
+invalid_pp(What, Value, Error) ->
+ {error, {invalid_PropertyParm, {What, Value, Error}}}.
+
+error(Reason) ->
+ throw({error, Reason}).
+
diff --git a/lib/megaco/src/engine/megaco_stats.erl b/lib/megaco/src/engine/megaco_stats.erl
new file mode 100644
index 0000000000..af180fb9d6
--- /dev/null
+++ b/lib/megaco/src/engine/megaco_stats.erl
@@ -0,0 +1,207 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2002-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: Functions for handling statistic counters
+%%-----------------------------------------------------------------
+-module(megaco_stats).
+
+
+%%-----------------------------------------------------------------
+%% Application internal exports
+%%-----------------------------------------------------------------
+
+-export([init/1, init/2]).
+
+-export([inc/2, inc/3, inc/4]).
+
+-export([get_stats/1, get_stats/2, get_stats/3,
+ reset_stats/1, reset_stats/2]).
+
+%% -include_lib("megaco/include/megaco.hrl").
+
+
+%%-----------------------------------------------------------------
+%% Func: init/1, init/2
+%% Description: Initiate the statistics. Creates the stats table
+%% and the global counters.
+%%-----------------------------------------------------------------
+init(Name) ->
+ init(Name, []).
+
+init(Name, GlobalCounters) ->
+ ets:new(Name, [public, named_table, {keypos, 1}]),
+ ets:insert(Name, {global_counters, GlobalCounters}),
+ create_global_snmp_counters(Name, GlobalCounters).
+
+
+create_global_snmp_counters(_Name, []) ->
+ ok;
+create_global_snmp_counters(Name, [Counter|Counters]) ->
+ ets:insert(Name, {Counter, 0}),
+ create_global_snmp_counters(Name, Counters).
+
+
+%%-----------------------------------------------------------------
+%% Func: inc/2, inc/3, inc/4
+%% Description: Increment counter value. Default increment is one
+%% (1).
+%%-----------------------------------------------------------------
+inc(Tab, GlobalCnt) when is_atom(GlobalCnt) ->
+ inc(Tab, GlobalCnt, 1).
+
+inc(Tab, GlobalCnt, Incr)
+ when is_atom(GlobalCnt) andalso (is_integer(Incr) andalso (Incr > 0)) ->
+ do_inc(Tab, GlobalCnt, Incr);
+inc(Tab, Handle, Cnt)
+ when is_atom(Cnt) ->
+ inc(Tab, Handle, Cnt, 1).
+
+inc(Tab, Handle, Cnt, Incr)
+ when is_atom(Cnt) andalso (is_integer(Incr) andalso (Incr > 0)) ->
+ Key = {Handle, Cnt},
+ do_inc(Tab, Key, Incr).
+
+do_inc(Tab, Key, Incr) ->
+ case (catch ets:update_counter(Tab, Key, Incr)) of
+ {'EXIT', {badarg, _Reason}} ->
+ ets:insert(Tab, {Key, Incr}),
+ Incr;
+ Val ->
+ Val
+ end.
+
+
+%%-----------------------------------------------------------------
+%% Func: get_stats/1, get_stats/2, get_stats/3
+%% Description: Get statistics
+%%-----------------------------------------------------------------
+get_stats(Ets) ->
+ Handles = get_handles_and_global_counters(Ets),
+ (catch do_get_stats(Ets, Handles, [])).
+
+do_get_stats(_Ets, [], Acc) ->
+ {ok, lists:reverse(Acc)};
+do_get_stats(Ets, [Handle|Handles], Acc) ->
+ case get_stats(Ets, Handle) of
+ {ok, Stats} ->
+ do_get_stats(Ets, Handles, [{Handle, Stats}|Acc]);
+ {error, Reason} ->
+ throw({error, Reason})
+ end.
+
+get_stats(Ets, GlobalCounter) when is_atom(GlobalCounter) ->
+ case (catch ets:lookup(Ets, GlobalCounter)) of
+ [{GlobalCounter, Val}] ->
+ {ok, Val};
+ [] ->
+ {error, {no_such_counter, GlobalCounter}}
+ end;
+
+get_stats(Ets, Handle) ->
+ case (catch ets:match(Ets, {{Handle, '$1'},'$2'})) of
+ CounterVals when is_list(CounterVals) ->
+ {ok, [{Counter, Val} || [Counter, Val] <- CounterVals]};
+ Other ->
+ {error, {unexpected_result, Other}}
+ end.
+
+
+get_stats(Ets, Handle, Counter) when is_atom(Counter) ->
+ Key = {Handle, Counter},
+ case (catch ets:lookup(Ets, Key)) of
+ [{Key, Val}] ->
+ {ok, Val};
+ _ ->
+ {error, {undefined_counter, Counter}}
+ end.
+
+
+%%-----------------------------------------------------------------
+%% Funcs: reset_stats/1, reset_stats/2
+%% Description: Reset statistics
+%%-----------------------------------------------------------------
+reset_stats(Ets) ->
+ Handles = get_handles_and_global_counters(Ets),
+ (catch do_reset_stats(Ets, Handles, [])).
+
+do_reset_stats(_Ets, [], Acc) ->
+ {ok, lists:reverse(Acc)};
+do_reset_stats(Ets, [Handle|Handles], Acc) ->
+ case reset_stats(Ets, Handle) of
+ {ok, OldStats} ->
+ do_reset_stats(Ets, Handles, [{Handle, OldStats}|Acc]);
+ {error, Reason} ->
+ throw({error, Reason})
+ end.
+
+reset_stats(Ets, GlobalCounter) when is_atom(GlobalCounter) ->
+ %% First get the current value of the counter
+ case (catch ets:lookup(Ets, GlobalCounter)) of
+ [{GlobalCounter, Val}] ->
+ ets:insert(Ets, {GlobalCounter, 0}),
+ {ok, Val};
+ [] -> %% Oooups
+ {error, {no_such_counter, GlobalCounter}}
+ end;
+
+reset_stats(Ets, Handle) ->
+ case (catch ets:match(Ets, {{Handle, '$1'},'$2'})) of
+ CounterVals when is_list(CounterVals) ->
+ CVs = [{Counter, Val} || [Counter, Val] <- CounterVals],
+ reset_stats(Ets, Handle, CVs),
+ {ok, CVs};
+ Other ->
+ {error, {unexpected_result, Other}}
+ end.
+
+reset_stats(_Ets, _Handle, []) ->
+ ok;
+reset_stats(Ets, Handle, [{Counter, _}|CVs]) ->
+ ets:insert(Ets, {{Handle, Counter}, 0}),
+ reset_stats(Ets, Handle, CVs).
+
+
+
+%%-----------------------------------------------------------------
+%% Internal functions
+%%-----------------------------------------------------------------
+get_handles_and_global_counters(Ets) ->
+ GlobalCounters =
+ case ets:lookup(Ets, global_counters) of
+ [{global_counters, GC}] ->
+ GC;
+ [] ->
+ []
+ end,
+ L1 = ets:match(Ets, {{'$1', '_'}, '_'}),
+ GlobalCounters ++
+ lists:sort([Handle || [Handle] <- remove_duplicates(L1, [])]).
+
+remove_duplicates([], L) ->
+ L;
+remove_duplicates([H|T], L) ->
+ case lists:member(H,T) of
+ true ->
+ remove_duplicates(T, L);
+ false ->
+ remove_duplicates(T, [H|L])
+ end.
+
diff --git a/lib/megaco/src/engine/megaco_sup.erl b/lib/megaco/src/engine/megaco_sup.erl
new file mode 100644
index 0000000000..c61a1da298
--- /dev/null
+++ b/lib/megaco/src/engine/megaco_sup.erl
@@ -0,0 +1,116 @@
+%%
+%% %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%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: The top supervisor for the Megaco/H.248 application
+%%----------------------------------------------------------------------
+
+-module(megaco_sup).
+
+-behaviour(application).
+-behaviour(supervisor).
+
+%% public
+-export([start/0, start/2, stop/1]).
+-export([start_sup_child/1, stop_sup_child/1]).
+
+%% internal
+-export([init/1]).
+
+%% debug
+-export([supervisor_timeout/1]).
+
+
+%% -define(d(F,A), io:format("~p~p:" ++ F ++ "~n", [self(),?MODULE|A])).
+-define(d(F,A), ok).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% application and supervisor callback functions
+
+start(normal, Args) ->
+ ?d("start(normal) -> entry with"
+ "~n Args: ~p", [Args]),
+ SupName = {local, ?MODULE},
+ case supervisor:start_link(SupName, ?MODULE, [Args]) of
+ {ok, Pid} ->
+ {ok, Pid, {normal, Args}};
+ Error ->
+ Error
+ end;
+start(_, _) ->
+ {error, badarg}.
+
+start() ->
+ ?d("start -> entry", []),
+ SupName = {local,?MODULE},
+ supervisor:start_link(SupName, ?MODULE, []).
+
+stop(_StartArgs) ->
+ ok.
+
+init([]) -> % Supervisor
+ init();
+init([[]]) -> % Application
+ init();
+init(BadArg) ->
+ ?d("init -> entry when"
+ "~n BadArg: ~p",[BadArg]),
+ {error, {badarg, BadArg}}.
+
+init() ->
+ ?d("init -> entry", []),
+ Flags = {one_for_one, 0, 1},
+ Sups = [sup_spec(megaco_misc_sup),
+ sup_spec(megaco_trans_sup),
+ worker_spec(megaco_config, [gen_server]),
+ worker_spec(megaco_monitor, [gen_server])],
+ ?d("init -> done when"
+ "~n Flags: ~p"
+ "~n Sups: ~p", [Flags, Sups]),
+ {ok, {Flags, Sups}}.
+
+
+start_sup_child(Name) ->
+ ?d("start_sup_child -> entry with Name: ~p", [Name]),
+ Spec = sup_spec(Name),
+ supervisor:start_child(?MODULE, Spec).
+
+
+stop_sup_child(Name) ->
+ ?d("stop_sup_child -> entry with Name: ~p", [Name]),
+ ok = supervisor:terminate_child(?MODULE, Name),
+ ok = supervisor:delete_child(?MODULE, Name).
+
+
+
+sup_spec(Name) ->
+ {Name, {Name, start, []}, permanent, 2000, supervisor,[Name, supervisor]}.
+
+worker_spec(Name, Modules) ->
+ {Name, {Name, start_link, []}, permanent, 2000, worker, [Name] ++ Modules}.
+
+-ifdef(debug_shutdown).
+supervisor_timeout(_KillAfter) -> timer:hours(500).
+-else.
+supervisor_timeout(KillAfter) -> KillAfter.
+-endif.
+
+
diff --git a/lib/megaco/src/engine/megaco_timer.erl b/lib/megaco/src/engine/megaco_timer.erl
new file mode 100644
index 0000000000..9f524523a8
--- /dev/null
+++ b/lib/megaco/src/engine/megaco_timer.erl
@@ -0,0 +1,117 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2007-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: Timer handling
+%%----------------------------------------------------------------------
+
+-module(megaco_timer).
+
+%% Application internal export
+-export([
+ init/1,
+ restart/1,
+ verify/1
+ ]).
+
+
+-include_lib("megaco/include/megaco.hrl").
+
+
+%%-----------------------------------------------------------------
+
+%% init(Timer) -> {TimeoutTime, NewTimer}
+%% Timer = megaco_timer()
+%% NewTimer = megaco_timer()
+%% TimeoutTime = infinity | integer()
+%%
+init(SingleWaitFor) when SingleWaitFor == infinity ->
+ {SingleWaitFor, timeout};
+init(SingleWaitFor) when is_integer(SingleWaitFor) and (SingleWaitFor >= 0) ->
+ {SingleWaitFor, timeout};
+init(Timer) when is_record(Timer, megaco_incr_timer) ->
+ return_incr(Timer).
+
+
+%% Returns {WaitFor, NewTimer} | {WaitFor, timeout}
+restart(#megaco_incr_timer{wait_for = Old,
+ factor = Factor,
+ incr = Incr,
+ max_retries = MaxRetries} = Timer) ->
+ New = wait_for(Old, Factor, Incr),
+ Max = decr(MaxRetries),
+ Timer2 = Timer#megaco_incr_timer{wait_for = New,
+ max_retries = Max},
+ return_incr(Timer2);
+restart({Timer, timeout}) when is_record(Timer, megaco_incr_timer) ->
+ restart(Timer).
+
+wait_for(Old, Factor, Incr) ->
+ New = (Old * Factor) + Incr,
+ if
+ New < 0 ->
+ 0;
+ true ->
+ New
+ end.
+
+verify(#megaco_incr_timer{wait_for = WaitFor,
+ factor = Factor,
+ incr = Incr,
+ max_retries = MaxRetries}) ->
+ (megaco_config:verify_strict_uint(WaitFor) and
+ megaco_config:verify_strict_uint(Factor) and
+ megaco_config:verify_strict_int(Incr) and
+ verify_max_retries(MaxRetries));
+verify(Timer) ->
+ megaco_config:verify_uint(Timer).
+
+verify_max_retries(infinity_restartable) ->
+ true;
+verify_max_retries(Val) ->
+ megaco_config:verify_uint(Val).
+
+
+%%-----------------------------------------------------------------
+
+
+return_incr(#megaco_incr_timer{wait_for = WaitFor,
+ max_retries = infinity} = Timer) ->
+ {WaitFor, Timer};
+
+return_incr(#megaco_incr_timer{wait_for = WaitFor,
+ max_retries = infinity_restartable} = Timer) ->
+ {WaitFor, {Timer, timeout}};
+
+return_incr(#megaco_incr_timer{wait_for = WaitFor,
+ max_retries = Int} = Timer)
+ when is_integer(Int) and (Int > 0) ->
+ {WaitFor, Timer};
+
+return_incr(#megaco_incr_timer{wait_for = WaitFor,
+ max_retries = 0} = _Timer) ->
+ {WaitFor, timeout}.
+
+
+decr(infinity = V) -> V;
+decr(infinity_restartable = V) -> V;
+decr(Int) when is_integer(Int) -> Int - 1.
+
+
diff --git a/lib/megaco/src/engine/megaco_trans_sender.erl b/lib/megaco/src/engine/megaco_trans_sender.erl
new file mode 100644
index 0000000000..710fef405a
--- /dev/null
+++ b/lib/megaco/src/engine/megaco_trans_sender.erl
@@ -0,0 +1,699 @@
+%%
+%% %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: Transaction sender process
+%%----------------------------------------------------------------------
+
+-module(megaco_trans_sender).
+
+-export([start_link/5,
+ stop/1,
+ upgrade/2,
+ send_req/3,
+ send_reqs/3,
+ send_ack/2,
+ send_ack_now/2,
+ send_pending/2,
+ send_reply/2,
+ timeout/2,
+ ack_maxcount/2,
+ req_maxcount/2,
+ req_maxsize/2]).
+-export([system_continue/3, system_terminate/4, system_code_change/4]).
+-export([init/6]).
+
+
+-include_lib("megaco/include/megaco.hrl").
+-include("megaco_message_internal.hrl").
+-include_lib("megaco/src/app/megaco_internal.hrl").
+
+
+-record(state,
+ {
+ parent,
+ conn_handle,
+ timeout,
+ req_sz = 0,
+ req_maxsize, %% Max total size of all accumulated reqs
+ req_maxcount,
+ ack_maxcount,
+ reqs = [],
+ acks = []
+ }).
+
+
+%%%-----------------------------------------------------------------
+%%% Public API
+%%%-----------------------------------------------------------------
+start_link(CH, To, MaxSzReqs, MaxNoReqs, MaxNoAcks) ->
+ ?d("start_link -> entry with"
+ "~n CH: ~p"
+ "~n To: ~p"
+ "~n MaxSzReqs: ~p"
+ "~n MaxNoReqs: ~p"
+ "~n MaxNoAcks: ~p", [CH, To, MaxSzReqs, MaxNoReqs, MaxNoAcks]),
+ Args = [self(), CH, To, MaxSzReqs, MaxNoReqs, MaxNoAcks],
+ proc_lib:start_link(?MODULE, init, Args).
+
+stop(Pid) when is_pid(Pid) ->
+ Pid ! stop,
+ ok.
+
+upgrade(Pid, CH) when is_pid(Pid) ->
+ Pid ! {upgrade, CH},
+ ok.
+
+send_req(Pid, Tid, Req) when is_pid(Pid) andalso is_binary(Req) ->
+ Pid ! {send_req, Tid, Req},
+ ok.
+
+send_reqs(Pid, Tids, Reqs)
+ when is_pid(Pid) andalso
+ is_list(Tids) andalso
+ is_list(Reqs) andalso
+ (length(Tids) =:= length(Reqs)) ->
+ Pid ! {send_reqs, Tids, Reqs},
+ ok.
+
+send_ack(Pid, Serial) when is_pid(Pid) andalso is_integer(Serial) ->
+ Pid ! {send_ack, Serial},
+ ok.
+
+send_ack_now(Pid, Serial) when is_pid(Pid) andalso is_integer(Serial) ->
+ Pid ! {send_ack_now, Serial},
+ ok.
+
+send_pending(Pid, Serial) when is_pid(Pid) andalso is_integer(Serial) ->
+ Pid ! {send_pending, Serial},
+ ok.
+
+send_reply(Pid, Reply) when is_pid(Pid) andalso is_binary(Reply) ->
+ Pid ! {send_reply, Reply}.
+
+ack_maxcount(Pid, Max) when is_pid(Pid) andalso is_integer(Max) ->
+ Pid ! {ack_maxcount, Max},
+ ok.
+
+req_maxcount(Pid, Max) when is_pid(Pid) andalso is_integer(Max) ->
+ Pid ! {req_maxcount, Max},
+ ok.
+
+req_maxsize(Pid, Max) when is_pid(Pid) andalso is_integer(Max) ->
+ Pid ! {req_maxsize, Max},
+ ok.
+
+timeout(Pid, Timeout) when is_pid(Pid) ->
+ Pid ! {timeout, Timeout},
+ ok.
+
+
+
+%%%-----------------------------------------------------------------
+%%% Internal exports
+%%%-----------------------------------------------------------------
+
+init(Parent, CH, To, MaxSzReqs, MaxNoReqs, MaxNoAcks) ->
+ ?d("init -> entry with"
+ "~n Parent: ~p"
+ "~n CH: ~p"
+ "~n To: ~p"
+ "~n MaxSzReqs: ~p"
+ "~n MaxNoReqs: ~p"
+ "~n MaxNoAcks: ~p", [Parent, CH, To, MaxSzReqs, MaxNoReqs, MaxNoAcks]),
+ process_flag(trap_exit, true),
+ proc_lib:init_ack(Parent, {ok, self()}),
+ S = #state{parent = Parent,
+ conn_handle = CH,
+ timeout = To,
+ req_maxsize = MaxSzReqs,
+ req_maxcount = MaxNoReqs,
+ ack_maxcount = MaxNoAcks},
+ loop(S, To).
+
+
+%%%-----------------------------------------------------------------
+%%% Internal functions
+%%%-----------------------------------------------------------------
+%% idle (= empty)
+loop(#state{reqs = [], acks = [], timeout = Timeout} = S, _) ->
+ receive
+ {send_ack, Serial} ->
+ ?d("loop(empty) -> received send_ack [~w] request", [Serial]),
+ loop(S#state{acks = [Serial]}, Timeout);
+
+ {send_ack_now, Serial} ->
+ ?d("loop(empty) -> received send_ack_now [~w] request", [Serial]),
+ send_msg(S#state.conn_handle, [], [Serial]),
+ loop(S, Timeout);
+
+ {send_req, Tid, Req} when size(Req) >= S#state.req_maxsize ->
+ ?d("loop(empty) -> received (big) send_req request ~w", [Tid]),
+ send_msg(S#state.conn_handle, [{Tid, Req}], []),
+ loop(S, Timeout);
+
+ {send_req, Tid, Req} ->
+ ?d("loop(empty) -> received send_req request ~w", [Tid]),
+ loop(S#state{req_sz = size(Req), reqs = [{Tid,Req}]}, Timeout);
+
+ {send_reqs, Tids, Reqs} ->
+ ?d("loop(empty) -> received send_reqs request: ~w", [Tids]),
+ {NewS, _} = handle_send_reqs(Tids, Reqs, S),
+ loop(NewS, Timeout);
+
+ {send_pending, Serial} ->
+ ?d("loop(empty) -> received send_pending [~w] request", [Serial]),
+ handle_send_result(
+ send_pending(S#state.conn_handle, Serial, [], [])
+ ),
+ loop(S, Timeout);
+
+ {send_reply, Reply} ->
+ ?d("loop(empty) -> received send_reply request", []),
+ #state{conn_handle = CH, req_maxsize = MaxSz} = S,
+ handle_send_result( send_reply(CH, Reply, MaxSz, 0, [], []) ),
+ loop(S, Timeout);
+
+ {upgrade, CH} ->
+ ?d("loop(empty) -> received upgrade request:"
+ "~n CH: ~p", [CH]),
+ loop(S#state{conn_handle = CH}, Timeout);
+
+ {ack_maxcount, NewMax} ->
+ ?d("loop(empty) -> received ack_maxcount request", []),
+ loop(S#state{ack_maxcount = NewMax}, Timeout);
+
+ {req_maxcount, NewMax} ->
+ ?d("loop(empty) -> received req_maxcount request", []),
+ loop(S#state{req_maxcount = NewMax}, Timeout);
+
+ {req_maxsize, NewMax} ->
+ ?d("loop(empty) -> received req_maxsize request", []),
+ loop(S#state{req_maxsize = NewMax}, Timeout);
+
+ {timeout, NewTimeout} ->
+ ?d("loop(empty) -> received timeout request", []),
+ loop(S#state{timeout = NewTimeout}, NewTimeout);
+
+ stop ->
+ ?d("loop(empty) -> received stop request", []),
+ exit(normal);
+
+ {system, From, Msg} ->
+ ?d("loop(empty) -> received system message:"
+ "~n From: ~p"
+ "~n Msg: ~p", [From, Msg]),
+ Parent = S#state.parent,
+ sys:handle_system_msg(Msg, From, Parent,
+ ?MODULE, [], {S, Timeout});
+
+ {'EXIT', Parent, Reason} when S#state.parent == Parent ->
+ ?d("loop(empty) -> received upgrade request", []),
+ exit(Reason);
+
+ M ->
+ warning_msg("received unexpected message (ignoring): "
+ "~n~p", [M]),
+ loop(S, Timeout)
+
+ end;
+
+%% active (= some acks or reqs waiting to to be sent)
+loop(#state{reqs = Reqs, acks = Acks, ack_maxcount = MaxAcks,
+ timeout = Timeout} = S, To)
+ when To >= 0 ->
+ Start = t(),
+ receive
+ {send_ack, Serial} when length(Acks) + 1 >= MaxAcks ->
+ ?d("loop(active,~w) -> "
+ "received [~w] send_ack [~w] request",
+ [To, length(Acks), Serial]),
+ handle_send_result(
+ send_msg(S#state.conn_handle, Reqs, [Serial|Acks])
+ ),
+ loop(S#state{req_sz = 0, reqs = [], acks = []}, Timeout);
+
+ {send_ack, Serial} ->
+ ?d("loop(active,~w) -> received send_ack [~w] request",
+ [To, Serial]),
+ loop(S#state{acks = [Serial|Acks]}, to(To, Start));
+
+ {send_ack_now, Serial} ->
+ ?d("loop(active,~w) -> [~w,~w] "
+ "received send_ack_now [~w] request",
+ [To, length(Reqs), length(Acks), Serial]),
+ handle_send_result(
+ send_msg(S#state.conn_handle, Reqs, [Serial|Acks])
+ ),
+ loop(S#state{req_sz = 0, reqs = [], acks = []}, Timeout);
+
+ %% We need to check that this is not a resend!!
+ %% In that case, send whatever we have in store
+ {send_req, Tid, Req} ->
+ ?d("loop(active,~w) -> received send_req request ~w", [To,Tid]),
+ {NewS, NewT} =
+ case handle_send_req(Tid, Req, S) of
+ {S1, true} ->
+ {S1, Timeout};
+ {S1, false} ->
+ {S1, to(To, Start)}
+ end,
+ loop(NewS, NewT);
+
+ {send_reqs, Tids, NewReqs} ->
+ ?d("loop(active,~w) -> received send_reqs request ~w", [To,Tids]),
+ {NewS, NewT} =
+ case handle_send_reqs(Tids, NewReqs, S) of
+ {S1, true} ->
+ {S1, Timeout};
+ {S1, false} ->
+ {S1, to(To, Start)}
+ end,
+ loop(NewS, NewT);
+
+ {send_pending, Serial} ->
+ ?d("loop(active,~w) -> received send_pending [~w] request",
+ [To, Serial]),
+ handle_send_result(
+ send_pending(S#state.conn_handle, Serial, Reqs, Acks)
+ ),
+ loop(S#state{req_sz = 0, reqs = [], acks = []}, Timeout);
+
+ {send_reply, Reply} ->
+ ?d("loop(active,~w) -> received send_reply request", [To]),
+ #state{conn_handle = CH, req_maxsize = MaxSz, req_sz = ReqSz} = S,
+ handle_send_result(
+ send_reply(CH, Reply, MaxSz, ReqSz, Reqs, Acks)
+ ),
+ loop(S#state{req_sz = 0, reqs = [], acks = []}, Timeout);
+
+ {upgrade, CH} ->
+ ?d("loop(active,~w) -> received upgrade request", [To]),
+ loop(S#state{conn_handle = CH}, to(To, Start));
+
+ {req_maxsize, NewMax} ->
+ ?d("loop(active,~w) -> received req_maxsize request", [To]),
+ loop(S#state{req_maxsize = NewMax}, to(To, Start));
+
+ {req_maxcount, NewMax} ->
+ ?d("loop(active,~w) -> received req_maxcount request", [To]),
+ loop(S#state{req_maxcount = NewMax}, to(To, Start));
+
+ {ack_maxcount, NewMax} ->
+ ?d("loop(active,~w) -> received ack_maxcount request", [To]),
+ loop(S#state{ack_maxcount = NewMax}, to(To, Start));
+
+ {timeout, NewTimeout} when NewTimeout > Timeout ->
+ ?d("loop(active,~w) -> received timeout request: ~w",
+ [To, NewTimeout]),
+ %% We need to recalculate To
+ NewTo = NewTimeout - (Timeout - to(To, Start)),
+ loop(S#state{timeout = NewTimeout}, NewTo);
+
+ {timeout, NewTimeout} ->
+ ?d("loop(active,~w) -> received timeout request: ~w",
+ [To, NewTimeout]),
+ %% We need to recalculate To
+ NewTo = to(To, Start) - (Timeout - NewTimeout),
+ loop(S#state{timeout = NewTimeout}, NewTo);
+
+ stop ->
+ ?d("loop(active,~w) -> received stop request", [To]),
+ handle_send_result( send_msg(S#state.conn_handle, Reqs, Acks) ),
+ exit(normal);
+
+ {system, From, Msg} ->
+ ?d("loop(active,~w) -> received system message:"
+ "~n From: ~p"
+ "~n Msg: ~p", [To, From, Msg]),
+ Parent = S#state.parent,
+ sys:handle_system_msg(Msg, From, Parent,
+ ?MODULE, [], {S, to(To, Start)});
+
+ {'EXIT', Parent, Reason} when S#state.parent == Parent ->
+ ?d("loop(active,~w) -> received exit request", [To]),
+ exit(Reason);
+
+ M ->
+ warning_msg("received unexpected message (ignoring): "
+ "~n~p", [M]),
+ loop(S, to(To, Start))
+
+ after To ->
+ ?d("loop(active,~w) -> timeout - time to send", [To]),
+ handle_send_result( send_msg(S#state.conn_handle, Reqs, Acks) ),
+ loop(S#state{req_sz = 0, reqs = [], acks = []}, Timeout)
+ end;
+
+loop(#state{reqs = Reqs, acks = Acks, timeout = Timeout} = S, _To) ->
+ ?d("loop(active) -> timeout [~w, ~w]", [length(Reqs),length(Acks)]),
+ handle_send_result( send_msg(S#state.conn_handle, Reqs, Acks) ),
+ loop(S#state{req_sz = 0, reqs = [], acks = []}, Timeout).
+
+
+%%%-----------------------------------------------------------------
+
+%% The request is itself larger then the max size, so first send
+%% everything we have stored in one message, and then the new request
+%% in another.
+%% Note that it does not matter if we with this request
+%% passed the maxcount limit.
+%% Note that this message cannot be a re-sent, since
+%% such a request would have been stored, but sent immediatly.
+handle_send_req(Tid, Req,
+ #state{conn_handle = CH,
+ req_maxsize = MaxSz, reqs = Reqs, acks = Acks} = S)
+ when size(Req) >= MaxSz ->
+ ?d("handle_send_req -> request bigger then maxsize ~w", [MaxSz]),
+ handle_send_result( send_msg(CH, Reqs, Acks) ),
+ handle_send_result( send_msg(CH, [{Tid, Req}], []) ),
+ {S#state{req_sz = 0, reqs = [], acks = []}, true};
+
+%% And handle all the other cases
+handle_send_req(Tid, Req,
+ #state{conn_handle = CH, req_sz = ReqSz,
+ req_maxcount = MaxReqs, req_maxsize = MaxSz,
+ reqs = Reqs, acks = Acks} = S) ->
+ case lists:keymember(Tid, 1, Reqs) of
+ true ->
+ %% A re-send, time to send whatever we have in the store
+ ?d("handle_send_req -> was a re-send, so flush",[]),
+ handle_send_result( send_msg(CH, Reqs, Acks) ),
+ {S#state{req_sz = 0, reqs = [], acks = []}, true};
+
+ false when length(Reqs) + 1 >= MaxReqs ->
+ %% We finally passed the req-maxcount limit
+ ?d("handle_send_req -> maxcount ~w passed", [MaxReqs]),
+ handle_send_result(
+ send_msg(S#state.conn_handle, [{Tid, Req}|Reqs], Acks)
+ ),
+ {S#state{req_sz = 0, reqs = [], acks = []}, true};
+
+ false when size(Req) + ReqSz >= MaxSz ->
+ %% We finally passed the req-maxsize limit
+ ?d("handle_send_req -> maxsize ~w passed", [MaxSz]),
+ handle_send_result(
+ send_msg(S#state.conn_handle, [{Tid, Req}|Reqs], Acks)
+ ),
+ {S#state{req_sz = 0, reqs = [], acks = []}, true};
+
+ false ->
+ %% Still not time to send
+ ?d("handle_send_req -> nothing to be sent",[]),
+ {S#state{req_sz = ReqSz + size(Req), reqs = [{Tid, Req}|Reqs]},
+ false}
+ end.
+
+
+%% We passed the req-maxcount limit: Time to send, atleast some of
+%% the stuff...
+handle_send_reqs(Tids, Reqs0,
+ #state{conn_handle = CH,
+ req_maxsize = MaxSz, req_sz = ReqSz,
+ req_maxcount = MaxReqs, reqs = Reqs, acks = Acks} = S)
+ when length(Reqs0) + length(Reqs) >= MaxReqs ->
+ ?d("handle_send_reqs -> maxcount ~w: ~w, ~w",
+ [MaxSz,length(Reqs0),length(Reqs)]),
+ Reqs1 = merge_tids_and_reqs(Tids, Reqs0, []),
+ {NewReqs, NewReqSz} = send_reqs(CH, Reqs1, Acks, Reqs, ReqSz, MaxSz),
+ ?d("handle_send_reqs -> sent:"
+ "~n NewReqSz: ~w"
+ "~n length(NewReqs): ~w", [NewReqSz, length(NewReqs)]),
+ {S#state{req_sz = NewReqSz, reqs = NewReqs, acks = []}, true};
+
+%% We did not pass the req-maxcount limit, but we could have passed the
+%% req-maxsize limit, so maybe send...
+handle_send_reqs(Tids, Reqs0, #state{conn_handle = CH,
+ req_maxsize = MaxSz, req_sz = ReqSz,
+ reqs = Reqs, acks = Acks} = S) ->
+ ?d("handle_send_reqs -> not maxcount - maybe maxsize (~w)", [MaxSz]),
+ Reqs1 = merge_tids_and_reqs(Tids, Reqs0, []),
+
+ case maybe_send_reqs(CH, Reqs1, Acks, Reqs, ReqSz, MaxSz, false) of
+ {NewReqs, NewReqSz, true} ->
+ ?d("handle_send_reqs -> sent:"
+ "~n NewReqSz: ~w"
+ "~n length(NewReqs): ~w", [NewReqSz, length(NewReqs)]),
+ {S#state{req_sz = NewReqSz, reqs = NewReqs, acks = []}, true};
+ {NewReqs, NewReqSz, false} ->
+ ?d("handle_send_reqs -> not sent:"
+ "~n NewReqSz: ~w"
+ "~n length(NewReqs): ~w", [NewReqSz, length(NewReqs)]),
+ {S#state{req_sz = NewReqSz, reqs = NewReqs}, false}
+ end.
+
+merge_tids_and_reqs([], [], Reqs) ->
+ Reqs;
+merge_tids_and_reqs([Tid|Tids], [Req|Reqs], Acc) ->
+ merge_tids_and_reqs(Tids, Reqs, [{Tid,Req}|Acc]).
+
+%% We know that we shall send, so if maybe_send_reqs does not,
+%% we send it our self...
+send_reqs(CH, Reqs, Acks, Acc, AccSz, MaxSz) ->
+ ?d("send_reqs -> entry when"
+ "~n length(Reqs): ~w"
+ "~n Acks: ~w"
+ "~n length(Acc): ~w"
+ "~n AccSz: ~w", [length(Reqs), Acks, length(Acc), AccSz]),
+ case maybe_send_reqs(CH, Reqs, Acks, Acc, AccSz, MaxSz, false) of
+ {NewReqs, _NewReqSz, false} ->
+ ?d("send_reqs -> nothing sent yet"
+ "~n length(NewReqs): ~w", [length(NewReqs)]),
+ handle_send_result( send_msg(CH, NewReqs, Acks) ),
+ {[], 0};
+ {NewReqs, NewReqSz, true} ->
+ ?d("send_reqs -> something sent"
+ "~n length(NewReqs): ~w"
+ "~n NewReqSz: ~w", [length(NewReqs), NewReqSz]),
+ {NewReqs, NewReqSz}
+ end.
+
+
+maybe_send_reqs(_CH, [], _Acks, Acc, AccSz, _MaxSz, Sent) ->
+ ?d("maybe_send_reqs -> done when"
+ "~n Sent: ~w"
+ "~n AccSz: ~w"
+ "~n length(Acc): ~w", [Sent, AccSz, length(Acc)]),
+ {Acc, AccSz, Sent};
+maybe_send_reqs(CH, [{Tid, Req}|Reqs], Acks, Acc, _AccSz, MaxSz, _Sent)
+ when size(Req) >= MaxSz ->
+ %% The request was above the maxsize limit, so first send
+ %% what's in store and the the big request.
+ ?d("maybe_send_reqs -> entry when request [~w] size (~w) > max size"
+ "~n Acks: ~w"
+ "~n length(Acc): ~w", [Tid, size(Req), Acks, length(Acc)]),
+ handle_send_result( send_msg(CH, Acc, Acks) ),
+ handle_send_result( send_msg(CH, [{Tid, Req}], []) ),
+ maybe_send_reqs(CH, Reqs, [], [], 0, MaxSz, true);
+maybe_send_reqs(CH, [{Tid, Req}|Reqs], Acks, Acc, AccSz, MaxSz, _Sent)
+ when AccSz + size(Req) >= MaxSz ->
+ %% We _did_ pass the maxsize limit with this request, so send
+ ?d("maybe_send_reqs -> entry when sum of requests (~w) > max size"
+ "~n Tid: ~w"
+ "~n Acks: ~w"
+ "~n length(Acc): ~w", [Tid, size(Req) + AccSz, Acks, length(Acc)]),
+ handle_send_result( send_msg(CH, [{Tid, Req}|Acc], Acks) ),
+ maybe_send_reqs(CH, Reqs, [], [], 0, MaxSz, true);
+maybe_send_reqs(CH, [{Tid, Req}|Reqs], Acks, Acc, AccSz, MaxSz, Sent) ->
+ ?d("maybe_send_reqs -> entry when"
+ "~n Tid: ~w"
+ "~n size(Req): ~w"
+ "~n Acks: ~w"
+ "~n length(Acc): ~w"
+ "~n AccSz: ~w", [Tid, size(Req), Acks, length(Acc), AccSz]),
+ NewAcc = [{Tid,Req}|Acc],
+ NewAccSz = AccSz + size(Req),
+ maybe_send_reqs(CH, Reqs, Acks, NewAcc, NewAccSz, MaxSz, Sent).
+
+
+%%%-----------------------------------------------------------------
+
+send_pending(CH, Serial, Reqs, Acks) ->
+ ?d("send_pending -> entry with"
+ "~n Serial: ~w"
+ "~n length(Reqs): ~w"
+ "~n length(Acks): ~w", [Serial, length(Reqs), length(Acks)]),
+ case megaco_config:lookup_local_conn(CH) of
+ [CD] ->
+ TP = #'TransactionPending'{transactionId = Serial},
+ Pend = {transactionPending, TP},
+ do_send_msg(CD, Pend, lists:reverse(Reqs), Acks);
+ [] ->
+ ok
+ end.
+
+
+%% We need to check the size of the reply. If the reply itself is
+%% larger then the max limit, then it is sent in a separate message.
+send_reply(CH, Reply, MaxSz, _ReqSz, Reqs, Acks) ->
+ ?d("send_reply -> entry with"
+ "~n length(Reqs): ~w"
+ "~n length(Acks): ~w", [length(Reqs), length(Acks)]),
+ case megaco_config:lookup_local_conn(CH) of
+ [CD] when size(Reply) > MaxSz ->
+ handle_send_result( send_msg(CD, lists:reverse(Reqs), Acks) ),
+ Rep = {transactionReply, Reply},
+ do_send_msg(CD, Rep, [], []);
+ [CD] ->
+ Rep = {transactionReply, Reply},
+ do_send_msg(CD, Rep, lists:reverse(Reqs), Acks);
+ [] ->
+ ok
+ end.
+
+do_send_msg(CD, Trans, [], []) ->
+ Body = {transactions, [Trans]},
+ Slogan = "send trans reply/pending",
+ ?d("do_send_msg -> ~s", [Slogan]),
+ megaco_messenger_misc:send_body(CD, Slogan, Body);
+do_send_msg(CD, Trans, Reqs0, []) ->
+ Reqs = [{transactionRequest, Req} || {_, Req} <- Reqs0],
+ Body = {transactions, [Trans|Reqs]},
+ Slogan = "send trans reply/pending and reqs",
+ ?d("do_send_msg -> ~s", [Slogan]),
+ megaco_messenger_misc:send_body(CD, Slogan, Body);
+do_send_msg(CD, Trans, [], SerialRanges) ->
+ Acks = make_acks(ranges(SerialRanges), []),
+ Body = {transactions, [Trans, {transactionResponseAck, Acks}]},
+ Slogan = "send trans reply/pending and acks",
+ ?d("do_send_msg -> ~s", [Slogan]),
+ megaco_messenger_misc:send_body(CD, Slogan, Body);
+do_send_msg(CD, Trans, Reqs0, SerialRanges) ->
+ Acks = make_acks(ranges(SerialRanges), []),
+ Reqs = [{transactionRequest, Req} || {_, Req} <- Reqs0],
+ Body = {transactions, [Trans, {transactionResponseAck, Acks}|Reqs]},
+ Slogan = "send trans reply/pending, reqs and acks",
+ ?d("do_send_msg -> ~s", [Slogan]),
+ megaco_messenger_misc:send_body(CD, Slogan, Body).
+
+
+
+send_msg(_, [], []) ->
+ ok;
+send_msg(CH, Reqs, Serials) ->
+ case megaco_config:lookup_local_conn(CH) of
+ [ConnData] ->
+ do_send_msg(ConnData, lists:reverse(Reqs), Serials);
+ [] ->
+ ok
+ end.
+
+
+do_send_msg(CD, Reqs0, []) ->
+ ?d("do_send_msg -> entry with"
+ "~n length(Reqs0): ~p", [length(Reqs0)]),
+ Reqs = [{transactionRequest, Req} || {_, Req} <- Reqs0],
+ %% ?d("do_send_msg -> Reqs: ~n~p", [Reqs]),
+ Body = {transactions, Reqs},
+ megaco_messenger_misc:send_body(CD, "send trans reqs", Body);
+do_send_msg(CD, [], SerialRanges) ->
+ ?d("do_send_msg -> entry with"
+ "~n SerialRanges: ~p", [SerialRanges]),
+ Acks = make_acks(ranges(SerialRanges), []),
+ %% ?d("do_send_msg -> Reqs: ~n~p", [Reqs]),
+ Body = {transactions, [{transactionResponseAck, Acks}]},
+ megaco_messenger_misc:send_body(CD, "send trans acks", Body);
+do_send_msg(CD, Reqs0, SerialRanges) ->
+ ?d("do_send_msg -> entry with"
+ "~n length(Reqs0): ~p"
+ "~n SerialRanges: ~p", [length(Reqs0), SerialRanges]),
+ Acks = make_acks(ranges(SerialRanges), []),
+ Reqs = [{transactionRequest, Req} || {_, Req} <- Reqs0],
+ %% ?d("do_send_msg -> Reqs: ~n~p", [Reqs]),
+ Body = {transactions, [{transactionResponseAck, Acks}|Reqs]},
+ megaco_messenger_misc:send_body(CD, "send trans reqs and acks", Body).
+
+
+handle_send_result(ok) ->
+ ok;
+handle_send_result({ok, _}) ->
+ ok;
+handle_send_result({error, {send_message_cancelled, _Reason}}) ->
+ ok;
+handle_send_result({error, {send_message_failed, Reason}}) ->
+ error_msg("Failed sending message: ~n ~p", [Reason]),
+ error;
+handle_send_result(Error) ->
+ error_msg("Failed sending message: ~n ~p", [Error]),
+ error.
+
+
+ranges(L) ->
+ lists:reverse(ranges(lists:sort(L), [], [])).
+
+ranges([], Range, Ranges) ->
+ ranges2(Range, Ranges);
+ranges([S1|Sn], [S2|_] = Range, Ranges) when S1 == (S2+1) ->
+ ranges(Sn, [S1|Range], Ranges);
+ranges([S|Sn], Range, Ranges) ->
+ ranges(Sn, [S], ranges2(Range, Ranges)).
+
+ranges2([], Ranges) ->
+ Ranges;
+ranges2([S], Ranges) ->
+ [{S,S}|Ranges];
+ranges2(Range0, Ranges) ->
+ Range = lists:reverse(Range0),
+ [{hd(Range),lists:last(Range)}|Ranges].
+
+
+make_acks([], Acks) ->
+ lists:reverse(Acks);
+make_acks([{S,S}|SerialRanges], Acks) ->
+ TRA = #'TransactionAck'{firstAck = S},
+ make_acks(SerialRanges, [TRA|Acks]);
+make_acks([{F,L}|SerialRanges], Acks) ->
+ TRA = #'TransactionAck'{firstAck = F, lastAck = L},
+ make_acks(SerialRanges, [TRA|Acks]).
+
+
+
+%%%-----------------------------------------------------------------
+
+to(To, Start) ->
+ To - (t() - Start).
+
+%% Time in milli seconds
+t() ->
+ {A,B,C} = erlang:now(),
+ A*1000000000+B*1000+(C div 1000).
+
+warning_msg(F, A) ->
+ ?megaco_warning("Transaction sender: " ++ F, A).
+
+error_msg(F, A) ->
+ ?megaco_error("Transaction sender: " ++ F, A).
+
+
+%%%-----------------------------------------------------------------
+%%% System messages handled here
+%%%-----------------------------------------------------------------
+
+system_continue(_Parent, _Dbg, {S,To}) ->
+ loop(S, To).
+
+system_terminate(Reason, _Parent, _Dbg, {S, _}) ->
+ #state{conn_handle = CH, reqs = Reqs, acks = Acks} = S,
+ send_msg(CH, Reqs, Acks),
+ exit(Reason).
+
+system_code_change(S, _Module, _OLdVsn, _Extra) ->
+ ?d("system_code_change -> entry", []),
+ {ok, S}.
diff --git a/lib/megaco/src/engine/megaco_trans_sup.erl b/lib/megaco/src/engine/megaco_trans_sup.erl
new file mode 100644
index 0000000000..6c4a0b7145
--- /dev/null
+++ b/lib/megaco/src/engine/megaco_trans_sup.erl
@@ -0,0 +1,88 @@
+%%
+%% %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: The supervisor for the Megaco/H.248 transaction sender
+%% processes.
+%%----------------------------------------------------------------------
+
+-module(megaco_trans_sup).
+
+-behaviour(supervisor).
+
+%% public
+-export([start/0, stop/1, init/1]).
+-export([start_trans_sender/5]).
+
+%% -define(d(F,A), io:format("~p~p:" ++ F ++ "~n", [self(),?MODULE|A])).
+-define(d(F,A), ok).
+
+start() ->
+ ?d("start -> entry",[]),
+ SupName = {local,?MODULE},
+ supervisor:start_link(SupName, ?MODULE, []).
+
+stop(_StartArgs) ->
+ ok.
+
+init([]) ->
+ init();
+init(BadArg) ->
+ {error, {badarg, BadArg}}.
+
+init() ->
+ ?d("init -> entry",[]),
+ Flags = {one_for_one, 500, 100},
+ Workers = [],
+ ?d("init -> done",[]),
+ {ok, {Flags, Workers}}.
+
+
+%%----------------------------------------------------------------------
+%% Function: start_ack_sender/3
+%% Description: Starts a transient worker (child) process
+%%----------------------------------------------------------------------
+
+start_trans_sender(CH, To, ReqsMaxSz, ReqsMax, AcksMax) ->
+ ?d("start_ack_sender -> entry with"
+ "~n CH: ~p"
+ "~n To: ~p"
+ "~n ReqsMaxSz: ~p"
+ "~n ReqsMax: ~p"
+ "~n AxksMax: ~p", [CH, To, ReqsMaxSz, ReqsMax, AcksMax]),
+ M = megaco_trans_sender,
+ F = start_link,
+ A = [CH, To, ReqsMaxSz, ReqsMax, AcksMax],
+ N = {M,CH},
+ Spec = {N,
+ {M,F,A},
+ temporary, timer:seconds(1), worker, [M,gen_server]},
+ case supervisor:start_child(?MODULE, Spec) of
+ {error, already_present} ->
+ supervisor:restart_child(?MODULE, N);
+ Else ->
+ Else
+ end.
+
+
+
+
+
+
diff --git a/lib/megaco/src/engine/megaco_transport.erl b/lib/megaco/src/engine/megaco_transport.erl
new file mode 100644
index 0000000000..79cec8781c
--- /dev/null
+++ b/lib/megaco/src/engine/megaco_transport.erl
@@ -0,0 +1,32 @@
+%%
+%% %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: Megaco transport behaviour module
+%%----------------------------------------------------------------------
+
+-module(megaco_transport).
+
+-export([behaviour_info/1]).
+
+behaviour_info(callbacks) ->
+ [{send_message,2}];
+behaviour_info(_) ->
+ undefined.
diff --git a/lib/megaco/src/engine/megaco_user_default.erl b/lib/megaco/src/engine/megaco_user_default.erl
new file mode 100644
index 0000000000..ff98107d57
--- /dev/null
+++ b/lib/megaco/src/engine/megaco_user_default.erl
@@ -0,0 +1,185 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1999-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: Default implementation of user callbacks
+%%----------------------------------------------------------------------
+
+-module(megaco_user_default).
+
+-behaviour(megaco_user).
+
+-export([
+ handle_connect/2, handle_connect/3,
+ handle_disconnect/3,
+ handle_syntax_error/3, handle_syntax_error/4,
+ handle_message_error/3, handle_message_error/4,
+ handle_trans_request/3, handle_trans_request/4,
+ handle_trans_long_request/3, handle_trans_long_request/4,
+ handle_trans_reply/4, handle_trans_reply/5,
+ handle_trans_ack/4, handle_trans_ack/5,
+ handle_unexpected_trans/3, handle_unexpected_trans/4,
+ handle_trans_request_abort/4, handle_trans_request_abort/5,
+ handle_segment_reply/5, handle_segment_reply/6
+ ]).
+
+-include_lib("megaco/include/megaco.hrl").
+-include_lib("megaco/include/megaco_message_v1.hrl").
+-include_lib("megaco/src/app/megaco_internal.hrl").
+
+
+%%----------------------------------------------------------------------
+%% Invoked when a new connection is established
+%%----------------------------------------------------------------------
+
+handle_connect(_ConnHandle, _ProtocolVersion) ->
+ ok.
+
+handle_connect(_ConnHandle, _ProtocolVersion, _ConnectInfo) ->
+ ok.
+
+
+%%----------------------------------------------------------------------
+%% Invoked when a connection is teared down
+%%----------------------------------------------------------------------
+
+handle_disconnect(ConnHandle, _ProtocolVersion, Reason) ->
+ megaco:cancel(ConnHandle, Reason), % Cancel the outstanding messages
+ ok.
+
+
+%%----------------------------------------------------------------------
+%% Invoked when a received message had syntax errors
+%%----------------------------------------------------------------------
+
+handle_syntax_error(_ReceiveHandle, _ProtocolVersion, _ErrorDescriptor) ->
+ reply.
+
+handle_syntax_error(_ReceiveHandle, _ProtocolVersion, _ErrorDescriptor, _Extra) ->
+ reply.
+
+
+%%----------------------------------------------------------------------
+%% Invoked when a received message contained no transactions
+%%----------------------------------------------------------------------
+
+handle_message_error(_ConnHandle, _ProtocolVersion, _ErrorDescriptor) ->
+ no_reply.
+
+handle_message_error(_ConnHandle, _ProtocolVersion, _ErrorDescriptor, _Extra) ->
+ no_reply.
+
+
+%%----------------------------------------------------------------------
+%% Invoked for each transaction request
+%%----------------------------------------------------------------------
+
+handle_trans_request(ConnHandle, ProtocolVersion, ActionRequests) ->
+ Extra = ?default_user_callback_extra,
+ handle_trans_request(ConnHandle, ProtocolVersion, ActionRequests, Extra).
+
+handle_trans_request(_ConnHandle, ProtocolVersion, _ActionRequests, _Extra) ->
+ case ProtocolVersion of
+ 1 ->
+ ED = #'ErrorDescriptor'{errorCode = ?megaco_not_implemented,
+ errorText = "Trans requests not handled"},
+ {discard_ack, ED};
+ _ ->
+ ED = #'ErrorDescriptor'{errorCode = ?megaco_version_not_supported,
+ errorText = "Only version 1 is supported"},
+ {discard_ack, ED}
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Optionally invoked for a time consuming transaction request
+%%----------------------------------------------------------------------
+
+handle_trans_long_request(ConnHandle, ProtocolVersion, ReqData) ->
+ Extra = ?default_user_callback_extra,
+ handle_trans_long_request(ConnHandle, ProtocolVersion, ReqData, Extra).
+
+handle_trans_long_request(_ConnHandle, _ProtocolVersion, _ReqData, _Extra) ->
+ ED = #'ErrorDescriptor'{errorCode = ?megaco_not_implemented,
+ errorText = "Long trans requests not handled"},
+ {discard_ack, ED}.
+
+
+%%----------------------------------------------------------------------
+%% Optionally invoked for a transaction reply
+%%----------------------------------------------------------------------
+
+handle_trans_reply(ConnHandle, ProtocolVersion, ActualReply, ReplyData) ->
+ Extra = ?default_user_callback_extra,
+ handle_trans_reply(ConnHandle, ProtocolVersion,
+ ActualReply, ReplyData, Extra).
+
+handle_trans_reply(ConnHandle, _, {error, {send_message_failed, Reason}}, _, _Extra) ->
+ megaco:disconnect(ConnHandle, {send_message_failed, Reason}),
+ ok;
+handle_trans_reply(_ConnHandle, _ProtocolVersion, _ActualReply, _ReplyData, _Extra) ->
+ ok.
+
+
+%%----------------------------------------------------------------------
+%% Optionally invoked for a transaction acknowledgement
+%%----------------------------------------------------------------------
+
+handle_trans_ack(_ConnHandle, _ProtocolVersion, _AckStatus, _AckData) ->
+ ok.
+
+handle_trans_ack(_ConnHandle, _ProtocolVersion, _AckStatus, _AckData, _Extra) ->
+ ok.
+
+
+%%----------------------------------------------------------------------
+%% Invoked when an unexpected message has been received
+%%----------------------------------------------------------------------
+
+handle_unexpected_trans(_ConnHandle, _ProtocolVersion, _Trans) ->
+ ok.
+
+handle_unexpected_trans(_ConnHandle, _ProtocolVersion, _Trans, _Extra) ->
+ ok.
+
+
+%%----------------------------------------------------------------------
+%% Invoked when an transaction has been aborted
+%% This happens when the originating pending limit has been exceeded
+%%----------------------------------------------------------------------
+
+handle_trans_request_abort(_ConnHandle, _ProtocolVersion, _TransId, _Pid) ->
+ ok.
+
+handle_trans_request_abort(_ConnHandle, _ProtocolVersion, _TransId, _Pid, _Extra) ->
+ ok.
+
+
+%%----------------------------------------------------------------------
+%% Invoked a segment reply has been received and the user has set
+%% config option segment_reply_ind = true.
+%%----------------------------------------------------------------------
+
+handle_segment_reply(_ConnHandle, _ProtocolVersion, _TransId, _SN, _SC) ->
+ ok.
+
+handle_segment_reply(_ConnHandle, _ProtocolVersion, _TransId, _SN, _SC, _Extra) ->
+ ok.
+
diff --git a/lib/megaco/src/engine/modules.mk b/lib/megaco/src/engine/modules.mk
new file mode 100644
index 0000000000..44bcadc37b
--- /dev/null
+++ b/lib/megaco/src/engine/modules.mk
@@ -0,0 +1,47 @@
+#-*-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%
+
+BEHAVIOUR_MODULES = \
+ megaco_edist_compress \
+ megaco_encoder \
+ megaco_transport
+
+MODULES = \
+ $(BEHAVIOUR_MODULES) \
+ megaco_config \
+ megaco_digit_map \
+ megaco_erl_dist_encoder \
+ megaco_erl_dist_encoder_mc \
+ megaco_filter \
+ megaco_messenger \
+ megaco_messenger_misc \
+ megaco_misc_sup \
+ megaco_monitor \
+ megaco_sdp \
+ megaco_sup \
+ megaco_stats \
+ megaco_timer \
+ megaco_trans_sender \
+ megaco_trans_sup \
+ megaco_user_default
+
+INTERNAL_HRL_FILES = \
+ megaco_message_internal.hrl
+
+
diff --git a/lib/megaco/src/flex/Makefile b/lib/megaco/src/flex/Makefile
new file mode 100644
index 0000000000..ab8183e548
--- /dev/null
+++ b/lib/megaco/src/flex/Makefile
@@ -0,0 +1,43 @@
+#
+# %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%
+
+#
+# Invoke with GNU make or clearmake -C gnu.
+#
+
+include $(ERL_TOP)/make/run_make.mk
+include modules.mk
+
+conf:
+ cd ../..; $(MAKE) conf
+
+dconf:
+ $(MAKE) FLEX_SCANNER_REENTRANT=disable conf
+
+econf:
+ $(MAKE) FLEX_SCANNER_REENTRANT=enable conf
+
+setup:
+ (cd ../../priv/lib && \
+ rm -f $(STD_DRV).so $(MT_DRV).so && \
+ ln -s $(TARGET)/$(STD_DRV).so && \
+ ln -s $(TARGET)/$(MT_DRV).so )
+
+info:
+ $(MAKE) -f $(TARGET)/Makefile $@
+
diff --git a/lib/megaco/src/flex/Makefile.in b/lib/megaco/src/flex/Makefile.in
new file mode 100644
index 0000000000..782d6a4807
--- /dev/null
+++ b/lib/megaco/src/flex/Makefile.in
@@ -0,0 +1,396 @@
+#
+# %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%
+
+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)
+
+
+# ----------------------------------------------------
+# The following variables differ on different systems, we set
+# reasonable defaults, if something different is needed it should
+# be set for that system only.
+# ----------------------------------------------------
+
+FLEX_VSN = $(shell flex --version)
+
+TMP_CFLAGS = @DED_CFLAGS@
+ifeq ($(TYPE),valgrind)
+CFLAGS = $(subst -O2, , $(TMP_CFLAGS)) -DVALGRIND
+else
+CFLAGS = $(TMP_CFLAGS)
+endif
+CC = @CC@
+CFLAGS_MT = $(CFLAGS) -D_THREAD_SAFE -D_REENTRANT
+LD = @DED_LD@
+LDFLAGS = @DED_LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+PERL = @PERL@
+ERLANG_OSTYPE = @ERLANG_OSTYPE@
+
+# Shall we build the flex scanner or not.
+# We assume that it does not exist on windows...
+ifeq ($(ENABLE_MEGACO_FLEX_SCANNER),)
+ifeq ($(findstring win32,$(TARGET)), win32)
+ENABLE_MEGACO_FLEX_SCANNER = false
+ENABLE_REENTRANT_MEGACO_FLEX_SCANNER = false
+else
+ENABLE_MEGACO_FLEX_SCANNER = @ENABLE_MEGACO_FLEX_SCANNER@
+ENABLE_REENTRANT_MEGACO_FLEX_SCANNER = @ENABLE_REENTRANT_MEGACO_FLEX_SCANNER@
+endif
+endif
+ERL_COMPILE_FLAGS += -DENABLE_MEGACO_FLEX_SCANNER=$(ENABLE_MEGACO_FLEX_SCANNER)
+
+ifeq ($(ENABLE_REENTRANT_MEGACO_FLEX_SCANNER),true)
+CFLAGS_MT += -DMEGACO_REENTRANT_FLEX_SCANNER
+MT_LEX_FLAGS += -R
+ERL_COMPILE_FLAGS += -DMEGACO_REENTRANT_FLEX_SCANNER=true
+else
+ERL_COMPILE_FLAGS += -DMEGACO_REENTRANT_FLEX_SCANNER=false
+endif
+
+# Shall the library be built with line-number checks or without
+ifeq ($(ENABLE_MEGACO_FLEX_SCANNER_LINENO),)
+# This is not really needed in this case (since we don't support
+# this for windows), but just to ensure that the variable _has_
+# a value...
+ifeq ($(findstring win32,$(TARGET)), win32)
+ENABLE_MEGACO_FLEX_SCANNER_LINENO = true
+else
+ENABLE_MEGACO_FLEX_SCANNER_LINENO = @ENABLE_MEGACO_FLEX_SCANNER_LINENO@
+endif
+endif
+
+
+SYSINCLUDE = -I$(ERL_TOP)/erts/emulator/beam \
+ -I$(ERL_TOP)/erts/emulator/sys/$(ERLANG_OSTYPE)
+ifeq ($(findstring vxworks,$(TARGET)),vxworks)
+ SYSINCLUDE += -I$(ERL_TOP)/erts/etc/vxworks
+endif
+
+DRIVER_INCLUDES = $(SYSINCLUDE)
+
+PRIVDIR = ../../priv
+LIBDIR = $(PRIVDIR)/lib/$(TARGET)
+
+
+# ----------------------------------------------------
+# Release directory specification
+# ----------------------------------------------------
+RELSYSDIR = $(RELEASE_PATH)/lib/megaco-$(VSN)
+
+
+# ----------------------------------------------------
+# Target Specs
+# ----------------------------------------------------
+
+include modules.mk
+
+ERL_FILES = $(MODULES:%=%.erl)
+
+TARGET_FILES = \
+ $(MODULES:%=$(EBIN)/%.$(EMULATOR))
+
+FLEX_SRC = $(FLEX_MODULES:%=%.flex.src)
+FLEX_FILES = $(STD_DRV).flex $(MT_DRV).flex
+
+C_TARGETS = $(STD_DRV).c $(MT_DRV).c
+
+
+# ----------------------------------------------------
+# Misc Macros
+# ----------------------------------------------------
+
+STD_DRV_NAME=-DMEGACO_DRV_NAME=\"$(STD_DRV)\"
+MT_DRV_NAME=-DMEGACO_DRV_NAME=\"$(MT_DRV)\"
+
+ifeq ($(findstring win32,$(TARGET)), win32)
+FLEX_SCANNER_SO =
+SOLIBS = $(FLEX_SCANNER_SO)
+else
+ifeq ($(findstring vxworks,$(TARGET)),vxworks)
+FLEX_SCANNER_SO =
+SOLIBS = $(FLEX_SCANNER_SO)
+else
+FLEX_SCANNER_SO = $(LIBDIR)/$(STD_DRV).so
+FLEX_SCANNER_MT_SO = $(LIBDIR)/$(MT_DRV).so
+SOLIBS = $(FLEX_SCANNER_SO) $(FLEX_SCANNER_MT_SO)
+endif
+endif
+
+
+# ----------------------------------------------------
+# FLAGS
+# ----------------------------------------------------
+ifeq ($(TYPE),debug)
+ERL_COMPILE_FLAGS += -Ddebug
+endif
+
+include ../app/megaco.mk
+
+ERL_COMPILE_FLAGS += \
+ $(MEGACO_ERL_COMPILE_FLAGS) \
+ -I../../include
+
+ifeq ($(MFS_DEBUG),true)
+CFLAGS += -DMFS_DEBUG=true
+endif
+
+ifeq ($(MFS_FLEX_PERF),true)
+STD_LEX_FLAGS += -p
+MT_LEX_FLAGS += -p
+endif
+
+ifeq ($(MFS_FLEX_DEBUG),true)
+CFLAGS += -DMFS_FLEX_DEBUG=1
+STD_LEX_FLAGS += -d
+MT_LEX_FLAGS += -d
+else
+CFLAGS += -DMFS_FLEX_DEBUG=0
+endif
+
+CFLAGS += $(DRIVER_INCLUDES) $(DRV_FLAGS) -funroll-loops -Wall
+
+#ifneq ($(FLEX_VSN),)
+#CFLAGS += -DFLEX_VERSION="$(FLEX_VSN)"
+#else
+#CFLAGS += -DFLEX_VERSION=unknown
+#endif
+
+ifeq ($(ENABLE_MEGACO_FLEX_SCANNER_LINENO),true)
+CFLAGS += -DMEGACO_LINENO
+STD_LEX_FLAGS += -Ca
+MT_LEX_FLAGS += -Ca
+ifeq ($(ENABLE_REENTRANT_MEGACO_FLEX_SCANNER),true)
+MT_LEX_FLAGS += --yylineno
+endif
+else
+CFLAGS += -DMEGACO_TOKENCNT
+STD_LEX_FLAGS += -Cfe
+MT_LEX_FLAGS += -Cfe
+endif
+
+
+
+# ----------------------------------------------------
+# Targets
+# ----------------------------------------------------
+
+ifeq ($(ENABLE_MEGACO_FLEX_SCANNER),true)
+debug opt: $(TARGET_FILES) $(C_TARGETS) solibs
+else
+debug opt: $(TARGET_FILES)
+endif
+
+clean:
+ rm -f $(TARGET_FILES)
+ rm -f $(FLEX_FILES)
+ rm -f $(C_TARGETS)
+ rm -f $(SOLIBS)
+ rm -f errs core *~
+
+docs:
+
+info:
+ @echo "ENABLE_MEGACO_FLEX_SCANNER = $(ENABLE_MEGACO_FLEX_SCANNER)"
+ @echo "ENABLE_MEGACO_FLEX_SCANNER_LINENO = $(ENABLE_MEGACO_FLEX_SCANNER_LINENO)"
+ @echo "ENABLE_REENTRANT_MEGACO_FLEX_SCANNER = $(ENABLE_REENTRANT_MEGACO_FLEX_SCANNER)"
+ @echo ""
+ @echo "FLEX_VSN = $(FLEX_VSN)"
+ @echo ""
+ @echo "CFLAGS = $(CFLAGS)"
+ @echo "CFLAGS_MT = $(CFLAGS_MT)"
+ @echo "DRV_FLAGS = $(DRV_FLAGS)"
+ @echo "STD_LEX_FLAGS = $(STD_LEX_FLAGS)"
+ @echo "MT_LEX_FLAGS = $(MT_LEX_FLAGS)"
+ @echo ""
+ @echo "MODULES = $(MODULES)"
+ @echo "ERL_FILES = $(ERL_FILES)"
+ @echo "TARGET_FILES = $(TARGET_FILES)"
+ @echo ""
+ @echo "FLEX_MODULES = $(FLEX_MODULES)"
+ @echo "FLEX_SRC = $(FLEX_SRC)"
+ @echo "FLEX_FILES = $(FLEX_FILES)"
+ @echo ""
+ @echo "C_TARGETS = $(C_TARGETS)"
+ @echo ""
+ @echo "LIBDIR = $(LIBDIR)"
+ @echo "LEXLIB = $(LEXLIB)"
+ @echo ""
+ @echo "STD_DRV = $(STD_DRV)"
+ @echo "MT_DRV = $(MT_DRV)"
+ @echo ""
+ @echo "STD_DRV_NAME = $(STD_DRV_NAME)"
+ @echo "MT_DRV_NAME = $(MT_DRV_NAME)"
+ @echo ""
+ @echo "SOLIBS = $(SOLIBS)"
+
+
+# ----------------------------------------------------
+# Release Target
+# ----------------------------------------------------
+include $(ERL_TOP)/make/otp_release_targets.mk
+
+
+release_spec: opt
+ $(INSTALL_DIR) $(RELSYSDIR)/ebin
+ $(INSTALL_DIR) $(RELSYSDIR)/src
+ $(INSTALL_DIR) $(RELSYSDIR)/src/flex
+ $(INSTALL_DIR) $(RELSYSDIR)/priv/lib
+ $(INSTALL_DIR) $(RELSYSDIR)/include
+ $(INSTALL_DATA) $(ERL_FILES) $(INTERNAL_HRL_FILES) $(RELSYSDIR)/src/flex
+ $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
+ifeq ($(ENABLE_MEGACO_FLEX_SCANNER),true)
+ $(INSTALL_DATA) $(FLEX_FILES) $(C_TARGETS) $(RELSYSDIR)/src/flex
+ $(INSTALL_DATA) $(SOLIBS) $(RELSYSDIR)/priv/lib
+endif
+
+
+release_docs_spec:
+
+# megaco_flex_scanner_drv.flex: megaco_flex_scanner_drv.flex.src
+# ifeq ($(ENABLE_MEGACO_FLEX_SCANNER_LINENO),true)
+# ifeq ($(ENABLE_REENTRANT_MEGACO_FLEX_SCANNER),true)
+# @printf "\treentrant [flex] scanner lineno enabled\n"
+# $(PERL) -p -e \
+# 's/%FLEX_VERSION%/$(FLEX_VSN)/ ; \
+# s/%MEGACO_YY_LINENO_OPTION%/%option yylineno/ ; \
+# s/%MEGACO_YY_REENTRANT_OPTION%/%option reentrant/ ; \
+# s/%MEGACO_DUMMY_DECL_YY_LINENO%/\/* static int yylineno = 1; *\//' \
+# < $< > $@
+# else
+# @printf "\tnon-reentrant [flex] scanner lineno enabled\n"
+# $(PERL) -p -e \
+# 's/%FLEX_VERSION%/$(FLEX_VSN)/ ; \
+# s/%MEGACO_YY_LINENO_OPTION%/%option yylineno/ ; \
+# s/%MEGACO_YY_REENTRANT_OPTION%/\/\* %option reentrant \*\// ; \
+# s/%MEGACO_DUMMY_DECL_YY_LINENO%/\/* static int yylineno = 1; *\//' \
+# < $< > $@
+# endif
+# else
+# ifeq ($(ENABLE_REENTRANT_MEGACO_FLEX_SCANNER),true)
+# @printf "\treentrant [flex] scanner lineno disabled\n"
+# $(PERL) -p -e \
+# 's/%FLEX_VERSION%/$(FLEX_VSN)/ ; \
+# s/%MEGACO_YY_LINENO_OPTION%/\/\* %option yylineno \*\// ; \
+# s/%MEGACO_YY_REENTRANT_OPTION%/%option reentrant/ ; \
+# s/%MEGACO_DUMMY_DECL_YY_LINENO%/\/* static int yylineno = 1; - REENTRANT SCANNER*\//' \
+# < $< > $@
+# else
+# @printf "\tnon-reentrant [flex] scanner lineno disabled\n"
+# $(PERL) -p -e \
+# 's/%FLEX_VERSION%/$(FLEX_VSN)/ ; \
+# s/%MEGACO_YY_LINENO_OPTION%/\/\* %option yylineno \*\// ; \
+# s/%MEGACO_YY_REENTRANT_OPTION%/\/\* %option reentrant \*\// ; \
+# s/%MEGACO_DUMMY_DECL_YY_LINENO%/static int yylineno = 1;/' \
+# < $< > $@
+# endif
+# endif
+#
+
+$(STD_DRV).flex: megaco_flex_scanner_drv.flex.src
+ifeq ($(ENABLE_MEGACO_FLEX_SCANNER_LINENO),true)
+ @printf "std [flex] scanner - lineno enabled\n"
+ $(PERL) -p -e \
+ 's/%FLEX_VERSION%/$(FLEX_VSN)/ ; \
+ s/%MEGACO_YY_LINENO_OPTION%/%option yylineno/ ; \
+ s/%MEGACO_YY_REENTRANT_OPTION%/\/\* %option reentrant \*\// ; \
+ s/%MEGACO_DUMMY_DECL_YY_LINENO%/\/* static int yylineno = 1; *\//' \
+ < $< > $@
+else
+ @printf "std [flex] scanner - lineno disabled\n"
+ $(PERL) -p -e \
+ 's/%FLEX_VERSION%/$(FLEX_VSN)/ ; \
+ s/%MEGACO_YY_LINENO_OPTION%/\/\* %option yylineno \*\// ; \
+ s/%MEGACO_YY_REENTRANT_OPTION%/\/\* %option reentrant \*\// ; \
+ s/%MEGACO_DUMMY_DECL_YY_LINENO%/static int yylineno = 1;/' \
+ < $< > $@
+endif
+
+$(MT_DRV).flex: megaco_flex_scanner_drv.flex.src
+ifeq ($(ENABLE_MEGACO_FLEX_SCANNER_LINENO),true)
+ifeq ($(ENABLE_REENTRANT_MEGACO_FLEX_SCANNER),true)
+ @printf "multi-threaded reentrant [flex] scanner - lineno enabled\n"
+ $(PERL) -p -e \
+ 's/%FLEX_VERSION%/$(FLEX_VSN)/ ; \
+ s/%MEGACO_YY_LINENO_OPTION%/%option yylineno/ ; \
+ s/%MEGACO_YY_REENTRANT_OPTION%/%option reentrant/ ; \
+ s/%MEGACO_DUMMY_DECL_YY_LINENO%/\/* static int yylineno = 1; *\//' \
+ < $< > $@
+else
+ @printf "multi-threaded non-reentrant [flex] scanner - lineno enabled\n"
+ $(PERL) -p -e \
+ 's/%FLEX_VERSION%/$(FLEX_VSN)/ ; \
+ s/%MEGACO_YY_LINENO_OPTION%/%option yylineno/ ; \
+ s/%MEGACO_YY_REENTRANT_OPTION%/\/\* %option reentrant \*\// ; \
+ s/%MEGACO_DUMMY_DECL_YY_LINENO%/\/* static int yylineno = 1; *\//' \
+ < $< > $@
+endif
+else
+ifeq ($(ENABLE_REENTRANT_MEGACO_FLEX_SCANNER),true)
+ @printf "multi-threaded reentrant [flex] scanner - lineno disabled\n"
+ $(PERL) -p -e \
+ 's/%FLEX_VERSION%/$(FLEX_VSN)/ ; \
+ s/%MEGACO_YY_LINENO_OPTION%/\/\* %option yylineno \*\// ; \
+ s/%MEGACO_YY_REENTRANT_OPTION%/%option reentrant/ ; \
+ s/%MEGACO_DUMMY_DECL_YY_LINENO%/\/* static int yylineno = 1; - REENTRANT SCANNER*\//' \
+ < $< > $@
+else
+ @printf "multi-threaded non-reentrant [flex] scanner - lineno disabled\n"
+ $(PERL) -p -e \
+ 's/%FLEX_VERSION%/$(FLEX_VSN)/ ; \
+ s/%MEGACO_YY_LINENO_OPTION%/\/\* %option yylineno \*\// ; \
+ s/%MEGACO_YY_REENTRANT_OPTION%/\/\* %option reentrant \*\// ; \
+ s/%MEGACO_DUMMY_DECL_YY_LINENO%/static int yylineno = 1;/' \
+ < $< > $@
+endif
+endif
+
+# megaco_flex_scanner_drv.c: megaco_flex_scanner_drv.flex
+# $(LEX) $(LEX_FLAGS) -P$* -o$@ $<
+$(STD_DRV).c: $(STD_DRV).flex
+ $(LEX) $(STD_LEX_FLAGS) -P$* -o$@ $<
+$(MT_DRV).c: $(MT_DRV).flex
+ $(LEX) $(MT_LEX_FLAGS) -P$* -o$@ $<
+
+solibs: $(LIBDIR) $(SOLIBS)
+
+# No need to link with -lfl as we have also defined %option noyywrap -
+# and having -lfl doesn't work under Darwin for some reason. - Sean
+$(LIBDIR)/$(STD_DRV).so: $(STD_DRV).c
+ @echo "std driver:"
+ $(CC) $(STD_DRV_NAME) $(CFLAGS) $(LDFLAGS) -o $(LIBDIR)/$(STD_DRV).so $<
+
+$(LIBDIR)/$(MT_DRV).so: $(MT_DRV).c
+ @echo "multi-threaded driver:"
+ $(CC) $(MT_DRV_NAME) $(CFLAGS_MT) $(LDFLAGS) -o $(LIBDIR)/$(MT_DRV).so $<
+
+$(LIBDIR):
+ -mkdir -p $(LIBDIR)
+
diff --git a/lib/megaco/src/flex/megaco_flex_scanner.erl b/lib/megaco/src/flex/megaco_flex_scanner.erl
new file mode 100644
index 0000000000..e471412c13
--- /dev/null
+++ b/lib/megaco/src/flex/megaco_flex_scanner.erl
@@ -0,0 +1,230 @@
+%%
+%% %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%
+%%
+
+%%----------------------------------------------------------------------
+%% Purpose : Scanner for text encoded Megaco/H.248 messages
+%%----------------------------------------------------------------------
+
+-module(megaco_flex_scanner).
+
+-export([is_enabled/0, is_reentrant_enabled/0, is_scanner_port/2]).
+-export([start/0, start/1, stop/1, scan/2]).
+
+-define(NUM_SCHED(), erlang:system_info(schedulers)).
+-define(SCHED_ID(), erlang:system_info(scheduler_id)).
+-define(SMP_SUPPORT_DEFAULT(), erlang:system_info(smp_support)).
+
+is_enabled() ->
+ case ?ENABLE_MEGACO_FLEX_SCANNER of
+ true ->
+ true;
+ _ ->
+ false
+ end.
+
+is_reentrant_enabled() ->
+ case ?MEGACO_REENTRANT_FLEX_SCANNER of
+ true ->
+ true;
+ _ ->
+ false
+ end.
+
+is_scanner_port(Port, Port) when is_port(Port) ->
+ true;
+is_scanner_port(Port, Ports) when is_tuple(Ports) ->
+ is_own_port(Port, Ports);
+is_scanner_port(_, _) ->
+ false.
+
+is_own_port(Port, Ports) ->
+ is_own_port(Port, size(Ports), Ports).
+
+is_own_port(_Port, 0, _Ports) ->
+ false;
+is_own_port(Port, N, Ports) when (N > 0) ->
+ case element(N, Ports) of
+ Port ->
+ true;
+ _ ->
+ is_own_port(Port, N-1, Ports)
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Start the flex scanner
+%%----------------------------------------------------------------------
+
+start() ->
+ start(?SMP_SUPPORT_DEFAULT()).
+
+start(SMP) when ((SMP =:= true) orelse (SMP =:= false)) ->
+ (catch do_start(is_reentrant_enabled() andalso SMP)).
+
+do_start(SMP) ->
+ Path = lib_dir(),
+ erl_ddll:start(),
+ load_driver(Path),
+ PortOrPorts = open_drv_port(SMP),
+ {ok, PortOrPorts}.
+
+
+lib_dir() ->
+ case code:priv_dir(megaco) of
+ {error, Reason} ->
+ throw({error, {priv_dir, Reason}});
+ P when is_list(P) ->
+ P ++ "/lib"
+ end.
+
+
+load_driver(Path) ->
+ case erl_ddll:load_driver(Path, drv_name()) of
+ ok ->
+ ok;
+ {error, Reason} ->
+ case (catch erl_ddll:format_error(Reason)) of
+ FormatReason when is_list(FormatReason) ->
+ throw({error, {load_driver, FormatReason}});
+ _ ->
+ throw({error, {load_driver, Reason}})
+ end
+ end.
+
+
+open_drv_port(true) ->
+ open_drv_ports(?NUM_SCHED(), []);
+open_drv_port(_) ->
+ open_drv_port().
+
+open_drv_ports(0, Acc) ->
+ list_to_tuple(Acc);
+open_drv_ports(N, Acc) when is_integer(N) andalso (N > 0) ->
+ Port = open_drv_port(),
+ open_drv_ports(N-1, [Port | Acc]).
+
+open_drv_port() ->
+ case (catch erlang:open_port({spawn, drv_name()}, [binary])) of
+ Port when is_port(Port) ->
+ Port;
+ {'EXIT', Reason} ->
+ erl_ddll:unload_driver(drv_name()),
+ throw({error, {open_port, Reason}})
+ end.
+
+drv_name() ->
+ case erlang:system_info(threads) of
+ true ->
+ "megaco_flex_scanner_drv_mt";
+ false ->
+ "megaco_flex_scanner_drv"
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Stop the flex scanner
+%%----------------------------------------------------------------------
+
+stop(Port) when is_port(Port) ->
+ erlang:port_close(Port),
+ erl_ddll:unload_driver(drv_name()),
+ stopped;
+stop(Ports) when is_tuple(Ports) ->
+ stop(tuple_to_list(Ports));
+stop(Ports) when is_list(Ports) ->
+ lists:foreach(fun(Port) -> erlang:port_close(Port) end, Ports),
+ erl_ddll:unload_driver(drv_name()),
+ stopped.
+
+
+%%----------------------------------------------------------------------
+%% Scan a message
+%%----------------------------------------------------------------------
+
+scan(Binary, Port) when is_port(Port) ->
+ do_scan(Binary, Port);
+scan(Binary, Ports) when is_tuple(Ports) ->
+%% p("scan -> entry with"
+%% "~n Ports: ~p", [Ports]),
+ do_scan(Binary, select_port(Ports)).
+
+do_scan(Binary, Port) ->
+%% p("do_scan -> entry with"
+%% "~n Port: ~p", [Port]),
+ case erlang:port_control(Port, $s, Binary) of
+ [] ->
+ receive
+ {tokens, Tokens, LatestLine} ->
+%% p("do_scan -> OK with:"
+%% "~n length(Tokens): ~p"
+%% "~n LatestLine: ~p", [length(Tokens), LatestLine]),
+ Vsn = version(Tokens),
+ {ok, Tokens, Vsn, LatestLine}
+ after 5000 ->
+%% p("do_scan -> ERROR", []),
+ {error, "Driver term send failure", 1}
+ end;
+ Reason ->
+%% p("do_scan -> port control failed: "
+%% "~n Reason: ~p", [Reason]),
+ {error, Reason, 1}
+ end.
+
+select_port(Ports) ->
+ SchedId = ?SCHED_ID(),
+ %% lists:nth(SchedId, Ports).
+ element(SchedId, Ports).
+
+version([]) ->
+ 99; % Let the parser deal with this
+version([{'SafeChars',_,"!/1"}|_]) ->
+ 1;
+version([{'SafeChars',_,"megaco/1"}|_]) ->
+ 1;
+version([{'SafeChars',_,"!/2"}|_]) ->
+ 2;
+version([{'SafeChars',_,"megaco/2"}|_]) ->
+ 2;
+version([{'SafeChars',_,"!/3"}|_]) ->
+ 3;
+version([{'SafeChars',_,"megaco/3"}|_]) ->
+ 3;
+version([{'SafeChars',_,[$!, $/ | Vstr]}|_]) ->
+ guess_version(Vstr);
+version([{'SafeChars',_,[$m, $e, $g, $a, $c, $o, $/ | Vstr]}|_]) ->
+ guess_version(Vstr);
+version([_|T]) ->
+ version(T).
+
+
+guess_version([C]) when (48 =< C) and (C =< 57) ->
+ C-48;
+guess_version(Str) when is_list(Str) ->
+ case (catch list_to_integer(Str)) of
+ I when is_integer(I) ->
+ I;
+ _ ->
+ 99 % Let the parser deal with this
+ end;
+guess_version(_) ->
+ 99. % Let the parser deal with this
+
+
+%% p(F, A) ->
+%% io:format("~w [~p,~p] " ++ F ++ "~n", [?MODULE, self(), ?SCHED_ID() | A]).
diff --git a/lib/megaco/src/flex/megaco_flex_scanner_drv.flex.src b/lib/megaco/src/flex/megaco_flex_scanner_drv.flex.src
new file mode 100644
index 0000000000..b96a69415d
--- /dev/null
+++ b/lib/megaco/src/flex/megaco_flex_scanner_drv.flex.src
@@ -0,0 +1,1943 @@
+ /*
+ * %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%
+ *
+ * ----------------------------------------------------------------------
+ * Purpose : Scanner for text encoded Megaco/H.248 messages
+ * ----------------------------------------------------------------------
+ *
+ * Throughout this file the prefix mfs is used for megaco_flex_scanner.
+ * The reason is to get shorter function and variable names.
+ */
+
+%option case-insensitive
+
+ /* MEGACO_YY_LINENO_OPTION
+ * Note that this construction is intended to make it
+ * possible to generate flex files that either reports
+ * line-number or one that don't.
+ * See MEGACO_DUMMY_DECL_YY_LINENO and
+ * MEGACO_LINENO_OR_TOKENCOUNTER below.
+ */
+%MEGACO_YY_LINENO_OPTION%
+
+%MEGACO_YY_REENTRANT_OPTION%
+%option noyywrap
+%option noinput
+%option nounput
+%{
+
+#define HAVE_UIO_H
+#include "erl_driver.h"
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#define TRUE 1
+#define FALSE 0
+#define SP 0x20
+#define HTAB 0x09
+#define CR 0x0d
+#define LF 0x0a
+#define SEMI_COLON 0x3b
+#define BACKSLASH 0x5c
+#define RBRKT 0x7b
+#define NUL 0x0
+
+#if defined(MEGACO_REENTRANT_FLEX_SCANNER)
+ #define MEGACO_EXTENDED_MARKER ERL_DRV_EXTENDED_MARKER
+ #define MEGACO_DRIVER_FLAGS ERL_DRV_FLAG_USE_PORT_LOCKING
+ #define MEGACO_EXTENDED_MAJOR_VERSION ERL_DRV_EXTENDED_MAJOR_VERSION
+ #define MEGACO_EXTENDED_MINOR_VERSION ERL_DRV_EXTENDED_MINOR_VERSION
+#else
+ #define MEGACO_EXTENDED_MARKER 0
+ #define MEGACO_DRIVER_FLAGS 0
+ #define MEGACO_EXTENDED_MAJOR_VERSION 0
+ #define MEGACO_EXTENDED_MINOR_VERSION 0
+#endif
+
+
+#define FREE(bufP) driver_free(bufP)
+#define ALLOC(sz) driver_alloc(sz)
+#define REALLOC(bufP, sz) driver_realloc(bufP, sz)
+
+#define YY_MAIN false
+
+// #define YY_FATAL_ERROR(msg) mfs_fatal_error(msg)
+
+
+typedef struct {
+ ErlDrvPort port;
+ char* digit_map_name_ptr;
+ int digit_map_name_len;
+ char* digit_map_value_ptr;
+ int digit_map_value_len;
+ char* digit_map_start_ptr;
+ char* digit_map_short_ptr;
+ char* digit_map_long_ptr;
+ char* digit_map_duration_ptr;
+ int error;
+ char error_msg[512];
+ char* text_buf;
+ char* text_ptr;
+ ErlDrvTermData* term_spec;
+ int term_spec_size;
+ int term_spec_index;
+ int token_counter;
+} MfsErlDrvData;
+
+#if !defined(MEGACO_REENTRANT_FLEX_SCANNER)
+static MfsErlDrvData mfs_drv_data;
+#endif
+
+char flex_version[] = "%FLEX_VERSION%";
+
+static ErlDrvTermData mfs_AddToken = 0;
+static ErlDrvTermData mfs_AndAUDITSelectToken = 0; /* v3 */
+static ErlDrvTermData mfs_AuditCapToken = 0;
+static ErlDrvTermData mfs_AuditToken = 0;
+static ErlDrvTermData mfs_AuditValueToken = 0;
+static ErlDrvTermData mfs_AuthToken = 0;
+static ErlDrvTermData mfs_BothToken = 0; /* v3 */
+static ErlDrvTermData mfs_BothwayToken = 0;
+static ErlDrvTermData mfs_BriefToken = 0;
+static ErlDrvTermData mfs_BufferToken = 0;
+static ErlDrvTermData mfs_COLON = 0;
+static ErlDrvTermData mfs_COMMA = 0;
+static ErlDrvTermData mfs_ContextAttrToken = 0; /* v3 */
+static ErlDrvTermData mfs_ContextAuditToken = 0;
+static ErlDrvTermData mfs_ContextListToken = 0; /* v3 */
+static ErlDrvTermData mfs_CtxToken = 0;
+static ErlDrvTermData mfs_DelayToken = 0;
+static ErlDrvTermData mfs_DeleteToken = 0;
+static ErlDrvTermData mfs_DigitMapDescriptor = 0;
+static ErlDrvTermData mfs_DigitMapDescriptorToken = 0;
+static ErlDrvTermData mfs_DigitMapToken = 0;
+static ErlDrvTermData mfs_DigitMapValue = 0;
+static ErlDrvTermData mfs_DirectionToken = 0; /* v3 */
+static ErlDrvTermData mfs_DiscardToken = 0;
+static ErlDrvTermData mfs_DisconnectedToken = 0;
+static ErlDrvTermData mfs_DurationToken = 0;
+static ErlDrvTermData mfs_EQUAL = 0;
+static ErlDrvTermData mfs_EmbedToken = 0;
+static ErlDrvTermData mfs_EmergencyToken = 0;
+static ErlDrvTermData mfs_EmergencyOffToken = 0; /* v3 */
+static ErlDrvTermData mfs_EmergencyValueToken = 0; /* v3 */
+static ErlDrvTermData mfs_ErrorToken = 0;
+static ErlDrvTermData mfs_EventBufferToken = 0;
+static ErlDrvTermData mfs_EventsToken = 0;
+static ErlDrvTermData mfs_ExternalToken = 0; /* v3 */
+static ErlDrvTermData mfs_FailoverToken = 0;
+static ErlDrvTermData mfs_ForcedToken = 0;
+static ErlDrvTermData mfs_GREATER = 0;
+static ErlDrvTermData mfs_GracefulToken = 0;
+static ErlDrvTermData mfs_H221Token = 0;
+static ErlDrvTermData mfs_H223Token = 0;
+static ErlDrvTermData mfs_H226Token = 0;
+static ErlDrvTermData mfs_HandOffToken = 0;
+static ErlDrvTermData mfs_IEPSToken = 0; /* v3 */
+static ErlDrvTermData mfs_IllegalChar = 0;
+static ErlDrvTermData mfs_ImmAckRequiredToken = 0;
+static ErlDrvTermData mfs_InactiveToken = 0;
+static ErlDrvTermData mfs_InSvcToken = 0;
+static ErlDrvTermData mfs_IntsigDelayToken = 0; /* v3 */
+static ErlDrvTermData mfs_InternalToken = 0; /* v3 */
+static ErlDrvTermData mfs_InterruptByEventToken = 0;
+static ErlDrvTermData mfs_InterruptByNewSignalsDescrToken = 0;
+static ErlDrvTermData mfs_IsolateToken = 0;
+static ErlDrvTermData mfs_IterationToken = 0; /* v3 */
+static ErlDrvTermData mfs_KeepActiveToken = 0;
+static ErlDrvTermData mfs_LBRKT = 0;
+static ErlDrvTermData mfs_LESSER = 0;
+static ErlDrvTermData mfs_LSBRKT = 0;
+static ErlDrvTermData mfs_LocalControlToken = 0;
+static ErlDrvTermData mfs_LocalDescriptorToken = 0;
+static ErlDrvTermData mfs_LocalToken = 0;
+static ErlDrvTermData mfs_LockStepToken = 0;
+static ErlDrvTermData mfs_LoopbackToken = 0;
+static ErlDrvTermData mfs_MediaToken = 0;
+static ErlDrvTermData mfs_MegacopToken = 0;
+static ErlDrvTermData mfs_MethodToken = 0;
+static ErlDrvTermData mfs_MessageSegmentToken = 0;
+static ErlDrvTermData mfs_MgcIdToken = 0;
+static ErlDrvTermData mfs_ModeToken = 0;
+static ErlDrvTermData mfs_ModemToken = 0;
+static ErlDrvTermData mfs_ModifyToken = 0;
+static ErlDrvTermData mfs_MoveToken = 0;
+static ErlDrvTermData mfs_MtpAddressToken = 0;
+static ErlDrvTermData mfs_MuxToken = 0;
+static ErlDrvTermData mfs_NEQUAL = 0;
+static ErlDrvTermData mfs_NeverNotifyToken = 0; /* v3 */
+static ErlDrvTermData mfs_NotifyCompletionToken = 0;
+static ErlDrvTermData mfs_NotifyImmediateToken = 0; /* v3 */
+static ErlDrvTermData mfs_NotifyRegulatedToken = 0; /* v3 */
+static ErlDrvTermData mfs_NotifyToken = 0;
+static ErlDrvTermData mfs_Nx64kToken = 0;
+static ErlDrvTermData mfs_ObservedEventsToken = 0;
+static ErlDrvTermData mfs_OffToken = 0;
+static ErlDrvTermData mfs_OnOffToken = 0;
+static ErlDrvTermData mfs_OnToken = 0;
+static ErlDrvTermData mfs_OnewayToken = 0;
+static ErlDrvTermData mfs_OnewayBothToken = 0; /* v3 */
+static ErlDrvTermData mfs_OnewayExternalToken = 0; /* v3 */
+static ErlDrvTermData mfs_OrAUDITselectToken = 0; /* v3 */
+static ErlDrvTermData mfs_OtherReasonToken = 0;
+static ErlDrvTermData mfs_OutOfSvcToken = 0;
+static ErlDrvTermData mfs_PackagesToken = 0;
+static ErlDrvTermData mfs_PendingToken = 0;
+static ErlDrvTermData mfs_PriorityToken = 0;
+static ErlDrvTermData mfs_ProfileToken = 0;
+static ErlDrvTermData mfs_QuotedChars = 0;
+static ErlDrvTermData mfs_RBRKT = 0;
+static ErlDrvTermData mfs_RSBRKT = 0;
+static ErlDrvTermData mfs_ReasonToken = 0;
+static ErlDrvTermData mfs_RecvonlyToken = 0;
+static ErlDrvTermData mfs_RemoteDescriptorToken = 0;
+static ErlDrvTermData mfs_RemoteToken = 0;
+static ErlDrvTermData mfs_RequestIDToken = 0; /* v3 */
+static ErlDrvTermData mfs_ReplyToken = 0;
+static ErlDrvTermData mfs_ReservedGroupToken = 0;
+static ErlDrvTermData mfs_ReservedValueToken = 0;
+static ErlDrvTermData mfs_ResetEventsDescriptorToken = 0; /* v3 */
+static ErlDrvTermData mfs_ResponseAckToken = 0;
+static ErlDrvTermData mfs_RestartToken = 0;
+static ErlDrvTermData mfs_SEP = 0;
+static ErlDrvTermData mfs_SafeChars = 0;
+static ErlDrvTermData mfs_SegmentationCompleteToken = 0; /* v3 */
+static ErlDrvTermData mfs_SendonlyToken = 0;
+static ErlDrvTermData mfs_SendrecvToken = 0;
+static ErlDrvTermData mfs_ServiceChangeAddressToken = 0;
+static ErlDrvTermData mfs_ServiceChangeIncompleteToken = 0; /* v3 */
+static ErlDrvTermData mfs_ServiceChangeToken = 0;
+static ErlDrvTermData mfs_ServiceStatesToken = 0;
+static ErlDrvTermData mfs_ServicesToken = 0;
+static ErlDrvTermData mfs_SignalListToken = 0;
+static ErlDrvTermData mfs_SignalTypeToken = 0;
+static ErlDrvTermData mfs_SignalsToken = 0;
+static ErlDrvTermData mfs_StatsToken = 0;
+static ErlDrvTermData mfs_StreamToken = 0;
+static ErlDrvTermData mfs_SubtractToken = 0;
+static ErlDrvTermData mfs_SynchISDNToken = 0;
+static ErlDrvTermData mfs_TerminationStateToken = 0;
+static ErlDrvTermData mfs_TestToken = 0;
+static ErlDrvTermData mfs_TimeOutToken = 0;
+static ErlDrvTermData mfs_TimeStampToken = 0; /* OTP-5042 */
+static ErlDrvTermData mfs_TopologyToken = 0;
+static ErlDrvTermData mfs_TransToken = 0;
+static ErlDrvTermData mfs_V18Token = 0;
+static ErlDrvTermData mfs_V22Token = 0;
+static ErlDrvTermData mfs_V22bisToken = 0;
+static ErlDrvTermData mfs_V32Token = 0;
+static ErlDrvTermData mfs_V32bisToken = 0;
+static ErlDrvTermData mfs_V34Token = 0;
+static ErlDrvTermData mfs_V76Token = 0;
+static ErlDrvTermData mfs_V90Token = 0;
+static ErlDrvTermData mfs_V91Token = 0;
+static ErlDrvTermData mfs_VersionToken = 0;
+static ErlDrvTermData mfs_asn1_NOVALUE = 0;
+static ErlDrvTermData mfs_endOfMessage = 0;
+static ErlDrvTermData mfs_PropertyParm = 0;
+static ErlDrvTermData mfs_ErrorDescriptor = 0;
+
+/* MEGACO_DUMMY_DECL_YY_LINENO
+ * Note that this construction is intended to make it
+ * possible to generate flex files that either reports
+ * line-number or one that don't.
+ * See MEGACO_YY_LINENO_OPTION above and
+ * MEGACO_LINENO_OR_TOKENCOUNTER below.
+ */
+#if !defined(MEGACO_REENTRANT_FLEX_SCANNER)
+%MEGACO_DUMMY_DECL_YY_LINENO%
+#endif
+
+/*
+static ErlDrvPort mfs_port = 0;
+static char* mfs_digit_map_name_ptr = 0;
+static int mfs_digit_map_name_len = 0;
+static char* mfs_digit_map_value_ptr = 0;
+static int mfs_digit_map_value_len = 0;
+static char* mfs_digit_map_start_ptr = 0;
+static char* mfs_digit_map_short_ptr = 0;
+static char* mfs_digit_map_long_ptr = 0;
+static char* mfs_digit_map_duration_ptr = 0;
+static int mfs_error = FALSE;
+static char mfs_error_msg[512];
+static char* mfs_text_buf = 0;
+static char* mfs_text_ptr = 0;
+static ErlDrvTermData* mfs_term_spec = 0;
+static int mfs_term_spec_size = 0;
+static int mfs_term_spec_index = 0;
+static int mfs_token_counter = 0;
+*/
+
+
+static void mfs_alloc_failed(MfsErlDrvData* dataP, char* msg, int sz);
+static void mfs_fatal_error(MfsErlDrvData* dataP, char* msg);
+static void mfs_ensure_term_spec(MfsErlDrvData* dataP, int size);
+
+#if defined(MEGACO_REENTRANT_FLEX_SCANNER)
+
+static void mfs_short_load_token(ErlDrvTermData token_tag,
+ yyscan_t yyscanner);
+static void mfs_lower_load_token(ErlDrvTermData token_tag, int is_empty,
+ yyscan_t yyscanner);
+static void mfs_octet_load_token(ErlDrvTermData token_tag, int is_empty,
+ yyscan_t yyscanner);
+static void mfs_load_property_groups(MfsErlDrvData* dataP, yyscan_t yyscanner);
+static void mfs_load_map_name(yyscan_t yyscanner);
+static void mfs_load_map_value(yyscan_t yyscanner);
+static void mfs_load_map_timer(yyscan_t yyscanner);
+static void mfs_load_map_token(yyscan_t yyscanner);
+
+#else
+
+static void mfs_short_load_token(ErlDrvTermData token_tag);
+static void mfs_lower_load_token(ErlDrvTermData token_tag, int is_empty);
+static void mfs_octet_load_token(ErlDrvTermData token_tag, int is_empty);
+static void mfs_load_property_groups(MfsErlDrvData* dataP);
+static void mfs_load_map_name();
+static void mfs_load_map_value();
+static void mfs_load_map_timer();
+static void mfs_load_map_token();
+
+#endif
+
+static ErlDrvData mfs_start(ErlDrvPort port, char *buf);
+static void mfs_stop(ErlDrvData handle);
+static void mfs_command(ErlDrvData handle,
+ char *buf, int buf_len);
+static int mfs_control(ErlDrvData handle,
+ unsigned int command,
+ char *buf, int buf_len,
+ char **res_buf, int res_buf_len);
+static void mfs_finish(void);
+
+/*
+ * The driver entry
+ */
+
+static ErlDrvEntry mfs_entry = {
+ NULL, /* init, always NULL for dynamic drivers */
+ mfs_start, /* start, called when port is opened */
+ mfs_stop, /* stop, called when port is closed */
+ mfs_command, /* output, called when erlang has sent */
+ NULL, /* ready_input, called when input descriptor ready */
+ NULL, /* ready_output, called when output descriptor ready */
+ MEGACO_DRV_NAME, /* char *driver_name, the arg to open_port */
+ mfs_finish, /* finish, called when unloaded */
+ NULL, /* void * that is not used (BC) */
+ mfs_control, /* control, port_control callback */
+ NULL, /* timeout, called on timeouts */
+ NULL, /* outputv, vector output interface */
+ NULL, /* ready_async, called after an asynchronous call has completed */
+ NULL, /* flush, port is about to be closed */
+ NULL, /* call, a syncronous call into the driver */
+ NULL, /* event, event selected by driver_event() has occurred */
+ MEGACO_EXTENDED_MARKER, /* extended_marker, which we use if reentrant */
+ MEGACO_EXTENDED_MAJOR_VERSION, /* major_version, ... */
+ MEGACO_EXTENDED_MINOR_VERSION, /* minor_version, ... */
+ MEGACO_DRIVER_FLAGS, /* driver_flags, used for port lock indication */
+ NULL, /* handle2, emulator internal use */
+ NULL /* process_exit, Called when a process monitor fires */
+#if defined(MEGACO_DRV_ENTRY_HAS_STOP_SELECT)
+ ,NULL /* stop_select, Called to close an event object */
+#endif
+};
+
+
+#if defined(MEGACO_REENTRANT_FLEX_SCANNER)
+
+#define LOAD_TOKEN(TokenTag) mfs_lower_load_token(TokenTag, FALSE, yyscanner)
+#define LOAD_EMPTY_TOKEN(TokenTag) mfs_lower_load_token(TokenTag, TRUE, yyscanner)
+#define LOAD_SHORT_TOKEN(TokenTag) mfs_short_load_token(TokenTag, yyscanner)
+#define LOAD_OCTET_TOKEN(TokenTag) mfs_octet_load_token(TokenTag, FALSE, yyscanner)
+#define LOAD_EMPTY_OCTET_TOKEN(TokenTag) mfs_octet_load_token(TokenTag, TRUE, yyscanner)
+#define LOAD_MAP_NAME() mfs_load_map_name(yyscanner)
+#define LOAD_MAP_TIMER() mfs_load_map_timer(yyscanner)
+#define LOAD_MAP_TOKEN() mfs_load_map_token(yyscanner)
+#define LOAD_MAP_VALUE() mfs_load_map_value(yyscanner)
+#define LOAD_PROP_GRPS(dataP) mfs_load_property_groups(dataP, yyscanner)
+
+#else
+
+#define LOAD_TOKEN(TokenTag) mfs_lower_load_token(TokenTag, FALSE)
+#define LOAD_EMPTY_TOKEN(TokenTag) mfs_lower_load_token(TokenTag, TRUE)
+#define LOAD_SHORT_TOKEN(TokenTag) mfs_short_load_token(TokenTag)
+#define LOAD_OCTET_TOKEN(TokenTag) mfs_octet_load_token(TokenTag, FALSE)
+#define LOAD_EMPTY_OCTET_TOKEN(TokenTag) mfs_octet_load_token(TokenTag, TRUE)
+#define LOAD_MAP_NAME() mfs_load_map_name()
+#define LOAD_MAP_TIMER() mfs_load_map_timer()
+#define LOAD_MAP_TOKEN() mfs_load_map_token()
+#define LOAD_MAP_VALUE() mfs_load_map_value()
+#define LOAD_PROP_GRPS(dataP) mfs_load_property_groups(dataP)
+
+#endif
+
+/* OTP-4236 */
+#define ASSIGN_TERM_SPEC(dataP, what) \
+{ \
+ if (dataP->term_spec != NULL) { \
+ dataP->term_spec[dataP->term_spec_index++] = what; \
+ } \
+}
+
+%}
+
+%x SKIP_RBRKT MTP_HEXDIG LOCAL_OCTETS REMOTE_OCTETS
+%x MAP_NAME MAP_OPT_LBRKT MAP_VALUE MAP_SKIP_COMMA MAP_BODY
+%x QUOTED_CHARS SKIP_DQUOTE
+
+digit ([0-9])
+alpha ([a-zA-Z])
+hexdig ([0-9a-fA-F])
+sp (\x20)
+htab (\x09)
+cr (\x0D)
+lf (\x0A)
+slash (\/)
+dquote (\")
+colon (\:)
+dot (\.)
+wsp ({sp}|{htab})
+eol ({cr}|({cr}{lf})|{lf})
+safechar ({digit}|{alpha}|[\+\-\&\!\_\/\'\?\@\^\`\~\*\$\\\(\)\%\|\.])
+restchar ([\;\[\]\{\}\:\,\#\<\>\=])
+octet ((\\\})|[\x01-\x7C\x7E-\xFF])
+
+comment (\;({safechar}|{restchar}|{wsp}|\x22)*{eol})
+lwsp ({wsp}|{comment}|{eol})*
+
+equal ({lwsp}\={lwsp})
+nequal ({lwsp}\#{lwsp})
+lesser ({lwsp}\<{lwsp})
+greater ({lwsp}\>{lwsp})
+lbrkt ({lwsp}\{{lwsp})
+rbrkt ({lwsp}\}{lwsp})
+lsbrkt ({lwsp}\[{lwsp})
+rsbrkt ({lwsp}\]{lwsp})
+lpar ({lwsp}\({lwsp})
+rpar ({lwsp}\){lwsp})
+vbar ({lwsp}\|{lwsp})
+comma ({lwsp}\,{lwsp})
+sep (({wsp}|{eol}|{comment}){lwsp})+
+opt ((o\-)?)
+wild ((w\-)?)
+
+%%
+
+<SKIP_RBRKT>{rbrkt} BEGIN(INITIAL);
+
+{digit}{8,8}t{digit}{8,8} LOAD_TOKEN(mfs_TimeStampToken); /* OTP-5042 */
+
+(MTP){lbrkt} BEGIN(MTP_HEXDIG);
+<MTP_HEXDIG>{hexdig}{4,8} {LOAD_TOKEN(mfs_MtpAddressToken); BEGIN(SKIP_RBRKT);}
+
+((Local)|L){lbrkt} BEGIN(LOCAL_OCTETS);
+<LOCAL_OCTETS>{rbrkt} {LOAD_EMPTY_OCTET_TOKEN(mfs_LocalDescriptorToken); BEGIN(INITIAL);}
+<LOCAL_OCTETS>{octet}+ {LOAD_OCTET_TOKEN(mfs_LocalDescriptorToken); BEGIN(SKIP_RBRKT);}
+
+((Remote)|R){lbrkt} BEGIN(REMOTE_OCTETS);
+<REMOTE_OCTETS>{rbrkt} {LOAD_EMPTY_OCTET_TOKEN(mfs_RemoteDescriptorToken); BEGIN(INITIAL);}
+<REMOTE_OCTETS>{octet}+ {LOAD_OCTET_TOKEN(mfs_RemoteDescriptorToken); BEGIN(SKIP_RBRKT);}
+
+((DigitMap)|DM) LOAD_TOKEN(mfs_DigitMapToken);
+((DigitMap)|DM){equal} BEGIN(MAP_NAME);
+((DigitMap)|DM){equal}{lbrkt} BEGIN(MAP_VALUE);
+((DigitMap)|DM){lbrkt} BEGIN(MAP_VALUE);
+
+<MAP_NAME>{safechar}+ {LOAD_MAP_NAME(); BEGIN(MAP_OPT_LBRKT);}
+
+<MAP_OPT_LBRKT>{lbrkt} BEGIN(MAP_VALUE);
+<MAP_OPT_LBRKT><<EOF>> {LOAD_MAP_TOKEN(); LOAD_TOKEN(mfs_endOfMessage); BEGIN(INITIAL); yyterminate();}
+<MAP_OPT_LBRKT>.|\n {LOAD_MAP_TOKEN(); yyless(0); BEGIN(INITIAL);}
+
+<MAP_VALUE>t{colon}{digit}{1,2} {LOAD_MAP_TIMER(); BEGIN(MAP_SKIP_COMMA);}
+<MAP_VALUE>s{colon}{digit}{1,2} {LOAD_MAP_TIMER(); BEGIN(MAP_SKIP_COMMA);}
+<MAP_VALUE>l{colon}{digit}{1,2} {LOAD_MAP_TIMER(); BEGIN(MAP_SKIP_COMMA);}
+<MAP_VALUE>z{colon}{digit}{1,2} {LOAD_MAP_TIMER(); BEGIN(MAP_SKIP_COMMA);}
+<MAP_VALUE>.|\n {yyless(0); BEGIN(MAP_BODY);}
+
+<MAP_SKIP_COMMA>{comma} BEGIN(MAP_VALUE);
+
+<MAP_BODY>{octet}+ {LOAD_MAP_VALUE(); LOAD_MAP_TOKEN(); BEGIN(SKIP_RBRKT);}
+
+{equal} LOAD_SHORT_TOKEN(mfs_EQUAL);
+{colon} LOAD_SHORT_TOKEN(mfs_COLON);
+{lbrkt} LOAD_SHORT_TOKEN(mfs_LBRKT);
+{rbrkt} LOAD_SHORT_TOKEN(mfs_RBRKT);
+{lsbrkt} LOAD_SHORT_TOKEN(mfs_LSBRKT);
+{rsbrkt} LOAD_SHORT_TOKEN(mfs_RSBRKT);
+{comma} LOAD_SHORT_TOKEN(mfs_COMMA);
+{nequal} LOAD_SHORT_TOKEN(mfs_NEQUAL);
+{lesser} LOAD_SHORT_TOKEN(mfs_LESSER);
+{greater} LOAD_SHORT_TOKEN(mfs_GREATER);
+{sep} LOAD_SHORT_TOKEN(mfs_SEP);
+
+{dquote} BEGIN(QUOTED_CHARS);
+
+<QUOTED_CHARS>{dquote} {LOAD_EMPTY_TOKEN(mfs_QuotedChars); BEGIN(INITIAL);}
+<QUOTED_CHARS>({safechar}|{restchar}|{wsp})+ {LOAD_TOKEN(mfs_QuotedChars); BEGIN(SKIP_DQUOTE);}
+
+<SKIP_DQUOTE>{dquote} BEGIN(INITIAL);
+
+{opt}{wild}add LOAD_TOKEN(mfs_AddToken);
+{opt}{wild}a LOAD_TOKEN(mfs_AddToken);
+andlgc LOAD_TOKEN(mfs_AndAUDITSelectToken);
+audit LOAD_TOKEN(mfs_AuditToken);
+at LOAD_TOKEN(mfs_AuditToken);
+{opt}{wild}auditcapability LOAD_TOKEN(mfs_AuditCapToken);
+{opt}{wild}ac LOAD_TOKEN(mfs_AuditCapToken);
+{opt}{wild}auditvalue LOAD_TOKEN(mfs_AuditValueToken);
+{opt}{wild}av LOAD_TOKEN(mfs_AuditValueToken);
+authentication LOAD_TOKEN(mfs_AuthToken);
+au LOAD_TOKEN(mfs_AuthToken);
+both LOAD_TOKEN(mfs_BothToken);
+b LOAD_TOKEN(mfs_BothToken);
+bothway LOAD_TOKEN(mfs_BothwayToken);
+bw LOAD_TOKEN(mfs_BothwayToken);
+brief LOAD_TOKEN(mfs_BriefToken);
+br LOAD_TOKEN(mfs_BriefToken);
+buffer LOAD_TOKEN(mfs_BufferToken);
+bf LOAD_TOKEN(mfs_BufferToken);
+context LOAD_TOKEN(mfs_CtxToken);
+c LOAD_TOKEN(mfs_CtxToken);
+contextattr LOAD_TOKEN(mfs_ContextAttrToken);
+ct LOAD_TOKEN(mfs_ContextAttrToken);
+contextaudit LOAD_TOKEN(mfs_ContextAuditToken);
+ca LOAD_TOKEN(mfs_ContextAuditToken);
+contextlist LOAD_TOKEN(mfs_ContextListToken);
+clt LOAD_TOKEN(mfs_ContextListToken);
+spadirection LOAD_TOKEN(mfs_DirectionToken);
+direction LOAD_TOKEN(mfs_DirectionToken);
+spadi LOAD_TOKEN(mfs_DirectionToken);
+di LOAD_TOKEN(mfs_DirectionToken);
+discard LOAD_TOKEN(mfs_DiscardToken);
+ds LOAD_TOKEN(mfs_DiscardToken);
+disconnected LOAD_TOKEN(mfs_DisconnectedToken);
+dc LOAD_TOKEN(mfs_DisconnectedToken);
+delay LOAD_TOKEN(mfs_DelayToken);
+dl LOAD_TOKEN(mfs_DelayToken);
+delete LOAD_TOKEN(mfs_DeleteToken);
+de LOAD_TOKEN(mfs_DeleteToken);
+duration LOAD_TOKEN(mfs_DurationToken);
+dr LOAD_TOKEN(mfs_DurationToken);
+embed LOAD_TOKEN(mfs_EmbedToken);
+em LOAD_TOKEN(mfs_EmbedToken);
+emergency LOAD_TOKEN(mfs_EmergencyToken);
+eg LOAD_TOKEN(mfs_EmergencyToken);
+emergencyoff LOAD_TOKEN(mfs_EmergencyOffToken);
+emergencyofftoken LOAD_TOKEN(mfs_EmergencyOffToken);
+ego LOAD_TOKEN(mfs_EmergencyOffToken);
+emergencyvalue LOAD_TOKEN(mfs_EmergencyValueToken);
+egv LOAD_TOKEN(mfs_EmergencyValueToken);
+error LOAD_TOKEN(mfs_ErrorToken);
+er LOAD_TOKEN(mfs_ErrorToken);
+eventbuffer LOAD_TOKEN(mfs_EventBufferToken);
+eb LOAD_TOKEN(mfs_EventBufferToken);
+events LOAD_TOKEN(mfs_EventsToken);
+e LOAD_TOKEN(mfs_EventsToken);
+external LOAD_TOKEN(mfs_ExternalToken);
+ex LOAD_TOKEN(mfs_ExternalToken);
+failover LOAD_TOKEN(mfs_FailoverToken);
+fl LOAD_TOKEN(mfs_FailoverToken);
+forced LOAD_TOKEN(mfs_ForcedToken);
+fo LOAD_TOKEN(mfs_ForcedToken);
+graceful LOAD_TOKEN(mfs_GracefulToken);
+gr LOAD_TOKEN(mfs_GracefulToken);
+h221 LOAD_TOKEN(mfs_H221Token);
+h223 LOAD_TOKEN(mfs_H223Token);
+h226 LOAD_TOKEN(mfs_H226Token);
+handoff LOAD_TOKEN(mfs_HandOffToken);
+ho LOAD_TOKEN(mfs_HandOffToken);
+iepscall LOAD_TOKEN(mfs_IEPSToken);
+ieps LOAD_TOKEN(mfs_IEPSToken);
+inactive LOAD_TOKEN(mfs_InactiveToken);
+in LOAD_TOKEN(mfs_InactiveToken);
+immackrequired LOAD_TOKEN(mfs_ImmAckRequiredToken);
+ia LOAD_TOKEN(mfs_ImmAckRequiredToken);
+inservice LOAD_TOKEN(mfs_InSvcToken);
+iv LOAD_TOKEN(mfs_InSvcToken);
+internal LOAD_TOKEN(mfs_InternalToken);
+it LOAD_TOKEN(mfs_InternalToken);
+intersignal LOAD_TOKEN(mfs_IntsigDelayToken);
+spais LOAD_TOKEN(mfs_IntsigDelayToken);
+isolate LOAD_TOKEN(mfs_IsolateToken);
+is LOAD_TOKEN(mfs_IsolateToken);
+intbyevent LOAD_TOKEN(mfs_InterruptByEventToken);
+ibe LOAD_TOKEN(mfs_InterruptByEventToken);
+intbysigdescr LOAD_TOKEN(mfs_InterruptByNewSignalsDescrToken);
+ibs LOAD_TOKEN(mfs_InterruptByNewSignalsDescrToken);
+iteration LOAD_TOKEN(mfs_IterationToken);
+ir LOAD_TOKEN(mfs_IterationToken);
+keepactive LOAD_TOKEN(mfs_KeepActiveToken);
+ka LOAD_TOKEN(mfs_KeepActiveToken);
+local LOAD_TOKEN(mfs_LocalToken);
+l LOAD_TOKEN(mfs_LocalToken);
+localcontrol LOAD_TOKEN(mfs_LocalControlToken);
+lockstep LOAD_TOKEN(mfs_LockStepToken);
+sp LOAD_TOKEN(mfs_LockStepToken);
+o LOAD_TOKEN(mfs_LocalControlToken);
+loopback LOAD_TOKEN(mfs_LoopbackToken);
+lb LOAD_TOKEN(mfs_LoopbackToken);
+media LOAD_TOKEN(mfs_MediaToken);
+m LOAD_TOKEN(mfs_MediaToken);
+megaco LOAD_TOKEN(mfs_MegacopToken);
+! LOAD_TOKEN(mfs_MegacopToken);
+segment LOAD_TOKEN(mfs_MessageSegmentToken);
+sm LOAD_TOKEN(mfs_MessageSegmentToken);
+method LOAD_TOKEN(mfs_MethodToken);
+mt LOAD_TOKEN(mfs_MethodToken);
+mgcidtotry LOAD_TOKEN(mfs_MgcIdToken);
+mg LOAD_TOKEN(mfs_MgcIdToken);
+mode LOAD_TOKEN(mfs_ModeToken);
+mo LOAD_TOKEN(mfs_ModeToken);
+{opt}modify LOAD_TOKEN(mfs_ModifyToken);
+{opt}mf LOAD_TOKEN(mfs_ModifyToken);
+modem LOAD_TOKEN(mfs_ModemToken);
+md LOAD_TOKEN(mfs_ModemToken);
+{opt}move LOAD_TOKEN(mfs_MoveToken);
+{opt}mv LOAD_TOKEN(mfs_MoveToken);
+mux LOAD_TOKEN(mfs_MuxToken);
+mx LOAD_TOKEN(mfs_MuxToken);
+nevernotify LOAD_TOKEN(mfs_NeverNotifyToken);
+nbnn LOAD_TOKEN(mfs_NeverNotifyToken);
+{opt}{wild}notify LOAD_TOKEN(mfs_NotifyToken);
+{opt}{wild}n LOAD_TOKEN(mfs_NotifyToken);
+notifycompletion LOAD_TOKEN(mfs_NotifyCompletionToken);
+nc LOAD_TOKEN(mfs_NotifyCompletionToken);
+immediatenotify LOAD_TOKEN(mfs_NotifyImmediateToken);
+nbin LOAD_TOKEN(mfs_NotifyImmediateToken);
+regulatednotify LOAD_TOKEN(mfs_NotifyRegulatedToken);
+nbrn LOAD_TOKEN(mfs_NotifyRegulatedToken);
+nx64kservice LOAD_TOKEN(mfs_Nx64kToken);
+n64 LOAD_TOKEN(mfs_Nx64kToken);
+observedevents LOAD_TOKEN(mfs_ObservedEventsToken);
+oe LOAD_TOKEN(mfs_ObservedEventsToken);
+oneway LOAD_TOKEN(mfs_OnewayToken);
+ow LOAD_TOKEN(mfs_OnewayToken);
+onewayboth LOAD_TOKEN(mfs_OnewayBothToken);
+owb LOAD_TOKEN(mfs_OnewayBothToken);
+onewayexternal LOAD_TOKEN(mfs_OnewayExternalToken);
+owe LOAD_TOKEN(mfs_OnewayExternalToken);
+off LOAD_TOKEN(mfs_OffToken);
+on LOAD_TOKEN(mfs_OnToken);
+onoff LOAD_TOKEN(mfs_OnOffToken);
+oo LOAD_TOKEN(mfs_OnOffToken);
+orlgc LOAD_TOKEN(mfs_OrAUDITselectToken);
+otherreason LOAD_TOKEN(mfs_OtherReasonToken);
+or LOAD_TOKEN(mfs_OtherReasonToken);
+outofservice LOAD_TOKEN(mfs_OutOfSvcToken);
+os LOAD_TOKEN(mfs_OutOfSvcToken);
+packages LOAD_TOKEN(mfs_PackagesToken);
+pg LOAD_TOKEN(mfs_PackagesToken);
+pending LOAD_TOKEN(mfs_PendingToken);
+pn LOAD_TOKEN(mfs_PendingToken);
+priority LOAD_TOKEN(mfs_PriorityToken);
+pr LOAD_TOKEN(mfs_PriorityToken);
+profile LOAD_TOKEN(mfs_ProfileToken);
+pf LOAD_TOKEN(mfs_ProfileToken);
+reason LOAD_TOKEN(mfs_ReasonToken);
+re LOAD_TOKEN(mfs_ReasonToken);
+receiveonly LOAD_TOKEN(mfs_RecvonlyToken);
+rc LOAD_TOKEN(mfs_RecvonlyToken);
+reply LOAD_TOKEN(mfs_ReplyToken);
+p LOAD_TOKEN(mfs_ReplyToken);
+reseteventsdescriptor LOAD_TOKEN(mfs_ResetEventsDescriptorToken);
+rse LOAD_TOKEN(mfs_ResetEventsDescriptorToken);
+transactionresponseack LOAD_TOKEN(mfs_ResponseAckToken);
+k LOAD_TOKEN(mfs_ResponseAckToken);
+restart LOAD_TOKEN(mfs_RestartToken);
+rs LOAD_TOKEN(mfs_RestartToken);
+remote LOAD_TOKEN(mfs_RemoteToken);
+r LOAD_TOKEN(mfs_RemoteToken);
+sparequestid LOAD_TOKEN(mfs_RequestIDToken);
+requestid LOAD_TOKEN(mfs_RequestIDToken);
+sparq LOAD_TOKEN(mfs_RequestIDToken);
+rq LOAD_TOKEN(mfs_RequestIDToken);
+reservedgroup LOAD_TOKEN(mfs_ReservedGroupToken);
+rg LOAD_TOKEN(mfs_ReservedGroupToken);
+reservedvalue LOAD_TOKEN(mfs_ReservedValueToken);
+rv LOAD_TOKEN(mfs_ReservedValueToken);
+end LOAD_TOKEN(mfs_SegmentationCompleteToken);
+& LOAD_TOKEN(mfs_SegmentationCompleteToken);
+sendonly LOAD_TOKEN(mfs_SendonlyToken);
+so LOAD_TOKEN(mfs_SendonlyToken);
+sendreceive LOAD_TOKEN(mfs_SendrecvToken);
+sr LOAD_TOKEN(mfs_SendrecvToken);
+services LOAD_TOKEN(mfs_ServicesToken);
+sv LOAD_TOKEN(mfs_ServicesToken);
+servicestates LOAD_TOKEN(mfs_ServiceStatesToken);
+si LOAD_TOKEN(mfs_ServiceStatesToken);
+{opt}{wild}servicechange LOAD_TOKEN(mfs_ServiceChangeToken);
+{opt}{wild}sc LOAD_TOKEN(mfs_ServiceChangeToken);
+servicechangeaddress LOAD_TOKEN(mfs_ServiceChangeAddressToken);
+ad LOAD_TOKEN(mfs_ServiceChangeAddressToken);
+servicechangeinc LOAD_TOKEN(mfs_ServiceChangeIncompleteToken);
+sic LOAD_TOKEN(mfs_ServiceChangeIncompleteToken);
+signallist LOAD_TOKEN(mfs_SignalListToken);
+sl LOAD_TOKEN(mfs_SignalListToken);
+signals LOAD_TOKEN(mfs_SignalsToken);
+sg LOAD_TOKEN(mfs_SignalsToken);
+signaltype LOAD_TOKEN(mfs_SignalTypeToken);
+sy LOAD_TOKEN(mfs_SignalTypeToken);
+statistics LOAD_TOKEN(mfs_StatsToken);
+sa LOAD_TOKEN(mfs_StatsToken);
+stream LOAD_TOKEN(mfs_StreamToken);
+st LOAD_TOKEN(mfs_StreamToken);
+{opt}{wild}subtract LOAD_TOKEN(mfs_SubtractToken);
+{opt}{wild}s LOAD_TOKEN(mfs_SubtractToken);
+synchisdn LOAD_TOKEN(mfs_SynchISDNToken);
+sn LOAD_TOKEN(mfs_SynchISDNToken);
+terminationstate LOAD_TOKEN(mfs_TerminationStateToken);
+ts LOAD_TOKEN(mfs_TerminationStateToken);
+test LOAD_TOKEN(mfs_TestToken);
+te LOAD_TOKEN(mfs_TestToken);
+timeout LOAD_TOKEN(mfs_TimeOutToken);
+to LOAD_TOKEN(mfs_TimeOutToken);
+topology LOAD_TOKEN(mfs_TopologyToken);
+tp LOAD_TOKEN(mfs_TopologyToken);
+transaction LOAD_TOKEN(mfs_TransToken);
+t LOAD_TOKEN(mfs_TransToken);
+v18 LOAD_TOKEN(mfs_V18Token);
+v22 LOAD_TOKEN(mfs_V22Token);
+v22b LOAD_TOKEN(mfs_V22bisToken);
+v32 LOAD_TOKEN(mfs_V32Token);
+v32b LOAD_TOKEN(mfs_V32bisToken);
+v34 LOAD_TOKEN(mfs_V34Token);
+v76 LOAD_TOKEN(mfs_V76Token);
+v90 LOAD_TOKEN(mfs_V90Token);
+v91 LOAD_TOKEN(mfs_V91Token);
+version LOAD_TOKEN(mfs_VersionToken);
+v LOAD_TOKEN(mfs_VersionToken);
+({safechar})+ LOAD_TOKEN(mfs_SafeChars);
+
+<<EOF>> {LOAD_SHORT_TOKEN(mfs_endOfMessage); BEGIN(INITIAL); yyterminate();}
+<*>.|\n {LOAD_TOKEN(mfs_IllegalChar); BEGIN(INITIAL); yyterminate();}
+
+%%
+
+/* MEGACO_LINENO_OR_TOKENCOUNTER
+ * Note that this construction is intended to make it
+ * possible to generate flex files that either reports
+ * line-number or one that don't.
+ * See MEGACO_YY_LINENO_OPTION and
+ * MEGACO_DUMMY_DECL_YY_LINENO above.
+ */
+
+#if defined(MEGACO_LINENO)
+#define LINENO_OR_TOKENCNT(P) yylineno
+#else
+#define LINENO_OR_TOKENCNT(P) P->token_counter
+#endif
+
+
+/* #define MFS_DEBUG true */ /* temporary */
+#if defined(MFS_DEBUG)
+# define DBG( proto ) printf proto
+# define DBG_BUF(func, bufName, buf, bufSz) mfs_dbg_buf_print(func, bufName, buf, bufSz)
+#else
+# define DBG( proto ) ((void) 0)
+# define DBG_BUF(func, bufName, buf, bufSz) ((void) 0)
+#endif /* if defined(MFS_DEBUG) */
+
+
+#if defined(MFS_DEBUG)
+
+#define CHUNK 16
+
+static void hexdump(unsigned char *buf, int bufsz)
+{
+ int i,j;
+ int count;
+
+ /* do this in chunks of CHUNK bytes */
+ for (i=0; i<bufsz; i+=CHUNK) {
+ /* show the offset */
+ printf("0x%06x ", i);
+
+ /* max of CHUNK or remaining bytes */
+ count = ((bufsz-i) > CHUNK ? CHUNK : bufsz-i);
+
+ /* show the bytes */
+ for (j=0; j<count; j++) {
+ if (j==CHUNK/2) printf(" ");
+ printf("%02x ",buf[i+j]);
+ }
+
+ /* pad with spaces if less than CHUNK */
+ for (j=count; j<CHUNK; j++) {
+ if (j==CHUNK/2) printf(" ");
+ printf(" ");
+ }
+
+ /* divider between hex and ascii */
+ printf(" ");
+
+ for (j=0; j<count; j++)
+ printf("%c",(isprint(buf[i+j]) ? buf[i+j] : '.'));
+
+ printf("\n");
+ }
+}
+
+static void mfs_dbg_buf_print(char* func, char* bufName, char* buf, int len)
+{
+ printf("%s -> %s (%d):\n", func, bufName, len);
+ hexdump((unsigned char*) buf, len);
+}
+
+
+#endif /* if defined(MFS_DEBUG) */
+
+static void mfs_alloc_failed(MfsErlDrvData* dataP, char* msg, int sz)
+{
+ /*
+ * Make sure we are not allready in error state
+ */
+ if (!dataP->error) {
+
+ /*
+ * Make sure that there is room in the buffer:
+ * length of msg + 10 chars for the ' of %d bytes'
+ * + 10 chars for the size value...
+ * This is really overkill since the msg string is never
+ * longer then 50 chars, but sinze this function is
+ * called when we have run out of memory...
+ */
+
+ int msg_len = strlen(msg);
+ if ((10 + 10 + msg_len) < sizeof(dataP->error_msg)) {
+ if (0 >= sprintf(dataP->error_msg, "%s of %d bytes", msg, sz)) {
+ mfs_fatal_error(dataP, msg);
+ }
+ } else {
+ mfs_fatal_error(dataP, msg);
+ }
+ dataP->error = TRUE;
+ }
+}
+
+
+static void mfs_ensure_term_spec(MfsErlDrvData* dataP, int size)
+{
+ DBG( ("mfs_ensure_term_spec -> entry with"
+ "\n size: %d"
+ "\nwhen"
+ "\n spec_index: %d"
+ "\n spec_size: %d"
+ "\n", size, dataP->term_spec_index, dataP->term_spec_size) );
+
+ /* OTP-4236 - BEGIN */
+ if ((dataP->term_spec_index + size) >= dataP->term_spec_size) {
+ void *tmp;
+
+ DBG( ("mfs_ensure_term_spec -> allocate more memory when"
+ "\n term_spec_index: %d"
+ "\n term_spec_size: %d\n",
+ dataP->term_spec_index, dataP->term_spec_size) );
+
+ dataP->term_spec_size = (dataP->term_spec_size * 2) + size;
+
+ DBG( ("mfs_ensure_term_spec -> "
+ "term_spec is at 0x%X, new term_spec_size is %d\n",
+ (unsigned int) dataP->term_spec, dataP->term_spec_size) );
+
+ tmp = REALLOC(dataP->term_spec,
+ dataP->term_spec_size * sizeof(ErlDrvTermData));
+
+ if (tmp == NULL) {
+ /*
+ * Ouch, we did'nt get any new memory.
+ * Just give ut. I.e. free the memory we have (note that
+ * the assign macro tests the buffer before assigning).
+ */
+ FREE(dataP->term_spec);
+ dataP->term_spec = NULL;
+
+ mfs_alloc_failed(dataP, "failed reallocating term spec buffer",
+ dataP->term_spec_size * sizeof(ErlDrvTermData));
+
+ } else {
+ dataP->term_spec = tmp;
+ }
+
+ DBG( ("mfs_ensure_term_spec -> new term_spec is at 0x%X\n",
+ (unsigned int) dataP->term_spec) );
+ }
+ /* OTP-4236 - END */
+}
+
+#if defined(MEGACO_REENTRANT_FLEX_SCANNER)
+static void mfs_short_load_token(ErlDrvTermData TokenTag, yyscan_t yyscanner)
+#else
+static void mfs_short_load_token(ErlDrvTermData TokenTag)
+#endif
+{
+ /* Build a {TokenTag, LineNumber} tuple */
+#if defined(MEGACO_REENTRANT_FLEX_SCANNER)
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ MfsErlDrvData* dataP = (MfsErlDrvData*) yyget_extra(yyscanner);
+#else
+ MfsErlDrvData* dataP = &mfs_drv_data;
+#endif
+
+ /*
+ DBG( ("mfs_short_load_token -> entry with"
+ "\n TokenTag: %ld\n", TokenTag) );
+ */
+
+ mfs_ensure_term_spec(dataP, 6);
+ dataP->token_counter++;
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_ATOM);
+ ASSIGN_TERM_SPEC(dataP, TokenTag);
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_INT);
+ ASSIGN_TERM_SPEC(dataP, LINENO_OR_TOKENCNT(dataP));
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_TUPLE);
+ ASSIGN_TERM_SPEC(dataP, 2);
+}
+
+#if defined(MEGACO_REENTRANT_FLEX_SCANNER)
+static void mfs_octet_load_token(ErlDrvTermData TokenTag, int is_empty,
+ yyscan_t yyscanner)
+#else
+static void mfs_octet_load_token(ErlDrvTermData TokenTag, int is_empty)
+#endif
+{
+ /* Build a {TokenTag, LineNumber, String} tuple */
+#if defined(MEGACO_REENTRANT_FLEX_SCANNER)
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ MfsErlDrvData* dataP = (MfsErlDrvData*) yyget_extra(yyscanner);
+#else
+ MfsErlDrvData* dataP = &mfs_drv_data;
+#endif
+
+ DBG( ("mfs_octet_load_token -> entry with"
+ "\n TokenTag: %d"
+ "\n is_empty: %d"
+ "\n yyleng: %d"
+ "\n", (int) TokenTag, is_empty, yyleng) );
+
+ mfs_ensure_term_spec(dataP, 9);
+ dataP->token_counter++;
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_ATOM);
+ ASSIGN_TERM_SPEC(dataP, TokenTag);
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_INT);
+ ASSIGN_TERM_SPEC(dataP, LINENO_OR_TOKENCNT(dataP));
+
+ if (is_empty) {
+
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_NIL); // End of list
+
+ } else {
+
+ LOAD_PROP_GRPS(dataP);
+
+ }
+
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_TUPLE);
+ ASSIGN_TERM_SPEC(dataP, 3);
+}
+
+#if defined(MEGACO_REENTRANT_FLEX_SCANNER)
+static void mfs_lower_load_token(ErlDrvTermData TokenTag, int is_empty,
+ yyscan_t yyscanner)
+#else
+static void mfs_lower_load_token(ErlDrvTermData TokenTag, int is_empty)
+#endif
+{
+ /* Build a {TokenTag, LineNumber, LowerCaseString} tuple */
+ int i;
+#if defined(MEGACO_REENTRANT_FLEX_SCANNER)
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ MfsErlDrvData* dataP = (MfsErlDrvData*) yyget_extra(yyscanner);
+#else
+ MfsErlDrvData* dataP = &mfs_drv_data;
+#endif
+
+ DBG( ("mfs_lower_load_token -> entry with"
+ "\n TokenTag: %ld"
+ "\n is_empty: %d"
+ "\n", TokenTag, is_empty) );
+
+ mfs_ensure_term_spec(dataP, 9);
+ dataP->token_counter++;
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_ATOM);
+ ASSIGN_TERM_SPEC(dataP, TokenTag);
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_INT);
+ ASSIGN_TERM_SPEC(dataP, LINENO_OR_TOKENCNT(dataP));
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_STRING);
+
+ if (is_empty) {
+
+ ASSIGN_TERM_SPEC(dataP, (ErlDrvTermData)"");
+ ASSIGN_TERM_SPEC(dataP, 0);
+
+ } else {
+ for ( i = 0; i < yyleng; ++i ) {
+ dataP->text_ptr[i] = tolower(yytext[i]);
+ }
+
+ DBG_BUF("mfs_lower_load_token", "dataP->text_ptr",
+ dataP->text_ptr, yyleng);
+
+ ASSIGN_TERM_SPEC(dataP, (ErlDrvTermData) dataP->text_ptr);
+ dataP->text_ptr += yyleng;
+ ASSIGN_TERM_SPEC(dataP, yyleng);
+ }
+
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_TUPLE);
+ ASSIGN_TERM_SPEC(dataP, 3);
+}
+
+#define PG_ERR_PRE "bad_property_parm:"
+#define PG_ERR1 "Could not find property parm value for"
+#define PG_ERR2 "Could not find proper property parm name"
+
+#if defined(MEGACO_REENTRANT_FLEX_SCANNER)
+static void mfs_load_property_groups(MfsErlDrvData* dataP, yyscan_t yyscanner)
+#else
+static void mfs_load_property_groups(MfsErlDrvData* dataP)
+#endif
+{
+#if defined(MEGACO_REENTRANT_FLEX_SCANNER)
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ // MfsErlDrvData* dataP = (MfsErlDrvData*) yyget_extra(yyscanner);
+#else
+ // MfsErlDrvData* dataP = &mfs_drv_data;
+#endif
+
+ /*
+ * Process the property groups string
+ * v= is a property group delimiter
+ */
+
+ /*
+ * For each string, look for the first '='.
+ * Everything to the left is the name and
+ * everything to the right is the value.
+ */
+
+ int i = 0; // loop counter
+ int numGroups = 0; // Number of property groups
+ int numPps = 0; // Number of property parms (in the group)
+ char* name; // Pointer to the name buffer
+ int nameStart = 0; // Start position of the property parm name
+ int nameLen; // Length of the name part
+ char* value; // Pointer to the value buffer
+ int valueStart = 0; // Start position of the property parm name
+ int valueLen = 0; // Length of the value part
+
+ DBG( ("mfs_load_property_groups -> entry\n") );
+
+ mfs_ensure_term_spec(dataP, 10); /*�Just in case... */
+
+ while (i <= yyleng) {
+
+ /* Skip white-spaces and end-of-line */
+
+ DBG( ("mfs_load_property_groups -> "
+ "skip white-spaces and end-of-line: i = %d\n", i) );
+
+ if ((yytext[i] != SP) &&
+ (yytext[i] != HTAB) &&
+ (yytext[i] != LF) &&
+ (yytext[i] != CR) &&
+ (yytext[i] != NUL)) {
+
+ DBG( ("mfs_load_property_groups -> "
+ "start looking for delimiter ('=')\n") );
+
+ /* Start looking for '=' */
+ nameStart = i;
+ nameLen = 0;
+ while (i <= yyleng) {
+
+ /* Is it a name-value delimiter? */
+ if (yytext[i] == '=') {
+
+ /*
+ * Found the name/value delimiter
+ */
+ nameLen = i-nameStart;
+
+ DBG( ("mfs_load_property_groups -> "
+ "found delimiter at %d (name length = %d)\n", i, nameLen) );
+
+ /*
+ * "v=" is the start of a new group.
+ * So, check if this maybe is the beginning of
+ * the first group or not. If not, we need to
+ * "terminate" the previous group.
+ */
+ if (0 == strncmp("v", &yytext[nameStart], nameLen)) {
+
+ DBG( ("mfs_load_property_groups -> "
+ "found a 'v' when group count is %d\n", numGroups) );
+
+ if (numGroups > 0) {
+ /*
+ * End the previous group
+ * (only if this is not the first group)
+ */
+
+ DBG( ("mfs_load_property_groups -> "
+ "start of new group - terminate previous group\n") );
+
+ mfs_ensure_term_spec(dataP, 3);
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_NIL); // End of list
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_LIST); // List
+ ASSIGN_TERM_SPEC(dataP, (ErlDrvTermData) numPps + 1); // Length of (group) list
+ numPps = 0; /* reset for next group */
+ } // if ...
+ numGroups++;
+ } // if ...
+ numPps++;
+ i++;
+
+ /*
+ * Now, look for the end of the value string,
+ * which is an EOL = (CR [LF] / LF )
+ */
+
+ DBG( ("mfs_load_property_groups -> "
+ "start looking for end of value\n") );
+ valueStart = i;
+ valueLen = 0;
+ while (i <= yyleng) {
+ if ((yytext[i] == CR) || (yytext[i] == LF)) {
+ valueLen = i-valueStart;
+ DBG( ("mfs_load_property_groups -> "
+ "found end of value at %d\n", i) );
+ break;
+ } else {
+ i++;
+ } // if ...
+ } // while ...
+
+ /* Name */
+ name = dataP->text_ptr;
+ strncpy(name, &yytext[nameStart], nameLen);
+ name[nameLen] = 0;
+ dataP->text_ptr += (nameLen + 1); // Make room for the NULL termination
+
+ /* Check that we actually got a proper value */
+ if (valueLen == 0) {
+ /* Invalid property parm value */
+ DBG( ("mfs_load_property_groups -> "
+ "property parm value not found\n") );
+
+ /**********************************************
+ * -record('ErrorDescriptor',
+ * {
+ * errorCode,
+ * errorText = asn1_NOVALUE
+ * }).
+ */
+
+ if (0 >= sprintf(dataP->error_msg, "%s %s %s",
+ PG_ERR_PRE, PG_ERR1, name)) {
+ mfs_fatal_error(dataP, PG_ERR1);
+ }
+ dataP->error = TRUE;
+
+ DBG( ("mfs_load_property_groups -> "
+ "done after value error (%s)\n", name) );
+
+ return; // Bail out
+
+ } else {
+
+
+ /***************************************
+ * -record('PropertyParm',
+ * {
+ * name,
+ * value,
+ * extraInfo = asn1_NOVALUE
+ * }). % with extension mark
+ */
+
+ mfs_ensure_term_spec(dataP, 15); // 2 + 3 + 6 + 2 + 2
+
+ DBG( ("mfs_load_property_groups -> "
+ "insert PropertyParm record name\n") );
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_ATOM);
+ ASSIGN_TERM_SPEC(dataP, (ErlDrvTermData) mfs_PropertyParm);
+
+ /* Name */
+ DBG( ("mfs_load_property_groups -> insert name field\n") );
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_STRING);
+ ASSIGN_TERM_SPEC(dataP, (ErlDrvTermData) name);
+ ASSIGN_TERM_SPEC(dataP, (ErlDrvTermData) nameLen);
+
+ /*
+ * value, which is actually a list of length 1
+ * where the "actual value" is the (only) element
+ */
+ DBG( ("mfs_load_property_groups -> "
+ "insert value field (length = %d)\n", valueLen) );
+ value = dataP->text_ptr;
+ strncpy(value, &yytext[valueStart], valueLen);
+ dataP->text_ptr += valueLen;
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_STRING);
+ ASSIGN_TERM_SPEC(dataP, (ErlDrvTermData) value);
+ ASSIGN_TERM_SPEC(dataP, (ErlDrvTermData) valueLen);
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_NIL); // End of value list
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_LIST);
+ ASSIGN_TERM_SPEC(dataP, (ErlDrvTermData) 1 + 1); // Length of (group) list
+
+ /* extraInfo - never used */
+ DBG( ("mfs_load_property_groups -> "
+ "insert the extraInfo field\n") );
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_ATOM);
+ ASSIGN_TERM_SPEC(dataP, (ErlDrvTermData) mfs_asn1_NOVALUE);
+
+ DBG( ("mfs_load_property_groups -> "
+ "terminate PropertyParm tuple\n") );
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_TUPLE);
+ ASSIGN_TERM_SPEC(dataP, (ErlDrvTermData) 4);
+ break;
+
+ } // if (valueLen == 0) ...
+
+ } else {
+ DBG( ("mfs_load_property_groups -> "
+ "b) skipping %d [%d] (%d)\n", i, yyleng - i, yytext[i]) );
+ i++;
+ } // if (yytext[i] == '=')
+
+ } // while (i <= yyleng)
+
+ /* Check that we actually got a proper name */
+ if (nameLen == 0) {
+ /* Invalid property parm name */
+ DBG( ("mfs_load_property_groups -> "
+ "property parm name not found when "
+ "nameStart = %d\n", nameStart) );
+
+ if (0 >= sprintf(dataP->error_msg, "%s %s (name start at %d)",
+ PG_ERR_PRE, PG_ERR2, nameStart)) {
+ mfs_fatal_error(dataP, PG_ERR2);
+ }
+
+ dataP->error = TRUE;
+
+ DBG( ("mfs_load_property_groups -> done after name error\n") );
+
+ return; // Bail out
+
+ } // if (nameLen == 0) ...
+
+ } else {
+ DBG( ("mfs_load_property_groups -> "
+ "a) skipping %d [%d] (%d)\n", i, yyleng - i, yytext[i]) );
+ i++; // next
+ } // if ((yytext[i] != SP)...
+ } // while ...
+
+ mfs_ensure_term_spec(dataP, 4); // 2 + 2 just in case
+
+ /* Make sure we actually have some groups */
+
+ if (numGroups > 0) {
+
+ DBG( ("mfs_load_property_groups -> "
+ "terminate group (list of properties) list (length = %d)\n",
+ numPps) );
+
+ /* Terminate the final group */
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_NIL); // End of list
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_LIST);
+ ASSIGN_TERM_SPEC(dataP, (ErlDrvTermData) numPps + 1); // Length of (group) list
+
+ }
+
+ DBG( ("mfs_load_property_groups -> "
+ "terminate groups (list of property groups) list (length = %d)\n",
+ numGroups) );
+
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_NIL); // End of list
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_LIST);
+ ASSIGN_TERM_SPEC(dataP, (ErlDrvTermData) numGroups + 1); // Length of (groups) list
+
+ DBG( ("mfs_load_property_groups -> done\n") );
+}
+
+
+#if defined(MEGACO_REENTRANT_FLEX_SCANNER)
+static void mfs_load_map_name(yyscan_t yyscanner)
+#else
+static void mfs_load_map_name()
+#endif
+{
+ /* Copy digit map name as lower case */
+ int i;
+#if defined(MEGACO_REENTRANT_FLEX_SCANNER)
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ MfsErlDrvData* dataP = (MfsErlDrvData*) yyget_extra(yyscanner);
+#else
+ MfsErlDrvData* dataP = &mfs_drv_data;
+#endif
+
+ for ( i = 0; i < yyleng; ++i ) {
+ dataP->text_ptr[i] = tolower(yytext[i]);
+ }
+
+ dataP->digit_map_name_ptr = dataP->text_ptr;
+ dataP->digit_map_name_len = yyleng;
+ dataP->text_ptr += yyleng;
+}
+
+#if defined(MEGACO_REENTRANT_FLEX_SCANNER)
+static void mfs_load_map_value(yyscan_t yyscanner)
+#else
+static void mfs_load_map_value()
+#endif
+{
+ /* Copy digit map value as lower case */
+ int i;
+#if defined(MEGACO_REENTRANT_FLEX_SCANNER)
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ MfsErlDrvData* dataP = (MfsErlDrvData*) yyget_extra(yyscanner);
+#else
+ MfsErlDrvData* dataP = &mfs_drv_data;
+#endif
+
+ for ( i = 0; i < yyleng; ++i ) {
+ dataP->text_ptr[i] = tolower(yytext[i]);
+ }
+
+ dataP->digit_map_value_ptr = dataP->text_ptr;
+ dataP->digit_map_value_len = yyleng;
+ dataP->text_ptr += yyleng;
+}
+
+#if defined(MEGACO_REENTRANT_FLEX_SCANNER)
+static void mfs_load_map_timer(yyscan_t yyscanner)
+#else
+static void mfs_load_map_timer()
+#endif
+{
+#if defined(MEGACO_REENTRANT_FLEX_SCANNER)
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ MfsErlDrvData* dataP = (MfsErlDrvData*) yyget_extra(yyscanner);
+#else
+ MfsErlDrvData* dataP = &mfs_drv_data;
+#endif
+ int timer_len = yyleng - 2;
+
+ /* The digit map timer consists of 3 or 4 characters:
+ * z and Z are actually version 2 only
+ * 0 - the kind of timer (t|T|s|S|l|L|z|Z)
+ * 1 - a colon
+ * 2 - mandatory digit
+ * 3 - optional digit
+ */
+
+ /*
+ DBG( ("mfs_load_map_timer -> entry when yyleng: %d\n", yyleng) );
+ DBG( ("mfs_load_map_timer -> yytext: 0x%x\n", yytext) );
+
+ DBG( ("mfs_load_map_timer -> yytext[0]: %u (%c)\n", yytext[0], yytext[0]) );
+ DBG( ("mfs_load_map_timer -> yytext[1]: %u (%c)\n", yytext[1], yytext[1]) );
+ DBG( ("mfs_load_map_timer -> yytext[2]: %u (%c)\n", yytext[2], yytext[2]) );
+ DBG( ("mfs_load_map_timer -> yytext[3]: %u (%c)\n", yytext[3], yytext[3]) );
+ */
+
+ /* Pad with leading zero */
+
+ if (timer_len == 1) {
+ dataP->text_ptr[0] = '0';
+ dataP->text_ptr[1] = yytext[2];
+ } else if (timer_len == 2) {
+ dataP->text_ptr[0] = yytext[2];
+ dataP->text_ptr[1] = yytext[3];
+ }
+
+ /*
+ DBG( ("mfs_load_map_timer -> dataP->text_ptr[0]: %u (%c)\n",
+ dataP->text_ptr[0], dataP->text_ptr[0]) );
+ DBG( ("mfs_load_map_timer -> dataP->text_ptr[1]: %u (%c)\n",
+ dataP->text_ptr[1], dataP->text_ptr[1]) );
+
+ DBG( ("mfs_load_map_timer -> dataP->text_ptr: 0x%x\n",
+ dataP->text_ptr) );
+ */
+
+ switch (yytext[0]) {
+ case 't':
+ case 'T':
+ dataP->digit_map_start_ptr = dataP->text_ptr;
+ break;;
+ case 's':
+ case 'S':
+ dataP->digit_map_short_ptr = dataP->text_ptr;
+ break;;
+ case 'l':
+ case 'L':
+ dataP->digit_map_long_ptr = dataP->text_ptr;
+ break;;
+ case 'z':
+ case 'Z':
+ dataP->digit_map_duration_ptr = dataP->text_ptr;
+ break;;
+ }
+
+ /* We pad when there is only one digit, so it will always be two */
+ dataP->text_ptr += 2;
+
+}
+
+static void mfs_load_timer_field(MfsErlDrvData* dataP, char* text)
+{
+ mfs_ensure_term_spec(dataP, 2); /* OTP-4236 */
+ if (text == NULL) {
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_ATOM);
+ ASSIGN_TERM_SPEC(dataP, mfs_asn1_NOVALUE);
+ } else {
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_INT);
+ ASSIGN_TERM_SPEC(dataP, ((text[0] - '0') * 10) + (text[1] - '0'));
+ }
+}
+
+#if defined(MEGACO_REENTRANT_FLEX_SCANNER)
+static void mfs_load_map_token(yyscan_t yyscanner)
+#else
+static void mfs_load_map_token()
+#endif
+{
+ /*
+ * Build a {'DigitMapDescriptorToken', LineNumber,
+ * {'DigitMapDescriptor', DigitMapName, DigitMapValue}} tuple
+ */
+#if defined(MEGACO_REENTRANT_FLEX_SCANNER)
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ MfsErlDrvData* dataP = (MfsErlDrvData*) yyget_extra(yyscanner);
+#else
+ MfsErlDrvData* dataP = &mfs_drv_data;
+#endif
+
+ mfs_ensure_term_spec(dataP, 20);
+ dataP->token_counter++;
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_ATOM);
+ ASSIGN_TERM_SPEC(dataP, mfs_DigitMapDescriptorToken);
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_INT);
+ ASSIGN_TERM_SPEC(dataP, LINENO_OR_TOKENCNT(dataP));
+
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_ATOM);
+ ASSIGN_TERM_SPEC(dataP, mfs_DigitMapDescriptor);
+
+ if (dataP->digit_map_name_ptr == 0) {
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_ATOM);
+ ASSIGN_TERM_SPEC(dataP, mfs_asn1_NOVALUE);
+ } else {
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_STRING);
+ ASSIGN_TERM_SPEC(dataP, (ErlDrvTermData) dataP->digit_map_name_ptr);
+ ASSIGN_TERM_SPEC(dataP, dataP->digit_map_name_len);
+ dataP->digit_map_name_ptr = NULL;
+ }
+
+ if (dataP->digit_map_value_ptr == NULL) {
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_ATOM);
+ ASSIGN_TERM_SPEC(dataP, mfs_asn1_NOVALUE);
+ } else {
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_ATOM);
+ ASSIGN_TERM_SPEC(dataP, mfs_DigitMapValue);
+
+ /* Take care of timer values */
+ mfs_load_timer_field(dataP, dataP->digit_map_start_ptr);
+ dataP->digit_map_start_ptr = NULL;
+
+ mfs_load_timer_field(dataP, dataP->digit_map_short_ptr);
+ dataP->digit_map_short_ptr = NULL;
+
+ mfs_load_timer_field(dataP, dataP->digit_map_long_ptr);
+ dataP->digit_map_long_ptr = NULL;
+
+ mfs_load_timer_field(dataP, dataP->digit_map_duration_ptr);
+ dataP->digit_map_duration_ptr = NULL;
+
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_STRING);
+ ASSIGN_TERM_SPEC(dataP, (ErlDrvTermData) dataP->digit_map_value_ptr);
+ ASSIGN_TERM_SPEC(dataP, dataP->digit_map_value_len);
+ dataP->digit_map_value_ptr = NULL;
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_TUPLE);
+ ASSIGN_TERM_SPEC(dataP, 6);
+ }
+
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_TUPLE);
+ ASSIGN_TERM_SPEC(dataP, 3);
+
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_TUPLE);
+ ASSIGN_TERM_SPEC(dataP, 3);
+
+}
+
+
+DRIVER_INIT(mfs_drv)
+{
+ DBG( ("DRIVER_INIT(mfs_drv) -> entry\n") );
+
+ return &mfs_entry;
+}
+
+static ErlDrvData mfs_start(ErlDrvPort port, char *buf)
+{
+#if defined(MEGACO_REENTRANT_FLEX_SCANNER)
+ MfsErlDrvData* dataP = ALLOC(sizeof(MfsErlDrvData));
+#else
+ MfsErlDrvData* dataP = &mfs_drv_data;
+#endif
+
+ DBG( ("mfs_start -> entry\n") );
+
+ dataP->port = port;
+ dataP->digit_map_name_ptr = NULL;
+ dataP->digit_map_name_len = 0;
+ dataP->digit_map_value_ptr = NULL;
+ dataP->digit_map_value_len = 0;
+ dataP->digit_map_start_ptr = NULL;
+ dataP->digit_map_short_ptr = NULL;
+ dataP->digit_map_long_ptr = NULL;
+ dataP->digit_map_duration_ptr = NULL;
+ dataP->error = FALSE;
+ /* dataP->error_msg[512]; */
+ dataP->text_buf = NULL;
+ dataP->text_ptr = NULL;
+ dataP->term_spec = NULL;
+ dataP->term_spec_size = 0;
+ dataP->term_spec_index = 0;
+ dataP->token_counter = 0;
+
+ mfs_AddToken = driver_mk_atom("AddToken");
+ mfs_AndAUDITSelectToken = driver_mk_atom("AndAUDITSelectToken");
+ mfs_AuditCapToken = driver_mk_atom("AuditCapToken");
+ mfs_AuditToken = driver_mk_atom("AuditToken");
+ mfs_AuditValueToken = driver_mk_atom("AuditValueToken");
+ mfs_AuthToken = driver_mk_atom("AuthToken");
+ mfs_BothToken = driver_mk_atom("BothToken");
+ mfs_BothwayToken = driver_mk_atom("BothwayToken");
+ mfs_BriefToken = driver_mk_atom("BriefToken");
+ mfs_BufferToken = driver_mk_atom("BufferToken");
+ mfs_COLON = driver_mk_atom("COLON");
+ mfs_COMMA = driver_mk_atom("COMMA");
+ mfs_ContextAttrToken = driver_mk_atom("ContextAttrToken");
+ mfs_ContextAuditToken = driver_mk_atom("ContextAuditToken");
+ mfs_ContextListToken = driver_mk_atom("ContextListToken");
+ mfs_CtxToken = driver_mk_atom("CtxToken");
+ mfs_DelayToken = driver_mk_atom("DelayToken");
+ mfs_DeleteToken = driver_mk_atom("DeleteToken");
+ mfs_DigitMapDescriptor = driver_mk_atom("DigitMapDescriptor");
+ mfs_DigitMapDescriptorToken = driver_mk_atom("DigitMapDescriptorToken");
+ mfs_DigitMapToken = driver_mk_atom("DigitMapToken");
+ mfs_DigitMapValue = driver_mk_atom("DigitMapValue");
+ mfs_DirectionToken = driver_mk_atom("DirectionToken");
+ mfs_DiscardToken = driver_mk_atom("DiscardToken");
+ mfs_DisconnectedToken = driver_mk_atom("DisconnectedToken");
+ mfs_DurationToken = driver_mk_atom("DurationToken");
+ mfs_EQUAL = driver_mk_atom("EQUAL");
+ mfs_EmbedToken = driver_mk_atom("EmbedToken");
+ mfs_EmergencyToken = driver_mk_atom("EmergencyToken");
+ mfs_EmergencyOffToken = driver_mk_atom("EmergencyOffToken");
+ mfs_EmergencyValueToken = driver_mk_atom("EmergencyValueToken");
+ mfs_ErrorToken = driver_mk_atom("ErrorToken");
+ mfs_EventBufferToken = driver_mk_atom("EventBufferToken");
+ mfs_EventsToken = driver_mk_atom("EventsToken");
+ mfs_ExternalToken = driver_mk_atom("ExternalToken");
+ mfs_FailoverToken = driver_mk_atom("FailoverToken");
+ mfs_ForcedToken = driver_mk_atom("ForcedToken");
+ mfs_GREATER = driver_mk_atom("GREATER");
+ mfs_GracefulToken = driver_mk_atom("GracefulToken");
+ mfs_H221Token = driver_mk_atom("H221Token");
+ mfs_H223Token = driver_mk_atom("H223Token");
+ mfs_H226Token = driver_mk_atom("H226Token");
+ mfs_HandOffToken = driver_mk_atom("HandOffToken");
+ mfs_IEPSToken = driver_mk_atom("IEPSToken");
+ mfs_IllegalChar = driver_mk_atom("IllegalChar");
+ mfs_ImmAckRequiredToken = driver_mk_atom("ImmAckRequiredToken");
+ mfs_InSvcToken = driver_mk_atom("InSvcToken");
+ mfs_InactiveToken = driver_mk_atom("InactiveToken");
+ mfs_InternalToken = driver_mk_atom("InternalToken");
+ mfs_InterruptByEventToken = driver_mk_atom("InterruptByEventToken");
+ mfs_InterruptByNewSignalsDescrToken = driver_mk_atom("InterruptByNewSignalsDescrToken");
+ mfs_IntsigDelayToken = driver_mk_atom("IntsigDelayToken");
+ mfs_IsolateToken = driver_mk_atom("IsolateToken");
+ mfs_IterationToken = driver_mk_atom("IterationToken");
+ mfs_KeepActiveToken = driver_mk_atom("KeepActiveToken");
+ mfs_LBRKT = driver_mk_atom("LBRKT");
+ mfs_LESSER = driver_mk_atom("LESSER");
+ mfs_LSBRKT = driver_mk_atom("LSBRKT");
+ mfs_LocalControlToken = driver_mk_atom("LocalControlToken");
+ mfs_LocalDescriptorToken = driver_mk_atom("LocalDescriptorToken");
+ mfs_LocalToken = driver_mk_atom("LocalToken");
+ mfs_LockStepToken = driver_mk_atom("LockStepToken");
+ mfs_LoopbackToken = driver_mk_atom("LoopbackToken");
+ mfs_MediaToken = driver_mk_atom("MediaToken");
+ mfs_MegacopToken = driver_mk_atom("MegacopToken");
+ mfs_MessageSegmentToken = driver_mk_atom("MessageSegmentToken");
+ mfs_MethodToken = driver_mk_atom("MethodToken");
+ mfs_MgcIdToken = driver_mk_atom("MgcIdToken");
+ mfs_ModeToken = driver_mk_atom("ModeToken");
+ mfs_ModemToken = driver_mk_atom("ModemToken");
+ mfs_ModifyToken = driver_mk_atom("ModifyToken");
+ mfs_MoveToken = driver_mk_atom("MoveToken");
+ mfs_MtpAddressToken = driver_mk_atom("MtpAddressToken");
+ mfs_MuxToken = driver_mk_atom("MuxToken");
+ mfs_NEQUAL = driver_mk_atom("NEQUAL");
+ mfs_NotifyCompletionToken = driver_mk_atom("NotifyCompletionToken");
+ mfs_NotifyImmediateToken = driver_mk_atom("NotifyImmediateToken");
+ mfs_NotifyRegulatedToken = driver_mk_atom("NotifyRegulatedToken");
+ mfs_NeverNotifyToken = driver_mk_atom("NeverNotifyToken");
+ mfs_NotifyToken = driver_mk_atom("NotifyToken");
+ mfs_Nx64kToken = driver_mk_atom("Nx64kToken");
+ mfs_ObservedEventsToken = driver_mk_atom("ObservedEventsToken");
+ mfs_OffToken = driver_mk_atom("OffToken");
+ mfs_OnOffToken = driver_mk_atom("OnOffToken");
+ mfs_OnToken = driver_mk_atom("OnToken");
+ mfs_OnewayToken = driver_mk_atom("OnewayToken");
+ mfs_OnewayBothToken = driver_mk_atom("OnewayBothToken");
+ mfs_OnewayExternalToken = driver_mk_atom("OnewayExternalToken");
+ mfs_OrAUDITselectToken = driver_mk_atom("OrAUDITselectToken");
+ mfs_OtherReasonToken = driver_mk_atom("OtherReasonToken");
+ mfs_OutOfSvcToken = driver_mk_atom("OutOfSvcToken");
+ mfs_PackagesToken = driver_mk_atom("PackagesToken");
+ mfs_PendingToken = driver_mk_atom("PendingToken");
+ mfs_PriorityToken = driver_mk_atom("PriorityToken");
+ mfs_ProfileToken = driver_mk_atom("ProfileToken");
+ mfs_QuotedChars = driver_mk_atom("QuotedChars");
+ mfs_RBRKT = driver_mk_atom("RBRKT");
+ mfs_RSBRKT = driver_mk_atom("RSBRKT");
+ mfs_ReasonToken = driver_mk_atom("ReasonToken");
+ mfs_RecvonlyToken = driver_mk_atom("RecvonlyToken");
+ mfs_RemoteDescriptorToken = driver_mk_atom("RemoteDescriptorToken");
+ mfs_RemoteToken = driver_mk_atom("RemoteToken");
+ mfs_ReplyToken = driver_mk_atom("ReplyToken");
+ mfs_RequestIDToken = driver_mk_atom("RequestIDToken");
+ mfs_ReservedGroupToken = driver_mk_atom("ReservedGroupToken");
+ mfs_ReservedValueToken = driver_mk_atom("ReservedValueToken");
+ mfs_ResetEventsDescriptorToken = driver_mk_atom("ResetEventsDescriptorToken");
+ mfs_ResponseAckToken = driver_mk_atom("ResponseAckToken");
+ mfs_RestartToken = driver_mk_atom("RestartToken");
+ mfs_SEP = driver_mk_atom("SEP");
+ mfs_SafeChars = driver_mk_atom("SafeChars");
+ mfs_SegmentationCompleteToken = driver_mk_atom("SegmentationCompleteToken");
+ mfs_SendonlyToken = driver_mk_atom("SendonlyToken");
+ mfs_SendrecvToken = driver_mk_atom("SendrecvToken");
+ mfs_ServiceChangeAddressToken = driver_mk_atom("ServiceChangeAddressToken");
+ mfs_ServiceChangeIncompleteToken = driver_mk_atom("ServiceChangeIncompleteToken");
+ mfs_ServiceChangeToken = driver_mk_atom("ServiceChangeToken");
+ mfs_ServiceStatesToken = driver_mk_atom("ServiceStatesToken");
+ mfs_ServicesToken = driver_mk_atom("ServicesToken");
+ mfs_SignalListToken = driver_mk_atom("SignalListToken");
+ mfs_SignalTypeToken = driver_mk_atom("SignalTypeToken");
+ mfs_SignalsToken = driver_mk_atom("SignalsToken");
+ mfs_StatsToken = driver_mk_atom("StatsToken");
+ mfs_StreamToken = driver_mk_atom("StreamToken");
+ mfs_SubtractToken = driver_mk_atom("SubtractToken");
+ mfs_SynchISDNToken = driver_mk_atom("SynchISDNToken");
+ mfs_TerminationStateToken = driver_mk_atom("TerminationStateToken");
+ mfs_TestToken = driver_mk_atom("TestToken");
+ mfs_TimeOutToken = driver_mk_atom("TimeOutToken");
+ mfs_TimeStampToken = driver_mk_atom("TimeStampToken"); /* OTP-5042 */
+ mfs_TopologyToken = driver_mk_atom("TopologyToken");
+ mfs_TransToken = driver_mk_atom("TransToken");
+ mfs_V18Token = driver_mk_atom("V18Token");
+ mfs_V22Token = driver_mk_atom("V22Token");
+ mfs_V22bisToken = driver_mk_atom("V22bisToken");
+ mfs_V32Token = driver_mk_atom("V32Token");
+ mfs_V32bisToken = driver_mk_atom("V32bisToken");
+ mfs_V34Token = driver_mk_atom("V34Token");
+ mfs_V76Token = driver_mk_atom("V76Token");
+ mfs_V90Token = driver_mk_atom("V90Token");
+ mfs_V91Token = driver_mk_atom("V91Token");
+ mfs_VersionToken = driver_mk_atom("VersionToken");
+ mfs_asn1_NOVALUE = driver_mk_atom("asn1_NOVALUE");
+ mfs_endOfMessage = driver_mk_atom("endOfMessage");
+ mfs_PropertyParm = driver_mk_atom("PropertyParm");
+ mfs_ErrorDescriptor = driver_mk_atom("ErrorDescriptor");
+
+ DBG( ("mfs_start -> exit\n") );
+
+ return (ErlDrvData) dataP;
+}
+
+static void mfs_stop(ErlDrvData handle)
+{
+ MfsErlDrvData* dataP = (MfsErlDrvData*) handle;
+
+ dataP->port = 0;
+
+ DBG( ("mfs_stop -> exit\n") );
+
+ return;
+}
+
+static void mfs_command(ErlDrvData handle,
+ char *buf, int buf_len)
+{
+ driver_failure_atom(((MfsErlDrvData*) handle)->port, "bad_usage");
+
+ return;
+}
+
+static int mfs_control(ErlDrvData handle,
+ unsigned int command,
+ char *buf, int buf_len,
+ char **res_buf, int res_buf_len)
+{
+ MfsErlDrvData* dataP = (MfsErlDrvData*) handle;
+ char* tmp;
+ YY_BUFFER_STATE state;
+#if defined(MEGACO_REENTRANT_FLEX_SCANNER)
+ yyscan_t scanner;
+ /* struct yyguts_t * yyg = (struct yyguts_t*) scanner; */
+#endif
+
+ DBG( ("mfs_control -> entry with"
+ "\n command: %d"
+ "\n buf_len: %d"
+ "\n res_buf_len: %d\n", command, buf_len, res_buf_len) );
+
+ if (NULL == (tmp = ALLOC(buf_len))) {
+ int len;
+ mfs_alloc_failed(dataP, "failed allocating text buffer", buf_len);
+
+ len = strlen(dataP->error_msg);
+
+ if (res_buf_len < len) {
+ /*
+ * Since we failed the memory allocation in the first place,
+ * there is no point in trying to get more memory for the
+ * error code...
+ */
+ len = res_buf_len;
+ }
+
+ strncpy(*res_buf, dataP->error_msg, len);
+
+ return len;
+ }
+ dataP->text_buf = tmp;
+ dataP->text_ptr = tmp;
+
+ dataP->term_spec_size = 1000 + buf_len; /* OTP-4237 */
+
+ DBG( ("mfs_control -> allocate term-spec buffer: "
+ "\n term_spec_size: %d\n", dataP->term_spec_size) );
+
+ dataP->term_spec = ALLOC(dataP->term_spec_size * sizeof(ErlDrvTermData));
+ if (NULL == dataP->term_spec) {
+ int len;
+ mfs_alloc_failed(dataP, "failed allocating term spec buffer",
+ dataP->term_spec_size * sizeof(ErlDrvTermData));
+
+ len = strlen(dataP->error_msg);
+
+ if (res_buf_len < len) {
+ /*
+ * Since we failed the memory allocation in the first place,
+ * there is no point in trying to get more memory for the
+ * error code...
+ */
+ len = res_buf_len;
+ }
+
+ strncpy(*res_buf, dataP->error_msg, len);
+
+ FREE(dataP->text_buf);
+
+ return len;
+ }
+ dataP->term_spec_index = 0;
+ dataP->token_counter = 0;
+ dataP->error = FALSE;
+
+ /* Prepare the first field in the {tokens, TokenList, LastLine} tuple */
+ DBG( ("mfs_control -> prepare the first field in the tokens tuple\n") );
+ mfs_ensure_term_spec(dataP, 2);
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_ATOM);
+ ASSIGN_TERM_SPEC(dataP, driver_mk_atom("tokens"));
+
+ /* Perform the actual scan */
+#if defined(MEGACO_REENTRANT_FLEX_SCANNER)
+
+ /*
+ * R e e n t r a n t s c a n n e r
+ */
+
+ DBG( ("mfs_control -> initiate scanner\n") );
+ yylex_init(&scanner);
+
+ DBG( ("mfs_control -> maybe enable flex debug\n") );
+ yyset_debug(MFS_FLEX_DEBUG, scanner);
+
+ DBG( ("mfs_control -> set my extra data (ErlDrvData)\n") );
+ yyset_extra(dataP, scanner);
+
+ DBG( ("mfs_control -> scan bytes\n") );
+ state = yy_scan_bytes(buf, buf_len, scanner);
+
+ DBG( ("mfs_control -> set initial line-no (1) when state is at 0x%x\n",
+ (unsigned int) state) );
+ yyset_lineno(1, scanner);
+
+ DBG( ("mfs_control -> do the actual scan\n") );
+ yylex(scanner);
+
+#else
+
+ /*
+ * N o n - R e e n t r a n t s c a n n e r
+ */
+
+ yylineno = 1;
+ state = yy_scan_bytes(buf, buf_len);
+ yylex();
+ yy_delete_buffer(state);
+
+#endif
+
+ DBG( ("mfs_control -> scan done - now check if ok or not (%d)\n", dataP->error) );
+ if (!dataP->error) {
+
+ /*
+ * Prepare the rest of the {tokens, TokenList, LastLine} tuple
+ * and send it as message top caller.
+ */
+
+ DBG( ("mfs_control -> ensure term spec(7)\n") );
+
+ mfs_ensure_term_spec(dataP, 7);
+ DBG( ("mfs_control -> assign nil\n") );
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_NIL);
+ DBG( ("mfs_control -> assign type list\n") );
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_LIST);
+ DBG( ("mfs_control -> assign size of list: %d\n", dataP->token_counter + 1) );
+ ASSIGN_TERM_SPEC(dataP, dataP->token_counter + 1);
+ DBG( ("mfs_control -> assign type int\n") );
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_INT);
+#if defined(MEGACO_REENTRANT_FLEX_SCANNER)
+ DBG( ("mfs_control -> assign lineno (or tokenno): %d\n", yyget_lineno(scanner)) );
+ // ASSIGN_TERM_SPEC(LINENO_OR_TOKENCNT);
+ ASSIGN_TERM_SPEC(dataP, yyget_lineno(scanner));
+#else
+ DBG( ("mfs_control -> assign lineno (or tokenno): %d\n", LINENO_OR_TOKENCNT(dataP)) );
+ // ASSIGN_TERM_SPEC(LINENO_OR_TOKENCNT);
+ ASSIGN_TERM_SPEC(dataP, LINENO_OR_TOKENCNT(dataP));
+#endif
+ // ASSIGN_TERM_SPEC(1);
+ DBG( ("mfs_control -> assign tuple\n") );
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_TUPLE);
+ DBG( ("mfs_control -> assign size 3\n") );
+ ASSIGN_TERM_SPEC(dataP, 3);
+
+ DBG( ("mfs_control -> send the term when"
+ "\n term_spec_index: %d"
+ "\n term_spec_size: %d\n",
+ dataP->term_spec_index, dataP->term_spec_size) );
+
+ driver_send_term(dataP->port,
+ driver_caller(dataP->port),
+ dataP->term_spec,
+ dataP->term_spec_index);
+
+ if (dataP->text_buf != NULL) FREE(dataP->text_buf);
+ if (dataP->term_spec != NULL) FREE(dataP->term_spec);
+
+#if defined(MEGACO_REENTRANT_FLEX_SCANNER)
+
+ /*
+ * R e e n t r a n t s c a n n e r
+ */
+
+ DBG( ("mfs_control -> delete buffer\n") );
+ yy_delete_buffer(state, scanner);
+
+ DBG( ("mfs_control -> destroy scanner\n") );
+ yylex_destroy(scanner);
+
+#endif
+
+ DBG( ("mfs_control -> done (0)\n") );
+
+ return 0;
+
+ } else {
+ /*
+ * Return the error message
+ */
+ int len = strlen(dataP->error_msg);
+
+ DBG( ("mfs_control -> return the error message: \n%s\n\n",
+ dataP->error_msg) );
+
+ /*
+ * If we fail to alloc a bigger block of memory
+ * we have to make do with what we got
+ */
+ if (res_buf_len < len) {
+ void *tmp = ALLOC(len);
+ if (tmp != NULL)
+ *res_buf = tmp;
+ else
+ len = res_buf_len;
+ }
+
+ strncpy(*res_buf, dataP->error_msg, len);
+
+ if (dataP->text_buf != NULL) FREE(dataP->text_buf);
+ if (dataP->term_spec != NULL) FREE(dataP->term_spec);
+
+#if defined(MEGACO_REENTRANT_FLEX_SCANNER)
+
+ /*
+ * R e e n t r a n t s c a n n e r
+ */
+
+ DBG( ("mfs_control -> delete buffer\n") );
+ yy_delete_buffer(state, scanner);
+
+ DBG( ("mfs_control -> destroy scanner\n") );
+ yylex_destroy(scanner);
+
+#endif
+
+ DBG( ("mfs_control -> done (%d)\n", len) );
+
+ return len;
+ }
+}
+
+static void mfs_finish(void)
+{
+ return;
+}
+
+static void mfs_fatal_error(MfsErlDrvData* dataP, char* msg)
+{
+ if (!dataP->error) {
+ int len = strlen(msg);
+
+ if (len >= sizeof(dataP->error_msg))
+ len = sizeof(dataP->error_msg) - 1;
+
+ strncpy(dataP->error_msg, msg, len);
+ dataP->error_msg[len] = '\0';
+ dataP->error = TRUE;
+ }
+}
diff --git a/lib/megaco/src/flex/megaco_flex_scanner_handler.erl b/lib/megaco/src/flex/megaco_flex_scanner_handler.erl
new file mode 100644
index 0000000000..d09e0c6fff
--- /dev/null
+++ b/lib/megaco/src/flex/megaco_flex_scanner_handler.erl
@@ -0,0 +1,232 @@
+%%
+%% %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%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Handle the flex scanner
+%%----------------------------------------------------------------------
+
+-module(megaco_flex_scanner_handler).
+
+-behaviour(gen_server).
+
+
+%%-----------------------------------------------------------------
+%% Include files
+%%-----------------------------------------------------------------
+-include_lib("megaco/src/app/megaco_internal.hrl").
+
+
+%% External exports
+-export([
+ start_link/0, start_link/1,
+ stop/1,
+ get_config/1
+ ]).
+
+%% gen_server callbacks
+-export([
+ init/1,
+ handle_call/3, handle_cast/2, handle_info/2,
+ terminate/2,
+ code_change/3
+ ]).
+
+-record(state, {conf}).
+
+
+%%%----------------------------------------------------------------------
+%%% API
+%%%----------------------------------------------------------------------
+
+start_link() ->
+ start_link([]).
+
+start_link(Opts) ->
+ case gen_server:start_link(?MODULE, Opts, []) of
+ {ok, Pid} ->
+ Conf = get_config(Pid),
+ {ok, Pid, Conf};
+ Else ->
+ Else
+ end.
+
+stop(Pid) ->
+ gen_server:call(Pid, stop).
+
+get_config(Pid) ->
+ gen_server:call(Pid, get_config).
+
+
+%%%----------------------------------------------------------------------
+%%% Callback functions from gen_server
+%%%----------------------------------------------------------------------
+
+%%----------------------------------------------------------------------
+%% Func: init/1
+%% Returns: {ok, State} |
+%% {ok, State, Timeout} |
+%% ignore |
+%% {stop, Reason}
+%%----------------------------------------------------------------------
+init(_Opts) ->
+ process_flag(trap_exit, true),
+ case start_flex_scanners() of
+ {ok, PortOrPorts} ->
+ {ok, #state{conf = {flex, PortOrPorts}}};
+ {error, Reason} ->
+ %% {stop, {failed_starting_scanner, Reason, Opts}};
+ {stop, {failed_starting_scanner, Reason, []}};
+ Else ->
+ {stop, {failed_starting_scanner, Else}}
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Func: handle_call/3
+%% Returns: {reply, Reply, State} |
+%% {reply, Reply, State, Timeout} |
+%% {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, Reply, State} | (terminate/2 is called)
+%% {stop, Reason, State} (terminate/2 is called)
+%%----------------------------------------------------------------------
+handle_call(get_config, _From, #state{conf = Conf} = S) ->
+ {reply, Conf, S};
+
+handle_call(stop, _From, #state{conf = {flex, PortOrPorts}} = S) ->
+ megaco_flex_scanner:stop(PortOrPorts),
+ Reason = normal,
+ Reply = ok,
+ {stop, Reason, Reply, S};
+
+handle_call(Req, From, S) ->
+ warning_msg("received unexpected request from ~p: "
+ "~n~w", [From, Req]),
+ {reply, {error, {unknown_request, Req}}, S}.
+
+
+%%----------------------------------------------------------------------
+%% Func: handle_cast/2
+%% Returns: {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, State} (terminate/2 is called)
+%%----------------------------------------------------------------------
+handle_cast(Msg, S) ->
+ warning_msg("received unexpected message: "
+ "~n~w", [Msg]),
+ {noreply, S}.
+
+
+%%----------------------------------------------------------------------
+%% Func: handle_info/2
+%% Returns: {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, State} (terminate/2 is called)
+%%----------------------------------------------------------------------
+handle_info({'EXIT', Port, Error}, #state{conf = {flex, PortOrPorts}} = S) ->
+ case megaco_flex_scanner:is_scanner_port(Port, PortOrPorts) of
+ true ->
+ error_msg("Port [~p] exited:"
+ "~n~w", [Port, Error]),
+ {stop, {port_exit, Port, Error}, S};
+ false ->
+ {noreply, S}
+ end;
+
+handle_info({'EXIT', Port, _Error}, S) when is_port(Port) ->
+ %% This is propably the old flex scanner,
+ %% terminating after a code change...
+ {noreply, S};
+
+handle_info({'EXIT', Id, Error}, S) ->
+ warning_msg("received unexpected 'EXIT' signal from ~p:"
+ "~n~w", [Id, Error]),
+ {noreply, S};
+
+handle_info(Info, S) ->
+ warning_msg("received unexpected info: "
+ "~n~w", [Info]),
+ {noreply, S}.
+
+
+%%----------------------------------------------------------------------
+%% Func: terminate/2
+%% Purpose: Shutdown the server
+%% Returns: any (ignored by gen_server)
+%%----------------------------------------------------------------------
+terminate(_Reason, _S) ->
+ ok.
+
+
+%%----------------------------------------------------------------------
+%% Func: code_change/3
+%% Purpose: Called to change the internal state
+%% Returns: {ok, NewState}
+%%----------------------------------------------------------------------
+%% code_change({down, _Vsn}, #state{conf = Conf} = State, downgrade_to_pre_3_8) ->
+%% Port = downgrade_flex_scanner(Conf),
+%% {ok, State#state{conf = {flex, Port}}};
+
+code_change(_Vsn, State, _Extra) ->
+ {ok, State}.
+
+%% downgrade_flex_scanner({flex, Port}) when is_port(Port) ->
+%% Port;
+%% downgrade_flex_scanner({flex, [Port]}) when is_port(Port) ->
+%% Port;
+%% downgrade_flex_scanner({flex, Ports}) when is_list(Ports) ->
+%% megaco_flex_scanner:stop(Ports),
+%% case megaco_flex_scanner:start() of
+%% {ok, Port} ->
+%% Port;
+%% Error ->
+%% exit(Error)
+%% end;
+%% downgrade_flex_scanner(BadConfig) ->
+%% exit({invalid_config, BadConfig}).
+
+
+%%%----------------------------------------------------------------------
+%%% Internal functions
+%%%----------------------------------------------------------------------
+
+start_flex_scanners() ->
+ megaco_flex_scanner:start().
+
+
+%% get_env(Key, Opts, Default) ->
+%% case lists:keysearch(Key, 1, Opts) of
+%% {value, {Key, Value}} ->
+%% Value;
+%% false ->
+%% Default
+%% end.
+
+warning_msg(F, A) ->
+ ?megaco_warning("Flex scanner handler: " ++ F, A).
+
+error_msg(F, A) ->
+ ?megaco_error("Flex scanner handler: " ++ F, A).
+
+
+
+% d(F, A) ->
+% io:format("~w:" ++ F ++ "~n", [?MODULE|A]).
+
diff --git a/lib/megaco/src/flex/modules.mk b/lib/megaco/src/flex/modules.mk
new file mode 100644
index 0000000000..fb9957cffd
--- /dev/null
+++ b/lib/megaco/src/flex/modules.mk
@@ -0,0 +1,27 @@
+#-*-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_flex_scanner \
+ megaco_flex_scanner_handler
+
+FLEX_MODULES = megaco_flex_scanner_drv
+
+STD_DRV = megaco_flex_scanner_drv
+MT_DRV = megaco_flex_scanner_drv_mt
diff --git a/lib/megaco/src/flex/prebuild.skip b/lib/megaco/src/flex/prebuild.skip
new file mode 100644
index 0000000000..9c558e357c
--- /dev/null
+++ b/lib/megaco/src/flex/prebuild.skip
@@ -0,0 +1 @@
+.
diff --git a/lib/megaco/src/rules.mk b/lib/megaco/src/rules.mk
new file mode 100644
index 0000000000..20fbed2a76
--- /dev/null
+++ b/lib/megaco/src/rules.mk
@@ -0,0 +1,100 @@
+#-*-makefile-*- ; force emacs to enter makefile-mode
+
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 1999-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%
+
+.SUFFIXES: .erl .jam .beam .yrl .hrl .sgml .html .so .c .flex .flex.src
+
+
+CC = gcc
+CFLAGS = -g -O2 -funroll-loops -Wall -fPIC
+FLEX = flex
+PERL = perl
+
+# ----------------------------------------------------
+# Erlang language section
+# ----------------------------------------------------
+EMULATOR = beam
+ifeq ($(findstring vxworks,$(TARGET)),vxworks)
+# VxWorks jam object files should be compressed
+ERL_COMPILE_FLAGS += +compressed
+endif
+ERLC_WFLAGS = -W
+ERLC = erlc $(ERLC_WFLAGS) $(ERLC_FLAGS)
+ERL.beam = erl.beam -boot start_clean
+ERL.jam = erl -boot start_clean
+ERL = $(ERL.$(EMULATOR))
+
+ifndef EBIN
+EBIN = ../ebin
+endif
+
+ifndef ESRC
+ESRC = .
+endif
+
+$(EBIN)/%.jam: $(ESRC)/%.erl
+ $(ERLC) -bjam $(ERL_COMPILE_FLAGS) -o$(EBIN) $<
+
+$(EBIN)/%.beam: $(ESRC)/%.erl
+ $(ERLC) -bbeam $(ERL_COMPILE_FLAGS) -o$(EBIN) $<
+
+.erl.jam:
+ $(ERLC) -bjam $(ERL_COMPILE_FLAGS) -o$(dir $@) $<
+
+.erl.beam:
+ $(ERLC) -bbeam $(ERL_COMPILE_FLAGS) -o$(dir $@) $<
+
+#
+# When .erl files are automatically created GNU make removes them if
+# they were the result of a chain of implicit rules. To prevent this
+# we say that all .erl files are "precious".
+#
+.PRECIOUS: %.erl
+
+## Uncomment these lines and add .idl to suffixes above to have erlc
+## eat IDL files
+##.idl.erl:
+## $(ERLC) $(IDL_FLAGS) $<
+
+.yrl.erl:
+ $(ERLC) $(YRL_FLAGS) $<
+
+.xrl.erl:
+ $(ERLC) $(XRL_FLAGS) $<
+
+## generating app files
+
+$(EBIN)/%.app: $(ESRC)/%.app.src $(VSN_FILE)
+ sed -e 's;%VSN%;$(VSN);' $< > $@
+
+$(EBIN)/%.appup: $(ESRC)/%.appup.src $(VSN_FILE)
+ sed -e 's;%VSN%;$(VSN);' $< > $@
+
+
+.c.so:
+ $(CC) $(CFLAGS) -fpic -shared -o $*.so $< -lfl
+
+
+# ----------------------------------------------------
+# Command macros
+# ----------------------------------------------------
+INSTALL = /usr/ucb/install -c
+INSTALL_DIR = /usr/ucb/install -c -d
+INSTALL_PROGRAM = ${INSTALL}
+INSTALL_DATA = ${INSTALL} -m 644
+
diff --git a/lib/megaco/src/subdirs.mk b/lib/megaco/src/subdirs.mk
new file mode 100644
index 0000000000..af1a679561
--- /dev/null
+++ b/lib/megaco/src/subdirs.mk
@@ -0,0 +1,21 @@
+#-*-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%
+
+SUB_DIRECTORIES = app engine text flex binary tcp udp
+
diff --git a/lib/megaco/src/tcp/Makefile b/lib/megaco/src/tcp/Makefile
new file mode 100644
index 0000000000..0bd4b7c4ee
--- /dev/null
+++ b/lib/megaco/src/tcp/Makefile
@@ -0,0 +1,107 @@
+#
+# %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)
+
+TARGET_FILES = \
+ $(MODULES:%=$(EBIN)/%.$(EMULATOR))
+
+
+# ----------------------------------------------------
+# FLAGS
+# ----------------------------------------------------
+ifeq ($(TYPE),debug)
+ERL_COMPILE_FLAGS += -Ddebug
+endif
+
+include ../app/megaco.mk
+
+ERL_COMPILE_FLAGS += \
+ $(MEGACO_ERL_COMPILE_FLAGS) \
+ -I../../include
+
+
+# ----------------------------------------------------
+# Targets
+# ----------------------------------------------------
+debug:
+ @${MAKE} TYPE=debug opt
+
+opt: $(TARGET_FILES)
+
+clean:
+ rm -f $(TARGET_FILES)
+ rm -f errs core *~
+
+docs:
+
+# ----------------------------------------------------
+# Special Build Targets
+# ----------------------------------------------------
+
+
+# ----------------------------------------------------
+# Release Target
+# ----------------------------------------------------
+include $(ERL_TOP)/make/otp_release_targets.mk
+
+
+release_spec: opt
+ $(INSTALL_DIR) $(RELSYSDIR)/ebin
+ $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
+ $(INSTALL_DIR) $(RELSYSDIR)/src
+ $(INSTALL_DIR) $(RELSYSDIR)/src/tcp
+ $(INSTALL_DATA) $(ERL_FILES) $(INTERNAL_HRL_FILES) $(RELSYSDIR)/src/tcp
+
+
+release_docs_spec:
+
+
+# ----------------------------------------------------
+# Include dependencies
+# ----------------------------------------------------
+
+include depend.mk
+
diff --git a/lib/megaco/src/tcp/depend.mk b/lib/megaco/src/tcp/depend.mk
new file mode 100644
index 0000000000..27b0feec94
--- /dev/null
+++ b/lib/megaco/src/tcp/depend.mk
@@ -0,0 +1,42 @@
+#-*-makefile-*- ; force emacs to enter makefile-mode
+
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2007-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%
+
+$(EBIN)/megaco_tcp.$(EMULATOR): megaco_tcp.erl \
+ megaco_tcp.hrl \
+ ../app/megaco_internal.hrl \
+ $(MEGACO_INCLUDEDIR)/megaco.hrl
+
+$(EBIN)/megaco_tcp_accept.$(EMULATOR): megaco_tcp_accept.erl \
+ ../app/megaco_internal.hrl \
+ $(MEGACO_INCLUDEDIR)/megaco.hrl
+
+$(EBIN)/megaco_tcp_connection.$(EMULATOR): megaco_tcp_connection.erl \
+ megaco_tcp.hrl \
+ ../app/megaco_internal.hrl \
+ $(MEGACO_INCLUDEDIR)/megaco.hrl
+
+$(EBIN)/megaco_tcp_sup.$(EMULATOR): megaco_tcp_sup.erl \
+ $(MEGACO_INCLUDEDIR)/megaco.hrl
+
+$(EBIN)/megaco_tcp_connection_sup.$(EMULATOR): megaco_tcp_connection_sup.erl \
+ $(MEGACO_INCLUDEDIR)/megaco.hrl
+
+$(EBIN)/megaco_tcp_accept_sup.$(EMULATOR): megaco_tcp_accept_sup.erl \
+ $(MEGACO_INCLUDEDIR)/megaco.hrl
+
diff --git a/lib/megaco/src/tcp/megaco_tcp.erl b/lib/megaco/src/tcp/megaco_tcp.erl
new file mode 100644
index 0000000000..45fd35eabc
--- /dev/null
+++ b/lib/megaco/src/tcp/megaco_tcp.erl
@@ -0,0 +1,692 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1999-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:
+%% Interface the TPKT (TCP/IP) transport module for Megaco/H.248
+%%
+%%-----------------------------------------------------------------
+-module(megaco_tcp).
+
+-behaviour(gen_server).
+
+
+%%-----------------------------------------------------------------
+%% Include files
+%%-----------------------------------------------------------------
+-include_lib("megaco/include/megaco.hrl").
+-include_lib("megaco/src/tcp/megaco_tcp.hrl").
+-include_lib("megaco/src/app/megaco_internal.hrl").
+
+
+-define(d1(F, A), ?d("~p " ++ F, [self()|A])).
+-define(d2(F), ?d1(F, [])).
+
+
+%%-----------------------------------------------------------------
+%% External exports
+%%-----------------------------------------------------------------
+-export([
+ start_transport/0, %% Start TPKT transport service
+ stop_transport/1, %% Stop TPKT transport service
+ listen/2, %% Starts a new listener socket
+ connect/2, %% Used on client side to connect server
+ socket/1, %% Returns the inet socket
+ send_message/2, %% Used to send data on connection
+ block/1, %% Used to block the socket for incomming
+ %% messages
+ unblock/1, %% Used to unblock the node
+ close/1, %% Used on both sides to close connection
+
+ upgrade_receive_handle/2
+ ]).
+
+%% Statistics exports
+-export([
+ get_stats/0, get_stats/1, get_stats/2,
+ reset_stats/0, reset_stats/1
+ ]).
+
+
+%%-----------------------------------------------------------------
+%% Internal exports
+%%-----------------------------------------------------------------
+-export([
+ start_link/1, %% Start TCP/IP net server
+ init/1, %%
+ terminate/2,
+ handle_call/3,
+ handle_cast/2,
+ handle_info/2,
+ code_change/3,
+ start_connection/2
+ ]).
+
+
+%%-----------------------------------------------------------------
+%% Server state record
+%%-----------------------------------------------------------------
+-record(state, {supervisor_pid, linkdb}).
+
+
+%%-----------------------------------------------------------------
+%% External interface functions
+%%-----------------------------------------------------------------
+
+%%-----------------------------------------------------------------
+%% Func: get_stats/0, get_stats/1, get_stats/2
+%% Description: Retreive statistics (counters) for TCP
+%%-----------------------------------------------------------------
+get_stats() ->
+ megaco_stats:get_stats(megaco_tcp_stats).
+
+get_stats(Socket) ->
+ megaco_stats:get_stats(megaco_tcp_stats, Socket).
+
+get_stats(Socket, Counter) ->
+ megaco_stats:get_stats(megaco_tcp_stats, Socket, Counter).
+
+
+%%-----------------------------------------------------------------
+%% Func: reset_stats/0, reaet_stats/1
+%% Description: Reset statistics (counters) for TCP
+%%-----------------------------------------------------------------
+reset_stats() ->
+ megaco_stats:reset_stats(megaco_tcp_stats).
+
+reset_stats(Socket) ->
+ megaco_stats:reset_stats(megaco_tcp_stats, Socket).
+
+
+%%-----------------------------------------------------------------
+%% Func: start_transport/0
+%% Description: Starts the TPKT transport service
+%%-----------------------------------------------------------------
+start_transport() ->
+ ?d2("start_transport -> entry"),
+ (catch megaco_stats:init(megaco_tcp_stats)),
+ megaco_tcp_sup:start_link().
+
+
+%%-----------------------------------------------------------------
+%% Func: stop_transport/1, 2
+%% Description: Stop the TPKT transport service
+%%-----------------------------------------------------------------
+stop_transport(Pid) ->
+ (catch unlink(Pid)),
+ stop_transport(Pid, shutdown).
+
+stop_transport(Pid, Reason) ->
+ ?d1("stop_transport -> entry with"
+ "~n Pid: ~p"
+ "~n Reason: ~p", [Pid, Reason]),
+ exit(Pid, Reason).
+
+
+%%-----------------------------------------------------------------
+%% Func: listen/2
+%% Description: Starts new TPKT listener sockets
+%%-----------------------------------------------------------------
+listen(SupPid, Parameters) ->
+ ?d1("listen -> entry with"
+ "~n SupPid: ~p"
+ "~n Parameters: ~p", [SupPid, Parameters]),
+ ProcList = supervisor:which_children(SupPid),
+ case lists:keysearch(megaco_tcp, 1, ProcList) of
+ {value, {_Name, Pid, _Type, _Modules}} ->
+ ?d1("listen -> found listener: "
+ "~n Pid: ~p", [Pid]),
+ call(Pid, {add_listener, Parameters});
+ false ->
+ {error, no_tcp_server}
+ end.
+
+
+%%-----------------------------------------------------------------
+%% Func: connect
+%% Description: Function is used when opening an TCP socket
+%% at the MG side when trying to connect an MGC
+%%-----------------------------------------------------------------
+connect(SupPid, Parameters) ->
+ ?d1("connect -> entry with"
+ "~n SupPid: ~p"
+ "~n Parameters: ~p", [SupPid, Parameters]),
+ Mand = [host, port, receive_handle],
+ case parse_options(Parameters, #megaco_tcp{}, Mand) of
+ {ok, Rec} ->
+
+ ?d1("connect -> options parsed: "
+ "~n Rec: ~p", [Rec]),
+
+ #megaco_tcp{host = Host,
+ port = Port,
+ options = Options} = Rec,
+
+ IpOpt = [binary, {packet, tpkt}, {active, once} | Options],
+
+ %%------------------------------------------------------
+ %% Connect the other side
+ case (catch gen_tcp:connect(Host, Port, IpOpt)) of
+ {ok, Socket} ->
+ ?d1("connect -> connected: "
+ "~n Socket: ~p", [Socket]),
+ %%----------------------------------------------
+ %% Socket up start a new control process
+ Rec2 = Rec#megaco_tcp{socket = Socket},
+ case start_connection(SupPid, Rec2) of
+ {ok, Pid} ->
+ ?d1("connect -> connection started: "
+ "~n Pid: ~p", [Pid]),
+ gen_tcp:controlling_process(Socket, Pid),
+ ?d2("connect -> control transferred"),
+ {ok, Socket, Pid};
+ {error, Reason} ->
+ ?d1("connect -> failed starting connection: "
+ "~n Reason: ~p", [Reason]),
+ {error, Reason}
+ end;
+
+ {error, Reason} ->
+ ?d1("connect -> failed connecting: "
+ "~n Reason: ~p", [Reason]),
+ Error = {error, {gen_tcp_connect, Reason}},
+ ?tcp_debug(Rec, "tcp connect failed", [Error]),
+ Error;
+
+ {'EXIT', _Reason} = Exit ->
+ ?d1("connect -> connect exited: "
+ "~n Exit: ~p", [Exit]),
+ Error = {error, {gen_tcp_connect, Exit}},
+ ?tcp_debug(Rec, "tcp connect failed", [Error]),
+ Error
+
+ end;
+
+ {error, _Reason} = Error ->
+ ?d1("connect -> failed parsing options: "
+ "~n Error: ~p", [Error]),
+ ?tcp_debug(#megaco_tcp{}, "tcp connect failed",
+ [Error, {options, Parameters}]),
+ Error
+ end.
+
+
+%%-----------------------------------------------------------------
+%% Func: send_message
+%% Description: Function is used for sending data on the TCP socket
+%%-----------------------------------------------------------------
+send_message(Socket, Data) ->
+ ?d1("send_message -> entry with"
+ "~n Socket: ~p"
+ "~n size(Data): ~p", [Socket, sz(Data)]),
+ {Size, NewData} = add_tpkt_header(Data),
+ Res = gen_tcp:send(Socket, NewData),
+ case Res of
+ ok ->
+ incNumOutMessages(Socket),
+ incNumOutOctets(Socket, Size);
+ _ ->
+ ok
+ end,
+ Res.
+
+-ifdef(megaco_debug).
+sz(Bin) when is_binary(Bin) ->
+ size(Bin);
+sz(List) when is_list(List) ->
+ length(List).
+-endif.
+
+
+%%-----------------------------------------------------------------
+%% Func: block
+%% Description: Function is used for blocking incomming messages
+%% on the TCP socket
+%%-----------------------------------------------------------------
+block(Socket) ->
+ ?tcp_debug({socket, Socket}, "tcp block", []),
+ inet:setopts(Socket, [{active, false}]).
+
+
+%%-----------------------------------------------------------------
+%% Func: unblock
+%% Description: Function is used for blocking incomming messages
+%% on the TCP socket
+%%-----------------------------------------------------------------
+unblock(Socket) ->
+ ?tcp_debug({socket, Socket}, "tcp unblock", []),
+ inet:setopts(Socket, [{active, once}]).
+
+
+%%-----------------------------------------------------------------
+%% Func: close
+%% Description: Function is used for closing the TCP socket
+%%-----------------------------------------------------------------
+close(Socket) ->
+ ?tcp_debug({socket, Socket}, "tcp close", []),
+ gen_tcp:close(Socket).
+
+
+%%-----------------------------------------------------------------
+%% Func: socket
+%% Description: Returns the inet socket
+%%-----------------------------------------------------------------
+socket(Socket) ->
+ Socket.
+
+upgrade_receive_handle(Pid, NewHandle)
+ when is_pid(Pid) andalso is_record(NewHandle, megaco_receive_handle) ->
+ megaco_tcp_connection:upgrade_receive_handle(Pid, NewHandle).
+
+
+%%-----------------------------------------------------------------
+%% Internal Interface functions
+%%-----------------------------------------------------------------
+%%-----------------------------------------------------------------
+%% Func: start_link/1
+%% Description: Starts the net server
+%%-----------------------------------------------------------------
+start_link(Args) ->
+ gen_server:start_link(?MODULE, Args, []).
+
+
+%%-----------------------------------------------------------------
+%% Func: start_connection
+%% Description: Function is used for starting up a connection
+%% process
+%%-----------------------------------------------------------------
+start_connection(SupPid, #megaco_tcp{socket = Socket} = TcpRec) ->
+ ?d1("start_connection -> entry with"
+ "~n SupPid: ~p"
+ "~n Socket: ~p", [SupPid, Socket]),
+
+ case connection_sup(SupPid) of
+ {ok, ConnSupPid} ->
+ ?d1("start_connection -> found connection supervisor: "
+ "~n ConnSupPid: ~p", [ConnSupPid]),
+ ?tcp_debug(TcpRec, "tcp connect", []),
+ case create_connection(ConnSupPid, TcpRec) of
+ {ok, Pid} ->
+ ?d1("start_connection -> started: "
+ "~n Pid: ~p", [Pid]),
+ ?tcp_debug(TcpRec, "connect handler started", [Pid]),
+ create_snmp_counters(Socket),
+ {ok, Pid};
+ {error, Reason} ->
+ ?d1("start_connection -> failed starting: "
+ "~n Reason: ~p", [Reason]),
+ Error = {error, {controlling_process_not_started, Reason}},
+ ?tcp_debug(TcpRec, "tcp connect failed", [Error]),
+ Error
+ end;
+ {error, _Reason} ->
+ ?d2("start_connection -> could not find connection supervisor"),
+ Error = {error, no_connection_supervisor},
+ ?tcp_debug(TcpRec, "tcp connect failed", [Error]),
+ Error
+ end.
+
+connection_sup(Pid) ->
+ megaco_tcp_sup:which_connection_sup(Pid).
+
+create_connection(Pid, Rec) ->
+ megaco_tcp_connection_sup:start_child(Pid, Rec).
+
+create_snmp_counters(Socket) ->
+ Counters = [medGwyGatewayNumInMessages,
+ medGwyGatewayNumInOctets,
+ medGwyGatewayNumOutMessages,
+ medGwyGatewayNumOutOctets,
+ medGwyGatewayNumErrors],
+ create_snmp_counters(Socket, Counters).
+
+create_snmp_counters(_Socket, []) ->
+ ok;
+create_snmp_counters(Socket, [Counter|Counters]) ->
+ Key = {Socket, Counter},
+ ets:insert(megaco_tcp_stats, {Key, 0}),
+ create_snmp_counters(Socket, Counters).
+
+
+%%-----------------------------------------------------------------
+%% Server functions
+%%-----------------------------------------------------------------
+%%-----------------------------------------------------------------
+%% Func: init/1
+%% Description: Init funcion for the supervisor
+%%-----------------------------------------------------------------
+init({SupPid, _}) ->
+ process_flag(trap_exit, true),
+ {ok, #state{supervisor_pid = SupPid}}.
+
+%%-----------------------------------------------------------------
+%% Func: terminate/1
+%% Description: Termination function for the generic server
+%%-----------------------------------------------------------------
+terminate(_Reason, _State) ->
+ ok.
+
+
+%%-----------------------------------------------------------------
+%% Internal Functions
+%%-----------------------------------------------------------------
+
+%%-----------------------------------------------------------------
+%% Func: start_tcp_listener/2
+%% Description: Function which parses the list of transport layers
+%% to start
+%%-----------------------------------------------------------------
+start_tcp_listener(P, State) ->
+ ?d1("start_tcp_listener -> entry with"
+ "~n P: ~p", [P]),
+ case setup(State#state.supervisor_pid, P) of
+ {ok, Pid, Data} ->
+ ?d1("start_tcp_listener -> setup ok"
+ "~n Pid: ~p"
+ "~n Data: ~p", [Pid, Data]),
+ link(Pid),
+ {reply, ok,
+ State#state{linkdb=[{Pid, Data} | State#state.linkdb]}};
+ {error, Reason} ->
+ ?d1("start_tcp_listener -> setup failed"
+ "~n Reason: ~p", [Reason]),
+ {reply, {error, {could_not_start_listener, Reason}}, State}
+ end.
+
+
+%%-----------------------------------------------------------------
+%% Func: handle_call/3
+%% Description: Handling call messages (really just garbage)
+%%-----------------------------------------------------------------
+handle_call({add_listener, Parameters}, _From, State) ->
+ ?d1("handle_call(add_listener) -> entry with"
+ "~n Parameters: ~p", [Parameters]),
+ start_tcp_listener(Parameters, State);
+handle_call(Req, From, State) ->
+ warning_msg("received unexpected request from ~p: "
+ "~n~w", [From, Req]),
+ {noreply, State}.
+
+
+%%------------------------------------------------------------
+%% Func: handle_cast/2
+%% Description: Handling cast messages (really just garbage)
+%%------------------------------------------------------------
+handle_cast(Msg, State) ->
+ warning_msg("received unexpected message: "
+ "~n~w", [Msg]),
+ {noreply, State}.
+
+
+%%-----------------------------------------------------------------
+%% Func: handle_info/2
+%% Description: Handling non call/cast messages, eg exit messages
+%%-----------------------------------------------------------------
+handle_info({'EXIT', Pid, Reason}, State) when is_pid(Pid) ->
+ %% Accept process died
+ NewState = resetup(Pid, Reason, State),
+ {noreply, NewState};
+handle_info(Info, State) ->
+ warning_msg("received unexpected info: "
+ "~n~w", [Info]),
+ {noreply, State}.
+
+
+%%-----------------------------------------------------------------
+%% Func: code_change/3
+%% Descrition: Handles code change messages during upgrade.
+%%-----------------------------------------------------------------
+code_change(_Vsn, State, _Extra) ->
+ {ok, State}.
+
+
+%%-----------------------------------------------------------------
+%% Internal functions
+%%-----------------------------------------------------------------
+%%-----------------------------------------------------------------
+%% Func: setup/2
+%% Description: Function is used when setting up an TCP listen
+%% socket in the MGC
+%%-----------------------------------------------------------------
+setup(SupPid, Options) ->
+ ?d1("setup -> entry with"
+ "~n SupPid: ~p"
+ "~n Options: ~p", [SupPid, Options]),
+ Mand = [port, receive_handle],
+ case parse_options(Options, #megaco_tcp{}, Mand) of
+ {ok, TcpRec} ->
+
+ ?d1("setup -> options parsed"
+ "~n TcpRec: ~p", [TcpRec]),
+
+ %%------------------------------------------------------
+ %% Setup the listen socket
+ IpOpts = [binary, {packet, tpkt}, {active, once},
+ {reuseaddr, true} | TcpRec#megaco_tcp.options],
+ case catch gen_tcp:listen(TcpRec#megaco_tcp.port, IpOpts) of
+ {ok, Listen} ->
+
+ ?d1("setup -> listen ok"
+ "~n Listen: ~p", [Listen]),
+
+ %%-----------------------------------------------
+ %% Startup the accept process that will wait for
+ %% connect attempts
+ case start_accept(SupPid, TcpRec, Listen) of
+ {ok, Pid} ->
+
+ ?d1("setup -> accept process started"
+ "~n Pid: ~p", [Pid]),
+
+ ?tcp_debug(TcpRec, "tcp listen setup", []),
+ {ok, Pid, {TcpRec, Listen}};
+ {error, _Reason} = Error ->
+ ?d1("setup -> failed starting accept process"
+ "~n Error: ~p", [Error]),
+ ?tcp_debug(TcpRec, "tcp listen setup failed",
+ [Error]),
+ Error
+ end;
+ {error, Reason} ->
+ ?d1("setup -> listen failed"
+ "~n Reason: ~p", [Reason]),
+ Error = {error, {gen_tcp_listen, Reason}},
+ ?tcp_debug(TcpRec, "tcp listen setup failed", [Error]),
+ Error;
+ {'EXIT', _Reason} = Exit ->
+ ?d1("setup -> listen exited"
+ "~n Exit: ~p", [Exit]),
+ Error = {error, {gen_tcp_listen, Exit}},
+ ?tcp_debug(TcpRec, "tcp listen setup failed", [Error]),
+ Error
+ end;
+ {error, _Reason} = Error ->
+ ?d1("setup -> failed parsing options"
+ "~n Error: ~p", [Error]),
+ ?tcp_debug(#megaco_tcp{}, "tcp listen setup failed",
+ [Error, {options, Options}]),
+ Error
+ end.
+
+
+%%-----------------------------------------------------------------
+%% Func: resetup
+%% Description: Function is used when restarting the accept process
+%% if it died for some reason.
+%%-----------------------------------------------------------------
+
+resetup(Pid, Reason, State) ->
+ ?d1("resetup -> entry with"
+ "~n Pid: ~p"
+ "~n Reason: ~p", [Pid, Reason]),
+ case lists:keysearch(Pid, 1, State#state.linkdb) of
+ {value, {Pid, {TcpRec, Listener}}} ->
+ ?d1("resetup -> found accept process: "
+ "~n TcpRec: ~p"
+ "~n Listener: ~p", [TcpRec, Listener]),
+ ?tcp_debug(TcpRec, "tcp listen resetup", [{error, Reason}]),
+ unlink(Pid),
+ warning_msg("received unexpected 'EXIT' signal "
+ "from accept process ~p: "
+ "~n~w", [Pid, Reason]),
+ case start_accept(State#state.supervisor_pid, TcpRec, Listener) of
+ {ok, NewPid} ->
+ ?d1("resetup -> start new accept process ok: "
+ "~n NewPid: ~p", [NewPid]),
+ link(NewPid),
+ NewList = lists:keyreplace(Pid, 1, State#state.linkdb,
+ {NewPid, {TcpRec, Listener}}),
+ State#state{linkdb = NewList};
+ {error, Reason} ->
+ ?d1("resetup -> failed starting new accept process: "
+ "~n :Reason ~p", [Reason]),
+ ?tcp_debug(TcpRec,
+ "tcp listen resetup failed", [{error, Reason}]),
+ State
+ end;
+ false ->
+ warning_msg("received unexpected 'EXIT' signal from ~p: "
+ "~n~w", [Pid, Reason]),
+ State
+ end.
+
+
+%%-----------------------------------------------------------------
+%% Func: start_accept
+%% Description: Function is used for starting up an TCP accept
+%% process
+%%-----------------------------------------------------------------
+start_accept(SupPid, TcpRec, Listen) ->
+ ?d1("start_accept -> entry with"
+ "~n SupPid: ~p"
+ "~n TcpRec: ~p"
+ "~n Reason: ~p", [SupPid, TcpRec, Listen]),
+ case accept_sup(SupPid) of
+ {ok, AcceptSupPid} ->
+ ?d1("start_accept -> found accept supervisor"
+ "~n AcceptSupPid: ~p", [AcceptSupPid]),
+ case create_acceptor(AcceptSupPid, TcpRec, SupPid, Listen) of
+ {ok, Pid} ->
+ ?d1("start_accept -> accept process started"
+ "~n Pid: ~p", [Pid]),
+ {ok, Pid};
+ {error, Reason} ->
+ ?d1("start_accept -> failed starting accept process: "
+ "~n Reason: ~p", [Reason]),
+ {error, {accept_not_started, Reason}}
+ end;
+ {error, Reason} ->
+ ?d1("start_accept -> could not find acceept supervisor: "
+ "~n Reason: ~p", [Reason]),
+ {error, {no_tcp_accept_sup, Reason}}
+ end.
+
+accept_sup(Pid) ->
+ megaco_tcp_sup:which_accept_sup(Pid).
+
+create_acceptor(Pid, Rec, TopSup, Listen) ->
+ megaco_tcp_accept_sup:start_child(Pid, Rec, TopSup, Listen).
+
+
+%%-----------------------------------------------------------------
+%% Func: add_tpkt_header
+%% Description: Function is used to add the TPKT header
+%%-----------------------------------------------------------------
+add_tpkt_header(Data) when is_binary(Data) ->
+ L = size(Data) + 4,
+ {L, [3, 0, ((L) bsr 8) band 16#ff, (L) band 16#ff ,Data]};
+add_tpkt_header(IOList) when is_list(IOList) ->
+ Binary = list_to_binary(IOList),
+ L = size(Binary) + 4,
+ {L, [3, 0, ((L) bsr 8) band 16#ff, (L) band 16#ff , Binary]}.
+
+%%-----------------------------------------------------------------
+%% Func: parse_options
+%% Description: Function that parses the options sent to the TCP
+%% module.
+%%-----------------------------------------------------------------
+parse_options([{Tag, Val} | T], TcpRec, Mand) ->
+ ?d1("parse_options -> entry with"
+ "~n Tag: ~p"
+ "~n Val: ~p", [Tag, Val]),
+ Mand2 = Mand -- [Tag],
+ case Tag of
+ port ->
+ parse_options(T, TcpRec#megaco_tcp{port = Val}, Mand2);
+ host ->
+ parse_options(T, TcpRec#megaco_tcp{host = Val}, Mand2);
+ tcp_options when is_list(Val) ->
+ parse_options(T, TcpRec#megaco_tcp{options = Val}, Mand2);
+ receive_handle ->
+ parse_options(T, TcpRec#megaco_tcp{receive_handle = Val}, Mand2);
+ module when is_atom(Val) ->
+ parse_options(T, TcpRec#megaco_tcp{module = Val}, Mand2);
+ serialize when (Val =:= true) orelse (Val =:= false) ->
+ parse_options(T, TcpRec#megaco_tcp{serialize = Val}, Mand2);
+ Bad ->
+ ?d1("parse_options -> bad option: "
+ "~n Tag: ~p", [Tag]),
+ {error, {bad_option, Bad}}
+ end;
+parse_options([], TcpRec, []) ->
+ ?d2("parse_options -> done"),
+ {ok, TcpRec};
+parse_options([], _TcpRec, Mand) ->
+ ?d1("parse_options -> entry with"
+ "~n Mand: ~p", [Mand]),
+ {error, {missing_options, Mand}};
+parse_options(BadList, _TcpRec, _Mand) ->
+ ?d1("parse_options -> entry with"
+ "~n BadList: ~p", [BadList]),
+ {error, {bad_option_list, BadList}}.
+
+
+%%-----------------------------------------------------------------
+%% Func: incNumOutMessages/1, incNumOutOctets/2, incNumErrors/1
+%% Description: SNMP counter increment functions
+%%
+%%-----------------------------------------------------------------
+incNumOutMessages(Socket) ->
+ incCounter({Socket, medGwyGatewayNumOutMessages}, 1).
+
+incNumOutOctets(Socket, NumOctets) ->
+ incCounter({Socket, medGwyGatewayNumOutOctets}, NumOctets).
+
+incCounter(Key, Inc) ->
+ ets:update_counter(megaco_tcp_stats, Key, Inc).
+
+% incNumErrors(Socket) ->
+% ets:update_counter(megaco_tcp_stats,
+% {Socket, medGwyGatewayNumErrors}, 1).
+
+
+%%-----------------------------------------------------------------
+
+
+warning_msg(F, A) ->
+ ?megaco_warning("TCP server: " ++ F, A).
+
+%% error_msg(F, A) ->
+%% ?megaco_error("TCP server: " ++ F, A).
+
+
+call(Pid, Req) ->
+ gen_server:call(Pid, Req, infinity).
diff --git a/lib/megaco/src/tcp/megaco_tcp.hrl b/lib/megaco/src/tcp/megaco_tcp.hrl
new file mode 100644
index 0000000000..5de1dd9070
--- /dev/null
+++ b/lib/megaco/src/tcp/megaco_tcp.hrl
@@ -0,0 +1,68 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1999-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 the protocol options for Megaco/H.248 IP connections
+%%-----------------------------------------------------------------
+
+%%----------------------------------------------------------------------
+%% IP options
+%%----------------------------------------------------------------------
+-record(megaco_tcp,
+ {host,
+ port,
+ options = [],
+ socket,
+ proxy_pid,
+ receive_handle,
+ module = megaco,
+ serialize = false % false: Spawn a new process for each message
+ }).
+
+
+-define(GC_MSG_LIMIT,1000).
+-define(HEAP_SIZE(S),5000 + 2*(S)).
+
+
+%%----------------------------------------------------------------------
+%% Event Trace
+%%----------------------------------------------------------------------
+
+-define(tcp_report(Level, TcpRec, From, To, Label, Contents),
+ megaco:report_event(Level, From, To, Label,
+ [{line, ?MODULE, ?LINE}, TcpRec | Contents])).
+
+-define(tcp_debug(TcpRec, Label, Contents),
+ ?tcp_report_debug(TcpRec,
+ megaco_tcp,
+ megaco_tcp,
+ Label,
+ Contents)).
+
+-define(tcp_report_important(C, From, To, Label, Contents),
+ ?tcp_report(20, C, From, To, Label, Contents)).
+-define(tcp_report_verbose(C, From, To, Label, Contents),
+ ?tcp_report(40, C, From, To, Label, Contents)).
+-define(tcp_report_debug(C, From, To, Label, Contents),
+ ?tcp_report(60, C, From, To, Label, Contents)).
+-define(tcp_report_trace(C, From, To, Label, Contents),
+ ?tcp_report(80, C, From, To, Label, Contents)).
+
+
diff --git a/lib/megaco/src/tcp/megaco_tcp_accept.erl b/lib/megaco/src/tcp/megaco_tcp_accept.erl
new file mode 100644
index 0000000000..68bda8a340
--- /dev/null
+++ b/lib/megaco/src/tcp/megaco_tcp_accept.erl
@@ -0,0 +1,123 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1999-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: Waiting in accept for new connections.
+%%-----------------------------------------------------------------
+-module(megaco_tcp_accept).
+
+%%-----------------------------------------------------------------
+%% Include files
+%%-----------------------------------------------------------------
+-include_lib("megaco/src/tcp/megaco_tcp.hrl").
+-include_lib("megaco/src/app/megaco_internal.hrl").
+
+
+-define(d1(F, A), ?d("~p " ++ F, [self()|A])).
+-define(d2(F), ?d1(F, [])).
+
+
+%%-----------------------------------------------------------------
+%% External exports
+%%-----------------------------------------------------------------
+-export([
+ start_link/1
+ ]).
+
+
+%%-----------------------------------------------------------------
+%% Internal exports
+%%-----------------------------------------------------------------
+-export([
+ net_accept/4
+ ]).
+
+
+%%-----------------------------------------------------------------
+%% External interface functions
+%%-----------------------------------------------------------------
+%%-----------------------------------------------------------------
+%% Func: start
+%% Description: Starts the proces that makes the accept call.
+%%-----------------------------------------------------------------
+start_link({TcpRec, SupPid, Listen}) ->
+ Args = [TcpRec, SupPid, Listen, self()],
+ Pid = proc_lib:spawn_link(?MODULE, net_accept, Args),
+ {ok, Pid}.
+
+%%-----------------------------------------------------------------
+%% Internal Interface Functions
+%%-----------------------------------------------------------------
+%%-----------------------------------------------------------------
+%% Func: net_accept
+%% Description: Loop function which calls accept and
+%% spawns a connection process when there is an initial
+%% contact.
+%%-----------------------------------------------------------------
+net_accept(TcpRec, SupPid, ListenFd, Parent) ->
+ do_accept(TcpRec, SupPid, ListenFd),
+ net_accept(TcpRec, SupPid, ListenFd, Parent).
+
+do_accept(Tcp, Sup, Fd) ->
+ case gen_tcp:accept(Fd) of
+ {ok, S} ->
+ ?d1("do_accept -> accepted: "
+ "~n S: ~p", [S]),
+ case megaco_tcp:start_connection(Sup,
+ Tcp#megaco_tcp{socket = S}) of
+ {ok, Pid} ->
+ ?d1("do_accept -> connection started"
+ "~n Pid: ~p", [Pid]),
+ case gen_tcp:controlling_process(S, Pid) of
+ ok ->
+ ?d2("do_accept -> control transferred"),
+ ok;
+ {error, _Reason} ->
+ ?d1("do_accept -> "
+ "failed changing controlling process: "
+ "n _Reason: ~p", [_Reason]),
+ tcp_clear(S),
+ gen_tcp:close(S)
+ end;
+
+ {error, _Reason} ->
+ ?d1("do_accept -> failed starting connection: "
+ "~n _Reason: ~p", [_Reason]),
+ tcp_clear(S),
+ gen_tcp:close(S)
+ end;
+ {error, _Reason} ->
+ ?d1("do_accept -> accept failed: "
+ "~n _Reason: ~p", [_Reason]),
+ ok
+ end.
+
+
+tcp_clear(Socket) ->
+ receive
+ {tcp, Socket, _Data} ->
+ tcp_clear(Socket);
+ {tcp_closed, Socket} ->
+ tcp_clear(Socket);
+ {tcp_error, Socket} ->
+ tcp_clear(Socket)
+ after 0 ->
+ ok
+ end.
diff --git a/lib/megaco/src/tcp/megaco_tcp_accept_sup.erl b/lib/megaco/src/tcp/megaco_tcp_accept_sup.erl
new file mode 100644
index 0000000000..a601f32558
--- /dev/null
+++ b/lib/megaco/src/tcp/megaco_tcp_accept_sup.erl
@@ -0,0 +1,95 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1999-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: Supervisor for the tcp "accept" processes.
+%%-----------------------------------------------------------------
+-module(megaco_tcp_accept_sup).
+
+-behaviour(supervisor).
+
+
+%%-----------------------------------------------------------------
+%% External exports
+%%-----------------------------------------------------------------
+-export([
+ start_link/0,
+ start_child/4
+ ]).
+
+%%-----------------------------------------------------------------
+%% Internal exports
+%%-----------------------------------------------------------------
+-export([
+ init/1,
+ terminate/2
+ ]).
+
+%%-----------------------------------------------------------------
+%% External interface functions
+%%-----------------------------------------------------------------
+
+%%-----------------------------------------------------------------
+%% Func: start_link/1
+%% Description: Starts the process that keeps track of the TCP
+%% accept processes
+%%-----------------------------------------------------------------
+start_link() ->
+ supervisor:start_link(?MODULE, []).
+
+
+%%-----------------------------------------------------------------
+%% Func: start_link/1
+%% Description: Starts the acceptor process (the TCP accept
+%% processes)
+%%-----------------------------------------------------------------
+start_child(Pid, Rec, Ref, Listen) ->
+ ChildSpec = [{Rec, Ref, Listen}], % Simple one-for-one
+ supervisor:start_child(Pid, ChildSpec).
+
+
+%%-----------------------------------------------------------------
+%% Server functions
+%%-----------------------------------------------------------------
+%%-----------------------------------------------------------------
+%% Func: init/1
+%% Description: Init funcion for the supervisor
+%%-----------------------------------------------------------------
+init(_Options) ->
+ SupFlags = {simple_one_for_one, 500, 100},
+ ChildSpec = [
+ {megaco_accept,
+ {megaco_tcp_accept, start_link, []},
+ temporary, 10000, worker, []}
+ ],
+ {ok, {SupFlags, ChildSpec}}.
+
+
+%%-----------------------------------------------------------------
+%% Func: terminate/2
+%% Description: Termination function for the supervisor
+%%-----------------------------------------------------------------
+terminate(_Reason, _State) ->
+ ok.
+
+%%-----------------------------------------------------------------
+%% Internal functions
+%%-----------------------------------------------------------------
+
diff --git a/lib/megaco/src/tcp/megaco_tcp_connection.erl b/lib/megaco/src/tcp/megaco_tcp_connection.erl
new file mode 100644
index 0000000000..614edf513a
--- /dev/null
+++ b/lib/megaco/src/tcp/megaco_tcp_connection.erl
@@ -0,0 +1,275 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1999-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: Handles the Megaco/H.248 TCP connections.
+%%
+%%-----------------------------------------------------------------
+-module(megaco_tcp_connection).
+
+-behaviour(gen_server).
+
+
+%%-----------------------------------------------------------------
+%% Include files
+%%-----------------------------------------------------------------
+
+-include_lib("megaco/src/tcp/megaco_tcp.hrl").
+-include_lib("megaco/src/app/megaco_internal.hrl").
+
+
+%%-----------------------------------------------------------------
+%% External exports
+%%-----------------------------------------------------------------
+-export([
+ start_link/1,
+ stop/1,
+
+ upgrade_receive_handle/2
+ ]).
+
+%%-----------------------------------------------------------------
+%% Internal exports
+%%-----------------------------------------------------------------
+
+-export([
+ init/1,
+ handle_call/3,
+ handle_cast/2,
+ handle_info/2,
+ code_change/3,
+ terminate/2,
+
+ handle_received_message/5
+ ]).
+
+
+%%-----------------------------------------------------------------
+%% External interface functions
+%%-----------------------------------------------------------------
+
+%%-----------------------------------------------------------------
+%% Func: start_link/1
+%% Description: Starts the proces that keeps track of an TCP
+%% connection.
+%%-----------------------------------------------------------------
+
+start_link(Arg) ->
+ gen_server:start_link(?MODULE, Arg, []).
+
+
+stop(Pid) ->
+ call(Pid, stop).
+
+
+upgrade_receive_handle(Pid, NewHandle) ->
+ call(Pid, {upgrade_receive_handle, NewHandle}).
+
+
+%%-----------------------------------------------------------------
+%% Internal interface functions
+%%-----------------------------------------------------------------
+
+%%-----------------------------------------------------------------
+%% Server functions
+%%-----------------------------------------------------------------
+
+%%-----------------------------------------------------------------
+%% Func: init/1
+%% Description: Init funcion for the generic server
+%%-----------------------------------------------------------------
+init(Arg) ->
+ %% process_flag(trap_exit, true),
+ ?tcp_debug(Arg, "tcp connection handler starting", [self()]),
+%% info_msg("starting with"
+%% "~n Arg: ~p", [Arg]),
+ {ok, Arg}.
+
+
+%%-----------------------------------------------------------------
+%% Func: handle_call/3
+%% Description: Handling call messages (really just stop and garbage)
+%%-----------------------------------------------------------------
+handle_call(stop, _From, TcpRec) ->
+ {stop, shutdown, ok, TcpRec};
+handle_call({upgrade_receive_handle, NewHandle}, _From, TcpRec) ->
+ {reply, ok, TcpRec#megaco_tcp{receive_handle = NewHandle}};
+handle_call(Req, From, TcpRec) ->
+ warning_msg("received unexpected request from ~p: "
+ "~n~w", [From, Req]),
+ {reply, {error, {invalid_request, Req}}, TcpRec}.
+
+
+%%-----------------------------------------------------------------
+%% Func: handle_cast/2
+%% Description: Handling cast messages (really just stop and garbage)
+%%-----------------------------------------------------------------
+handle_cast(stop, TcpRec) ->
+ {stop, shutdown, TcpRec};
+handle_cast(Msg, TcpRec) ->
+ warning_msg("received unexpected message: "
+ "~n~w", [Msg]),
+ {noreply, TcpRec}.
+
+%%-----------------------------------------------------------------
+%% Func: handle_info/2
+%% Description: Handling non call/cast messages. Incomming messages
+%% from the socket and exit messages.
+%%-----------------------------------------------------------------
+handle_info({tcp_closed, _Socket}, TcpRec) ->
+ {stop, shutdown, TcpRec};
+handle_info({tcp_error, _Socket}, TcpRec) ->
+ {stop, shutdown, TcpRec};
+handle_info({tcp, Socket, <<3:8, _X:8, Length:16, Msg/binary>>},
+ #megaco_tcp{socket = Socket, serialize = false} = TcpRec)
+ when Length < ?GC_MSG_LIMIT ->
+ #megaco_tcp{module = Mod, receive_handle = RH} = TcpRec,
+ incNumInMessages(Socket),
+ incNumInOctets(Socket, 4+size(Msg)),
+ apply(Mod, receive_message, [RH, self(), Socket, Msg]),
+ inet:setopts(Socket, [{active, once}]),
+ {noreply, TcpRec};
+handle_info({tcp, Socket, <<3:8, _X:8, Length:16, Msg/binary>>},
+ #megaco_tcp{socket = Socket, serialize = false} = TcpRec) ->
+ #megaco_tcp{module = Mod, receive_handle = RH} = TcpRec,
+ incNumInMessages(Socket),
+ incNumInOctets(Socket, 4+size(Msg)),
+ receive_message(Mod, RH, Socket, Length, Msg),
+ inet:setopts(Socket, [{active, once}]),
+ {noreply, TcpRec};
+handle_info({tcp, Socket, <<3:8, _X:8, _Length:16, Msg/binary>>},
+ #megaco_tcp{socket = Socket, serialize = true} = TcpRec) ->
+ #megaco_tcp{module = Mod, receive_handle = RH} = TcpRec,
+ incNumInMessages(Socket),
+ incNumInOctets(Socket, 4+size(Msg)),
+ process_received_message(Mod, RH, Socket, Msg),
+ inet:setopts(Socket, [{active, once}]),
+ {noreply, TcpRec};
+handle_info({tcp, Socket, Msg}, TcpRec) ->
+ incNumErrors(Socket),
+ error_msg("received bad tpkt packet: "
+ "~n~w", [Msg]),
+ {noreply, TcpRec};
+handle_info(Info, TcpRec) ->
+ warning_msg("received unexpected info: "
+ "~n~p", [Info]),
+ {noreply, TcpRec}.
+
+
+process_received_message(Mod, RH, SH, Msg) ->
+ case (catch Mod:process_received_message(RH, self(), SH, Msg)) of
+ ok ->
+ ok;
+ Error ->
+ error_msg("failed processing received message: "
+ "~n~p", [Error]),
+ ok
+ end.
+
+
+receive_message(Mod, RH, SendHandle, Length, Msg) ->
+ Opts = [link , {min_heap_size, ?HEAP_SIZE(Length)}],
+ spawn_opt(?MODULE, handle_received_message,
+ [Mod, RH, self(), SendHandle, Msg], Opts),
+ ok.
+
+
+handle_received_message(Mod, RH, Parent, SH, Msg) ->
+ Mod:process_received_message(RH, Parent, SH, Msg),
+ unlink(Parent),
+ exit(normal).
+
+
+%%-----------------------------------------------------------------
+%% Func: terminate/2
+%% Description: Termination function for the generic server
+%%-----------------------------------------------------------------
+terminate(shutdown = _Reason, TcpRec) ->
+ ?tcp_debug(TcpRec, "tcp connection handler terminating", [self(),_Reason]),
+ ok;
+
+terminate(Reason, TcpRec) ->
+ ?tcp_debug(TcpRec, "tcp connection handler terminating", [self(), Reason]),
+ SchedId = erlang:system_info(scheduler_id),
+ SchedNum = erlang:system_info(schedulers),
+ ProcCount = erlang:system_info(process_count),
+ ProcLimit = erlang:system_info(process_limit),
+ ProcMemUsed = erlang:memory(processes_used),
+ ProcMemAlloc = erlang:memory(processes),
+ MemTot = erlang:memory(total),
+ error_msg("abormal termination: "
+ "~n Scheduler id: ~p"
+ "~n Num scheduler: ~p"
+ "~n Process count: ~p"
+ "~n Process limit: ~p"
+ "~n Memory used by erlang processes: ~p"
+ "~n Memory allocated by erlang processes: ~p"
+ "~n The total amount of memory allocated: ~p"
+ "~n~p",
+ [SchedId, SchedNum, ProcCount, ProcLimit,
+ ProcMemUsed, ProcMemAlloc, MemTot, Reason]),
+ ok.
+
+
+%%-----------------------------------------------------------------
+%% Func: code_change/3
+%% Descrition: Handles code change messages during upgrade.
+%%-----------------------------------------------------------------
+code_change(_OldVsn, S, _Extra) ->
+ ?d("code_change -> entry with"
+ "~n OldVsn: ~p"
+ "~n S: ~p"
+ "~n Extra: ~p", [_OldVsn, S, _Extra]),
+ {ok, S}.
+
+
+
+%%-----------------------------------------------------------------
+%% Func: incNumInMessages/1, incNumInOctets/2, incNumErrors/1
+%% Description: SNMP counter increment functions
+%%
+%%-----------------------------------------------------------------
+incNumInMessages(Socket) ->
+ incCounter({Socket, medGwyGatewayNumInMessages}, 1).
+
+incNumInOctets(Socket, NumOctets) ->
+ incCounter({Socket, medGwyGatewayNumInOctets}, NumOctets).
+
+incNumErrors(Socket) ->
+ incCounter({Socket, medGwyGatewayNumErrors}, 1).
+
+incCounter(Key, Inc) ->
+ ets:update_counter(megaco_tcp_stats, Key, Inc).
+
+
+%% info_msg(F, A) ->
+%% ?megaco_info("TCP connection handler " ++ F, A).
+
+warning_msg(F, A) ->
+ ?megaco_warning("TCP connection handler: " ++ F, A).
+
+error_msg(F, A) ->
+ ?megaco_error("TCP connection handler: " ++ F, A).
+
+
+call(Pid, Req) ->
+ gen_server:call(Pid, Req, infinity).
+
diff --git a/lib/megaco/src/tcp/megaco_tcp_connection_sup.erl b/lib/megaco/src/tcp/megaco_tcp_connection_sup.erl
new file mode 100644
index 0000000000..0ca8697418
--- /dev/null
+++ b/lib/megaco/src/tcp/megaco_tcp_connection_sup.erl
@@ -0,0 +1,114 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1999-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: Supervisor for all active connections
+%% independent of transport protocol.
+%%-----------------------------------------------------------------
+
+-module(megaco_tcp_connection_sup).
+
+-behaviour(supervisor).
+
+%%-----------------------------------------------------------------
+%% Include files
+%%-----------------------------------------------------------------
+-include_lib("megaco/include/megaco.hrl").
+
+%%-----------------------------------------------------------------
+%% External exports
+%%-----------------------------------------------------------------
+-export([
+ start_link/0,
+ start_child/2
+ ]).
+
+
+%%-----------------------------------------------------------------
+%% Internal exports
+%%-----------------------------------------------------------------
+-export([
+ init/1,
+ terminate/2,
+ start_connection/1
+ ]).
+
+
+%%-----------------------------------------------------------------
+%% External interface functions
+%%-----------------------------------------------------------------
+%%-----------------------------------------------------------------
+%% Func: start_link
+%% Description: Starts the connection supervisor
+%%-----------------------------------------------------------------
+start_link() ->
+ supervisor:start_link(?MODULE, [[]]).
+
+
+%% -----------------------------------------------------------------
+%% Func: start_child/2
+%% DEscription: Start a child (the connection) process
+%% -----------------------------------------------------------------
+start_child(Pid, TcpRec) ->
+ supervisor:start_child(Pid, [TcpRec]).
+
+
+%%-----------------------------------------------------------------
+%% Internal interface functions
+%%-----------------------------------------------------------------
+
+%%-----------------------------------------------------------------
+%% Func: start_connection/1
+%% Description: Function which the supervisor calls to start a child
+%%-----------------------------------------------------------------
+start_connection(Args) ->
+ megaco_tcp_connection:start_link(Args).
+
+
+%%-----------------------------------------------------------------
+%% Server functions
+%%-----------------------------------------------------------------
+%%-----------------------------------------------------------------
+%% Func: init/1
+%% Description: Init funcion for the supervisor
+%%-----------------------------------------------------------------
+init(_) ->
+ SupFlags = {simple_one_for_one, 500, 100},
+ ChildSpec = [
+ {megaco_tcp_connection,
+ {?MODULE, start_connection, []},
+ temporary,
+ 10000,
+ worker,
+ []}
+ ],
+ {ok, {SupFlags, ChildSpec}}.
+
+
+%%-----------------------------------------------------------------
+%% Func: terminate/1
+%% Description: Termination function for the supervisor
+%%-----------------------------------------------------------------
+terminate(_Reason, _State) ->
+ ok.
+
+%%-----------------------------------------------------------------
+%% Internal functions
+%%-----------------------------------------------------------------
diff --git a/lib/megaco/src/tcp/megaco_tcp_sup.erl b/lib/megaco/src/tcp/megaco_tcp_sup.erl
new file mode 100644
index 0000000000..6afc7582ec
--- /dev/null
+++ b/lib/megaco/src/tcp/megaco_tcp_sup.erl
@@ -0,0 +1,145 @@
+%%
+%% %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: Supervisor
+%%-----------------------------------------------------------------
+-module(megaco_tcp_sup).
+
+-behaviour(supervisor).
+
+%%-----------------------------------------------------------------
+%% Include files
+%%-----------------------------------------------------------------
+
+%%-----------------------------------------------------------------
+%% External exports
+%%-----------------------------------------------------------------
+-export([
+ start_link/0,
+ which_accept_sup/1,
+ which_connection_sup/1,
+ start_accept_child/2
+ ]).
+
+%%-----------------------------------------------------------------
+%% Internal exports
+%%-----------------------------------------------------------------
+-export([
+ init/1,
+ terminate/2
+ ]).
+
+%%-----------------------------------------------------------------
+%% External interface functions
+%%-----------------------------------------------------------------
+%%-----------------------------------------------------------------
+%% Func: start_link/1
+%% Description: Start an megaco net element supervisor
+%%-----------------------------------------------------------------
+start_link() ->
+ supervisor:start_link(?MODULE, []).
+
+
+%%-----------------------------------------------------------------
+%% Func: which_accept_sup/1
+%% Description: Get the pid() of the accept supervisor process
+%%-----------------------------------------------------------------
+which_accept_sup(Pid) ->
+ which_child(Pid, megaco_tcp_accept_sup).
+
+
+%%-----------------------------------------------------------------
+%% Func: which_connection_sup/1
+%% Description: Get the pid() of the connection supervisor process
+%%-----------------------------------------------------------------
+which_connection_sup(Pid) ->
+ which_child(Pid, megaco_tcp_connection_sup).
+
+
+%%-----------------------------------------------------------------
+%% Func: start_accept_child/1
+%% Description: Starts the process that keeps track of the TCP
+%% accept processes
+%%-----------------------------------------------------------------
+start_accept_child(SupPid, Data) ->
+ case supervisor:start_child(SupPid,
+ {megaco_tcp_accept,
+ {megaco_tcp_accept, start_link, [Data]},
+ temporary, 10000, worker,
+ [megaco_tcp_accept]}) of
+ {ok, ChildPid} ->
+ ChildPid;
+ {error, Reason} ->
+ {error, Reason}
+ end.
+
+
+%%-----------------------------------------------------------------
+%% Internal interface functions
+%%-----------------------------------------------------------------
+
+%%-----------------------------------------------------------------
+%% Server functions
+%%-----------------------------------------------------------------
+%%-----------------------------------------------------------------
+%% Func: init/1
+%% Description: Init funcion for the supervisor
+%%-----------------------------------------------------------------
+init([]) ->
+ SupFlags = {one_for_one, 5, 1000}, % Max 5 restarts in 1 second
+ ChildSpec = [sup_spec(megaco_tcp_accept_sup, []),
+ sup_spec(megaco_tcp_connection_sup,[]),
+ worker_spec(megaco_tcp, [{self(), []}], [gen_server])],
+ {ok, {SupFlags, ChildSpec}}.
+
+
+%%-----------------------------------------------------------------
+%% Func: terminate/2
+%% Description: Termination function for the supervisor
+%%-----------------------------------------------------------------
+terminate(_Reason, _State) ->
+ ok.
+
+
+%%-----------------------------------------------------------------
+%% Local functions
+%%-----------------------------------------------------------------
+
+which_child(Pid, Name) ->
+ ProcList = supervisor:which_children(Pid),
+ %% ProcList of type [{Name, Pid, Type, Modules}]
+ case lists:keysearch(Name, 1, ProcList) of
+ {value, {_Name, ChildPid, _Type, _Modules}} ->
+ {ok, ChildPid};
+ false ->
+ {error, no_such_process}
+ end.
+
+
+sup_spec(Name, Args) ->
+ {Name,
+ {Name, start_link, Args},
+ permanent, 10000, supervisor, [Name, supervisor]}.
+
+worker_spec(Name, Args, Mods) ->
+ {Name, {Name, start_link, Args},
+ permanent, 10000, worker, [Name] ++ Mods}.
+
diff --git a/lib/megaco/src/tcp/modules.mk b/lib/megaco/src/tcp/modules.mk
new file mode 100644
index 0000000000..505bd67792
--- /dev/null
+++ b/lib/megaco/src/tcp/modules.mk
@@ -0,0 +1,33 @@
+#-*-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_tcp \
+ megaco_tcp_sup \
+ megaco_tcp_accept \
+ megaco_tcp_accept_sup \
+ megaco_tcp_connection \
+ megaco_tcp_connection_sup
+
+
+INTERNAL_HRL_FILES = \
+ megaco_tcp.hrl
+
+
+
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
+
+
diff --git a/lib/megaco/src/udp/Makefile b/lib/megaco/src/udp/Makefile
new file mode 100644
index 0000000000..64b6478c2c
--- /dev/null
+++ b/lib/megaco/src/udp/Makefile
@@ -0,0 +1,117 @@
+#
+# %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)
+
+TARGET_FILES = \
+ $(MODULES:%=$(EBIN)/%.$(EMULATOR))
+
+
+# ----------------------------------------------------
+# FLAGS
+# ----------------------------------------------------
+ifeq ($(TYPE),debug)
+ERL_COMPILE_FLAGS += -Ddebug
+endif
+
+include ../app/megaco.mk
+
+ERL_COMPILE_FLAGS += \
+ $(MEGACO_ERL_COMPILE_FLAGS) \
+ -I../../include
+
+
+# ----------------------------------------------------
+# Targets
+# ----------------------------------------------------
+debug:
+ @${MAKE} TYPE=debug opt
+
+opt: $(TARGET_FILES)
+
+clean:
+ rm -f $(TARGET_FILES)
+ rm -f errs core *~
+
+docs:
+
+
+# ----------------------------------------------------
+# Special Build Targets
+# ----------------------------------------------------
+
+
+# ----------------------------------------------------
+# Release Target
+# ----------------------------------------------------
+include $(ERL_TOP)/make/otp_release_targets.mk
+
+
+release_spec: opt
+ $(INSTALL_DIR) $(RELSYSDIR)/ebin
+ $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
+ $(INSTALL_DIR) $(RELSYSDIR)/src
+ $(INSTALL_DIR) $(RELSYSDIR)/src/udp
+ $(INSTALL_DATA) $(ERL_FILES) $(INTERNAL_HRL_FILES) $(RELSYSDIR)/src/udp
+
+
+release_docs_spec:
+
+
+# ----------------------------------------------------
+# Include dependencies
+# ----------------------------------------------------
+
+$(EBIN)/megaco_udp.$(EMULATOR): megaco_udp.erl \
+ megaco_udp.hrl $(MEGACO_INCLUDEDIR)/megaco.hrl
+
+$(EBIN)/megaco_udp_server.$(EMULATOR): megaco_udp_server.erl \
+ megaco_udp.hrl $(MEGACO_INCLUDEDIR)/megaco.hrl
+
+$(EBIN)/megaco_udp_sup.$(EMULATOR): megaco_udp_sup.erl \
+ megaco_udp.hrl $(MEGACO_INCLUDEDIR)/megaco.hrl
+
+$(EBIN)/megaco_udp_test.$(EMULATOR): megaco_udp_test.erl \
+ megaco_udp.hrl $(MEGACO_INCLUDEDIR)/megaco.hrl
+
diff --git a/lib/megaco/src/udp/megaco_udp.erl b/lib/megaco/src/udp/megaco_udp.erl
new file mode 100644
index 0000000000..c75b703949
--- /dev/null
+++ b/lib/megaco/src/udp/megaco_udp.erl
@@ -0,0 +1,324 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1999-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: Interface to the UDP transport module for Megaco/H.248
+%%-----------------------------------------------------------------
+-module(megaco_udp).
+
+-include_lib("megaco/include/megaco.hrl").
+-include_lib("megaco/src/udp/megaco_udp.hrl").
+
+-record(send_handle, {socket, addr, port}).
+
+
+%%-----------------------------------------------------------------
+%% External exports
+%%-----------------------------------------------------------------
+-export([
+ start_transport/0, stop_transport/1,
+ open/2,
+ socket/1,
+ create_send_handle/3,
+ send_message/2,
+ close/1,
+ block/1,
+ unblock/1,
+
+ upgrade_receive_handle/2
+ ]).
+
+%% Statistics exports
+-export([get_stats/0, get_stats/1, get_stats/2,
+ reset_stats/0, reset_stats/1]).
+
+
+%%-----------------------------------------------------------------
+%% External interface functions
+%%-----------------------------------------------------------------
+
+%%-----------------------------------------------------------------
+%% Func: get_stats/0, get_stats/1, get_stats/2
+%% Description: Retreive statistics (counters) for TCP
+%%-----------------------------------------------------------------
+get_stats() ->
+ megaco_stats:get_stats(megaco_udp_stats).
+
+get_stats(SH) when is_record(SH, send_handle) ->
+ megaco_stats:get_stats(megaco_udp_stats, SH).
+
+get_stats(SH, Counter)
+ when is_record(SH, send_handle) andalso is_atom(Counter) ->
+ megaco_stats:get_stats(megaco_udp_stats, SH, Counter).
+
+
+%%-----------------------------------------------------------------
+%% Func: reset_stats/0, reaet_stats/1
+%% Description: Reset statistics (counters) for TCP
+%%-----------------------------------------------------------------
+reset_stats() ->
+ megaco_stats:reset_stats(megaco_udp_stats).
+
+reset_stats(SH) when is_record(SH, send_handle) ->
+ megaco_stats:reset_stats(megaco_udp_stats, SH).
+
+
+
+%%-----------------------------------------------------------------
+%% Func: start_transport
+%% Description: Starts the UDP transport service
+%%-----------------------------------------------------------------
+start_transport() ->
+ (catch megaco_stats:init(megaco_udp_stats)),
+ megaco_udp_sup:start_link().
+
+
+%%-----------------------------------------------------------------
+%% Func: stop_transport
+%% Description: Stop the UDP transport service
+%%-----------------------------------------------------------------
+stop_transport(Pid) ->
+ (catch unlink(Pid)),
+ stop_transport(Pid, shutdown).
+
+stop_transport(Pid, Reason) ->
+ exit(Pid, Reason).
+
+
+%%-----------------------------------------------------------------
+%% Func: open
+%% Description: Function is used when opening an UDP socket
+%%-----------------------------------------------------------------
+open(SupPid, Options) ->
+ Mand = [port, receive_handle],
+ case parse_options(Options, #megaco_udp{}, Mand) of
+ {ok, UdpRec} ->
+
+ %%------------------------------------------------------
+ %% Setup the socket
+ IpOpts = [binary, {reuseaddr, true}, {active, once} |
+ UdpRec#megaco_udp.options],
+
+ case (catch gen_udp:open(UdpRec#megaco_udp.port, IpOpts)) of
+ {ok, Socket} ->
+ ?udp_debug(UdpRec, "udp open", []),
+ NewUdpRec = UdpRec#megaco_udp{socket = Socket},
+ case start_udp_server(SupPid, NewUdpRec) of
+ {ok, ControlPid} ->
+ gen_udp:controlling_process(Socket, ControlPid),
+ {ok, Socket, ControlPid};
+ {error, Reason} ->
+ Error = {error, {could_not_start_udp_server, Reason}},
+ ?udp_debug({socket, Socket}, "udp close", []),
+ gen_udp:close(Socket),
+ Error
+
+ end;
+ {'EXIT', Reason} ->
+ Error = {error, {could_not_open_udp_port, Reason}},
+ ?udp_debug(UdpRec, "udp open exited", [Error]),
+ Error;
+ {error, Reason} ->
+ Error = {error, {could_not_open_udp_port, Reason}},
+ ?udp_debug(UdpRec, "udp open failed", [Error]),
+ Error
+ end;
+ {error, Reason} = Error ->
+ ?udp_debug(#megaco_udp{}, "udp open failed",
+ [Error, {options, Options}]),
+ {error, Reason}
+ end.
+
+
+%%-----------------------------------------------------------------
+%% Func: socket
+%% Description: Returns the inet socket
+%%-----------------------------------------------------------------
+socket(SH) when is_record(SH, send_handle) ->
+ SH#send_handle.socket;
+socket(Socket) ->
+ Socket.
+
+
+upgrade_receive_handle(Pid, NewHandle)
+ when is_pid(Pid) andalso is_record(NewHandle, megaco_receive_handle) ->
+ megaco_udp_server:upgrade_receive_handle(Pid, NewHandle).
+
+
+%%-----------------------------------------------------------------
+%% Func: create_send_handle
+%% Description: Function is used for creating the handle used when
+%% sending data on the UDP socket
+%%-----------------------------------------------------------------
+create_send_handle(Socket, {_, _, _, _} = Addr, Port) ->
+ do_create_send_handle(Socket, Addr, Port);
+create_send_handle(Socket, Addr0, Port) ->
+ {ok, Addr} = inet:getaddr(Addr0, inet),
+ do_create_send_handle(Socket, Addr, Port).
+
+do_create_send_handle(Socket, Addr, Port) ->
+ %% If neccessary create snmp counter's
+ SH = #send_handle{socket = Socket, addr = Addr, port = Port},
+ maybe_create_snmp_counters(SH),
+ SH.
+
+
+maybe_create_snmp_counters(SH) ->
+ Counters = [medGwyGatewayNumInMessages,
+ medGwyGatewayNumInOctets,
+ medGwyGatewayNumOutMessages,
+ medGwyGatewayNumOutOctets,
+ medGwyGatewayNumErrors],
+ %% Only need to check one of them, since either all of them exist
+ %% or none of them exist:
+ Key = {SH, medGwyGatewayNumInMessages},
+ case (catch ets:lookup(megaco_udp_stats, Key)) of
+ [] ->
+ create_snmp_counters(SH, Counters);
+ [_] ->
+ ok;
+ _ ->
+ ok
+ end.
+
+create_snmp_counters(_SH, []) ->
+ ok;
+create_snmp_counters(SH, [Counter|Counters]) ->
+ Key = {SH, Counter},
+ ets:insert(megaco_udp_stats, {Key, 0}),
+ create_snmp_counters(SH, Counters).
+
+
+%%-----------------------------------------------------------------
+%% Func: send_message
+%% Description: Function is used for sending data on the UDP socket
+%%-----------------------------------------------------------------
+send_message(SH, Data) when is_record(SH, send_handle) ->
+ #send_handle{socket = Socket, addr = Addr, port = Port} = SH,
+ Res = gen_udp:send(Socket, Addr, Port, Data),
+ case Res of
+ ok ->
+ incNumOutMessages(SH),
+ incNumOutOctets(SH, size(Data));
+ _ ->
+ ok
+ end,
+ Res;
+send_message(SH, _Data) ->
+ {error, {bad_send_handle, SH}}.
+
+
+%%-----------------------------------------------------------------
+%% Func: block
+%% Description: Function is used for blocking incomming messages
+%% on the TCP socket
+%%-----------------------------------------------------------------
+block(SH) when is_record(SH, send_handle) ->
+ block(SH#send_handle.socket);
+block(Socket) ->
+ ?udp_debug({socket, Socket}, "udp block", []),
+ inet:setopts(Socket, [{active, false}]).
+
+
+%%-----------------------------------------------------------------
+%% Func: unblock
+%% Description: Function is used for blocking incomming messages
+%% on the TCP socket
+%%-----------------------------------------------------------------
+unblock(SH) when is_record(SH, send_handle) ->
+ unblock(SH#send_handle.socket);
+unblock(Socket) ->
+ ?udp_debug({socket, Socket}, "udp unblock", []),
+ inet:setopts(Socket, [{active, once}]).
+
+
+%%-----------------------------------------------------------------
+%% Func: close
+%% Description: Function is used for closing the UDP socket
+%%-----------------------------------------------------------------
+close(#send_handle{socket = Socket}) ->
+ close(Socket);
+close(Socket) ->
+ ?udp_debug({socket, Socket}, "udp close", []),
+ case erlang:port_info(Socket, connected) of
+ {connected, ControlPid} ->
+ megaco_udp_server:stop(ControlPid);
+ undefined ->
+ {error, already_closed}
+ end.
+
+
+%%-----------------------------------------------------------------
+%% Internal functions
+%%-----------------------------------------------------------------
+%%-----------------------------------------------------------------
+%% Func: start_udp_server/1
+%% Description: Function is used for starting up a connection
+%% process
+%%-----------------------------------------------------------------
+start_udp_server(SupPid, UdpRec) ->
+ megaco_udp_sup:start_child(SupPid, UdpRec).
+
+
+%%-----------------------------------------------------------------
+%% Func: parse_options
+%% Description: Function that parses the options sent to the UDP
+%% module.
+%%-----------------------------------------------------------------
+parse_options([{Tag, Val} | T], UdpRec, Mand) ->
+ Mand2 = Mand -- [Tag],
+ case Tag of
+ port ->
+ parse_options(T, UdpRec#megaco_udp{port = Val}, Mand2);
+ udp_options when is_list(Val) ->
+ parse_options(T, UdpRec#megaco_udp{options = Val}, Mand2);
+ receive_handle ->
+ parse_options(T, UdpRec#megaco_udp{receive_handle = Val}, Mand2);
+ module when is_atom(Val) ->
+ parse_options(T, UdpRec#megaco_udp{module = Val}, Mand2);
+ serialize when (Val =:= true) orelse (Val =:= false) ->
+ parse_options(T, UdpRec#megaco_udp{serialize = Val}, Mand2);
+ Bad ->
+ {error, {bad_option, Bad}}
+ end;
+parse_options([], UdpRec, []) ->
+ {ok, UdpRec};
+parse_options([], _UdpRec, Mand) ->
+ {error, {missing_options, Mand}};
+parse_options(BadList, _UdpRec, _Mand) ->
+ {error, {bad_option_list, BadList}}.
+
+
+%%-----------------------------------------------------------------
+%% Func: incNumOutMessages/1, incNumOutOctets/2, incNumErrors/1
+%% Description: SNMP counter increment functions
+%%
+%%-----------------------------------------------------------------
+incNumOutMessages(SH) ->
+ incCounter({SH, medGwyGatewayNumOutMessages}, 1).
+
+incNumOutOctets(SH, NumOctets) ->
+ incCounter({SH, medGwyGatewayNumOutOctets}, NumOctets).
+
+incCounter(Key, Inc) ->
+ ets:update_counter(megaco_udp_stats, Key, Inc).
+
+% incNumErrors(SH) ->
+% incCounter({SH, medGwyGatewayNumErrors}, 1).
diff --git a/lib/megaco/src/udp/megaco_udp.hrl b/lib/megaco/src/udp/megaco_udp.hrl
new file mode 100644
index 0000000000..d0b9ec1916
--- /dev/null
+++ b/lib/megaco/src/udp/megaco_udp.hrl
@@ -0,0 +1,64 @@
+%%
+%% %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 the protocol options for Megaco/H.248 IP connections
+%%-----------------------------------------------------------------
+
+%%----------------------------------------------------------------------
+%% IP options
+%%----------------------------------------------------------------------
+-record(megaco_udp,
+ {port,
+ options = [],
+ socket,
+ receive_handle,
+ module = megaco,
+ serialize = false % false: Spawn a new process for each message
+ }).
+
+
+-define(GC_MSG_LIMIT,1000).
+-define(HEAP_SIZE(S),5000 + 2*(S)).
+
+
+%%----------------------------------------------------------------------
+%% Event Trace
+%%----------------------------------------------------------------------
+
+-define(udp_report(Level, UdpRec, From, To, Label, Contents),
+ megaco:report_event(Level, From, To, Label,
+ [{line, ?MODULE, ?LINE}, UdpRec | Contents])).
+
+-define(udp_debug(UdpRec, Label, Contents),
+ ?udp_report_debug(UdpRec,
+ megaco_udp,
+ megaco_udp,
+ Label,
+ Contents)).
+
+-define(udp_report_important(C, From, To, Label, Contents),
+ ?udp_report(20, C, From, To, Label, Contents)).
+-define(udp_report_verbose(C, From, To, Label, Contents),
+ ?udp_report(40, C, From, To, Label, Contents)).
+-define(udp_report_debug(C, From, To, Label, Contents),
+ ?udp_report(60, C, From, To, Label, Contents)).
+-define(udp_report_trace(C, From, To, Label, Contents),
+ ?udp_report(80, C, From, To, Label, Contents)).
diff --git a/lib/megaco/src/udp/megaco_udp_server.erl b/lib/megaco/src/udp/megaco_udp_server.erl
new file mode 100644
index 0000000000..f126043141
--- /dev/null
+++ b/lib/megaco/src/udp/megaco_udp_server.erl
@@ -0,0 +1,234 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1999-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%
+%%
+
+%%
+%%-----------------------------------------------------------------
+%%
+%% Description:
+%% This file handles the H.248 UDP connections.
+%%
+%%-----------------------------------------------------------------
+-module(megaco_udp_server).
+
+-behaviour(gen_server).
+
+%%-----------------------------------------------------------------
+%% Include files
+%%-----------------------------------------------------------------
+-include_lib("megaco/src/udp/megaco_udp.hrl").
+-include_lib("megaco/src/app/megaco_internal.hrl").
+
+
+%%-----------------------------------------------------------------
+%% External exports
+%%-----------------------------------------------------------------
+-export([
+ start_link/1,
+ stop/1,
+
+ upgrade_receive_handle/2
+ ]).
+
+%%-----------------------------------------------------------------
+%% Internal exports
+%%-----------------------------------------------------------------
+-export([
+ init/1,
+ handle_call/3,
+ handle_cast/2,
+ handle_info/2,
+ code_change/3,
+ terminate/2,
+
+ handle_received_message/5
+ ]).
+
+%%-----------------------------------------------------------------
+%% External interface functions
+%%-----------------------------------------------------------------
+%%-----------------------------------------------------------------
+%% Func: start_link/1
+%% Description: Starts the process that keeps track of an UDP
+%% socket.
+%%-----------------------------------------------------------------
+start_link(Arg) ->
+ gen_server:start_link(?MODULE, Arg, []).
+
+%%-----------------------------------------------------------------
+%% Func: stop/1
+%% Description: Stops the process that keeps track of an UDP
+%% socket.
+%%-----------------------------------------------------------------
+stop(Pid) ->
+ call(Pid, stop).
+
+
+upgrade_receive_handle(Pid, NewHandle) ->
+ call(Pid, {upgrade_receive_handle, NewHandle}).
+
+%%-----------------------------------------------------------------
+%% Internal interface functions
+%%-----------------------------------------------------------------
+
+%%-----------------------------------------------------------------
+%% Server functions
+%%-----------------------------------------------------------------
+%%-----------------------------------------------------------------
+%% Func: init/1
+%% Description: Init funcion for the generic server
+%%-----------------------------------------------------------------
+init(Arg) ->
+ ?udp_debug(Arg, "udp server starting", [self()]),
+ {ok, Arg}.
+
+%%-----------------------------------------------------------------
+%% Func: terminate/2
+%% Description: Termination function for the generic server
+%%-----------------------------------------------------------------
+terminate(Reason, State) ->
+ ?udp_debug(State, "udp server terminating", [self(), Reason]),
+ ok.
+
+%%-----------------------------------------------------------------
+%% Func: handle_call/3
+%% Description: Handling call messages (really just stop and garbage)
+%%-----------------------------------------------------------------
+handle_call(stop, _From, UdpRec) ->
+ Reply = do_stop(UdpRec),
+ {stop, shutdown, Reply, UdpRec};
+handle_call({upgrade_receive_handle, NewHandle}, _From, UdpRec) ->
+ {reply, ok, UdpRec#megaco_udp{receive_handle = NewHandle}};
+handle_call(Req, From, UdpRec) ->
+ warning_msg("received unexpected request from ~p: "
+ "~n~p", [From, Req]),
+ {reply, {error, {invalid_request, Req}}, UdpRec}.
+
+%%-----------------------------------------------------------------
+%% Func: handle_cast/2
+%% Description: Handling cast messages (really just stop and garbage)
+%%-----------------------------------------------------------------
+handle_cast(stop, UdpRec) ->
+ do_stop(UdpRec),
+ {stop, shutdown, UdpRec};
+handle_cast(Msg, UdpRec) ->
+ warning_msg("received unexpected message: "
+ "~n~w", [Msg]),
+ {noreply, UdpRec}.
+
+%%-----------------------------------------------------------------
+%% Func: handle_info/2
+%% Description: Handling non call/cast messages. Incomming messages
+%% from the socket and exit codes.
+%%-----------------------------------------------------------------
+handle_info({udp, _UdpId, Ip, Port, Msg},
+ #megaco_udp{serialize = false} = UdpRec) ->
+ #megaco_udp{socket = Socket, module = Mod, receive_handle = RH} = UdpRec,
+ SH = megaco_udp:create_send_handle(Socket, Ip, Port),
+ MsgSize = size(Msg),
+ incNumInMessages(SH),
+ incNumInOctets(SH, MsgSize),
+ case MsgSize of
+ Sz when Sz < ?GC_MSG_LIMIT ->
+ apply(Mod, receive_message, [RH, self(), SH, Msg]);
+ Sz ->
+ receive_message(Mod, RH, SH, Sz, Msg)
+ end,
+ inet:setopts(Socket, [{active, once}]),
+ {noreply, UdpRec};
+handle_info({udp, _UdpId, Ip, Port, Msg},
+ #megaco_udp{serialize = true} = UdpRec) ->
+ #megaco_udp{socket = Socket, module = Mod, receive_handle = RH} = UdpRec,
+ SH = megaco_udp:create_send_handle(Socket, Ip, Port),
+ MsgSize = size(Msg),
+ incNumInMessages(SH),
+ incNumInOctets(SH, MsgSize),
+ process_received_message(Mod, RH, SH, Msg),
+ inet:setopts(Socket, [{active, once}]),
+ {noreply, UdpRec};
+handle_info(Info, UdpRec) ->
+ warning_msg("received unexpected info: "
+ "~n~w", [Info]),
+ {noreply, UdpRec}.
+
+
+process_received_message(Mod, RH, SH, Msg) ->
+ case (catch Mod:process_received_message(RH, self(), SH, Msg)) of
+ ok ->
+ ok;
+ Error ->
+ error_msg("failed processing received message: "
+ "~n~p", [Error]),
+ ok
+ end.
+
+
+receive_message(Mod, RH, SendHandle, Length, Msg) ->
+ Opts = [link , {min_heap_size, ?HEAP_SIZE(Length)}],
+ spawn_opt(?MODULE, handle_received_message,
+ [Mod, RH, self(), SendHandle, Msg], Opts).
+
+
+handle_received_message(Mod, RH, Parent, SH, Msg) ->
+ Mod:process_received_message(RH, Parent, SH, Msg),
+ unlink(Parent),
+ exit(normal).
+
+
+
+%%-----------------------------------------------------------------
+%% Func: code_change/3
+%% Descrition: Handles code change messages during upgrade.
+%%-----------------------------------------------------------------
+code_change(_Vsn, State, _Extra) ->
+ {ok, State}.
+
+do_stop(#megaco_udp{socket = Socket}) ->
+ gen_udp:close(Socket).
+
+
+%%-----------------------------------------------------------------
+%% Func: incNumInMessages/1, incNumInOctets/2, incNumErrors/1
+%% Description: SNMP counter increment functions
+%%
+%%-----------------------------------------------------------------
+incNumInMessages(SH) ->
+ incCounter({SH, medGwyGatewayNumInMessages}, 1).
+
+incNumInOctets(SH, NumOctets) ->
+ incCounter({SH, medGwyGatewayNumInOctets}, NumOctets).
+
+incCounter(Key, Inc) ->
+ ets:update_counter(megaco_udp_stats, Key, Inc).
+
+% incNumErrors(SH) ->
+% incCounter({SH, medGwyGatewayNumErrors}, 1).
+
+
+%% info_msg(F, A) ->
+%% ?megaco_info("UDP server: " ++ F, A).
+
+warning_msg(F, A) ->
+ ?megaco_warning("UDP server: " ++ F, A).
+
+error_msg(F, A) ->
+ ?megaco_error("UDP server: " ++ F, A).
+
+
+call(Pid, Req) ->
+ gen_server:call(Pid, Req, infinity).
diff --git a/lib/megaco/src/udp/megaco_udp_sup.erl b/lib/megaco/src/udp/megaco_udp_sup.erl
new file mode 100644
index 0000000000..6a381c22d8
--- /dev/null
+++ b/lib/megaco/src/udp/megaco_udp_sup.erl
@@ -0,0 +1,112 @@
+%%
+%% %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: Supervisor for all active UDP port servers
+%%-----------------------------------------------------------------
+-module(megaco_udp_sup).
+
+-behaviour(supervisor).
+
+%%-----------------------------------------------------------------
+%% Include files
+%%-----------------------------------------------------------------
+-include_lib("megaco/include/megaco.hrl").
+
+%%-----------------------------------------------------------------
+%% External exports
+%%-----------------------------------------------------------------
+-export([
+ start_link/0,
+ start_child/2
+ ]).
+
+
+%%-----------------------------------------------------------------
+%% Internal exports
+%%-----------------------------------------------------------------
+-export([
+ init/1,
+ terminate/2,
+ start_server/1
+ ]).
+
+
+%%-----------------------------------------------------------------
+%% External interface functions
+%%-----------------------------------------------------------------
+
+%%-----------------------------------------------------------------
+%% Func: start_link
+%% Description: Starts the UDP port server supervisor
+%%-----------------------------------------------------------------
+start_link() ->
+ supervisor:start_link(?MODULE, [[]]).
+
+
+%%-----------------------------------------------------------------
+%% Func: start_child
+%% Description: Starts the UDP port server supervisor
+%%-----------------------------------------------------------------
+start_child(SupPid, UdpRec) ->
+ supervisor:start_child(SupPid, [UdpRec]).
+
+
+%%-----------------------------------------------------------------
+%% Internal interface functions
+%%-----------------------------------------------------------------
+%%-----------------------------------------------------------------
+%% Func: start_server/1
+%% Description: Function which the supervisor calls to start a child
+%%-----------------------------------------------------------------
+start_server(Args) ->
+ megaco_udp_server:start_link(Args).
+
+
+%%-----------------------------------------------------------------
+%% Server functions
+%%-----------------------------------------------------------------
+%%-----------------------------------------------------------------
+%% Func: init/1
+%% Description: Init funcion for the supervisor
+%%-----------------------------------------------------------------
+init(_) ->
+ SupFlags = {simple_one_for_one, 500, 100},
+ ChildSpec = [
+ {megaco_udp_server,
+ {?MODULE, start_server, []},
+ permanent,
+ 10000,
+ worker,
+ []}
+ ],
+ {ok, {SupFlags, ChildSpec}}.
+
+
+%%-----------------------------------------------------------------
+%% Func: terminate/1
+%% Description: Termination function for the supervisor
+%%-----------------------------------------------------------------
+terminate(_Reason, _State) ->
+ ok.
+
+%%-----------------------------------------------------------------
+%% Internal functions
+%%-----------------------------------------------------------------
diff --git a/lib/megaco/src/udp/modules.mk b/lib/megaco/src/udp/modules.mk
new file mode 100644
index 0000000000..47126f6207
--- /dev/null
+++ b/lib/megaco/src/udp/modules.mk
@@ -0,0 +1,30 @@
+#-*-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_udp \
+ megaco_udp_sup \
+ megaco_udp_server
+
+
+INTERNAL_HRL_FILES = \
+ megaco_udp.hrl
+
+
+