1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 2000-2019. 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 Megaco/H.248 text messages from internal form 24%%---------------------------------------------------------------------- 25 26-define(META_ENC(Type, Item), Item) . 27%% -define(META_ENC(Type, Item), megaco_meta_package:encode(text, Type, Item)). 28%% -define(META_DEC(Type, Item), megaco_meta_package:decode(text, Type, Item)). 29 30enc_MegacoMessage(Val) -> 31 State = ?INIT_INDENT, 32 enc_MegacoMessage(Val, State). 33 34enc_MegacoMessage(#'MegacoMessage'{authHeader = asn1_NOVALUE, 35 mess = Mess}, State) -> 36 [ 37 ?LWSP, 38 enc_Message(Mess, State) 39 ]; 40enc_MegacoMessage(#'MegacoMessage'{authHeader = Auth, 41 mess = Mess}, State) -> 42 [ 43 ?LWSP, 44 enc_AuthenticationHeader(Auth, State), 45 enc_Message(Mess, State) 46 ]. 47 48%% Note that encoding the transaction this way 49%% make the message look a bit strange. 50enc_Transaction(Val) -> 51 State = ?INIT_INDENT, 52 enc_Transaction(Val, State). 53 54%% Note that encoding the action request's this way 55%% make the message look a bit strange. 56enc_ActionRequests(Val) -> 57 State = ?INIT_INDENT, 58 enc_TransactionRequest_actions(Val, State). 59 60%% Note that encoding the action request this way 61%% make the message look a bit strange. 62enc_ActionRequest(Val) -> 63 State = ?INIT_INDENT, 64 enc_ActionRequest(Val, State). 65 66enc_CommandRequest(Val) -> 67 State = ?INIT_INDENT, 68 enc_CommandRequest(Val, State). 69 70enc_ActionReply(Val) -> 71 State = ?INIT_INDENT, 72 enc_ActionReply(Val, State). 73 74enc_AuthenticationHeader(asn1_NOVALUE, _State) -> 75 []; 76enc_AuthenticationHeader(Val, State) 77 when is_record(Val, 'AuthenticationHeader') -> 78 [ 79 ?AuthToken, 80 ?EQUAL, 81 enc_SecurityParmIndex(Val#'AuthenticationHeader'.secParmIndex, State), 82 ?COLON, 83 enc_SequenceNum(Val#'AuthenticationHeader'.seqNum, State), 84 ?COLON, 85 enc_AuthData(Val#'AuthenticationHeader'.ad, State), 86 ?SEP_INDENT(State) 87 ]. 88 89enc_SecurityParmIndex({'SecurityParmIndex',Val}, State) -> 90 enc_SecurityParmIndex(Val, State); 91enc_SecurityParmIndex(Val, State) -> 92 [ 93 "0x", 94 enc_HEXDIG(Val, State, 8, 8) 95 ]. 96 97enc_SequenceNum({'SequenceNum',Val}, State) -> 98 enc_SequenceNum(Val, State); 99enc_SequenceNum(Val, State) -> 100 [ 101 "0x", 102 enc_HEXDIG(Val, State, 8, 8) 103 ]. 104 105enc_AuthData({'AuthData',Val}, State) -> 106 enc_AuthData(Val, State); 107enc_AuthData(Val, State) -> 108 [ 109 "0x", 110 enc_HEXDIG(Val, State, 24, 64) %% OTP-4710 111 ]. 112 113enc_Message(Val, State) 114 when is_record(Val, 'Message') -> 115 [ 116 ?MegacopToken, 117 ?SLASH, 118 enc_version(Val#'Message'.version, State), 119 ?SEP, 120 enc_MId(Val#'Message'.mId, State), 121 ?SEP_INDENT(State), 122 enc_Message_messageBody(Val#'Message'.messageBody, State) 123 ]. 124 125enc_version(Val, State) when is_integer(Val) andalso (Val >= 0) -> 126 enc_DIGIT(Val, State, 0, 99). 127 128enc_Message_messageBody({'Message_messageBody',Val}, State) -> 129 enc_Message_messageBody(Val, State); 130enc_Message_messageBody({Tag, Val}, State) -> 131 case Tag of 132 messageError -> 133 enc_ErrorDescriptor(Val, State); 134 transactions -> 135 enc_Message_messageBody_transactions(Val, State); 136 _ -> 137 error({invalid_messageBody_tag, Tag}) 138 end. 139 140enc_Message_messageBody_transactions({'Message_messageBody_transactions',Val}, 141 State) -> 142 enc_Message_messageBody_transactions(Val, State); 143enc_Message_messageBody_transactions(Val, State) 144 when is_list(Val) andalso (Val =/= []) -> 145 [enc_Transaction(T, State) || T <- Val]. 146 147enc_MId({'MId',Val}, State) -> 148 enc_MId(Val, State); 149enc_MId({Tag, Val}, State) -> 150 case Tag of 151 ip4Address -> 152 enc_IP4Address(Val, State); 153 ip6Address -> 154 enc_IP6Address(Val, State); 155 domainName -> 156 enc_DomainName(Val, State); 157 deviceName -> 158 enc_PathName(Val, State); 159 mtpAddress -> 160 enc_mtpAddress(Val, State); 161 _ -> 162 error({invalid_MId_tag, Tag}) 163 end. 164 165enc_mtpAddress(Val, State) -> 166 [ 167 ?MtpToken, 168 ?LBRKT, 169 enc_OCTET_STRING(Val, State, 2, 4), 170 ?RBRKT 171 ]. 172 173enc_DomainName(#'DomainName'{portNumber = asn1_NOVALUE, 174 name = Name}, State) -> 175 [ 176 $<, 177 %% BUGBUG: (ALPHA / DIGIT) *63(ALPHA / DIGIT / "-" / ".") 178 enc_STRING(Name, State, 1, 64), 179 $> 180 ]; 181enc_DomainName(#'DomainName'{portNumber = PortNumber, 182 name = Name}, State) -> 183 [ 184 $<, 185 %% BUGBUG: (ALPHA / DIGIT) *63(ALPHA / DIGIT / "-" / ".") 186 enc_STRING(Name, State, 1, 64), 187 $>, 188 $:, 189 enc_portNumber(PortNumber, State) 190 ]. 191 192enc_IP4Address(#'IP4Address'{portNumber = asn1_NOVALUE, 193 address = [A1, A2, A3, A4]}, State) -> 194 [ 195 $[, 196 enc_V4hex(A1, State), 197 ?DOT, 198 enc_V4hex(A2, State), 199 ?DOT, 200 enc_V4hex(A3, State), 201 ?DOT, 202 enc_V4hex(A4, State), 203 $] 204 ]; 205enc_IP4Address(#'IP4Address'{portNumber = PortNumber, 206 address = [A1, A2, A3, A4]}, State) -> 207 [ 208 $[, 209 enc_V4hex(A1, State), 210 ?DOT, 211 enc_V4hex(A2, State), 212 ?DOT, 213 enc_V4hex(A3, State), 214 ?DOT, 215 enc_V4hex(A4, State), 216 $], 217 $:, 218 enc_portNumber(PortNumber, State) 219 ]. 220 221enc_V4hex(Val, State) -> 222 enc_DIGIT(Val, State, 0, 255). 223 224enc_IP6Address(#'IP6Address'{portNumber = asn1_NOVALUE, 225 address = Addr}, State) 226 when is_list(Addr) andalso (length(Addr) =:= 16) -> 227 [ 228 $[, 229 enc_IP6Address_address(Addr, State), 230 $] 231 ]; 232enc_IP6Address(#'IP6Address'{portNumber = PortNumber, 233 address = Addr}, State) 234 when is_list(Addr) andalso (length(Addr) =:= 16) -> 235 [ 236 $[, 237 enc_IP6Address_address(Addr, State), 238 $], 239 $:, 240 enc_portNumber(PortNumber, State) 241 ]. 242 243enc_IP6Address_address([0, 0|Addr], State) -> 244 enc_IP6Address_address2(Addr, 1, false, true, State); 245enc_IP6Address_address(Addr, State) -> 246 enc_IP6Address_address2(Addr, 0, false, false, State). 247 248enc_IP6Address_address2([0,0], 0, _Padding, _First, _State) -> 249 [$0]; 250enc_IP6Address_address2([0,0], PadN, false, true, _State) when PadN > 0 -> 251 [$:, $:]; % Padding from the beginning (all zero's) 252enc_IP6Address_address2([0,0], PadN, false, false, _State) when PadN > 0 -> 253 [$:]; % Padding in the middle or end 254enc_IP6Address_address2([0,0], _, true, _First, _State) -> 255 [$0]; 256enc_IP6Address_address2([N1,N2], 0, _Padding, _First, State) -> 257 [enc_hex4([N1, N2], State)]; 258enc_IP6Address_address2([N1,N2], 1, _Padding, _First, State) -> 259 [$0, $:, enc_hex4([N1, N2], State)]; 260enc_IP6Address_address2([N1,N2], PadN, false, true, State) when PadN > 1 -> 261 [$:, $:, enc_hex4([N1, N2], State)]; 262enc_IP6Address_address2([N1,N2], PadN, false, false, State) when PadN > 1 -> 263 [$:, enc_hex4([N1, N2], State)]; 264enc_IP6Address_address2([N1,N2], _PadN, true, _First, State) -> 265 [enc_hex4([N1, N2], State)]; 266enc_IP6Address_address2([0, 0|Ns], PadN, false, First, State) -> 267 enc_IP6Address_address2(Ns, PadN+1, false, First, State); 268enc_IP6Address_address2([0, 0|Ns], _PadN, true, _First, State) -> 269 [ 270 $0, 271 $:, 272 enc_IP6Address_address2(Ns, 0, true, false, State) 273 ]; 274enc_IP6Address_address2([N1, N2|Ns], 0, Padded, _First, State) -> 275 [ 276 enc_hex4([N1, N2], State), 277 $:, 278 enc_IP6Address_address2(Ns, 0, Padded, false, State) 279 ]; 280enc_IP6Address_address2([N1, N2|Ns], 1, Padded, _First, State) -> 281 [ 282 $0, 283 $:, 284 enc_hex4([N1, N2], State), 285 $:, 286 enc_IP6Address_address2(Ns, 0, Padded, false, State) 287 ]; 288enc_IP6Address_address2([N1, N2|Ns], PadN, false, true, State) when PadN > 1 -> 289 %% Padding from the beginning 290 [ 291 $:, 292 $:, 293 enc_hex4([N1, N2], State), 294 $:, 295 enc_IP6Address_address2(Ns, 0, true, false, State) 296 ]; 297enc_IP6Address_address2([N1, N2|Ns], PadN, false, false, State) 298 when PadN > 1 -> 299 [ 300 $:, %% The other ':' has already added 301 enc_hex4([N1, N2], State), 302 $:, 303 enc_IP6Address_address2(Ns, 0, true, false, State) 304 ]; 305enc_IP6Address_address2([N1, N2|Ns], _PadN, true, _First, State) -> 306 [ 307 enc_hex4([N1, N2], State), 308 $:, 309 enc_IP6Address_address2(Ns, 0, true, false, State) 310 ]. 311 312 313enc_hex4([0,0], _State) -> 314 $0; 315enc_hex4([0,N], _State) -> 316 hex(N); 317enc_hex4([N1, N2], _State) when N2 =< 15 -> 318 [hex(N1), $0, hex(N2)]; 319enc_hex4([N1, N2], _State) -> 320 [hex(N1), hex(N2)]. 321 322enc_PathName({'PathName',Val}, State) -> 323 enc_PathName(Val, State); 324enc_PathName(Val, State) -> 325 %% BUGBUG: ["*"] NAME *("/" / "*"/ ALPHA / DIGIT /"_" / "$" ) 326 %% BUGBUG: ["@" pathDomainName ] 327 enc_STRING(Val, State, 1, 64). 328 329enc_Transaction(Bin, _State) when is_binary(Bin) -> 330 [Bin]; %% Already encoded... 331enc_Transaction({'Transaction',Val}, State) -> 332 enc_Transaction(Val, State); 333enc_Transaction({Tag, Val}, State) -> 334 case Tag of 335 transactionRequest -> 336 enc_TransactionRequest(Val, State); 337 transactionPending -> 338 enc_TransactionPending(Val, State); 339 transactionReply -> 340 enc_TransactionReply(Val, State); 341 transactionResponseAck -> 342 enc_TransactionResponseAck(Val, State); 343 _ -> 344 error({invalid_Transaction_tag, Tag}) 345 end. 346 347enc_TransactionResponseAck([Mand], State) -> 348 [ 349 ?ResponseAckToken, 350 ?LBRKT_INDENT(State), 351 [enc_TransactionAck(Mand, State)], 352 ?RBRKT_INDENT(State) 353 ]; 354enc_TransactionResponseAck([Mand | Opt], State) -> 355 [ 356 ?ResponseAckToken, 357 ?LBRKT_INDENT(State), 358 [enc_TransactionAck(Mand, State) | 359 [[?COMMA_INDENT(State), 360 ?INC_INDENT(State), 361 enc_TransactionAck(Val, State)] || Val <- Opt]], 362 ?RBRKT_INDENT(State) 363 ]. 364 365enc_TransactionAck(Val, State) 366 when is_record(Val, 'TransactionAck') -> 367 [ 368 enc_TransactionId(Val#'TransactionAck'.firstAck, ?INC_INDENT(State)), 369 case Val#'TransactionAck'.lastAck of 370 asn1_NOVALUE -> 371 []; 372 LastAck -> 373 ["-",enc_TransactionId(LastAck, State)] 374 end 375 ]. 376 377enc_TransactionId({'TransactionId',Val}, State) -> 378 enc_TransactionId(Val, State); 379enc_TransactionId(Val, State) -> 380 enc_UINT32(Val, State). 381 382enc_TransactionRequest(#'TransactionRequest'{transactionId = Tid, 383 actions = Acts}, State) -> 384 [ 385 ?TransToken, 386 ?EQUAL, 387 enc_TransactionId(Tid, State), 388 ?LBRKT_INDENT(State), 389 enc_TransactionRequest_actions(Acts, ?INC_INDENT(State)), 390 ?RBRKT_INDENT(State) 391 ]; 392enc_TransactionRequest(Bin, _State) when is_binary(Bin) -> 393 [Bin]. 394 395 396enc_TransactionRequest_actions(Bin, _State) when is_binary(Bin) -> 397 [Bin]; %% Already encoded... 398enc_TransactionRequest_actions({'TransactionRequest_actions',Val}, State) -> 399 enc_TransactionRequest_actions(Val, State); 400enc_TransactionRequest_actions([Mand], State) -> 401 [enc_ActionRequest(Mand, State)]; 402enc_TransactionRequest_actions([Mand | Opt], State) -> 403 [enc_ActionRequest(Mand, State) | 404 [[?COMMA_INDENT(State), enc_ActionRequest(Val, State)] || Val <- Opt]]. 405 406enc_TransactionPending(#'TransactionPending'{transactionId = Tid}, State) -> 407 [?PendingToken, 408 ?EQUAL, 409 enc_TransactionId(Tid, State), 410 ?LBRKT_INDENT(State), 411 ?RBRKT_INDENT(State) 412 ]; 413enc_TransactionPending(Bin, _State) when is_binary(Bin) -> 414 [Bin]. 415 416 417enc_TransactionReply(#'TransactionReply'{transactionId = Tid, 418 immAckRequired = asn1_NOVALUE, 419 transactionResult = Res}, 420 State) -> 421 [ 422 ?ReplyToken, 423 ?EQUAL, 424 enc_TransactionId(Tid, State), 425 ?LBRKT_INDENT(State), 426 enc_TransactionReply_transactionResult(Res, ?INC_INDENT(State)), 427 ?RBRKT_INDENT(State) 428 ]; 429enc_TransactionReply(#'TransactionReply'{transactionId = Tid, 430 immAckRequired = Req, 431 transactionResult = Res}, State) -> 432 [ 433 ?ReplyToken, 434 ?EQUAL, 435 enc_TransactionId(Tid, State), 436 ?LBRKT_INDENT(State), 437 enc_immAckRequired(Req, State), 438 enc_TransactionReply_transactionResult(Res, ?INC_INDENT(State)), 439 ?RBRKT_INDENT(State) 440 ]; 441enc_TransactionReply(Bin, _State) when is_binary(Bin) -> 442 [Bin]. 443 444 445enc_immAckRequired(Val, _State) -> 446 case Val of 447 asn1_NOVALUE -> 448 []; 449 'NULL' -> 450 [?ImmAckRequiredToken, ?COMMA_INDENT(?INC_INDENT(_State))] 451 end. 452 453enc_TransactionReply_transactionResult({'TransactionReply_transactionResult',Val}, State) -> 454 enc_TransactionReply_transactionResult(Val, State); 455enc_TransactionReply_transactionResult({Tag, Val}, State) -> 456 case Tag of 457 transactionError -> 458 enc_ErrorDescriptor(Val, State); 459 actionReplies -> 460 enc_TransactionReply_transactionResult_actionReplies(Val, State); 461 _ -> 462 error({invalid_TransactionReply_transactionResult_tag, Tag}) 463 end. 464 465enc_TransactionReply_transactionResult_actionReplies({'TransactionReply_transactionResult_actionReplies',Val}, State) -> 466 enc_TransactionReply_transactionResult_actionReplies(Val, State); 467enc_TransactionReply_transactionResult_actionReplies([Mand], State) -> 468 [enc_ActionReply(Mand, State)]; 469enc_TransactionReply_transactionResult_actionReplies([Mand | Opt], State) -> 470 [enc_ActionReply(Mand, State), 471 [[?COMMA_INDENT(State), enc_ActionReply(Val, State)] || Val <- Opt]]. 472 473enc_ErrorDescriptor(#'ErrorDescriptor'{errorText = asn1_NOVALUE, 474 errorCode = Code}, State) -> 475 [ 476 ?ErrorToken, 477 ?EQUAL, 478 enc_ErrorCode(Code, State), 479 ?LBRKT, 480 ?RBRKT 481 ]; 482enc_ErrorDescriptor(#'ErrorDescriptor'{errorText = Text, 483 errorCode = Code}, State) -> 484 [ 485 ?ErrorToken, 486 ?EQUAL, 487 enc_ErrorCode(Code, State), 488 ?LBRKT, 489 enc_ErrorText(Text, State), 490 ?RBRKT 491 ]. 492 493enc_ErrorCode({'ErrorCode',Val}, State)-> 494 enc_ErrorCode(Val, State); 495enc_ErrorCode(Val, State) -> 496 enc_DIGIT(Val, State, 0, 999). 497 498enc_ErrorText({'ErrorText',Val}, State) -> 499 enc_ErrorText(Val, State); 500enc_ErrorText(Val, State) -> 501 enc_QUOTED_STRING(Val, State). 502 503enc_ContextID({'ContextID',Val}, State) -> 504 enc_ContextID(Val, State); 505enc_ContextID(Val, State) -> 506 case Val of 507 ?megaco_all_context_id -> $*; 508 ?megaco_null_context_id -> $-; 509 ?megaco_choose_context_id -> $$; 510 Int when is_integer(Int) -> enc_UINT32(Int, State) 511 end. 512 513enc_ActionRequest(Bin, _State) when is_binary(Bin) -> 514 [Bin]; %% Already encoded... 515enc_ActionRequest(Val, State) 516 when is_record(Val, 'ActionRequest') -> 517 [ 518 ?CtxToken, 519 ?EQUAL, 520 enc_ContextID(Val#'ActionRequest'.contextId, State), 521 ?LBRKT_INDENT(State), 522 enc_list([{[Val#'ActionRequest'.contextAttrAuditReq], 523 fun enc_ContextAttrAuditRequest/2}] ++ 524 decompose_ContextRequest(Val#'ActionRequest'.contextRequest) ++ 525 [{Val#'ActionRequest'.commandRequests, 526 fun enc_CommandRequest/2}], 527 ?INC_INDENT(State)), 528 ?RBRKT_INDENT(State) 529 ]. 530 531%% OTP-5085 532enc_ActionReply(#'ActionReply'{contextId = Id, 533 errorDescriptor = ED, 534 contextReply = CtxRep, 535 commandReply = CmdRep}, 536 State) -> 537 [ 538 ?CtxToken, 539 ?EQUAL, 540 enc_ContextID(Id, State), 541 ?LBRKT_INDENT(State), 542 do_enc_ActionReply(ED, CtxRep, CmdRep, State), 543 ?RBRKT_INDENT(State) 544 ]. 545 546do_enc_ActionReply(asn1_NOVALUE, CtxRep, CmdRep, State) 547 when (CtxRep =/= asn1_NOVALUE) orelse (CmdRep =/= []) -> 548 [ 549 enc_list(decompose_ContextRequest(CtxRep) ++ 550 [{CmdRep, fun enc_CommandReply/2}], 551 ?INC_INDENT(State)) 552 ]; 553do_enc_ActionReply(ED, CtxRep, CmdRep, State) 554 when (CtxRep =/= asn1_NOVALUE) orelse (CmdRep =/= []) -> 555 [ 556 enc_list(decompose_ContextRequest(CtxRep) ++ 557 [{CmdRep, fun enc_CommandReply/2}, 558 {[ED], fun enc_ErrorDescriptor/2}], % Indention cosmetics 559 ?INC_INDENT(State)) 560 ]; 561do_enc_ActionReply(ED, asn1_NOVALUE, [], State) -> 562 [ 563 enc_ErrorDescriptor(ED, ?INC_INDENT(State)) 564 ]. 565 566 567decompose_ContextRequest(asn1_NOVALUE) -> 568 [{[], dummy}] ; 569decompose_ContextRequest(Val) 570 when is_record(Val, 'ContextRequest') -> 571 OptPriority = 572 case Val#'ContextRequest'.priority of 573 asn1_NOVALUE -> {[], dummy}; 574 Prio -> {[Prio], fun enc_priority/2} 575 end, 576 OptEmergency = 577 case Val#'ContextRequest'.emergency of 578 asn1_NOVALUE -> {[], dummy}; 579 false -> {[], dummy}; 580 true -> {[?EmergencyToken], fun(Elem, _) -> Elem end} 581 end, 582 OptTopologyReq = 583 case Val#'ContextRequest'.topologyReq of 584 asn1_NOVALUE -> 585 {[], dummy}; 586 {'ContextRequest_topologyReq', asn1_NOVALUE} -> 587 {[], dummy}; 588 {'ContextRequest_topologyReq', List} -> 589 {List, fun enc_TopologyRequest/2}; 590 List -> 591 {[List], fun enc_TopologyRequest/2} 592 end, 593 [OptPriority, OptEmergency, OptTopologyReq]. 594 595enc_priority(Val, State) -> 596 [ 597 ?PriorityToken, 598 ?EQUAL, 599 enc_UINT16(Val, State) 600 ]. 601 602enc_ContextAttrAuditRequest(Val, State) 603 when is_record(Val, 'ContextAttrAuditRequest') -> 604 [ 605 ?ContextAuditToken, 606 ?LBRKT_INDENT(State), 607 enc_list([{[Val#'ContextAttrAuditRequest'.topology], 608 fun('NULL', _) -> ?TopologyToken end}, 609 {[Val#'ContextAttrAuditRequest'.emergency], 610 fun('NULL', _) -> ?EmergencyToken end}, 611 {[Val#'ContextAttrAuditRequest'.priority], 612 fun('NULL', _) -> ?PriorityToken end}], 613 ?INC_INDENT(State)), 614 ?RBRKT_INDENT(State) 615 ]. 616 617enc_CommandRequest(#'CommandRequest'{optional = asn1_NOVALUE, 618 wildcardReturn = asn1_NOVALUE, 619 command = Cmd}, State) -> 620 [ 621 enc_Command(Cmd, State) 622 ]; 623enc_CommandRequest(#'CommandRequest'{optional = 'NULL', 624 wildcardReturn = asn1_NOVALUE, 625 command = Cmd}, State) -> 626 [ 627 "O-", 628 enc_Command(Cmd, State) 629 ]; 630enc_CommandRequest(#'CommandRequest'{optional = asn1_NOVALUE, 631 wildcardReturn = 'NULL', 632 command = Cmd}, State) -> 633 [ 634 "W-", 635 enc_Command(Cmd, State) 636 ]; 637enc_CommandRequest(#'CommandRequest'{optional = 'NULL', 638 wildcardReturn = 'NULL', 639 command = Cmd}, State) -> 640 [ 641 "O-", 642 "W-", 643 enc_Command(Cmd, State) 644 ]. 645 646enc_Command({'Command',Val}, State) -> 647 enc_Command(Val, State); 648enc_Command({Tag, Val}, State) -> 649 case Tag of 650 addReq -> 651 [?AddToken, enc_AmmRequest(Val, State)]; 652 moveReq -> 653 [?MoveToken, enc_AmmRequest(Val, State)]; 654 modReq -> 655 [?ModifyToken, enc_AmmRequest(Val, State)]; 656 subtractReq -> 657 [?SubtractToken, enc_SubtractRequest(Val, State)]; 658 auditCapRequest -> 659 [?AuditCapToken, enc_AuditRequest(Val, State)]; 660 auditValueRequest -> 661 [?AuditValueToken, enc_AuditRequest(Val, State)]; 662 notifyReq -> 663 [?NotifyToken, enc_NotifyRequest(Val, State)]; 664 serviceChangeReq -> 665 [?ServiceChangeToken, enc_ServiceChangeRequest(Val, State)]; 666 _ -> 667 error({invalid_Command_tag, Tag}) 668 end. 669 670enc_CommandReply({'CommandReply',Val}, State) -> 671 enc_CommandReply(Val, State); 672enc_CommandReply({Tag, Val}, State) -> 673 case Tag of 674 addReply -> 675 [?AddToken, enc_AmmsReply(Val, State)]; 676 moveReply -> 677 [?MoveToken, enc_AmmsReply(Val, State)]; 678 modReply -> 679 [?ModifyToken, enc_AmmsReply(Val, State)]; 680 subtractReply -> 681 [?SubtractToken, enc_AmmsReply(Val, State)]; 682 auditCapReply -> 683 [?AuditCapToken, enc_AuditReply(Val, State)]; 684 auditValueReply -> 685 [?AuditValueToken, enc_AuditReply(Val, State)]; 686 notifyReply -> 687 [?NotifyToken, enc_NotifyReply(Val, State)]; 688 serviceChangeReply -> 689 [?ServiceChangeToken, enc_ServiceChangeReply(Val, State)]; 690 _ -> 691 error({invalid_CommandReply_tag, Tag}) 692 end. 693 694enc_TopologyRequest(Val, State) 695 when is_list(Val) -> 696 [ 697 ?TopologyToken, 698 ?LBRKT_INDENT(State), 699 enc_list([{Val, fun enc_TopologyRequest1/2}],?INC_INDENT(State)), 700 ?RBRKT_INDENT(State) 701 ]. 702 703enc_TopologyRequest1(Val, State) 704 when is_record(Val, 'TopologyRequest') -> 705 [ 706 fun(S) -> 707 [ 708 enc_TerminationID(Val#'TopologyRequest'.terminationFrom, S), 709 ?COMMA_INDENT(S), 710 enc_TerminationID(Val#'TopologyRequest'.terminationTo, S), 711 ?COMMA_INDENT(S), 712 case Val#'TopologyRequest'.topologyDirection of 713 bothway -> ?BothwayToken; 714 isolate -> ?IsolateToken; 715 oneway -> ?OnewayToken 716 end 717 ] 718 end(?INC_INDENT(State)) 719 ]. 720 721enc_AmmRequest(Val, State) 722 when is_record(Val, 'AmmRequest') -> 723 [ 724 %% Assume that Token is added elsewhere 725 ?EQUAL, 726 enc_TerminationIDList1(Val#'AmmRequest'.terminationID, State), 727 enc_opt_brackets( 728 enc_list([{Val#'AmmRequest'.descriptors, fun enc_ammDescriptor/2}], 729 ?INC_INDENT(State)), 730 State) 731 ]. 732 733enc_ammDescriptor({Tag, Desc}, State) -> 734 case Tag of 735 mediaDescriptor -> enc_MediaDescriptor(Desc, State); 736 modemDescriptor -> enc_ModemDescriptor(Desc, State); 737 muxDescriptor -> enc_MuxDescriptor(Desc, State); 738 eventsDescriptor -> enc_EventsDescriptor(Desc, State); 739 eventBufferDescriptor -> enc_EventBufferDescriptor(Desc, State); 740 signalsDescriptor -> enc_SignalsDescriptor(Desc, State); 741 digitMapDescriptor -> enc_DigitMapDescriptor(Desc, State); 742 auditDescriptor -> enc_AuditDescriptor(Desc, State); 743 _ -> 744 error({invalid_ammDescriptor_tag, Tag}) 745 end. 746 747enc_AmmsReply(#'AmmsReply'{terminationID = ID, 748 terminationAudit = asn1_NOVALUE}, State) -> 749 [ 750 ?EQUAL, 751 enc_TerminationIDList1(ID, State) 752 ]; 753enc_AmmsReply(#'AmmsReply'{terminationID = ID, 754 terminationAudit = []}, State) -> 755 [ 756 ?EQUAL, 757 enc_TerminationIDList1(ID, State) 758 ]; 759enc_AmmsReply(#'AmmsReply'{terminationID = ID, 760 terminationAudit = Res}, State) -> 761 [ 762 ?EQUAL, 763 enc_TerminationIDList1(ID, State), 764 case lists:flatten(enc_TerminationAudit(Res, ?INC_INDENT(State))) of 765 [] -> 766 []; 767 L -> 768 [ 769 ?LBRKT_INDENT(State), 770 L, 771 ?RBRKT_INDENT(State) 772 ] 773 end 774 ]. 775 776enc_SubtractRequest(Val, State) 777 when is_record(Val, 'SubtractRequest') -> 778 [ 779 %% Assume that Token is added elsewhere 780 ?EQUAL, 781 enc_TerminationIDList1(Val#'SubtractRequest'.terminationID, State), 782 case Val#'SubtractRequest'.auditDescriptor of 783 asn1_NOVALUE -> 784 []; 785 AuditDescr -> 786 [ 787 ?LBRKT_INDENT(State) , 788 enc_AuditDescriptor(AuditDescr, ?INC_INDENT(State)), 789 ?RBRKT_INDENT(State) 790 ] 791 end 792 ]. 793 794enc_AuditRequest(Val, State) 795 when is_record(Val, 'AuditRequest') -> 796 [ 797 %% Assume that Token is added elsewhere 798 ?EQUAL, 799 enc_TerminationIDList1([Val#'AuditRequest'.terminationID], State), 800 case Val#'AuditRequest'.auditDescriptor of 801 asn1_NOVALUE -> 802 []; 803 AuditDescr -> 804 [ 805 ?LBRKT_INDENT(State) , 806 enc_AuditDescriptor(AuditDescr, ?INC_INDENT(State)), 807 ?RBRKT_INDENT(State) 808 ] 809 end 810 ]. 811 812%% auditReply = (AuditValueToken / AuditCapToken ) 813%% ( contextTerminationAudit / auditOther) 814%% auditOther = EQUAL TerminationID LBRKT 815%% terminationAudit RBRKT 816%% terminationAudit = auditReturnParameter *(COMMA auditReturnParameter) 817%% 818%% contextTerminationAudit = EQUAL CtxToken ( terminationIDList / 819%% LBRKT errorDescriptor RBRKT ) 820enc_AuditReply({Tag, Val}, State) -> 821 case Tag of 822 contextAuditResult -> 823 [ 824 ?EQUAL, 825 ?CtxToken, 826 enc_TerminationIDListN(Val, State) 827 ]; 828 error -> 829 [ 830 ?EQUAL, 831 ?CtxToken, 832 ?LBRKT_INDENT(State), 833 enc_ErrorDescriptor(Val, ?INC_INDENT(State)), 834 ?RBRKT_INDENT(State) 835 ]; 836 auditResult when is_record(Val, 'AuditResult') -> 837 enc_auditOther(Val, State); 838 auditResult -> 839 error({invalid_auditResult, Val}); 840 _ -> 841 error({invalid_AuditReply_tag, Tag}) 842 end. 843 844enc_auditOther(#'AuditResult'{terminationID = ID, 845 terminationAuditResult = asn1_NOVALUE}, State) -> 846 [ 847 ?EQUAL, 848 enc_TerminationID(ID, State) 849 ]; 850enc_auditOther(#'AuditResult'{terminationID = ID, 851 terminationAuditResult = []}, State) -> 852 [ 853 ?EQUAL, 854 enc_TerminationID(ID, State) 855 ]; 856enc_auditOther(#'AuditResult'{terminationID = ID, 857 terminationAuditResult = Res}, State) -> 858 [ 859 ?EQUAL, 860 enc_TerminationID(ID, State), 861 case lists:flatten(enc_TerminationAudit(Res, ?INC_INDENT(State))) of 862 [] -> 863 []; 864 L -> 865 [ 866 ?LBRKT_INDENT(State), 867 L, 868 ?RBRKT_INDENT(State) 869 ] 870 end 871 ]. 872 873 874enc_AuditDescriptor(#'AuditDescriptor'{auditToken = asn1_NOVALUE}, 875 _State) -> 876 [ 877 ?AuditToken, 878 [?LBRKT, ?RBRKT] 879 ]; 880enc_AuditDescriptor(#'AuditDescriptor'{auditToken = []}, 881 _State) -> 882 [ 883 ?AuditToken, 884 [?LBRKT, ?RBRKT] 885 ]; 886enc_AuditDescriptor(#'AuditDescriptor'{auditToken = List}, 887 State) -> 888 [ 889 ?AuditToken, 890 [ 891 ?LBRKT_INDENT(State), 892 enc_list([{List, fun enc_auditItem/2}], ?INC_INDENT(State)), 893 ?RBRKT_INDENT(State) 894 ] 895 ]. 896 897enc_auditItem(signalsToken, _State) -> 898 ?SignalsToken; 899enc_auditItem(eventBufferToken, _State) -> 900 ?EventBufferToken; 901enc_auditItem(eventsToken, _State) -> 902 ?EventsToken; 903enc_auditItem(Val, State) -> 904 enc_auditReturnItem(Val, State). 905 906enc_auditReturnItem(muxToken, _State) -> 907 ?MuxToken; 908enc_auditReturnItem(modemToken, _State) -> 909 ?ModemToken; 910enc_auditReturnItem(mediaToken, _State) -> 911 ?MediaToken; 912enc_auditReturnItem(digitMapToken, _State) -> 913 ?DigitMapToken; 914enc_auditReturnItem(statsToken, _State) -> 915 ?StatsToken; 916enc_auditReturnItem(observedEventsToken, _State) -> 917 ?ObservedEventsToken; 918enc_auditReturnItem(packagesToken, _State) -> 919 ?PackagesToken. 920 921enc_TerminationAudit({'TerminationAudit',Val}, State) -> 922 enc_TerminationAudit(Val, State); 923enc_TerminationAudit([], _State) -> 924 []; 925enc_TerminationAudit([Mand | Opt], State) -> 926 [enc_AuditReturnParameter(Mand, State), 927 [[?COMMA_INDENT(State), 928 enc_AuditReturnParameter(Val, State)] || Val <- Opt]]. 929 930 931enc_AuditReturnParameter({'AuditReturnParameter',Val}, State) -> 932 enc_AuditReturnParameter(Val, State); 933enc_AuditReturnParameter({Tag, Val}, State) -> 934 case Tag of 935 mediaDescriptor -> 936 enc_MediaDescriptor(Val, State); 937 modemDescriptor -> 938 enc_ModemDescriptor(Val, State); 939 muxDescriptor -> 940 enc_MuxDescriptor(Val, State); 941 eventsDescriptor -> 942 enc_EventsDescriptor(Val, State); 943 signalsDescriptor -> 944 enc_SignalsDescriptor(Val, State); 945 digitMapDescriptor -> 946 enc_DigitMapDescriptor(Val, State); 947 observedEventsDescriptor -> 948 enc_ObservedEventsDescriptor(Val, State); 949 eventBufferDescriptor -> 950 enc_EventBufferDescriptor(Val, State); 951 statisticsDescriptor -> 952 enc_StatisticsDescriptor(Val, State); 953 packagesDescriptor -> 954 enc_PackagesDescriptor(Val, State); 955 errorDescriptor -> 956 enc_ErrorDescriptor(Val, State); 957 emptyDescriptors -> 958 enc_EmptyDescriptors(Val, State); 959 _ -> 960 error({unknown_AuditReturnParameter_tag, Tag}) 961 end. 962 963enc_EmptyDescriptors(#'AuditDescriptor'{auditToken = asn1_NOVALUE}, _State) -> 964 []; 965enc_EmptyDescriptors(#'AuditDescriptor'{auditToken = []}, _State) -> 966 []; 967enc_EmptyDescriptors(#'AuditDescriptor'{auditToken = List}, State) -> 968 enc_list([{List, fun enc_auditReturnItem/2}], ?INC_INDENT(State)). 969 970 971enc_NotifyRequest(Val, State) 972 when is_record(Val, 'NotifyRequest') -> 973 [ 974 %% Assume that Token is added elsewhere 975 ?EQUAL, 976 enc_TerminationIDList1(Val#'NotifyRequest'.terminationID, State), 977 ?LBRKT_INDENT(State), 978 %% BUGBUG: Mismatch between ASN.1 and ABNF 979 %% BUGBUG: The following ought to be a 'choice' 980 case Val#'NotifyRequest'.errorDescriptor of 981 asn1_NOVALUE -> 982 OED = Val#'NotifyRequest'.observedEventsDescriptor, 983 enc_ObservedEventsDescriptor(OED, ?INC_INDENT(State)); 984 ErrorDescr -> 985 enc_ErrorDescriptor(ErrorDescr, ?INC_INDENT(State)) 986 end, 987 ?RBRKT_INDENT(State) 988 ]. 989 990enc_NotifyReply(Val, State) 991 when is_record(Val, 'NotifyReply') -> 992 [ 993 %% Assume that Token is added elsewhere 994 ?EQUAL, 995 case Val#'NotifyReply'.terminationID of 996 asn1_NOVALUE -> 997 error(asn1_not_compliant_with_abnf); 998 TermId -> 999 enc_TerminationIDList1(TermId, State) 1000 end, 1001 case Val#'NotifyReply'.errorDescriptor of 1002 asn1_NOVALUE -> 1003 []; 1004 ErrorDescr -> 1005 [ 1006 ?LBRKT_INDENT(State), 1007 enc_ErrorDescriptor(ErrorDescr, ?INC_INDENT(State)), 1008 ?RBRKT_INDENT(State) 1009 ] 1010 end 1011 ]. 1012 1013enc_ObservedEventsDescriptor(Val, State) 1014 when is_record(Val, 'ObservedEventsDescriptor') -> 1015 [ 1016 ?ObservedEventsToken, 1017 ?EQUAL, 1018 enc_RequestID(Val#'ObservedEventsDescriptor'.requestId, State), 1019 ?LBRKT_INDENT(State), 1020 enc_observedEventsDescriptors(Val#'ObservedEventsDescriptor'.observedEventLst, ?INC_INDENT(State)), 1021 ?RBRKT_INDENT(State) 1022 ]. 1023 1024enc_observedEventsDescriptors([Mand | Opt], State) -> 1025 [enc_ObservedEvent(Mand, State), 1026 [[?COMMA_INDENT(State), enc_ObservedEvent(Val, State)] || Val <- Opt]]. 1027 1028%% ;time per event, because it might be buffered 1029%% observedEvent = [ TimeStamp LWSP COLON] LWSP 1030%% pkgdName [ LBRKT observedEventParameter 1031%% *(COMMA observedEventParameter) RBRKT ] 1032%% 1033%% ;at-most-once eventStream, every eventParameterName at most once 1034%% observedEventParameter = eventStream / eventOther 1035enc_ObservedEvent(Val, State) 1036 when is_record(Val, 'ObservedEvent') -> 1037 [ 1038 case Val#'ObservedEvent'.timeNotation of 1039 asn1_NOVALUE -> 1040 []; 1041 TimeStamp -> 1042 [ 1043 enc_TimeNotation(TimeStamp, State), 1044 ?LWSP, 1045 ?COLON 1046 ] 1047 end, 1048 ?LWSP, 1049 enc_EventName(Val#'ObservedEvent'.eventName, State), 1050 enc_opt_brackets( 1051 enc_list([{[Val#'ObservedEvent'.streamID], fun enc_eventStream/2}, 1052 {Val#'ObservedEvent'.eventParList, fun enc_eventOther/2}], 1053 ?INC_INDENT(State)), 1054 State) 1055 ]. 1056 1057enc_EventName({'EventName',Val}, State) -> 1058 enc_EventName(Val, State); 1059enc_EventName(Val, State) -> 1060 PkgdName = ?META_ENC(event, Val), 1061 enc_PkgdName(PkgdName, State). 1062 1063enc_eventStream(Val, State) -> 1064 [ 1065 ?StreamToken, 1066 ?EQUAL, 1067 enc_StreamID(Val, State) 1068 ]. 1069 1070%% The value is already encoded 1071enc_eventOther(#megaco_event_parameter{name = Name, 1072 value = Value}, State) 1073 when is_list(Value) -> 1074 [ 1075 enc_Name(Name, State), 1076 ?EqualToken, 1077 Value 1078 ]; 1079%% Special treatment of the ds parameter of the dd/ce event 1080enc_eventOther(#'EventParameter'{eventParameterName = "ds" = Name, 1081 value = [DigitString], 1082 extraInfo = asn1_NOVALUE}, State) -> 1083 [ 1084 enc_Name(Name, State), 1085 ?EqualToken, 1086 enc_DigitString(DigitString, State) 1087 ]; 1088enc_eventOther(#'EventParameter'{eventParameterName = Name, 1089 value = Value, 1090 extraInfo = Extra}, State) -> 1091 [ 1092 enc_Name(Name, State), 1093 enc_propertyParmValues(Value, Extra, State) 1094 ]. 1095 1096enc_ServiceChangeRequest(Val, State) 1097 when is_record(Val, 'ServiceChangeRequest') -> 1098 [ 1099 %% Assume that Token is added elsewhere 1100 ?EQUAL, 1101 enc_TerminationIDList1(Val#'ServiceChangeRequest'.terminationID, State), 1102 ?LBRKT_INDENT(State), 1103 enc_ServiceChangeParm(Val#'ServiceChangeRequest'.serviceChangeParms, 1104 ?INC_INDENT(State)), 1105 ?RBRKT_INDENT(State) 1106 ]. 1107 1108%% serviceChangeReply = ServiceChangeToken EQUAL TerminationID 1109%% [LBRKT (errorDescriptor / 1110%% serviceChangeReplyDescriptor) RBRKT] 1111%% serviceChangeReplyDescriptor = ServicesToken LBRKT 1112%% servChgReplyParm *(COMMA servChgReplyParm) RBRKT 1113%% 1114%% ;at-most-once. Version is REQUIRED on first ServiceChange response 1115%% servChgReplyParm = (serviceChangeAddress / serviceChangeMgcId / 1116%% serviceChangeProfile / serviceChangeVersion ) 1117enc_ServiceChangeReply(Val, State) 1118 when is_record(Val, 'ServiceChangeReply') -> 1119 [ 1120 %% Assume that Token is added elsewhere 1121 ?EQUAL, 1122 enc_TerminationIDList1(Val#'ServiceChangeReply'.terminationID, State), 1123 enc_ServiceChangeResult(Val#'ServiceChangeReply'.serviceChangeResult, State) 1124 ]. 1125 1126enc_ServiceChangeResult({'ServiceChangeResult',Val}, State) -> 1127 enc_ServiceChangeResult(Val, State); 1128enc_ServiceChangeResult({Tag, Val}, State) -> 1129 case Tag of 1130 errorDescriptor -> 1131 [ 1132 ?LBRKT_INDENT(State), 1133 enc_ErrorDescriptor(Val, ?INC_INDENT(State)), 1134 ?RBRKT_INDENT(State) 1135 ]; 1136 serviceChangeResParms -> 1137 case enc_ServiceChangeResParm(Val, ?INC_INDENT(?INC_INDENT(State))) of 1138 [] -> 1139 []; 1140 ResParms -> 1141 [ 1142 ?LBRKT_INDENT(State), 1143 ?ServicesToken, 1144 fun(_S) -> 1145 [ 1146 ?LBRKT_INDENT(_S), 1147 ResParms, 1148 ?RBRKT_INDENT(_S) 1149 ] 1150 end(?INC_INDENT(State)), 1151 ?RBRKT_INDENT(State) 1152 ] 1153 end; 1154 _ -> 1155 error({invalid_ServiceChangeResult_tag, Tag}) 1156 end. 1157 1158%% Required length of termination ID list is 1 1159enc_TerminationIDList1({'TerminationIDList',Val}, State) -> 1160 enc_TerminationIDList1(Val, State); 1161enc_TerminationIDList1([Singleton], State) -> 1162 enc_TerminationID(Singleton, State). 1163 1164%% No required length of termination ID list 1165enc_TerminationIDListN({'TerminationIDList',Val}, State) -> 1166 enc_TerminationIDListN(Val, State); 1167enc_TerminationIDListN([TID], State) -> 1168 [ 1169 ?LBRKT_INDENT(State), 1170 enc_TerminationID(TID, State), 1171 ?RBRKT_INDENT(State) 1172 ]; 1173enc_TerminationIDListN(TIDs, State) -> 1174 [ 1175 ?LBRKT_INDENT(State), 1176 enc_list([{TIDs, fun enc_TerminationID/2}], State), 1177 ?RBRKT_INDENT(State) 1178 ]. 1179 1180 1181%% TerminationID = "ROOT" / pathNAME / "$" / "*" 1182%% ; Total length of pathNAME must not exceed 64 chars. 1183%% pathNAME = ["*"] NAME *("/" / "*"/ ALPHA / DIGIT /"_" / "$" ) 1184%% ["@" pathDomainName ] 1185enc_TerminationID(Tid, State) 1186 when is_record(Tid, megaco_term_id) -> 1187 List = [{Tid#megaco_term_id.id, fun enc_tid_component/2 }], 1188 enc_list(List, State, fun(_S) -> ?SLASH end, false). 1189 1190enc_tid_component(Component, State) when is_list(Component) -> 1191 [enc_tid_sub_component(Sub, State) || Sub <- Component]; 1192enc_tid_component(Invalid, _State) -> 1193 error({invalid_id_list_component, Invalid}). 1194 1195enc_tid_sub_component(all = _Sub, _State) -> 1196 ?megaco_all; 1197enc_tid_sub_component(choose = _Sub, _State) -> 1198 ?megaco_choose; 1199enc_tid_sub_component(Char, _State) when is_integer(Char) -> 1200 Char; 1201enc_tid_sub_component(Invalid, _State) -> 1202 error({invalid_id_list_sub_component, Invalid}). 1203 1204%% enc_tid_sub_component(Sub, _State) -> 1205%% case Sub of 1206%% all -> ?megaco_all; 1207%% choose -> ?megaco_choose; 1208%% Char when is_integer(Char) -> Char 1209%% end. 1210 1211%% mediaDescriptor = MediaToken LBRKT mediaParm *(COMMA mediaParm) RBRKT 1212%% ; at-most-once per item 1213%% ; and either streamParm or streamDescriptor but not both 1214%% mediaParm = (streamParm / streamDescriptor / 1215%% terminationStateDescriptor) 1216%% ; at-most-once 1217%% streamParm = ( localDescriptor / remoteDescriptor / 1218%% localControlDescriptor ) 1219%% streamDescriptor = StreamToken EQUAL StreamID LBRKT streamParm 1220%% *(COMMA streamParm) RBRKT 1221enc_MediaDescriptor(Val, State) 1222 when is_record(Val, 'MediaDescriptor') -> 1223 [ 1224 ?MediaToken, 1225 ?LBRKT_INDENT(State), 1226 enc_list([{[Val#'MediaDescriptor'.termStateDescr], 1227 fun enc_TerminationStateDescriptor/2} | 1228 decompose_streams(Val#'MediaDescriptor'.streams)], 1229 ?INC_INDENT(State)), 1230 ?RBRKT_INDENT(State) 1231 ]. 1232 1233decompose_streams(asn1_NOVALUE) -> 1234 []; 1235decompose_streams({'MediaDescriptor_streams',Val}) -> 1236 decompose_streams(Val); 1237decompose_streams({Tag, Val}) -> 1238 case Tag of 1239 oneStream -> 1240 decompose_StreamParms(Val); 1241 multiStream -> 1242 [{Val, fun enc_StreamDescriptor/2}]; 1243 _ -> 1244 error({invalid_streams_tag, Tag}) 1245 end. 1246 1247decompose_StreamParms(Val) 1248 when is_record(Val, 'StreamParms') -> 1249 [ 1250 {[Val#'StreamParms'.localControlDescriptor], 1251 fun enc_LocalControlDescriptor/2}, 1252 {[Val#'StreamParms'.localDescriptor], 1253 fun enc_localDescriptor/2}, 1254 {[Val#'StreamParms'.remoteDescriptor], 1255 fun enc_remoteDescriptor/2} 1256 ]. 1257 1258enc_StreamDescriptor(Val, State) 1259 when is_record(Val, 'StreamDescriptor') -> 1260 [ 1261 ?StreamToken, 1262 ?EQUAL, 1263 enc_StreamID(Val#'StreamDescriptor'.streamID, State), 1264 ?LBRKT_INDENT(State), 1265 enc_list(decompose_StreamParms(Val#'StreamDescriptor'.streamParms), 1266 ?INC_INDENT(State)), 1267 ?RBRKT_INDENT(State) 1268 ]. 1269 1270%% localControlDescriptor = LocalControlToken LBRKT localParm 1271%% *(COMMA localParm) RBRKT 1272%% 1273%% ; at-most-once per item 1274%% localParm = ( streamMode / propertyParm / 1275%% reservedValueMode / reservedGroupMode ) 1276%% reservedValueMode = ReservedValueToken EQUAL ( "ON" / "OFF" ) 1277%% reservedGroupMode = ReservedGroupToken EQUAL ( "ON" / "OFF" ) 1278%% 1279%% reservedMode = ReservedToken EQUAL ( "ON" / "OFF" ) 1280%% 1281%% streamMode = ModeToken EQUAL streamModes 1282enc_LocalControlDescriptor( 1283 #'LocalControlDescriptor'{streamMode = asn1_NOVALUE, 1284 reserveValue = asn1_NOVALUE, 1285 reserveGroup = asn1_NOVALUE, 1286 propertyParms = []}, _State) -> 1287 error({invalid_LocalControlDescriptor, empty}); 1288enc_LocalControlDescriptor( 1289 #'LocalControlDescriptor'{streamMode = SM, 1290 reserveValue = RV, 1291 reserveGroup = RG, 1292 propertyParms = PPs}, State) -> 1293 [ 1294 ?LocalControlToken, 1295 ?LBRKT_INDENT(State), 1296 enc_list([{[SM], fun enc_StreamMode/2}, 1297 {[RG], fun enc_reservedGroupMode/2}, 1298 {[RV], fun enc_reservedValueMode/2}, 1299 {PPs, fun enc_PropertyParm/2}], ?INC_INDENT(State)), 1300 ?RBRKT_INDENT(State) 1301 ]. 1302 1303enc_reservedGroupMode(Val, _State) -> 1304 [ 1305 ?ReservedGroupToken, 1306 ?EQUAL, 1307 case Val of 1308 false -> ?OffToken; 1309 true -> ?OnToken 1310 end 1311 ]. 1312 1313enc_reservedValueMode(Val, _State) -> 1314 [ 1315 ?ReservedValueToken, 1316 ?EQUAL, 1317 case Val of 1318 false -> ?OffToken; 1319 true -> ?OnToken 1320 end 1321 ]. 1322 1323enc_StreamMode({'StreamMode',Val}, State) -> 1324 enc_StreamMode(Val, State); 1325enc_StreamMode(Val, _State) -> 1326 [ 1327 ?ModeToken, 1328 ?EQUAL, 1329 case Val of 1330 sendOnly -> ?SendonlyToken; 1331 recvOnly -> ?RecvonlyToken; 1332 sendRecv -> ?SendrecvToken; 1333 inactive -> ?InactiveToken; 1334 loopBack -> ?LoopbackToken 1335 end 1336 ]. 1337 1338enc_Name({'Name',Val}, State) -> 1339 enc_Name(Val, State); 1340enc_Name(Val, State) -> 1341 %% BUGBUG: NAME = ALPHA *63(ALPHA / DIGIT / "_" ) 1342 enc_STRING(Val, State, 1, 64). 1343 1344enc_PkgdName({'PkgdName', Val}, State) -> 1345 enc_PkgdName(Val, State); 1346enc_PkgdName(Val, _State) -> 1347 %% BUGBUG: pkgdName = (NAME / "*") SLASH (ItemID / "*" ) 1348 %% enc_OCTET_STRING(Val, _State, 1, 64). 1349 if 1350 is_list(Val) -> 1351 Length = length(Val), 1352 if 1353 (Length >= 1) -> 1354 if 1355 (Length =< 64) -> 1356 Val; 1357 true -> 1358 error({pkgdName_toolong, Length, 64}) 1359 end; 1360 true -> 1361 error({pkgdName_tooshort, Length, 1}) 1362 end; 1363 true -> 1364 error({invalid_PkgdName, Val}) 1365 end. 1366 1367 1368enc_localDescriptor(Val, State) 1369 when is_record(Val, 'LocalRemoteDescriptor') -> 1370 [ 1371 ?LocalToken, 1372 ?LBRKT, 1373 enc_LocalRemoteDescriptor(Val, State), 1374 ?RBRKT_INDENT(State) 1375 ]. 1376 1377enc_remoteDescriptor(Val, State) 1378 when is_record(Val, 'LocalRemoteDescriptor') -> 1379 [ 1380 ?RemoteToken, 1381 ?LBRKT, 1382 enc_LocalRemoteDescriptor(Val, State), 1383 ?RBRKT_INDENT(State) 1384 ]. 1385 1386%% When text encoding the protocol, the descriptors consist of session 1387%% descriptions as defined in SDP (RFC2327), except that the "s=", "t=" 1388%% and "o=" lines are optional. When multiple session descriptions are 1389%% provided in one descriptor, the "v=" lines are required as delimiters; 1390%% otherwise they are optional. Implementations shall accept session 1391%% descriptions that are fully conformant to RFC2327. <When binary 1392%% encoding the protocol the descriptor consists of groups of properties 1393%% (tag-value pairs) as specified in Annex C. Each such group may 1394%% contain the parameters of a session description. 1395enc_LocalRemoteDescriptor(Val, State) 1396 when is_record(Val, 'LocalRemoteDescriptor') -> 1397 case Val#'LocalRemoteDescriptor'.propGrps of 1398 [] -> 1399 []; 1400 [OptV | MandV] -> 1401 [?LfToken, 1402 enc_PropertyGroup(OptV, opt_v, State) | 1403 [enc_PropertyGroup(M, mand_v, State) || M <- MandV]] 1404 end. 1405 1406enc_PropertyGroup({'PropertyGroup',Val}, RequiresV, State) -> 1407 enc_PropertyGroup(Val, RequiresV, State); 1408enc_PropertyGroup([H | _T] = List, mand_v, State) 1409 when is_record(H, 'PropertyParm') andalso (H#'PropertyParm'.name =:= "v") -> 1410 enc_PropertyGroup(List, opt_v, State); 1411enc_PropertyGroup(PG, opt_v, State) -> 1412 [ 1413 [[enc_PropertyGroupParm(PP, State), ?CrToken, ?LfToken] || PP <- PG] 1414 ]. 1415 1416enc_PropertyGroupParm(Val, State) 1417 when is_record(Val, 'PropertyParm') -> 1418 [OctetString] = Val#'PropertyParm'.value, 1419 [ 1420 enc_PkgdName(Val#'PropertyParm'.name, State), 1421 ?EqualToken, 1422 enc_OCTET_STRING(OctetString, State, 0, infinity) 1423 ]. 1424 1425%% propertyParm = pkgdName parmValue 1426%% parmValue = (EQUAL alternativeValue/ INEQUAL VALUE) 1427%% alternativeValue = ( VALUE / LSBRKT VALUE *(COMMA VALUE) RSBRKT / 1428%% LSBRKT VALUE DOT DOT VALUE RSBRKT ) 1429enc_PropertyParm(Val, State) 1430 when is_record(Val, 'PropertyParm') -> 1431 PkgdName = ?META_ENC(property, Val#'PropertyParm'.name), 1432 [ 1433 enc_PkgdName(PkgdName, State), 1434 enc_propertyParmValues(Val#'PropertyParm'.value, 1435 Val#'PropertyParm'.extraInfo, 1436 State) 1437 ]. 1438 1439enc_propertyParmValues([Single], asn1_NOVALUE, State) -> 1440 [ 1441 ?EqualToken, 1442 enc_Value(Single, State) 1443 ]; 1444enc_propertyParmValues([Single], {relation, Rel}, State) -> 1445 case Rel of 1446 greaterThan -> [$>, enc_Value(Single, State)]; 1447 smallerThan -> [$<, enc_Value(Single, State)]; 1448 unequalTo -> [$#, enc_Value(Single, State)] 1449 end; 1450enc_propertyParmValues([Low, High], {range, true}, State)-> 1451 %% Exact two values 1452 [ 1453 ?EqualToken, 1454 ?LSBRKT, 1455 enc_Value(Low, State), 1456 ?COLON, 1457 enc_Value(High, State), 1458 ?RSBRKT 1459 ]; 1460enc_propertyParmValues(Values, {sublist, true}, State)-> 1461 %% sublist (i.e. A AND B AND ...) 1462 [ 1463 ?EqualToken, 1464 ?LSBRKT, 1465 enc_list([{Values, fun enc_Value/2}], State), 1466 ?RSBRKT 1467 ]; 1468enc_propertyParmValues(Values, {sublist, false}, State) -> 1469 %% alternatives (i.e. A OR B OR ...) 1470 [ 1471 ?EqualToken, 1472 ?LBRKT, 1473 enc_list([{Values, fun enc_Value/2}], State), 1474 ?RBRKT 1475 ]; 1476enc_propertyParmValues(V, EI, _State) -> 1477 error({invalid_property_parm_values, V, EI}). 1478 1479enc_TerminationStateDescriptor(Val, State) 1480 when is_record(Val, 'TerminationStateDescriptor') -> 1481 [ 1482 ?TerminationStateToken, 1483 ?LBRKT_INDENT(State), 1484 enc_list([{Val#'TerminationStateDescriptor'.propertyParms, 1485 fun enc_PropertyParm/2}, 1486 {[Val#'TerminationStateDescriptor'.eventBufferControl], 1487 fun enc_eventBufferControl/2}, 1488 {[Val#'TerminationStateDescriptor'.serviceState], 1489 fun enc_serviceState/2}], 1490 ?INC_INDENT(State)), 1491 ?RBRKT_INDENT(State) 1492 ]. 1493 1494enc_eventBufferControl(Val, _State) -> 1495 [ 1496 1497 ?BufferToken, 1498 ?EQUAL, 1499 case Val of 1500 off -> ?OffToken; 1501 lockStep -> ?LockStepToken 1502 end 1503 ]. 1504 1505enc_serviceState({'ServiceState',Val}, State) -> 1506 enc_serviceState(Val, State); 1507enc_serviceState(Val, _State) -> 1508 [ 1509 ?ServiceStatesToken, 1510 ?EQUAL, 1511 case Val of 1512 test -> ?TestToken; 1513 outOfSvc -> ?OutOfSvcToken; 1514 inSvc -> ?InSvcToken 1515 end 1516 ]. 1517 1518enc_MuxDescriptor(Val, State) 1519 when is_record(Val, 'MuxDescriptor') -> 1520 [ 1521 ?MuxToken, 1522 ?EQUAL, 1523 enc_MuxType(Val#'MuxDescriptor'.muxType, State), 1524 enc_TerminationIDListN(Val#'MuxDescriptor'.termList, State) 1525 ]. 1526 1527enc_MuxType({'MuxType',Val}, State) -> 1528 enc_MuxType(Val, State); 1529enc_MuxType(Val, _State) -> 1530 case Val of 1531 h221 -> ?H221Token; 1532 h223 -> ?H223Token; 1533 h226 -> ?H226Token; 1534 v76 -> ?V76Token 1535 end. 1536 1537enc_StreamID({'StreamID',Val}, State) -> 1538 enc_StreamID(Val, State); 1539enc_StreamID(Val, State) -> 1540 enc_UINT16(Val, State). 1541 1542enc_EventsDescriptor(Val, State) 1543 when is_record(Val, 'EventsDescriptor') -> 1544 #'EventsDescriptor'{requestID = RequestId, 1545 eventList = Events} = Val, 1546 if 1547 RequestId == asn1_NOVALUE, Events == [] -> 1548 [ 1549 ?EventsToken 1550 ]; 1551 1552 RequestId =/= asn1_NOVALUE, Events =/= [] -> 1553 [ 1554 ?EventsToken, 1555 ?EQUAL, 1556 enc_RequestID(RequestId, State), 1557 ?LBRKT_INDENT(State), 1558 enc_list([{Events, fun enc_RequestedEvent/2}], 1559 ?INC_INDENT(State)), 1560 ?RBRKT_INDENT(State) 1561 ] 1562 end. 1563 1564enc_RequestedEvent(Val, State) 1565 when is_record(Val, 'RequestedEvent') -> 1566 PkgdName = ?META_ENC(event, Val#'RequestedEvent'.pkgdName), 1567 [ 1568 enc_PkgdName(PkgdName, State), 1569 enc_opt_brackets( 1570 enc_list([{[Val#'RequestedEvent'.streamID], fun enc_eventStream/2}, 1571 {Val#'RequestedEvent'.evParList, fun enc_eventOther/2} | 1572 decompose_requestedActions(Val#'RequestedEvent'.eventAction)], 1573 ?INC_INDENT(State)), 1574 State) 1575 ]. 1576 1577decompose_requestedActions(asn1_NOVALUE) -> 1578 []; 1579 1580%% 1581%% This in the ABNF: 1582%% at-most-once each of KeepActiveToken , eventDM and eventStream 1583%% at most one of either embedWithSig or embedNoSig but not both 1584%% KeepActiveToken and embedWithSig must not both be present 1585%% 1586 1587%% embedWithSig 1588decompose_requestedActions(#'RequestedActions'{keepActive = KA, 1589 eventDM = EDM, 1590 secondEvent = SE, 1591 signalsDescriptor = SD}) 1592 when (KA =/= true) andalso 1593 (SD =/= asn1_NOVALUE) andalso 1594 (SD /= []) -> 1595% d("decompose_requestedActions -> entry with" 1596% "~n EDM: ~p" 1597% "~n SE: ~p" 1598% "~n SD: ~p", [EDM, SE, SD]), 1599 [ 1600 {[EDM], fun enc_EventDM/2}, 1601 {[{SE, SD}], fun enc_embedWithSig/2} 1602 ]; 1603 1604%% embedNoSig 1605decompose_requestedActions(#'RequestedActions'{keepActive = KA, 1606 eventDM = EDM, 1607 secondEvent = SE, 1608 signalsDescriptor = SD}) 1609 when (SD =:= asn1_NOVALUE) orelse (SD =:= []) -> 1610 [ 1611 {[KA], fun enc_keepActive/2}, 1612 {[EDM], fun enc_EventDM/2}, 1613 {[SE], fun enc_embedNoSig/2} 1614 ]; 1615 1616%% Fallback, if everything else failes.... 1617decompose_requestedActions(#'RequestedActions'{keepActive = KA, 1618 eventDM = EDM, 1619 secondEvent = SE, 1620 signalsDescriptor = SD}) -> 1621 [ 1622 {[KA], fun enc_keepActive/2}, 1623 {[EDM], fun enc_EventDM/2}, 1624 {[{SE, SD}], fun enc_embedWithSig/2} 1625 ]. 1626 1627enc_embedNoSig(#'SecondEventsDescriptor'{requestID = RID, 1628 eventList = Evs}, State) -> 1629 [ 1630 ?EmbedToken, 1631 ?LBRKT_INDENT(State), 1632 enc_embedFirst(RID, Evs, ?INC_INDENT(State)), 1633 ?RBRKT_INDENT(State) 1634 ]. 1635 1636enc_embedWithSig({asn1_NOVALUE, SD}, State) -> 1637 [ 1638 ?EmbedToken, 1639 ?LBRKT_INDENT(State), 1640 enc_SignalsDescriptor(SD, ?INC_INDENT(State)), 1641 ?RBRKT_INDENT(State) 1642 ]; 1643enc_embedWithSig({#'SecondEventsDescriptor'{requestID = RID, 1644 eventList = Evs}, SD}, State) -> 1645 [ 1646 ?EmbedToken, 1647 ?LBRKT_INDENT(State), 1648 enc_SignalsDescriptor(SD, ?INC_INDENT(State)), 1649 ?COMMA_INDENT(?INC_INDENT(State)), 1650 enc_embedFirst(RID, Evs, ?INC_INDENT(State)), 1651 ?RBRKT_INDENT(State) 1652 ]. 1653 1654enc_keepActive(Val, _State) -> 1655 case Val of 1656 true -> [?KeepActiveToken]; 1657 false -> [] 1658 end. 1659 1660enc_EventDM({'EventDM',Val}, State) -> 1661 enc_EventDM(Val, State); 1662enc_EventDM({Tag, Val}, State) -> 1663 case Tag of 1664 digitMapName -> 1665 [ 1666 ?DigitMapToken, 1667 ?EQUAL, 1668 enc_DigitMapName(Val, State) 1669 ]; 1670 digitMapValue -> 1671 [ 1672 ?DigitMapToken, 1673 ?LBRKT_INDENT(State), 1674 enc_DigitMapValue(Val, ?INC_INDENT(State)), 1675 ?RBRKT_INDENT(State) 1676 ]; 1677 _ -> 1678 error({invalid_EventDM_tag, Tag}) 1679 end. 1680 1681enc_embedFirst(RID, Evs, State) 1682 when (RID =/= asn1_NOVALUE) andalso is_list(Evs) andalso (Evs =/= []) -> 1683 [ 1684 ?EventsToken, 1685 ?EQUAL, 1686 enc_RequestID(RID, State), 1687 ?LBRKT_INDENT(State), 1688 enc_list([{Evs, fun enc_SecondRequestedEvent/2}], ?INC_INDENT(State)), 1689 ?RBRKT_INDENT(State) 1690 ]; 1691enc_embedFirst(_RID, _Evs, _State) -> 1692 [ 1693 ?EventsToken 1694 ]. 1695 1696enc_SecondRequestedEvent(#'SecondRequestedEvent'{pkgdName = N, 1697 streamID = SID, 1698 evParList = EPL, 1699 eventAction = EA}, State) -> 1700 PkgdName = ?META_ENC(event, N), 1701 [ 1702 enc_PkgdName(PkgdName, State), 1703 enc_opt_brackets( 1704 enc_list( 1705 [{[SID], fun enc_eventStream/2}, 1706 {EPL, fun enc_eventOther/2} | 1707 decompose_secondRequestedActions(EA)], 1708 ?INC_INDENT(State)), 1709 State) 1710 ]. 1711 1712decompose_secondRequestedActions(asn1_NOVALUE) -> 1713 []; 1714decompose_secondRequestedActions(Val) 1715 when is_record(Val, 'SecondRequestedActions') -> 1716 [ 1717 {[Val#'SecondRequestedActions'.keepActive], 1718 fun enc_keepActive/2}, 1719 {[Val#'SecondRequestedActions'.eventDM], 1720 fun enc_EventDM/2}, 1721 {[Val#'SecondRequestedActions'.signalsDescriptor], 1722 fun enc_embeddedSignalsDescriptor/2} 1723 ]. 1724 1725enc_embeddedSignalsDescriptor(Val, State) -> 1726 [ 1727 ?EmbedToken, 1728 ?LBRKT_INDENT(State), 1729 enc_SignalsDescriptor(Val, ?INC_INDENT(State)), 1730 ?RBRKT_INDENT(State) 1731 ]. 1732 1733enc_EventBufferDescriptor({'EventBufferDescriptor',Val}, State) -> 1734 enc_EventBufferDescriptor(Val, State); 1735enc_EventBufferDescriptor([], _State) -> 1736 [ 1737 ?EventBufferToken 1738 ]; 1739enc_EventBufferDescriptor(EventSpecs, State) 1740 when is_list(EventSpecs) andalso (length(EventSpecs) >= 1) -> 1741 [ 1742 ?EventBufferToken, 1743 ?LBRKT_INDENT(State), 1744 enc_eventSpecs(EventSpecs, ?INC_INDENT(State)), 1745 ?RBRKT_INDENT(State) 1746 ]; 1747enc_EventBufferDescriptor(EventSpecs, _State) -> 1748 error({bad_eventSpecs, EventSpecs}). 1749 1750 1751enc_eventSpecs([Mand | Opt], State) -> 1752 [enc_eventSpec(Mand, State), 1753 [[?COMMA_INDENT(State), enc_eventSpec(Val, State)] || Val <- Opt]]. 1754 1755enc_eventSpec(#'EventSpec'{eventName = Name, 1756 streamID = SID, 1757 eventParList = EPL}, State) -> 1758 [ 1759 enc_EventName(Name, State), 1760 enc_opt_brackets( 1761 enc_list([{[SID], fun enc_eventStream/2}, 1762 {EPL, fun enc_eventOther/2}], 1763 ?INC_INDENT(State)), 1764 State) 1765 ]. 1766 1767enc_SignalsDescriptor({'SignalsDescriptor',Val}, State) -> 1768 enc_SignalsDescriptor(Val, State); 1769enc_SignalsDescriptor([], _State) -> 1770 [ 1771 ?SignalsToken 1772 ]; 1773enc_SignalsDescriptor(List, State) when is_list(List) -> 1774 [ 1775 ?SignalsToken, 1776 ?LBRKT_INDENT(State), 1777 enc_list([{List, fun enc_SignalRequest/2}], ?INC_INDENT(State)), 1778 ?RBRKT_INDENT(State) 1779 ]. 1780 1781enc_SignalRequest({'SignalRequest',Val}, State) -> 1782 enc_SignalRequest(Val, State); 1783enc_SignalRequest({Tag, Val}, State) -> 1784 case Tag of 1785 signal -> 1786 enc_Signal(Val, State); 1787 seqSigList -> 1788 enc_SeqSigList(Val, State); 1789 _ -> 1790 error({invalid_SignalRequest_tag, Tag}) 1791 end. 1792 1793 1794enc_SeqSigList(Val, State) 1795 when is_record(Val, 'SeqSigList') -> 1796 [ 1797 ?SignalListToken, 1798 ?EQUAL, 1799 enc_UINT16(Val#'SeqSigList'.id, State), 1800 ?LBRKT_INDENT(State), 1801 enc_list([{Val#'SeqSigList'.signalList, fun enc_Signal/2}], 1802 ?INC_INDENT(State)), 1803 ?RBRKT_INDENT(State) 1804 ]. 1805 1806enc_Signal(Val, State) 1807 when is_record(Val, 'Signal') -> 1808 [ 1809 enc_SignalName(Val#'Signal'.signalName, State), 1810 enc_opt_brackets( 1811 enc_list([{[Val#'Signal'.streamID], fun enc_sigStream/2}, 1812 {[Val#'Signal'.sigType], fun enc_sigSignalType/2}, 1813 {[Val#'Signal'.duration], fun enc_sigDuration/2}, 1814 {[Val#'Signal'.notifyCompletion], fun enc_notifyCompletion/2}, 1815 {[Val#'Signal'.keepActive], fun enc_keepActive/2}, 1816 {Val#'Signal'.sigParList, fun enc_sigOther/2}], 1817 ?INC_INDENT(State)), 1818 State) 1819 ]. 1820 1821enc_sigStream(Val, State) -> 1822 [ 1823 ?StreamToken, 1824 ?EQUAL, 1825 enc_StreamID(Val, State) 1826 ]. 1827 1828enc_sigSignalType(Val, State) -> 1829 [ 1830 ?SignalTypeToken, 1831 ?EQUAL, 1832 enc_SignalType(Val, State) 1833 ]. 1834 1835enc_sigDuration(Val, State) -> 1836 [ 1837 ?DurationToken, 1838 ?EQUAL, 1839 enc_UINT16(Val, State) 1840 ]. 1841 1842enc_notifyCompletion(List, State) when is_list(List) -> 1843 [ 1844 ?NotifyCompletionToken, 1845 ?EQUAL, 1846 ?LBRKT_INDENT(State), 1847 enc_list([{List, fun enc_notifyCompletionItem/2}], ?INC_INDENT(State)), 1848 ?RBRKT_INDENT(State) 1849 ]. 1850 1851enc_notifyCompletionItem(Val, _State) -> 1852 case Val of 1853 onTimeOut -> ?TimeOutToken; 1854 onInterruptByEvent -> ?InterruptByEventToken; 1855 onInterruptByNewSignalDescr -> ?InterruptByNewSignalsDescrToken; 1856 otherReason -> ?OtherReasonToken 1857 end. 1858 1859enc_SignalType({'SignalType',Val}, State) -> 1860 enc_SignalType(Val, State); 1861enc_SignalType(Val, _State) -> 1862 case Val of 1863 brief -> ?BriefToken; 1864 onOff -> ?OnOffToken; 1865 timeOut -> ?TimeOutToken 1866 end. 1867 1868enc_SignalName({'SignalName',Val}, State)-> 1869 enc_SignalName(Val, State); 1870enc_SignalName(Val, State) -> 1871 PkgdName = ?META_ENC(signal, Val), 1872 enc_PkgdName(PkgdName, State). 1873 1874enc_sigOther(Val, State) 1875 when is_record(Val, 'SigParameter') -> 1876 [ 1877 enc_Name(Val#'SigParameter'.sigParameterName, State), 1878 enc_propertyParmValues(Val#'SigParameter'.value, 1879 Val#'SigParameter'.extraInfo, 1880 State) 1881 ]. 1882 1883enc_RequestID({'RequestID',Val}, State) -> 1884 enc_RequestID(Val, State); 1885enc_RequestID(Val, _State) when (Val =:= ?megaco_all_request_id) -> 1886 "*"; 1887enc_RequestID(Val, State) -> 1888 enc_UINT32(Val, State). 1889 1890enc_ModemDescriptor(#'ModemDescriptor'{mtl = [Val], 1891 mpl = [], 1892 nonStandardData = asn1_NOVALUE}, 1893 State) -> 1894 [ 1895 ?ModemToken, 1896 ?EQUAL, 1897 enc_ModemType(Val, State) 1898 ]; 1899enc_ModemDescriptor(Val, State) 1900 when is_record(Val, 'ModemDescriptor') -> 1901 [ 1902 ?ModemToken, 1903 ?LSBRKT, 1904 enc_list([{Val#'ModemDescriptor'.mtl, fun enc_ModemType/2}], State), 1905 ?RSBRKT, 1906 enc_opt_brackets( 1907 enc_list([{Val#'ModemDescriptor'.mpl, fun enc_PropertyParm/2}], 1908 ?INC_INDENT(State)), 1909 State) 1910 %% BUGBUG: Is PropertyParm == NAME parmValue? 1911 ]. 1912 1913 1914enc_ModemType({'ModemType',Val}, State)-> 1915 enc_ModemType(Val, State); 1916enc_ModemType(Val, _State) -> 1917 %% BUGBUG: Does not handle extensionParameter 1918 case Val of 1919 v18 -> ?V18Token; 1920 v22 -> ?V22Token; 1921 v22bis -> ?V22bisToken; 1922 v32 -> ?V32Token; 1923 v32bis -> ?V32bisToken; 1924 v34 -> ?V34Token; 1925 v90 -> ?V90Token; 1926 v91 -> ?V91Token; 1927 synchISDN -> ?SynchISDNToken 1928 end. 1929 1930enc_DigitMapDescriptor(#'DigitMapDescriptor'{digitMapName = asn1_NOVALUE, 1931 digitMapValue = Value} = Val, 1932 State) 1933 when (Value =/= asn1_NOVALUE) -> 1934 case is_empty_DigitMapValue(Value) of 1935 true -> 1936 error({invalid_DigitMapDescriptor, Val}); 1937 false -> 1938 [ 1939 ?DigitMapToken, 1940 ?EQUAL, 1941 ?LBRKT_INDENT(State), 1942 enc_DigitMapValue(Value, ?INC_INDENT(State)), 1943 ?RBRKT_INDENT(State) 1944 ] 1945 end; 1946enc_DigitMapDescriptor(#'DigitMapDescriptor'{digitMapName = Name, 1947 digitMapValue = asn1_NOVALUE}, 1948 State) 1949 when (Name =/= asn1_NOVALUE) -> 1950 [ 1951 ?DigitMapToken, 1952 ?EQUAL, 1953 enc_DigitMapName(Name, State) 1954 ]; 1955enc_DigitMapDescriptor(#'DigitMapDescriptor'{digitMapName = Name, 1956 digitMapValue = Value}, 1957 State) 1958 when (Name =/= asn1_NOVALUE) andalso (Value =/= asn1_NOVALUE) -> 1959 case is_empty_DigitMapValue(Value) of 1960 true -> 1961 [ 1962 ?DigitMapToken, 1963 ?EQUAL, 1964 enc_DigitMapName(Name, State) 1965 ]; 1966 false -> 1967 [ 1968 ?DigitMapToken, 1969 ?EQUAL, 1970 enc_DigitMapName(Name, State), 1971 ?LBRKT_INDENT(State), 1972 enc_DigitMapValue(Value, ?INC_INDENT(State)), 1973 ?RBRKT_INDENT(State) 1974 ] 1975 end; 1976enc_DigitMapDescriptor(BadVal, _State) -> 1977 error({invalid_DigitMapDescriptor, BadVal}). 1978 1979enc_DigitMapName({'DigitMapName',Val}, State) -> 1980 enc_DigitMapName(Val, State); 1981enc_DigitMapName(Val, State) -> 1982 enc_Name(Val, State). 1983 1984is_empty_DigitMapValue(#'DigitMapValue'{startTimer = asn1_NOVALUE, 1985 shortTimer = asn1_NOVALUE, 1986 longTimer = asn1_NOVALUE, 1987 digitMapBody = []}) -> 1988 true; 1989is_empty_DigitMapValue(#'DigitMapValue'{}) -> 1990 false. 1991 1992enc_DigitMapValue(Val, State) 1993 when is_record(Val, 'DigitMapValue') -> 1994 [ 1995 enc_timer(Val#'DigitMapValue'.startTimer, $T, State), 1996 enc_timer(Val#'DigitMapValue'.shortTimer, $S, State), 1997 enc_timer(Val#'DigitMapValue'.longTimer, $L, State), 1998 %% BUGBUG: digitMapBody not handled at all 1999 enc_STRING(Val#'DigitMapValue'.digitMapBody, State, 0, infinity) 2000 ]. 2001 2002enc_timer(asn1_NOVALUE, _Prefix, _State) -> 2003 []; 2004enc_timer(Timer, Prefix, State) -> 2005 [ 2006 Prefix, 2007 ?COLON, 2008 enc_DIGIT(Timer, State, 0, 99), 2009 ?COMMA_INDENT(State) 2010 ]. 2011 2012enc_ServiceChangeParm(Val, State) 2013 when is_record(Val, 'ServiceChangeParm') -> 2014 [ 2015 ?ServicesToken, 2016 ?LBRKT_INDENT(State), 2017 enc_list([{[Val#'ServiceChangeParm'.serviceChangeMethod], 2018 fun enc_ServiceChangeMethod/2}, 2019 {[Val#'ServiceChangeParm'.serviceChangeAddress], 2020 fun enc_ServiceChangeAddress/2}, 2021 {[Val#'ServiceChangeParm'.serviceChangeVersion], 2022 fun enc_serviceChangeVersion/2}, 2023 {[Val#'ServiceChangeParm'.serviceChangeProfile], 2024 fun enc_ServiceChangeProfile/2}, 2025 {[{reason, Val#'ServiceChangeParm'.serviceChangeReason}], 2026 fun enc_serviceChangeReason/2}, 2027 {[Val#'ServiceChangeParm'.serviceChangeDelay], 2028 fun enc_serviceChangeDelay/2}, 2029 {[Val#'ServiceChangeParm'.serviceChangeMgcId], 2030 fun enc_serviceChangeMgcId/2}, 2031 {[Val#'ServiceChangeParm'.timeStamp], 2032 fun enc_TimeNotation/2}], 2033 ?INC_INDENT(State)), 2034 ?RBRKT_INDENT(State) 2035 ]. 2036 2037enc_ServiceChangeMethod({'ServiceChangeMethod',Val}, State) -> 2038 enc_ServiceChangeMethod(Val, State); 2039enc_ServiceChangeMethod(Val, _State) -> 2040 [ 2041 ?MethodToken, 2042 ?EQUAL, 2043 case Val of 2044 failover -> ?FailoverToken; 2045 forced -> ?ForcedToken; 2046 graceful -> ?GracefulToken; 2047 restart -> ?RestartToken; 2048 disconnected -> ?DisconnectedToken; 2049 handOff -> ?HandOffToken 2050 end 2051 %% BUGBUG: extension 2052 ]. 2053 2054enc_ServiceChangeAddress({'ServiceChangeAddress',Val}, State) -> 2055 enc_ServiceChangeAddress(Val, State); 2056enc_ServiceChangeAddress({Tag, Val}, State) -> 2057 [ 2058 ?ServiceChangeAddressToken, 2059 ?EQUAL, 2060 case Tag of 2061 portNumber -> 2062 enc_portNumber(Val, State); 2063 ip4Address -> 2064 enc_IP4Address(Val, State); 2065 ip6Address -> 2066 enc_IP6Address(Val, State); 2067 domainName -> 2068 enc_DomainName(Val, State); 2069 deviceName -> 2070 enc_PathName(Val, State); 2071 mtpAddress -> 2072 enc_mtpAddress(Val, State); 2073 _ -> 2074 error({invalid_ServiceChangeAddress_tag, Tag}) 2075 end 2076 ]. 2077 2078enc_serviceChangeVersion(Val, State) -> 2079 [ 2080 ?VersionToken, 2081 ?EQUAL, 2082 enc_version(Val, State) 2083 ]. 2084 2085enc_ServiceChangeProfile(#'ServiceChangeProfile'{profileName = Name, 2086 version = Version}, 2087 State) -> 2088 [ 2089 ?ProfileToken, 2090 ?EQUAL, 2091 enc_Name(Name, State), 2092 ?SLASH, 2093 enc_version(Version, State) 2094 ]. 2095 2096enc_serviceChangeReason({reason, Val}, State) -> 2097 case Val of 2098 asn1_NOVALUE -> 2099 []; 2100 [List] when is_list(List) -> 2101 [ 2102 ?ReasonToken, 2103 ?EQUAL, 2104 enc_QUOTED_STRING(List,State) % OTP-4632 enc_Value(List, State) 2105 ] 2106 end. 2107 2108enc_serviceChangeDelay(Val, State) -> 2109 [ 2110 ?DelayToken, 2111 ?EQUAL, 2112 enc_UINT32(Val, State) 2113 ]. 2114 2115enc_serviceChangeMgcId(Val, State) -> 2116 [ 2117 ?MgcIdToken, 2118 ?EQUAL, 2119 enc_MId(Val, State) 2120 ]. 2121 2122enc_portNumber(Val, State) when is_integer(Val) andalso (Val >= 0) -> 2123 enc_UINT16(Val, State). 2124 2125enc_ServiceChangeResParm(Val, State) 2126 when is_record(Val, 'ServiceChangeResParm') -> 2127 enc_list([{[Val#'ServiceChangeResParm'.serviceChangeAddress], 2128 fun enc_ServiceChangeAddress/2}, 2129 {[Val#'ServiceChangeResParm'.serviceChangeVersion], 2130 fun enc_serviceChangeVersion/2}, 2131 {[Val#'ServiceChangeResParm'.serviceChangeProfile], 2132 fun enc_ServiceChangeProfile/2}, 2133 {[Val#'ServiceChangeResParm'.serviceChangeMgcId], 2134 fun enc_serviceChangeMgcId/2}, 2135 {[Val#'ServiceChangeResParm'.timeStamp], 2136 fun enc_TimeNotation/2}], 2137 State). 2138 2139enc_PackagesDescriptor({'PackagesDescriptor',Val}, State) -> 2140 enc_PackagesDescriptor(Val, State); 2141enc_PackagesDescriptor(Val, State) -> 2142 [ 2143 ?PackagesToken, 2144 ?LBRKT_INDENT(State), 2145 enc_list([{Val, fun enc_PackagesItem/2}], ?INC_INDENT(State)), 2146 ?RBRKT_INDENT(State) 2147 ]. 2148 2149enc_PackagesItem(Val, State) 2150 when is_record(Val, 'PackagesItem') -> 2151 PkgdName = ?META_ENC(package, Val#'PackagesItem'.packageName), 2152 [ 2153 enc_Name(PkgdName, State), 2154 "-", 2155 enc_UINT16(Val#'PackagesItem'.packageVersion, State) 2156 ]. 2157 2158enc_StatisticsDescriptor({'StatisticsDescriptor',Val}, State) -> 2159 enc_StatisticsDescriptor(Val, State); 2160enc_StatisticsDescriptor(List, State) when is_list(List) -> 2161 [ 2162 ?StatsToken, 2163 ?LBRKT_INDENT(State), 2164 enc_list([{List, fun enc_StatisticsParameter/2}], ?INC_INDENT(State)), 2165 ?RBRKT_INDENT(State) 2166 ]. 2167 2168enc_StatisticsParameter(Val, State) 2169 when is_record(Val, 'StatisticsParameter') -> 2170 PkgdName = ?META_ENC(statistics, Val#'StatisticsParameter'.statName), 2171 case Val#'StatisticsParameter'.statValue of 2172 asn1_NOVALUE -> 2173 [ 2174 enc_PkgdName(PkgdName, State) 2175 ]; 2176 [StatVal] when is_list(StatVal) -> 2177 [ 2178 enc_PkgdName(PkgdName, State), 2179 ?EQUAL, 2180 enc_Value(StatVal, State) 2181 ] 2182 end. 2183 2184enc_TimeNotation(Val, State) 2185 when is_record(Val, 'TimeNotation') -> 2186 [ 2187 enc_STRING(Val#'TimeNotation'.date, State, 8, 8), % "yyyymmdd" 2188 "T", 2189 enc_STRING(Val#'TimeNotation'.time, State, 8, 8) % "hhmmssss" 2190 ]. 2191 2192%% BUGBUG: Does not verify that string must contain at least one char 2193%% BUGBUG: This violation of the is required in order to comply with 2194%% BUGBUG: the dd/ce ds parameter that may possibly be empty. 2195enc_Value({'Value',Val}, State) -> 2196 enc_Value(Val, State); 2197enc_Value(String, _State) -> 2198 case quoted_string_count(String, 0, true, false) of 2199 {_, 0, _} -> 2200 [?DQUOTE, String, ?DQUOTE]; 2201 {false, _, _} -> 2202 [?DQUOTE, String, ?DQUOTE]; 2203 {true, _, _} -> 2204 [String] 2205 end. 2206 2207quoted_string_count([?DoubleQuoteToken | T], 0 = Count, _IsSafe, _MaybeQuoted) -> 2208 %% Already a quoted string. Make sure it ends 2209 quoted_string_count(T, Count + 1, true, true); 2210quoted_string_count([?DoubleQuoteToken], Count, IsSafe, true = MaybeQuoted) -> 2211 %% An explicitly quoted string 2212 {IsSafe, Count, MaybeQuoted}; 2213quoted_string_count([H | T], Count, IsSafe, MaybeQuoted) -> 2214 case ?classify_char(H) of 2215 safe_char_upper -> quoted_string_count(T, Count + 1, IsSafe, MaybeQuoted); 2216 safe_char -> quoted_string_count(T, Count + 1, IsSafe, MaybeQuoted); 2217 rest_char -> quoted_string_count(T, Count + 1, false, MaybeQuoted); 2218 white_space -> quoted_string_count(T, Count + 1, false, MaybeQuoted); 2219 _ -> error({illegal_char, H}) 2220 end; 2221quoted_string_count([], _Count, _IsSafe, true = _MaybeQuoted) -> 2222 error({illegal_char, ?DoubleQuoteToken}); 2223quoted_string_count([], Count, IsSafe, MaybeQuoted) -> 2224 {IsSafe, Count, MaybeQuoted}. 2225 2226enc_DigitString(String, _State) when is_list(String) -> 2227 [?DQUOTE, String, ?DQUOTE]. 2228 2229 2230%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2231 2232%% Encode an octet string, escape } by \ if necessary 2233enc_OCTET_STRING(List, State, Min, Max) -> 2234 do_enc_OCTET_STRING(List, State, Min, Max, 0). 2235 2236do_enc_OCTET_STRING([H | T], State, Min, Max, Count) -> 2237 case H of 2238 $} -> 2239 [$\\, H | do_enc_OCTET_STRING(T, State, Min, Max, Count + 1)]; 2240 _ -> 2241 [H | do_enc_OCTET_STRING(T, State, Min, Max, Count + 1)] 2242 end; 2243do_enc_OCTET_STRING([], _State, Min, Max, Count) -> 2244 verify_count(Count, Min, Max), 2245 []. 2246 2247enc_QUOTED_STRING(String, _State) when is_list(String) -> 2248 case quoted_string_count(String, 0, true, false) of 2249 {_IsSafe, Count, false = _QuotedString} -> 2250 verify_count(Count, 1, infinity), 2251 [?DQUOTE, String, ?DQUOTE]; 2252 {_IsSafe, Count, true = _QuotedString} -> 2253 verify_count(Count, 3, infinity), % quotes not included in the count 2254 [String] 2255 end. 2256 2257 2258%% The internal format of hex digits is a list of octets 2259%% Min and Max means #hexDigits 2260%% Leading zeros are prepended in order to fulfill Min 2261enc_HEXDIG(Octets, State, Min, Max) when is_list(Octets) -> 2262 do_enc_HEXDIG(Octets, State, Min, Max, 0, []). 2263 2264do_enc_HEXDIG([Octet | Rest], State, Min, Max, Count, Acc) 2265 when (Octet >= 0) andalso (Octet =< 255) -> 2266 Hex = hex(Octet), % OTP-4921 2267 if 2268 Octet =< 15 -> 2269 Acc2 = [[$0|Hex]|Acc], % OTP-4921 2270 do_enc_HEXDIG(Rest, State, Min, Max, Count + 2, Acc2); 2271 true -> 2272 Acc2 = [Hex|Acc], % OTP-4921 2273 do_enc_HEXDIG(Rest, State, Min, Max, Count + 2, Acc2) 2274 end; 2275do_enc_HEXDIG([], State, Min, Max, Count, Acc) 2276 when is_integer(Min) andalso (Count < Min) -> 2277 do_enc_HEXDIG([0], State, Min, Max, Count, Acc); 2278do_enc_HEXDIG([], _State, Min, Max, Count, Acc) -> %% OTP-4710 2279 verify_count(Count, Min, Max), 2280 lists:reverse(Acc). 2281 2282enc_DIGIT(Val, State, Min, Max) -> 2283 enc_integer(Val, State, Min, Max). 2284 2285enc_STRING(String, _State, Min, Max) when is_list(String) -> 2286 verify_count(length(String), Min, Max), 2287 String. 2288 2289enc_UINT16(Val, State) -> 2290 enc_integer(Val, State, 0, 65535). 2291 2292enc_UINT32(Val, State) -> 2293 enc_integer(Val, State, 0, 4294967295). 2294 2295enc_integer(Val, _State, Min, Max) -> 2296 verify_count(Val, Min, Max), 2297 integer_to_list(Val). 2298 2299%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2300%% Encodes a list of elements with separator tokens between 2301%% the elements. Optional asn1_NOVALUE values are ignored. 2302 2303enc_list(List, State) -> 2304 enc_list(List, State, fun(_S) -> ?COMMA_INDENT(_S) end, false). 2305 2306-dialyzer({nowarn_function, enc_list/4}). % Future compat 2307enc_list([], _State, _SepEncoder, _NeedsSep) -> 2308 []; 2309enc_list([{Elems, ElemEncoder} | Tail], State, SepEncoder, NeedsSep) -> 2310 case do_enc_list(Elems, State, ElemEncoder, SepEncoder, NeedsSep) of 2311 [] -> 2312 enc_list(Tail, State, SepEncoder, NeedsSep); 2313 List -> 2314 [List, 2315 enc_list(Tail, State, SepEncoder, true)] 2316 end; 2317enc_list(A, B, C, D) -> 2318 error({invlid_list, A, B, C, D}). 2319 2320do_enc_list(asn1_NOVALUE, _State, _ElemEncoder, _SepEncoder, _NeedsSep) -> 2321 []; 2322do_enc_list([], _State, _ElemEncoder, _SepEncoder, _NeedsSep) -> 2323 []; 2324do_enc_list([asn1_NOVALUE | T], State, ElemEncoder, SepEncoder, NeedsSep) -> 2325 do_enc_list(T, State, ElemEncoder, SepEncoder, NeedsSep); 2326do_enc_list([H | T], State, ElemEncoder, SepEncoder, NeedsSep) 2327 when is_function(ElemEncoder) andalso is_function(SepEncoder) -> 2328 case ElemEncoder(H, State) of 2329 [] -> 2330 do_enc_list(T, State, ElemEncoder, SepEncoder, NeedsSep); 2331 List when NeedsSep =:= true -> 2332 [SepEncoder(State), 2333 List, do_enc_list(T, State, ElemEncoder, SepEncoder, true)]; 2334 List when NeedsSep =:= false -> 2335 [List, 2336 do_enc_list(T, State, ElemEncoder, SepEncoder, true)] 2337 end. 2338 2339%% Add brackets if list is non-empty 2340enc_opt_brackets([], _State) -> 2341 []; 2342enc_opt_brackets(List, _State) when is_list(List) -> 2343 [?LBRKT_INDENT(_State), List, ?RBRKT_INDENT(_State)]. 2344 2345%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2346 2347%% Int -> list of hex chars 2348hex(Int) -> 2349 hexi(get_lo_bits(Int, 4), []). 2350 2351hexi({0, Lo}, Ack) -> 2352 [hex4(Lo) | Ack]; 2353hexi({Hi, Lo} , Ack) -> 2354 hexi(get_lo_bits(Hi, 4), [hex4(Lo) | Ack]). 2355 2356hex4(Int) when Int < 10 -> 2357 Int + $0; 2358hex4(Int) -> 2359 ($A - 10) + Int. 2360 2361get_lo_bits(Int, Size) -> 2362 Lo = Int band ones_mask(Size), 2363 Hi = Int bsr Size, 2364 {Hi, Lo}. 2365 2366ones_mask(Ones) -> 2367 (1 bsl Ones) - 1. 2368 2369%% Verify that Count is within the range of Min and Max 2370verify_count(Count, Min, Max) -> 2371 if 2372 is_integer(Count) -> 2373 if 2374 is_integer(Min) andalso (Count >= Min) -> 2375 if 2376 is_integer(Max) andalso (Count =< Max) -> 2377 Count; 2378 Max =:= infinity -> 2379 Count; 2380 true -> 2381 error({count_too_large, Count, Max}) 2382 end; 2383 true -> 2384 error({count_too_small, Count, Min}) 2385 end; 2386 true -> 2387 error({count_not_an_integer, Count}) 2388 end. 2389 2390 2391 2392% d(F) -> 2393% d(F, []). 2394 2395% d(F, A) -> 2396% %% d(get(dbg), F, A). 2397% d(true, F, A). 2398 2399% d(true, F, A) -> 2400% io:format("DBG:~p:" ++ F ++ "~n", [?MODULE|A]); 2401% d(_, _, _) -> 2402% ok. 2403