1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 2000-2020. All Rights Reserved.
5%%
6%% Licensed under the Apache License, Version 2.0 (the "License");
7%% you may not use this file except in compliance with the License.
8%% You may obtain a copy of the License at
9%%
10%%     http://www.apache.org/licenses/LICENSE-2.0
11%%
12%% Unless required by applicable law or agreed to in writing, software
13%% distributed under the License is distributed on an "AS IS" BASIS,
14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15%% See the License for the specific language governing permissions and
16%% limitations under the License.
17%%
18%% %CopyrightEnd%
19%%
20
21%%
22%%----------------------------------------------------------------------
23%% Purpose: Externalize/internalize Megaco/H.248 messages
24%%----------------------------------------------------------------------
25
26-module(megaco_erl_dist_encoder).
27
28-behaviour(megaco_encoder).
29
30-export([encode_message/3, decode_message/3,
31         decode_mini_message/3,
32
33	 encode_transaction/3,
34	 encode_action_requests/3,
35	 encode_action_request/3,
36	 encode_command_request/3,
37	 encode_action_reply/3
38	]).
39-export([version_of/2]).
40
41%% Backward compatible funcs:
42-export([encode_message/2, decode_message/2]).
43
44
45-include("megaco_message_internal.hrl").
46
47-define(MC_MOD, megaco_erl_dist_encoder_mc).
48
49
50%%----------------------------------------------------------------------
51%% Convert a 'MegacoMessage' record into a binary
52%% Return {ok, DeepIoList} | {error, Reason}
53%%----------------------------------------------------------------------
54
55encode_message(Config,
56	       #'MegacoMessage'{mess = #'Message'{version = V}} = MegaMsg) ->
57    encode_message(Config, V, MegaMsg).
58
59%% <BACKWARD-COMPAT-CLAUSE>
60encode_message([{version3, _}|EC], Vsn, MegaMsg) ->
61    encode_message(EC, Vsn, MegaMsg);
62%% </BACKWARD-COMPAT-CLAUSE>
63
64encode_message([megaco_compressed|Config], Vsn, MegaMsg)
65  when is_record(MegaMsg, 'MegacoMessage') ->
66    {ok, erlang:term_to_binary(?MC_MOD:encode(MegaMsg, Vsn), Config)};
67encode_message([{megaco_compressed, Mod}|Config], Vsn, MegaMsg)
68  when is_atom(Mod) and is_record(MegaMsg, 'MegacoMessage') ->
69    {ok, erlang:term_to_binary(Mod:encode(MegaMsg, Vsn), Config)};
70encode_message(Config, _Vsn, MegaMsg)
71  when is_record(MegaMsg, 'MegacoMessage') ->
72    {ok, erlang:term_to_binary(MegaMsg, Config)};
73encode_message(_Config, _Vsn, _MegaMsg) ->
74    {error, not_a_megaco_message}.
75
76
77%%----------------------------------------------------------------------
78%% Convert a transaction record into a binary
79%% Return {ok, Bin} | {error, Reason}
80%%----------------------------------------------------------------------
81
82%% <BACKWARD-COMPAT-CLAUSE>
83encode_transaction([{version3, _}|EC], Vsn, Trans) ->
84    encode_transaction(EC, Vsn, Trans);
85%% </BACKWARD-COMPAT-CLAUSE>
86
87encode_transaction([megaco_compressed|Config], _Vsn, Trans) ->
88    {ok, erlang:term_to_binary(?MC_MOD:encode(Trans), Config)};
89encode_transaction([{megaco_compressed, Mod}|Config], _Vsn, Trans) ->
90    {ok, erlang:term_to_binary(Mod:encode(Trans), Config)};
91encode_transaction(Config, _Vsn, Trans) ->
92    {ok, erlang:term_to_binary(Trans, Config)}.
93
94
95%%----------------------------------------------------------------------
96%% Convert a list of ActionRequest record's into a binary
97%% Return {ok, Binary} | {error, Reason}
98%%----------------------------------------------------------------------
99
100%% <BACKWARD-COMPAT-CLAUSE>
101encode_action_requests([{version3, _}|EC], Vsn, ActReqs) ->
102    encode_action_requests(EC, Vsn, ActReqs);
103%% </BACKWARD-COMPAT-CLAUSE>
104
105encode_action_requests([megaco_compressed|Config], Vsn, ActReqs0)
106  when is_list(ActReqs0) ->
107    ActReqs = [?MC_MOD:encode(AR, Vsn) || AR <- ActReqs0],
108    {ok, erlang:term_to_binary(ActReqs, Config)};
109encode_action_requests([{megaco_compressed, Mod}|Config], Vsn, ActReqs0)
110  when is_list(ActReqs0) ->
111    ActReqs = [Mod:encode(AR, Vsn) || AR <- ActReqs0],
112    {ok, erlang:term_to_binary(ActReqs, Config)};
113encode_action_requests(Config, _Vsn, ActReqs)
114  when is_list(ActReqs) ->
115    {ok, erlang:term_to_binary(ActReqs, Config)}.
116
117
118
119%%----------------------------------------------------------------------
120%% Convert a ActionRequest record into a binary
121%% Return {ok, Binary} | {error, Reason}
122%%----------------------------------------------------------------------
123
124%% <BACKWARD-COMPAT-CLAUSE>
125encode_action_request([{version3, _}|EC], Vsn, ActReq) ->
126    encode_action_request(EC, Vsn, ActReq);
127%% </BACKWARD-COMPAT-CLAUSE>
128
129encode_action_request([megaco_compressed|Config], Vsn, ActReq)
130  when is_tuple(ActReq) ->
131    {ok, erlang:term_to_binary(?MC_MOD:encode(ActReq, Vsn), Config)};
132encode_action_request([{megaco_compressed, Mod}|Config], Vsn, ActReq)
133  when is_tuple(ActReq) ->
134    {ok, erlang:term_to_binary(Mod:encode(ActReq, Vsn), Config)};
135encode_action_request(Config, _Vsn, ActReq)
136  when is_tuple(ActReq) ->
137    {ok, erlang:term_to_binary(ActReq, Config)}.
138
139
140
141%%----------------------------------------------------------------------
142%% Convert a CommandRequest record into a binary
143%% Return {ok, DeepIoList} | {error, Reason}
144%%----------------------------------------------------------------------
145
146%% <BACKWARD-COMPAT-CLAUSE>
147encode_command_request([{version3, _}|EC], Vsn, CmdReq) ->
148    encode_command_request(EC, Vsn, CmdReq);
149%% </BACKWARD-COMPAT-CLAUSE>
150
151encode_command_request([megaco_compressed|Config], Vsn, CmdReq)
152  when is_tuple(CmdReq) ->
153    {ok, erlang:term_to_binary(?MC_MOD:encode(CmdReq, Vsn), Config)};
154encode_command_request([{megaco_compressed, Mod}|Config], Vsn, CmdReq)
155  when is_tuple(CmdReq) ->
156    {ok, erlang:term_to_binary(Mod:encode(CmdReq, Vsn), Config)};
157encode_command_request(Config, _Vsn, CmdReq)
158  when is_tuple(CmdReq) ->
159    {ok, erlang:term_to_binary(CmdReq, Config)}.
160
161
162%%----------------------------------------------------------------------
163%% Convert a action reply into a binary
164%% Return {ok, DeepIoList} | {error, Reason}
165%%----------------------------------------------------------------------
166
167%% <BACKWARD-COMPAT-CLAUSE>
168encode_action_reply([{version3, _}|EC], Vsn, ActRep) ->
169    encode_action_reply(EC, Vsn, ActRep);
170%% </BACKWARD-COMPAT-CLAUSE>
171
172encode_action_reply([megaco_compressed|Config], Vsn, ActRep)
173  when is_tuple(ActRep) ->
174    {ok, erlang:term_to_binary(?MC_MOD:encode(ActRep, Vsn), Config)};
175encode_action_reply([{megaco_compressed, Mod}|Config], Vsn, ActRep)
176  when is_tuple(ActRep) ->
177    {ok, erlang:term_to_binary(Mod:encode(ActRep, Vsn), Config)};
178encode_action_reply(Config, _Vsn, ActRep)
179  when is_tuple(ActRep) ->
180    {ok, erlang:term_to_binary(ActRep, Config)}.
181
182
183%%----------------------------------------------------------------------
184%% Get the megaco version of the message
185%% Return {ok, Version} | {error, Reason}
186%%----------------------------------------------------------------------
187
188version_of(Config, Bin) when is_binary(Bin) ->
189    case decode_message(Config, 1, Bin) of
190	{ok, M} ->
191	    V = (M#'MegacoMessage'.mess)#'Message'.version,
192	    {ok, V};
193	Error ->
194	    Error
195    end.
196
197decode_message(Config, Bin) ->
198    decode_message(Config, 1, Bin).
199
200%% <BACKWARD-COMPAT-CLAUSE>
201decode_message([{version3, _}|EC], V, Bin) ->
202    decode_message(EC, V, Bin);
203%% </BACKWARD-COMPAT-CLAUSE>
204
205decode_message([megaco_compressed = MC|_Config], Vsn, Bin) ->
206    case catch erlang:binary_to_term(Bin) of
207	Msg when is_tuple(Msg) ->
208	    case (?MC_MOD:decode(Msg, Vsn)) of
209		MegaMsg when is_record(MegaMsg, 'MegacoMessage') ->
210		    {ok, dm(MegaMsg, MC, Vsn)};
211		_ ->
212		    {error, {bad_message, Msg}}
213	    end;
214	{'EXIT', _Reason} ->
215	    {error, bad_binary}
216    end;
217decode_message([{megaco_compressed, Mod} = MC|_Config], Vsn, Bin)
218  when is_atom(Mod) ->
219    case catch erlang:binary_to_term(Bin) of
220	Msg when is_tuple(Msg) ->
221	    case (Mod:decode(Msg, Vsn)) of
222		MegaMsg when is_record(MegaMsg, 'MegacoMessage') ->
223		    {ok, dm(MegaMsg, MC, Vsn)};
224		_ ->
225		    {error, {bad_message, Msg}}
226	    end;
227	{'EXIT', _Reason} ->
228	    {error, bad_binary}
229    end;
230decode_message(_Config, Vsn, Bin) ->
231    case catch erlang:binary_to_term(Bin) of
232	MegaMsg when is_record(MegaMsg, 'MegacoMessage') ->
233	    {ok, dm(MegaMsg, undefined, Vsn)};
234	{'EXIT', _Reason} ->
235	    {error, bad_binary}
236    end.
237
238
239decode_mini_message(EC, Vsn, Bin) when is_binary(Bin) ->
240    decode_message(EC, Vsn, Bin).
241
242
243%% This crap is because the transactions or the action-requests
244%% might have been encoded separetely
245
246dm(#'MegacoMessage'{mess = Mess} = M, MC, Vsn) ->
247    #'Message'{messageBody = Body} = Mess,
248    case Body of
249	{transactions, Transactions} ->
250	    Body2 = {transactions, dmt(Transactions, [], MC, Vsn)},
251	    Mess2 = Mess#'Message'{messageBody = Body2},
252	    M#'MegacoMessage'{mess = Mess2};
253	_ ->
254	    M
255    end.
256
257dmt([], Acc, _, _Vsn) ->
258    lists:reverse(Acc);
259dmt([Trans0|Transactions], Acc, MC, Vsn) when is_binary(Trans0) ->
260    Trans1 = erlang:binary_to_term(Trans0),
261    Trans2 = dmt1(Trans1, MC, Vsn),
262    dmt(Transactions, [Trans2|Acc], MC, Vsn);
263dmt([{Tag, Trans0}|Transactions], Acc, MC, Vsn) when is_binary(Trans0) ->
264    Trans1 = erlang:binary_to_term(Trans0),
265    Trans2 = dmt1(Trans1, MC, Vsn),
266    dmt(Transactions, [{Tag, Trans2}|Acc], MC, Vsn);
267dmt([{transactionRequest,
268      #'TransactionRequest'{actions = Acts0} = TR0}|Transactions],
269    Acc, MC, Vsn)
270  when is_binary(Acts0) ->
271    Acts1 = erlang:binary_to_term(Acts0),
272    Acts2 = dmt1(Acts1, MC, Vsn),
273    TR1 = TR0#'TransactionRequest'{actions = Acts2},
274    dmt(Transactions, [{transactionRequest, TR1}|Acc], MC, Vsn);
275dmt([{transactionRequest,
276      #'TransactionRequest'{actions = Acts0} = TR0}|Transactions],
277    Acc, MC, Vsn) ->
278    Acts2 = [dmt2(AR, MC, Vsn) || AR <- Acts0],
279    TR1 = TR0#'TransactionRequest'{actions = Acts2},
280    dmt(Transactions, [{transactionRequest, TR1}|Acc], MC, Vsn);
281dmt([Trans|Transactions], Acc, MC, Vsn) ->
282    dmt(Transactions, [Trans|Acc], MC, Vsn).
283
284dmt1(L, megaco_compressed, Vsn) when is_list(L) ->
285    [?MC_MOD:decode(E, Vsn) || E <- L];
286dmt1(L, {megaco_compressed, Mod}, Vsn) when is_list(L) ->
287    [Mod:decode(E, Vsn) || E <- L];
288dmt1(T, megaco_compressed, Vsn) when is_tuple(T) ->
289    ?MC_MOD:decode(T, Vsn);
290dmt1(T, {megaco_compressed, Mod}, Vsn) when is_tuple(T) ->
291    Mod:decode(T, Vsn);
292dmt1(Else, _, _Vsn) ->
293    Else.
294
295dmt2(Bin, MC, Vsn) when is_binary(Bin) ->
296    AR = erlang:binary_to_term(Bin),
297    dmt1(AR, MC, Vsn);
298dmt2(AR, _MC, _Vsn) ->
299    AR.
300
301
302