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: Encode COMPACT Megaco/H.248 text messages from internal form 24%%---------------------------------------------------------------------- 25 26-module(megaco_compact_text_encoder). 27 28-behaviour(megaco_encoder). 29 30-export([encode_message/3, decode_message/3, 31 decode_mini_message/3, 32 33 version_of/2, 34 35 encode_transaction/3, 36 encode_action_requests/3, 37 encode_action_request/3, 38 encode_command_request/3, 39 encode_action_reply/3]). 40 41-export([token_tag2string/1, token_tag2string/2]). 42 43%% Backward compatible funcs: 44-export([encode_message/2, decode_message/2]). 45 46 47-include_lib("megaco/src/engine/megaco_message_internal.hrl"). 48 49-define(V1_PARSE_MOD, megaco_text_parser_v1). 50-define(V2_PARSE_MOD, megaco_text_parser_v2). 51-define(V3_PARSE_MOD, megaco_text_parser_v3). 52 53 54%%---------------------------------------------------------------------- 55%% Convert a 'MegacoMessage' record into a binary 56%% Return {ok, DeepIoList} | {error, Reason} 57%%---------------------------------------------------------------------- 58 59encode_message(EncodingConfig, 60 #'MegacoMessage'{mess = #'Message'{version = V}} = MegaMsg) -> 61 encode_message(EncodingConfig, V, MegaMsg). 62 63%% <BACKWARD-COMPAT-CLAUSE> 64encode_message([{version3,_}|EC], 1, MegaMsg) -> 65 megaco_compact_text_encoder_v1:encode_message(EC, MegaMsg); 66%% </BACKWARD-COMPAT-CLAUSE> 67 68encode_message(EC, 1, MegaMsg) -> 69 megaco_compact_text_encoder_v1:encode_message(EC, MegaMsg); 70 71%% <BACKWARD-COMPAT-CLAUSE> 72encode_message([{version3,_}|EC], 2, MegaMsg) -> 73 megaco_compact_text_encoder_v2:encode_message(EC, MegaMsg); 74%% </BACKWARD-COMPAT-CLAUSE> 75 76encode_message(EC, 2, MegaMsg) -> 77 megaco_compact_text_encoder_v2:encode_message(EC, MegaMsg); 78 79%% <BACKWARD-COMPAT-CLAUSE> 80encode_message([{version3,v3}|EC], 3, MegaMsg) -> 81 megaco_compact_text_encoder_v3:encode_message(EC, MegaMsg); 82%% </BACKWARD-COMPAT-CLAUSE> 83 84encode_message(EC, 3, MegaMsg) -> 85 megaco_compact_text_encoder_v3:encode_message(EC, MegaMsg); 86encode_message(_EC, V, _MegaMsg) -> 87 {error, {bad_version, V}}. 88 89 90%%---------------------------------------------------------------------- 91%% Convert a binary into a 'MegacoMessage' record 92%% Return {ok, MegacoMessageRecord} | {error, Reason} 93%%---------------------------------------------------------------------- 94 95version_of(_EC, Bin) -> 96 case megaco_text_scanner:scan(Bin) of 97 {ok, _Tokens, V, _LastLine} -> 98 {ok, V}; 99 {error, Reason, Line} -> 100 {error, {decode_failed, Reason, Line}} 101 end. 102 103decode_message(EC, Bin) -> 104 %% d("decode_message -> entry with" 105 %% "~n EC: ~p", [EC]), 106 decode_message(EC, dynamic, Bin). 107 108decode_message([], _, Bin) when is_binary(Bin) -> 109 %% d("decode_message([]) -> entry"), 110 case megaco_text_scanner:scan(Bin) of 111 {ok, Tokens, 1, _LastLine} -> 112 do_decode_message(?V1_PARSE_MOD, Tokens, Bin); 113 114 {ok, Tokens, 2, _LastLine} -> 115 do_decode_message(?V2_PARSE_MOD, Tokens, Bin); 116 117 {ok, Tokens, 3, _LastLine} -> 118 do_decode_message(?V3_PARSE_MOD, Tokens, Bin); 119 120 {ok, _Tokens, V, _LastLine} -> 121 {error, {unsupported_version, V}}; 122 123 {error, Reason, Tokens, Line} -> 124 scan_error(Reason, Line, Tokens, Bin); 125 126 {error, Reason, Line} -> %% OTP-4007 127 scan_error(Reason, Line, Bin) %% OTP-4007 128 end; 129 130%% <BACKWARD-COMPAT-CLAUSE> 131decode_message([{version3,v3}], _, Bin) when is_binary(Bin) -> 132 %% d("decode_message(v3) -> entry"), 133 case megaco_text_scanner:scan(Bin) of 134 {ok, Tokens, 1, _LastLine} -> 135 do_decode_message(?V1_PARSE_MOD, Tokens, Bin); 136 137 {ok, Tokens, 2, _LastLine} -> 138 do_decode_message(?V2_PARSE_MOD, Tokens, Bin); 139 140 {ok, Tokens, 3, _LastLine} -> 141 do_decode_message(?V3_PARSE_MOD, Tokens, Bin); 142 143 {ok, _Tokens, V, _LastLine} -> 144 {error, {unsupported_version, V}}; 145 146 {error, Reason, Tokens, Line} -> 147 scan_error(Reason, Line, Tokens, Bin); 148 149 {error, Reason, Line} -> %% OTP-4007 150 scan_error(Reason, Line, Bin) %% OTP-4007 151 end; 152%% </BACKWARD-COMPAT-CLAUSE> 153 154decode_message([{flex, Port}], _, Bin) when is_binary(Bin) -> 155 %% d("decode_message(flex) -> entry"), 156 case megaco_flex_scanner:scan(Bin, Port) of 157 {ok, Tokens, 1, _LastLine} -> 158 do_decode_message(?V1_PARSE_MOD, Tokens, Bin); 159 160 {ok, Tokens, 2, _LastLine} -> 161 do_decode_message(?V2_PARSE_MOD, Tokens, Bin); 162 163 {ok, Tokens, 3, _LastLine} -> 164 do_decode_message(?V3_PARSE_MOD, Tokens, Bin); 165 166 {ok, _Tokens, V, _LastLine} -> 167 {error, {unsupported_version, V}}; 168 169 %% {error, Reason, Tokens, Line} -> 170 %% scan_error(Reason, Line, Tokens, Bin); 171 172 {error, Reason, Line} -> %% OTP-4007 173 scan_error(Reason, Line, Bin) %% OTP-4007 174 end; 175 176%% <BACKWARD-COMPAT-CLAUSE> 177decode_message([{version3,v3},{flex, Port}], _, Bin) when is_binary(Bin) -> 178 %% d("decode_message(v3,flex) -> entry"), 179 case megaco_flex_scanner:scan(Bin, Port) of 180 {ok, Tokens, 1, _LastLine} -> 181 do_decode_message(?V1_PARSE_MOD, Tokens, Bin); 182 183 {ok, Tokens, 2, _LastLine} -> 184 do_decode_message(?V2_PARSE_MOD, Tokens, Bin); 185 186 {ok, Tokens, 3, _LastLine} -> 187 do_decode_message(?V3_PARSE_MOD, Tokens, Bin); 188 189 {ok, _Tokens, V, _LastLine} -> 190 {error, {unsupported_version, V}}; 191 192 %% {error, Reason, Tokens, Line} -> 193 %% scan_error(Reason, Line, Tokens, Bin); 194 195 {error, Reason, Line} -> %% OTP-4007 196 scan_error(Reason, Line, Bin) %% OTP-4007 197 end; 198%% <BACKWARD-COMPAT-CLAUSE> 199 200decode_message(EC, _, Bin) when is_binary(Bin) -> 201 {error, {bad_encoding_config, EC}}; 202decode_message(_EC, _, _BadBin) -> 203 {error, bad_binary}. 204 205 206do_decode_message(ParseMod, Tokens, Bin) -> 207%% d("do_decode_message -> entry with" 208%% "~n ParseMod: ~p" 209%% "~n Tokens: ~p", [ParseMod, Tokens]), 210 case (catch ParseMod:parse(Tokens)) of 211 {ok, MegacoMessage} -> 212%% d("do_decode_message -> " 213%% "~n MegacoMessage: ~p", [MegacoMessage]), 214 {ok, MegacoMessage}; 215 {error, Reason} -> 216 parse_error(Reason, Tokens, Bin); 217 218 %% OTP-4007 219 {'EXIT', Reason} -> 220 parse_error(Reason, Tokens, Bin) 221 end. 222 223 224decode_mini_message(EC, _, Bin) when is_binary(Bin) -> 225 megaco_text_mini_decoder:decode_message(EC, Bin). 226 227 228scan_error(Reason, Line, Bin) -> 229 scan_error(Reason, Line, [], Bin). 230 231scan_error("bad_property_parm: " ++ Reason, _Line, _Tokens, _Bin) -> 232 {error, {bad_property_parm, Reason}}; 233scan_error(Reason, Line, Tokens, Bin) -> 234 %% io:format("scanner error: " 235 %% "~n Reason: ~p" 236 %% "~n Line: ~p" 237 %% "~n Tokens: ~p" 238 %% "~n Bin: ~p" 239 %% "~n", [Reason, Line, Tokens, Bin]), 240 {error, [{reason, Reason, Line}, {token, Tokens}, {chars, Bin}]}. 241 242parse_error(Reason, Tokens, Chars) -> 243 %% io:format("parser error -> entry with" 244 %% "~n Reason: ~p" 245 %% "~n Tokens: ~p" 246 %% "~n", [Reason, Tokens]), 247 case Reason of 248 {Line, Mod, [Prefix, [$[, TokenStringRaw, $]]]} when 249 is_integer(Line) andalso 250 is_atom(Mod) andalso 251 is_list(Prefix) andalso 252 is_list(TokenStringRaw) -> 253 TokenString = [l2i(X) || X <- TokenStringRaw, is_list(X)], 254 ReasonStr = Prefix ++ TokenString, 255 {error, [{reason, ReasonStr, Line}, {tokens, Tokens}, {chars, Chars}, {module, Mod}]}; 256 _ -> 257 {error, [{reason, Reason}, {token, Tokens}, {chars, Chars}]} 258 end. 259 260 261l2i(L) when is_list(L) -> 262 case (catch list_to_integer(L)) of 263 I when is_integer(I) -> 264 I; 265 _ -> 266 L 267 end. 268 269 270%%---------------------------------------------------------------------- 271%% Convert a transaction record into a deep io list 272%% Return {ok, DeepIoList} | {error, Reason} 273%%---------------------------------------------------------------------- 274 275%% <BACKWARD-COMPAT-CLAUSE> 276encode_transaction([{version3,_}|EC], 1, Trans) -> 277 megaco_compact_text_encoder_v1:encode_transaction(EC, Trans); 278%% </BACKWARD-COMPAT-CLAUSE> 279 280encode_transaction(EC, 1, Trans) -> 281 megaco_compact_text_encoder_v1:encode_transaction(EC, Trans); 282 283%% <BACKWARD-COMPAT-CLAUSE> 284encode_transaction([{version3,_}|EC], 2, Trans) -> 285 megaco_compact_text_encoder_v2:encode_transaction(EC, Trans); 286%% </BACKWARD-COMPAT-CLAUSE> 287 288encode_transaction(EC, 2, Trans) -> 289 megaco_compact_text_encoder_v2:encode_transaction(EC, Trans); 290 291%% <BACKWARD-COMPAT-CLAUSE> 292encode_transaction([{version3,v3}|EC], 3, Trans) -> 293 megaco_compact_text_encoder_v3:encode_transaction(EC, Trans); 294%% </BACKWARD-COMPAT-CLAUSE> 295 296encode_transaction(EC, 3, Trans) -> 297 megaco_compact_text_encoder_v3:encode_transaction(EC, Trans); 298encode_transaction(_EC, V, _Trans) -> 299 {error, {bad_version, V}}. 300 301 302%%---------------------------------------------------------------------- 303%% Convert a list of ActionRequest record's into a binary 304%% Return {ok, DeepIoList} | {error, Reason} 305%%---------------------------------------------------------------------- 306 307%% <BACKWARD-COMPAT-CLAUSE> 308encode_action_requests([{version3,_}|EC], 1, ActReqs) 309 when is_list(ActReqs) -> 310 megaco_compact_text_encoder_v1:encode_action_requests(EC, ActReqs); 311%% </BACKWARD-COMPAT-CLAUSE> 312 313encode_action_requests(EC, 1, ActReqs) when is_list(ActReqs) -> 314 megaco_compact_text_encoder_v1:encode_action_requests(EC, ActReqs); 315 316%% <BACKWARD-COMPAT-CLAUSE> 317encode_action_requests([{version3,_}|EC], 2, ActReqs) 318 when is_list(ActReqs) -> 319 megaco_compact_text_encoder_v2:encode_action_requests(EC, ActReqs); 320%% </BACKWARD-COMPAT-CLAUSE> 321 322encode_action_requests(EC, 2, ActReqs) when is_list(ActReqs) -> 323 megaco_compact_text_encoder_v2:encode_action_requests(EC, ActReqs); 324 325%% <BACKWARD-COMPAT-CLAUSE> 326encode_action_requests([{version3,v3}|EC], 3, ActReqs) 327 when is_list(ActReqs) -> 328 megaco_compact_text_encoder_v3:encode_action_requests(EC, ActReqs); 329%% </BACKWARD-COMPAT-CLAUSE> 330 331encode_action_requests(EC, 3, ActReqs) when is_list(ActReqs) -> 332 megaco_compact_text_encoder_v3:encode_action_requests(EC, ActReqs); 333encode_action_requests(_EC, V, _ActReqs) -> 334 {error, {bad_version, V}}. 335 336 337%%---------------------------------------------------------------------- 338%% Convert a ActionRequest record into a binary 339%% Return {ok, DeepIoList} | {error, Reason} 340%%---------------------------------------------------------------------- 341 342%% <BACKWARD-COMPAT-CLAUSE> 343encode_action_request([{version3,_}|EC], 1, ActReq) -> 344 megaco_compact_text_encoder_v1:encode_action_request(EC, ActReq); 345%% </BACKWARD-COMPAT-CLAUSE> 346 347encode_action_request(EC, 1, ActReq) -> 348 megaco_compact_text_encoder_v1:encode_action_request(EC, ActReq); 349 350%% <BACKWARD-COMPAT-CLAUSE> 351encode_action_request([{version3,_}|EC], 2, ActReq) -> 352 megaco_compact_text_encoder_v2:encode_action_request(EC, ActReq); 353%% </BACKWARD-COMPAT-CLAUSE> 354 355encode_action_request(EC, 2, ActReq) -> 356 megaco_compact_text_encoder_v2:encode_action_request(EC, ActReq); 357 358%% <BACKWARD-COMPAT-CLAUSE> 359encode_action_request([{version3,v3}|EC], 3, ActReq) -> 360 megaco_compact_text_encoder_v3:encode_action_request(EC, ActReq); 361%% </BACKWARD-COMPAT-CLAUSE> 362 363encode_action_request(EC, 3, ActReq) -> 364 megaco_compact_text_encoder_v3:encode_action_request(EC, ActReq); 365encode_action_request(_EC, V, _ActReq) -> 366 {error, {bad_version, V}}. 367 368 369%%---------------------------------------------------------------------- 370%% Convert a CommandRequest record into a deep io list 371%% Return {ok, DeepIoList} | {error, Reason} 372%%---------------------------------------------------------------------- 373 374%% <BACKWARD-COMPAT-CLAUSE> 375encode_command_request([{version3,_}|EC], 1, CmdReq) -> 376 megaco_compact_text_encoder_v1:encode_command_request(EC, CmdReq); 377%% </BACKWARD-COMPAT-CLAUSE> 378 379encode_command_request(EC, 1, CmdReq) -> 380 megaco_compact_text_encoder_v1:encode_command_request(EC, CmdReq); 381 382%% <BACKWARD-COMPAT-CLAUSE> 383encode_command_request([{version3,_}|EC], 2, CmdReq) -> 384 megaco_compact_text_encoder_v2:encode_command_request(EC, CmdReq); 385%% </BACKWARD-COMPAT-CLAUSE> 386 387encode_command_request(EC, 2, CmdReq) -> 388 megaco_compact_text_encoder_v2:encode_command_request(EC, CmdReq); 389 390%% <BACKWARD-COMPAT-CLAUSE> 391encode_command_request([{version3,v3}|EC], 3, CmdReq) -> 392 megaco_compact_text_encoder_v3:encode_command_request(EC, CmdReq); 393%% </BACKWARD-COMPAT-CLAUSE> 394 395encode_command_request(EC, 3, CmdReq) -> 396 megaco_compact_text_encoder_v3:encode_command_request(EC, CmdReq); 397encode_command_request(_EC, V, _CmdReq) -> 398 {error, {bad_version, V}}. 399 400 401%%---------------------------------------------------------------------- 402%% Convert a action reply into a deep io list 403%% Return {ok, DeepIoList} | {error, Reason} 404%%---------------------------------------------------------------------- 405 406%% <BACKWARD-COMPAT-CLAUSE> 407encode_action_reply([{version3,_}|EC], 1, ActRep) -> 408 megaco_compact_text_encoder_v1:encode_action_reply(EC, ActRep); 409%% </BACKWARD-COMPAT-CLAUSE> 410 411encode_action_reply(EC, 1, ActRep) -> 412 megaco_compact_text_encoder_v1:encode_action_reply(EC, ActRep); 413 414%% <BACKWARD-COMPAT-CLAUSE> 415encode_action_reply([{version3,_}|EC], 2, ActRep) -> 416 megaco_compact_text_encoder_v2:encode_action_reply(EC, ActRep); 417%% </BACKWARD-COMPAT-CLAUSE> 418 419encode_action_reply(EC, 2, ActRep) -> 420 megaco_compact_text_encoder_v2:encode_action_reply(EC, ActRep); 421 422%% <BACKWARD-COMPAT-CLAUSE> 423encode_action_reply([{version3,v3}|EC], 3, ActRep) -> 424 megaco_compact_text_encoder_v3:encode_action_reply(EC, ActRep); 425%% </BACKWARD-COMPAT-CLAUSE> 426 427encode_action_reply(EC, 3, ActRep) -> 428 megaco_compact_text_encoder_v3:encode_action_reply(EC, ActRep); 429encode_action_reply(_EC, V, _ActRep) -> 430 {error, {bad_version, V}}. 431 432 433 434%%---------------------------------------------------------------------- 435%% A utility function to pretty print the tags found in a megaco message 436%%---------------------------------------------------------------------- 437 438-define(TT2S_BEST_VERSION, v3). 439 440token_tag2string(Tag) -> 441 token_tag2string(Tag, ?TT2S_BEST_VERSION). 442 443token_tag2string(Tag, 1) -> 444 token_tag2string(Tag, v1); 445token_tag2string(Tag, v1) -> 446 megaco_compact_text_encoder_v1:token_tag2string(Tag); 447token_tag2string(Tag, 2) -> 448 token_tag2string(Tag, v2); 449token_tag2string(Tag, v2) -> 450 megaco_compact_text_encoder_v2:token_tag2string(Tag); 451token_tag2string(Tag, 3) -> 452 token_tag2string(Tag, v3); 453token_tag2string(Tag, v3) -> 454 megaco_compact_text_encoder_v3:token_tag2string(Tag); 455 456token_tag2string(Tag, _Vsn) -> 457 token_tag2string(Tag, ?TT2S_BEST_VERSION). 458 459