1
%% ``The contents of this file are subject to the Erlang Public License,
2
%% Version 1.1, (the "License"); you may not use this file except in
3
%% compliance with the License. You should have received a copy of the
4
%% Erlang Public License along with this software. If not, it can be
5
%% retrieved via the world wide web at http://www.erlang.org/.
7
%% Software distributed under the License is distributed on an "AS IS"
8
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
9
%% the License for the specific language governing rights and limitations
12
%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
13
%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
14
%% AB. All Rights Reserved.''
18
%%----------------------------------------------------------------------
19
%% Purpose : Define semantic text parser actions
20
%%----------------------------------------------------------------------
23
-include_lib("megaco/include/megaco.hrl").
24
-include_lib("megaco/include/megaco_message_prev3b.hrl").
25
-define(encoder_version_pre_prev3c,true).
26
-include("megaco_text_tokens.hrl").
28
make_safe_token({_TokenTag, Line, Text}) ->
29
{safeToken, Line, Text}.
31
ensure_value({safeToken, _Line, Text}) ->
33
ensure_value({'QuotedChars', _Line, Text}) ->
35
ensure_value(Text) when list(Text) ->
36
Text. %% BUGBUG: ensure length
38
%% NAME = ALPHA *63(ALPHA / DIGIT / "_" )
39
ensure_NAME({_TokenTag, _Line, Text}) ->
40
Text. %% BUGBUG: ensure length and chars
42
ensure_requestID({safeToken, _Line, "*"}) ->
43
?megaco_all_request_id;
44
ensure_requestID(RequestId) ->
45
ensure_uint32(RequestId).
47
ensure_streamID(StreamId) ->
48
ensure_uint16(StreamId).
50
ensure_auth_header(SpiToken, SnToken, AdToken) ->
51
Spi = ensure_hex(SpiToken, 8, 8),
52
Sn = ensure_hex(SnToken, 8, 8),
53
Ad = ensure_hex(AdToken, 24, 64),
54
#'AuthenticationHeader'{secParmIndex = Spi, seqNum = Sn, ad = Ad}.
56
%% The values 0x0, 0xFFFFFFFE and 0xFFFFFFFF are reserved.
57
%% ContextID = (UINT32 / "*" / "-" / "$")
58
ensure_contextID({_TokenTag, Line, Text}) ->
60
"*" -> ?megaco_all_context_id;
61
"-" -> ?megaco_null_context_id;
62
"\$" -> ?megaco_choose_context_id;
64
CID = ensure_uint32(Int),
67
(CID =/= 16#FFFFFFFE) and
68
(CID =/= 16#FFFFFFFF) ->
71
return_error(Line, {bad_ContextID, CID})
75
ensure_domainAddress([{_T, _L, _A} = Addr0], Port) ->
76
Addr = ensure_ip4addr(Addr0),
77
{ip4Address, #'IP4Address'{address = Addr, portNumber = Port}};
78
ensure_domainAddress([colon,colon], Port) ->
79
Addr = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
80
{ip6Address, #'IP6Address'{address = Addr, portNumber = Port}};
81
ensure_domainAddress(Addr0, Port) ->
82
Addr = ensure_ip6addr(Addr0),
83
{ip6Address, #'IP6Address'{address = Addr, portNumber = Port}}.
86
ensure_ip4addr({TokenTag, Line, Addr}) ->
87
case string:tokens(Addr, [$.]) of
89
A1 = ensure_uint({TokenTag, Line, T1}, 0, 255),
90
A2 = ensure_uint({TokenTag, Line, T2}, 0, 255),
91
A3 = ensure_uint({TokenTag, Line, T3}, 0, 255),
92
A4 = ensure_uint({TokenTag, Line, T4}, 0, 255),
95
return_error(Line, {bad_IP4address, Addr})
99
ensure_ip6addr([colon,colon|T]) ->
100
[H1|T1] = lists:reverse(T),
101
case do_ensure_ip6addr(T1, true, [ensure_hex4_or_ip4addr(H1)], 1) of
102
{true, A} when length(A) == 16 ->
104
{true, B} when length(B) < 16 ->
105
lists:duplicate(16 - length(B), 0) ++ B;
107
throw({error, {?MODULE, {bad_mid_ip6addr_length, C}}})
110
case lists:reverse(L) of
112
case do_ensure_ip6addr(T, true, [], 1) of
113
{true, A} when length(A) == 16 ->
115
{true, B} when length(B) < 16 ->
116
B ++ lists:duplicate(16 - length(B), 0);
118
throw({error, {?MODULE, {bad_mid_ip6addr_length, C}}})
120
[H|L1] -> % A (last element) could be an ip4 address
121
case do_ensure_ip6addr(L1,false,[ensure_hex4_or_ip4addr(H)],1) of
122
{false, A} when length(A) == 16 ->
124
%% allow a pad even if the address is full (i.e. 16)
125
{true, B} when length(B) =< 17 ->
126
do_ensure_ip6addr_padding(B, 0);
128
throw({error, {?MODULE, {bad_mid_ip6addr_length, Pad, C}}})
134
do_ensure_ip6addr([], Pad, Acc, _) ->
135
{Pad, lists:flatten(Acc)};
136
do_ensure_ip6addr([colon,colon|T], false, Acc, Line) ->
137
do_ensure_ip6addr(T, true, [pad|Acc], Line);
138
do_ensure_ip6addr([colon,colon|T], true, Acc, Line) ->
139
return_error(Line, {bad_mid_duplicate_padding, T, Acc});
140
do_ensure_ip6addr([colon|T], Pad, Acc, Line) ->
141
do_ensure_ip6addr(T, Pad, Acc, Line);
142
do_ensure_ip6addr([{_, Line, _} = A|T], Pad, Acc, _) ->
143
do_ensure_ip6addr(T, Pad, [ensure_hex4(A)|Acc], Line).
145
do_ensure_ip6addr_padding([], _) ->
147
do_ensure_ip6addr_padding([pad|T], N) ->
148
lists:duplicate(16 - (N + length(T)), 0) ++ T;
149
do_ensure_ip6addr_padding([H|T], N) ->
150
[H|do_ensure_ip6addr_padding(T, N+1)].
152
ensure_hex4_or_ip4addr({TokenTag, Line, Addr} = V) ->
153
case string:tokens(Addr, [$.]) of
155
A1 = ensure_uint({TokenTag, Line, T1}, 0, 255),
156
A2 = ensure_uint({TokenTag, Line, T2}, 0, 255),
157
A3 = ensure_uint({TokenTag, Line, T3}, 0, 255),
158
A4 = ensure_uint({TokenTag, Line, T4}, 0, 255),
163
%% %% Here we should test for hexseq
164
%% return_error(Line, {bad_IP4address, Addr})
167
ensure_hex4({_TokenTag, Line, Hex4})
168
when length(Hex4) =< 4, length(Hex4) > 0 ->
169
case (catch do_ensure_hex4(Hex4)) of
170
IL when list(IL), length(IL) == 2 ->
173
return_error(Line, {bad_hex4, Hex4, Error})
176
do_ensure_hex4([_H1, _H2, _H3, _H4] = H) ->
178
do_ensure_hex4([H2, H3, H4]) ->
179
hex_to_int([$0, H2, H3, H4], []);
180
do_ensure_hex4([H3, H4]) ->
181
hex_to_int([$0, $0, H3, H4], []);
182
do_ensure_hex4([H4]) ->
183
hex_to_int([$0, $0, $0, H4], []).
185
ensure_domainName({_TokenTag, _Line, Name}, Port) ->
186
%% BUGBUG: validate name
187
{domainName, #'DomainName'{name = Name, portNumber = Port}}.
189
%% extensionParameter= "X" ("-" / "+") 1*6(ALPHA / DIGIT)
190
ensure_extensionParameter({_TokenTag, Line, Text}) ->
196
return_error(Line, {bad_extension_parameter, Text});
198
{extension_parameter, Text}
201
return_error(Line, {bad_extension_parameter, Text})
204
ensure_message(MegacopToken, MID, Body) ->
205
#'ServiceChangeProfile'{profileName = Name,
207
ensure_profile(MegacopToken),
210
#'Message'{version = Version, mId = MID, messageBody = Body};
212
#'Message'{version = Version, mId = MID, messageBody = Body}
217
%% As of corr 1 ModemDescriptor has been deprecated.
218
%% and since this functon is only used when creating
219
%% a ModemDescriptor, iit is removed.
220
%% modemType = (V32bisToken / V22bisToken / V18Token /
221
%% V22Token / V32Token / V34Token / V90Token /
222
%% V91Token / SynchISDNToken / extensionParameter)
223
%% ensure_modemType({_TokenTag, _Line, Text} = Token) ->
233
%% "synchisdn" -> synchISDN;
234
%% "sn" -> synchISDN;
235
%% [$x | _] -> ensure_extensionParameter(Token)
238
%% An mtp address is five octets long
239
ensure_mtpAddress({_TokenTag, _Line, Addr}) ->
240
%% BUGBUG: validate address
243
%% MuxType = ( H221Token / H223Token / H226Token / V76Token / extensionParameter )
244
ensure_muxType({_TokenTag, _Line, Text} = Token) ->
250
"nx64k" -> nx64k; % v2
251
[$x | _] -> ensure_extensionParameter(Token)
254
%% packagesItem = NAME "-" UINT16
255
%% NAME = ALPHA *63(ALPHA / DIGIT / "_" )
256
ensure_packagesItem({TokenTag, Line, Text}) ->
257
case string:tokens(Text, [$-]) of
259
#'PackagesItem'{packageName = ensure_NAME({TokenTag, Line, Name}),
260
packageVersion = ensure_uint({TokenTag, Line, Version}, 0, 99)};
262
return_error(Line, {bad_PackagesItem, Text})
265
%% pkgdName = (PackageName / "*") SLASH (ItemID / "*" )
266
%% PackageName = NAME
268
ensure_pkgdName({TokenTag, Line, Text}) ->
269
case string:tokens(Text, [$/]) of
271
ensure_name_or_star({TokenTag, Line, Name}),
272
ensure_name_or_star({TokenTag, Line, Item}),
275
return_error(Line, {bad_pkgdName, Text})
278
ensure_name_or_star({_, _, Name}) when Name == "*" ->
280
ensure_name_or_star(Name) ->
287
merge_indAudMediaDescriptor_streams(asn1_NOVALUE, []) ->
289
merge_indAudMediaDescriptor_streams(Stream, [])
290
when record(Stream, 'IndAudStreamParms') ->
292
merge_indAudMediaDescriptor_streams(asn1_NOVALUE, MStreams) ->
293
{multiStream, lists:reverse(MStreams)};
294
merge_indAudMediaDescriptor_streams(Stream, MStreams) ->
296
{invalid_indAudMediaDescriptor_streams, {Stream, MStreams}}).
298
merge_indAudMediaDescriptor(Vals) ->
299
merge_indAudMediaDescriptor(Vals, asn1_NOVALUE, asn1_NOVALUE, []).
301
merge_indAudMediaDescriptor([], TSD, OneStream, MultiStreams) ->
302
Streams = merge_indAudMediaDescriptor_streams(OneStream, MultiStreams),
303
#'IndAudMediaDescriptor'{termStateDescr = TSD,
306
merge_indAudMediaDescriptor([{termStateDescr, H}|T], asn1_NOVALUE, OS, MS) ->
307
merge_indAudMediaDescriptor(T, H, OS, MS);
308
merge_indAudMediaDescriptor([{streamDescr, Val}|T], TSD, asn1_NOVALUE, MS) ->
309
merge_indAudMediaDescriptor(T, TSD, asn1_NOVALUE, [Val|MS]);
310
merge_indAudMediaDescriptor([{streamParm, Val}|T], TSD, asn1_NOVALUE, []) ->
311
merge_indAudMediaDescriptor(T, TSD, Val, []);
312
merge_indAudMediaDescriptor(Vals, TSD, OneStream, MultiStream) ->
313
return_error(0, {invalid_indAudMediaDescriptor,
314
{Vals, TSD, OneStream, MultiStream}}).
317
merge_indAudLocalControlDescriptor(Parms) ->
318
do_merge_indAudLocalControlDescriptor(Parms,
319
#'IndAudLocalControlDescriptor'{}).
321
do_merge_indAudLocalControlDescriptor([Parm | Parms], Desc) ->
322
%% d("do_merge_indAudLocalControlDescriptor -> entry when"
324
%% "~n Desc: ~p", [Parm, Desc]),
326
modeToken when Desc#'IndAudLocalControlDescriptor'.streamMode == asn1_NOVALUE ->
327
Desc2 = Desc#'IndAudLocalControlDescriptor'{streamMode = 'NULL'},
328
do_merge_indAudLocalControlDescriptor(Parms, Desc2);
329
reservedGroupToken when Desc#'IndAudLocalControlDescriptor'.reserveGroup == asn1_NOVALUE ->
330
Desc2 = Desc#'IndAudLocalControlDescriptor'{reserveGroup = 'NULL'},
331
do_merge_indAudLocalControlDescriptor(Parms, Desc2);
332
reservedValueToken when Desc#'IndAudLocalControlDescriptor'.reserveValue == asn1_NOVALUE ->
333
Desc2 = Desc#'IndAudLocalControlDescriptor'{reserveValue = 'NULL'},
334
do_merge_indAudLocalControlDescriptor(Parms, Desc2);
335
{pkgdName, Val} when Desc#'IndAudLocalControlDescriptor'.propertyParms == asn1_NOVALUE ->
336
PropParms = [#'IndAudPropertyParm'{name = Val}],
337
Desc2 = Desc#'IndAudLocalControlDescriptor'{propertyParms = PropParms},
338
do_merge_indAudLocalControlDescriptor(Parms, Desc2);
339
{pkgdName, Val} when list(Desc#'IndAudLocalControlDescriptor'.propertyParms) ->
340
PropParms = Desc#'IndAudLocalControlDescriptor'.propertyParms,
341
PropParms2 = [#'IndAudPropertyParm'{name = Val} | PropParms],
342
Desc2 = Desc#'IndAudLocalControlDescriptor'{propertyParms = PropParms2},
343
do_merge_indAudLocalControlDescriptor(Parms, Desc2)
345
do_merge_indAudLocalControlDescriptor([], Desc) ->
346
%% d("do_merge_indAudLocalControlDescriptor -> entry when"
347
%% "~n Desc: ~p", [Desc]),
348
case Desc#'IndAudLocalControlDescriptor'.propertyParms of
349
[_ | _] = PropParms -> % List has more then one element
350
PropParms2= lists:reverse(PropParms),
351
Desc#'IndAudLocalControlDescriptor'{propertyParms = PropParms2};
356
ensure_indAudLocalParm(Token) ->
358
{safeToken, _Line, "mode"} -> modeToken;
359
{safeToken, _Line, "mo"} -> modeToken;
360
{safeToken, _Line, "reservedgroup"} -> reservedGroupToken;
361
{safeToken, _Line, "rg"} -> reservedGroupToken;
362
{safeToken, _Line, "reservedvalue"} -> reservedValueToken;
363
{safeToken, _Line, "rv"} -> reservedValueToken;
364
PkgdName -> {pkgdName,
365
ensure_pkgdName(PkgdName)}
368
merge_indAudTerminationStateDescriptor({pkgdName, Val}) ->
369
PropParm = #'IndAudPropertyParm'{name = Val},
370
#'IndAudTerminationStateDescriptor'{propertyParms = [PropParm]};
371
merge_indAudTerminationStateDescriptor(serviceStatesToken) ->
372
#'IndAudTerminationStateDescriptor'{serviceState = 'NULL'};
373
merge_indAudTerminationStateDescriptor(bufferToken) ->
374
#'IndAudTerminationStateDescriptor'{eventBufferControl = 'NULL'}.
377
merge_indAudEventBufferDescriptor(EventName, SpecParams) ->
378
IAEBD = #'IndAudEventBufferDescriptor'{eventName = EventName},
379
do_merge_indAudEventBufferDescriptor(SpecParams, IAEBD).
381
do_merge_indAudEventBufferDescriptor(asn1_NOVALUE, IAEBD) ->
383
do_merge_indAudEventBufferDescriptor({streamID, StreamID}, IAEBD) ->
384
IAEBD#'IndAudEventBufferDescriptor'{streamID = StreamID};
385
do_merge_indAudEventBufferDescriptor({eventParameterName, _Name} = EPN,
387
%% BUGBUG BUGBUG BUGBUG
388
%% This is an ugly hack to allow the eventParamName which only
389
%% exists in the text encoding...
390
IAEBD#'IndAudEventBufferDescriptor'{streamID = EPN}.
393
ensure_indAudSignalListParm(SIG) when record(SIG, 'Signal') ->
394
ensure_indAudSignal(SIG).
396
ensure_indAudSignal(#'Signal'{signalName = SignalName,
397
streamID = asn1_NOVALUE,
398
sigType = asn1_NOVALUE,
399
duration = asn1_NOVALUE,
400
notifyCompletion = asn1_NOVALUE,
401
keepActive = asn1_NOVALUE,
403
#'IndAudSignal'{signalName = SignalName}.
406
ensure_IADMD({_TokenTag, _Line,
407
#'DigitMapDescriptor'{digitMapName = Name,
408
digitMapValue = asn1_NOVALUE}}) ->
409
#'IndAudDigitMapDescriptor'{digitMapName = Name}.
412
merge_indAudPackagesDescriptor(#'PackagesItem'{packageName = N,
413
packageVersion = V}) ->
414
#'IndAudPackagesDescriptor'{packageName = N,
418
ensure_indAudTerminationStateParm(Token) ->
420
{safeToken, _Line, "servicestates"} -> serviceStatesToken;
421
{safeToken, _Line, "si"} -> serviceStatesToken;
422
{safeToken, _Line, "buffer"} -> bufferToken;
423
{safeToken, _Line, "bf"} -> bufferToken;
424
PkgdName -> {pkgdName,
425
ensure_pkgdName(PkgdName)}
429
%% Types modified by v2:
431
merge_auditDescriptor([]) ->
432
#'AuditDescriptor'{};
433
merge_auditDescriptor(Tokens) when list(Tokens) ->
434
case lists:keysearch(terminationAudit, 1, Tokens) of
435
{value, {terminationAudit, TA}} ->
436
case lists:keydelete(terminationAudit, 1, Tokens) of
438
#'AuditDescriptor'{auditPropertyToken = TA};
440
#'AuditDescriptor'{auditToken = AuditTokens,
441
auditPropertyToken = TA}
444
#'AuditDescriptor'{auditToken = Tokens}
446
merge_auditDescriptor(_) ->
447
#'AuditDescriptor'{}.
454
merge_ServiceChangeParm(Parms) ->
455
Required = [serviceChangeReason, serviceChangeMethod],
456
merge_ServiceChangeParm(Parms, #'ServiceChangeParm'{}, Required).
458
merge_ServiceChangeParm([], SCP, []) ->
461
merge_ServiceChangeParm([], _SCP, Required) ->
462
exit({missing_required_serviceChangeParm, Required});
464
merge_ServiceChangeParm([{address, Val}|Parms], SCP0, Req)
465
when SCP0#'ServiceChangeParm'.serviceChangeAddress == asn1_NOVALUE,
466
SCP0#'ServiceChangeParm'.serviceChangeMgcId == asn1_NOVALUE ->
467
SCP = SCP0#'ServiceChangeParm'{serviceChangeAddress = Val},
468
merge_ServiceChangeParm(Parms, SCP, Req);
469
merge_ServiceChangeParm([{address, Val}|_Parms], SCP0, _Req)
470
when SCP0#'ServiceChangeParm'.serviceChangeAddress == asn1_NOVALUE ->
471
MgcId = SCP0#'ServiceChangeParm'.serviceChangeMgcId,
472
exit({not_both_address_mgcid_serviceChangeParm, Val, MgcId});
474
merge_ServiceChangeParm([{mgc_id, Val}|Parms], SCP0, Req)
475
when SCP0#'ServiceChangeParm'.serviceChangeMgcId == asn1_NOVALUE,
476
SCP0#'ServiceChangeParm'.serviceChangeAddress == asn1_NOVALUE ->
477
SCP = SCP0#'ServiceChangeParm'{serviceChangeMgcId = Val},
478
merge_ServiceChangeParm(Parms, SCP, Req);
479
merge_ServiceChangeParm([{mgc_id, Val}|_Parms], SCP0, _Req)
480
when SCP0#'ServiceChangeParm'.serviceChangeMgcId == asn1_NOVALUE ->
481
Addr = SCP0#'ServiceChangeParm'.serviceChangeAddress,
482
exit({not_both_address_mgcid_serviceChangeParm, Val, Addr});
484
merge_ServiceChangeParm([{profile, Val}|Parms], SCP0, Req)
485
when SCP0#'ServiceChangeParm'.serviceChangeProfile == asn1_NOVALUE ->
486
SCP = SCP0#'ServiceChangeParm'{serviceChangeProfile = Val},
487
merge_ServiceChangeParm(Parms, SCP, Req);
489
merge_ServiceChangeParm([{version, Val}|Parms], SCP0, Req)
490
when SCP0#'ServiceChangeParm'.serviceChangeVersion == asn1_NOVALUE ->
491
SCP = SCP0#'ServiceChangeParm'{serviceChangeVersion = Val},
492
merge_ServiceChangeParm(Parms, SCP, Req);
494
%% REQUIRED (i.e. no default value)
495
merge_ServiceChangeParm([{reason, Val}|Parms], SCP0, Req0)
496
when SCP0#'ServiceChangeParm'.serviceChangeReason == undefined ->
497
SCP = SCP0#'ServiceChangeParm'{serviceChangeReason = Val},
498
Req = lists:delete(serviceChangeReason, Req0),
499
merge_ServiceChangeParm(Parms, SCP, Req);
501
merge_ServiceChangeParm([{delay, Val}|Parms], SCP0, Req)
502
when SCP0#'ServiceChangeParm'.serviceChangeDelay == asn1_NOVALUE ->
503
SCP = SCP0#'ServiceChangeParm'{serviceChangeDelay = Val},
504
merge_ServiceChangeParm(Parms, SCP, Req);
506
%% REQUIRED (i.e. no default value)
507
merge_ServiceChangeParm([{method, Val}|Parms], SCP0, Req0)
508
when SCP0#'ServiceChangeParm'.serviceChangeMethod == undefined ->
509
SCP = SCP0#'ServiceChangeParm'{serviceChangeMethod = Val},
510
Req = lists:delete(serviceChangeMethod, Req0),
511
merge_ServiceChangeParm(Parms, SCP, Req);
513
merge_ServiceChangeParm([{time_stamp, Val}|Parms], SCP0, Req)
514
when SCP0#'ServiceChangeParm'.timeStamp == asn1_NOVALUE ->
515
SCP = SCP0#'ServiceChangeParm'{timeStamp = Val},
516
merge_ServiceChangeParm(Parms, SCP, Req);
518
merge_ServiceChangeParm([{extension, _Val}|Parms], SCP0, Req) ->
519
merge_ServiceChangeParm(Parms, SCP0, Req);
521
merge_ServiceChangeParm([{audit_item, Val}|Parms], SCP0, Req)
522
when SCP0#'ServiceChangeParm'.serviceChangeInfo == asn1_NOVALUE, atom(Val) ->
523
SCI = #'AuditDescriptor'{auditToken = [Val]},
524
SCP = SCP0#'ServiceChangeParm'{serviceChangeInfo = SCI},
525
merge_ServiceChangeParm(Parms, SCP, Req);
526
merge_ServiceChangeParm([{audit_item, Val}|Parms], SCP0, Req)
527
when SCP0#'ServiceChangeParm'.serviceChangeInfo == asn1_NOVALUE,tuple(Val) ->
528
SCI = #'AuditDescriptor'{auditPropertyToken = [Val]},
529
SCP = SCP0#'ServiceChangeParm'{serviceChangeInfo = SCI},
530
merge_ServiceChangeParm(Parms, SCP, Req);
531
merge_ServiceChangeParm([{audit_item, Val}|Parms], SCP0, Req)
532
when record(SCP0#'ServiceChangeParm'.serviceChangeInfo, 'AuditDescriptor'),
534
SCI0 = SCP0#'ServiceChangeParm'.serviceChangeInfo,
535
L = SCI0#'AuditDescriptor'.auditToken,
536
SCI = SCI0#'AuditDescriptor'{auditToken = [Val|L]},
537
SCP = SCP0#'ServiceChangeParm'{serviceChangeInfo = SCI},
538
merge_ServiceChangeParm(Parms, SCP, Req);
539
merge_ServiceChangeParm([{audit_item, Val}|Parms], SCP0, Req)
540
when record(SCP0#'ServiceChangeParm'.serviceChangeInfo, 'AuditDescriptor'),
542
SCI0 = SCP0#'ServiceChangeParm'.serviceChangeInfo,
543
L = SCI0#'AuditDescriptor'.auditPropertyToken,
544
SCI = SCI0#'AuditDescriptor'{auditPropertyToken = [Val|L]},
545
SCP = SCP0#'ServiceChangeParm'{serviceChangeInfo = SCI},
546
merge_ServiceChangeParm(Parms, SCP, Req);
548
merge_ServiceChangeParm([incomplete|Parms], SCP0, Req)
549
when SCP0#'ServiceChangeParm'.serviceChangeIncompleteFlag == asn1_NOVALUE ->
550
SCP = SCP0#'ServiceChangeParm'{serviceChangeIncompleteFlag = 'NULL'},
551
merge_ServiceChangeParm(Parms, SCP, Req);
553
merge_ServiceChangeParm([{Tag, Val}|_Parms], SCP, _Req) ->
557
SCP#'ServiceChangeParm'.serviceChangeAddress;
559
SCP#'ServiceChangeParm'.serviceChangeMgcId;
561
SCP#'ServiceChangeParm'.serviceChangeProfile;
563
SCP#'ServiceChangeParm'.serviceChangeVersion;
565
SCP#'ServiceChangeParm'.serviceChangeReason;
567
SCP#'ServiceChangeParm'.serviceChangeDelay;
569
SCP#'ServiceChangeParm'.serviceChangeMethod;
571
SCP#'ServiceChangeParm'.timeStamp;
573
SCP#'ServiceChangeParm'.serviceChangeInfo
575
exit({at_most_once_serviceChangeParm, {Tag, Val, Val2}});
576
merge_ServiceChangeParm([Parm|_Parms], SCP, _Req) ->
580
SCP#'ServiceChangeParm'.serviceChangeIncompleteFlag
582
exit({at_most_once_serviceChangeParm, {Parm, Parm2}}).
585
merge_ServiceChangeResParm(Parms) ->
586
merge_ServiceChangeResParm(Parms, #'ServiceChangeResParm'{}).
588
merge_ServiceChangeResParm([], SCRP) ->
590
merge_ServiceChangeResParm([{address, Val}|Parms], SCRP0)
591
when SCRP0#'ServiceChangeResParm'.serviceChangeAddress == asn1_NOVALUE,
592
SCRP0#'ServiceChangeResParm'.serviceChangeMgcId == asn1_NOVALUE ->
593
SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeAddress = Val},
594
merge_ServiceChangeResParm(Parms, SCRP);
595
merge_ServiceChangeResParm([{address, Val}|_Parms], SCRP0)
596
when SCRP0#'ServiceChangeResParm'.serviceChangeAddress == asn1_NOVALUE ->
597
MgcId = SCRP0#'ServiceChangeResParm'.serviceChangeMgcId,
598
exit({not_both_address_mgcid_servChgReplyParm, Val, MgcId});
600
merge_ServiceChangeResParm([{mgc_id, Val}|Parms], SCRP0)
601
when SCRP0#'ServiceChangeResParm'.serviceChangeMgcId == asn1_NOVALUE,
602
SCRP0#'ServiceChangeResParm'.serviceChangeAddress == asn1_NOVALUE ->
603
SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeMgcId = Val},
604
merge_ServiceChangeResParm(Parms, SCRP);
605
merge_ServiceChangeResParm([{mgc_id, Val}|_Parms], SCRP0)
606
when SCRP0#'ServiceChangeResParm'.serviceChangeMgcId == asn1_NOVALUE ->
607
Addr = SCRP0#'ServiceChangeResParm'.serviceChangeAddress,
608
exit({not_both_address_mgcid_servChgReplyParm, Val, Addr});
610
merge_ServiceChangeResParm([{profile, Val}|Parms], SCRP0)
611
when SCRP0#'ServiceChangeResParm'.serviceChangeProfile == asn1_NOVALUE ->
612
SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeProfile = Val},
613
merge_ServiceChangeResParm(Parms, SCRP);
615
merge_ServiceChangeResParm([{version, Val}|Parms], SCRP0)
616
when SCRP0#'ServiceChangeResParm'.serviceChangeVersion == asn1_NOVALUE ->
617
SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeVersion = Val},
618
merge_ServiceChangeResParm(Parms, SCRP);
620
merge_ServiceChangeResParm([{time_stamp, Val}|Parms], SCRP0)
621
when SCRP0#'ServiceChangeResParm'.timeStamp == asn1_NOVALUE ->
622
SCRP = SCRP0#'ServiceChangeResParm'{timeStamp = Val},
623
merge_ServiceChangeResParm(Parms, SCRP);
625
merge_ServiceChangeResParm([{Tag, Val}|_Parms], SCRP) ->
628
address -> SCRP#'ServiceChangeResParm'.serviceChangeAddress;
629
mgc_id -> SCRP#'ServiceChangeResParm'.serviceChangeMgcId;
630
profile -> SCRP#'ServiceChangeResParm'.serviceChangeProfile;
631
version -> SCRP#'ServiceChangeResParm'.serviceChangeVersion;
632
time_stamp -> SCRP#'ServiceChangeResParm'.timeStamp
634
exit({at_most_once_servChgReplyParm, {Tag, Val, Val2}}).
637
ensure_serviceChangeMethod({safeToken, _Line, "fl"}) ->
639
ensure_serviceChangeMethod({safeToken, _Line, "failover"}) ->
641
ensure_serviceChangeMethod({safeToken, _Line, "fo"}) ->
643
ensure_serviceChangeMethod({safeToken, _Line, "forced"}) ->
645
ensure_serviceChangeMethod({safeToken, _Line, "gr"}) ->
647
ensure_serviceChangeMethod({safeToken, _Line, "graceful"}) ->
649
ensure_serviceChangeMethod({safeToken, _Line, "rs"}) ->
651
ensure_serviceChangeMethod({safeToken, _Line, "restart"}) ->
653
ensure_serviceChangeMethod({safeToken, _Line, "dc"}) ->
655
ensure_serviceChangeMethod({safeToken, _Line, "disconnected"}) ->
657
ensure_serviceChangeMethod({safeToken, _Line, "ho"}) ->
659
ensure_serviceChangeMethod({safeToken, _Line, "handoff"}) ->
661
ensure_serviceChangeMethod({safeToken, Line, Text}) ->
662
return_error(Line, {bad_serviceChangeMethod, Text}).
665
ensure_profile({_TokenTag, Line, Text}) ->
666
case string:tokens(Text, [$/]) of
668
Version2 = ensure_version(Version),
669
#'ServiceChangeProfile'{profileName = Name, version = Version2};
671
return_error(Line, {bad_profile, Text})
674
ensure_version(Version) ->
675
ensure_uint(Version, 0, 99).
677
merge_signalRequest(SignalName, PropertyParms) ->
678
Sig = #'Signal'{signalName = SignalName},
680
do_merge_signalRequest(Sig, PropertyParms, SPL).
682
do_merge_signalRequest(Sig, [H | T], SPL) ->
684
{stream, SID} when Sig#'Signal'.streamID == asn1_NOVALUE ->
685
do_merge_signalRequest(Sig#'Signal'{streamID = SID}, T, SPL);
686
{signal_type, SigType} when Sig#'Signal'.sigType == asn1_NOVALUE ->
687
do_merge_signalRequest(Sig#'Signal'{sigType = SigType}, T, SPL);
688
{duration, Duration} when Sig#'Signal'.duration == asn1_NOVALUE ->
689
do_merge_signalRequest(Sig#'Signal'{duration = Duration}, T, SPL);
690
{notify_completion, NC} when Sig#'Signal'.notifyCompletion == asn1_NOVALUE ->
691
do_merge_signalRequest(Sig#'Signal'{notifyCompletion = NC}, T, SPL);
692
keepActive when Sig#'Signal'.keepActive == asn1_NOVALUE->
693
do_merge_signalRequest(Sig#'Signal'{keepActive = true}, T, SPL);
695
SP = #'SigParameter'{sigParameterName = Name,
696
value = PP#'PropertyParm'.value,
697
extraInfo = PP#'PropertyParm'.extraInfo},
698
do_merge_signalRequest(Sig, T, [SP | SPL]);
699
{direction, Dir} when Sig#'Signal'.direction == asn1_NOVALUE->
700
do_merge_signalRequest(Sig#'Signal'{direction = Dir}, T, SPL);
701
{requestId, RID} when Sig#'Signal'.requestID == asn1_NOVALUE->
702
do_merge_signalRequest(Sig#'Signal'{requestID = RID}, T, SPL);
704
return_error(0, {bad_sigParm, H})
706
do_merge_signalRequest(Sig, [], SPL) ->
707
Sig#'Signal'{sigParList = lists:reverse(SPL)} .
709
%% eventStream = StreamToken EQUAL StreamID
710
%% eventOther = eventParameterName parmValue
711
select_stream_or_other("st", #'PropertyParm'{value = [Value]}) ->
712
{stream, ensure_uint16(Value)};
713
select_stream_or_other("st", Value) ->
714
{stream, ensure_uint16(Value)};
715
select_stream_or_other("stream", #'PropertyParm'{value = [Value]}) ->
716
{stream, ensure_uint16(Value)};
717
select_stream_or_other("stream", Value) ->
718
{stream, ensure_uint16(Value)};
719
select_stream_or_other(Name, #'PropertyParm'{value = Value}) ->
720
EP = #'EventParameter'{eventParameterName = Name,
724
ensure_eventDM({_TokenTag, Line, DMD})
725
when record(DMD, 'DigitMapDescriptor') ->
726
Name = DMD#'DigitMapDescriptor'.digitMapName,
727
Val = DMD#'DigitMapDescriptor'.digitMapValue,
729
Name == asn1_NOVALUE, Val /= asn1_NOVALUE ->
730
{'DigitMapValue', Start, Short, Long, Duration, Body} = Val,
731
DMV = #'DigitMapValue'{startTimer = Start,
735
durationTimer = Duration},
736
{eventDM, {digitMapValue, DMV}};
737
Name /= asn1_NOVALUE, Val == asn1_NOVALUE ->
738
{eventDM, {digitMapName, Name}};
740
return_error(Line, {bad_eventDM, DMD})
743
ensure_DMD({_TokenTag, _Line, DMD})
744
when record(DMD, 'DigitMapDescriptor') ->
746
case DMD#'DigitMapDescriptor'.digitMapValue of
747
%% Note that the values of the digitMapBody and durationTimers
748
%% are swapped by the scanner (this is done because of a
749
%% problem in the flex scanner).
750
#'DigitMapValue'{durationTimer = Body,
751
digitMapBody = Duration} = DMV ->
752
%% Convert to version 1 DigitMapValue
753
DMV#'DigitMapValue'{digitMapBody = Body,
754
durationTimer = Duration};
758
DMD#'DigitMapDescriptor'{digitMapValue = Val2}.
761
merge_observed_event(ObservedEvents, EventName, TimeStamp) ->
762
StreamId = asn1_NOVALUE,
764
do_merge_observed_event(ObservedEvents, EventName, TimeStamp, StreamId, EPL).
766
do_merge_observed_event([{stream, StreamID} | T], EventName, TimeStamp, asn1_NOVALUE, EPL) ->
767
do_merge_observed_event(T, EventName, TimeStamp, StreamID, EPL);
768
do_merge_observed_event([{other, PP} | T], EventName, TimeStamp, StreamID, EPL) ->
769
do_merge_observed_event(T, EventName, TimeStamp, StreamID, [PP | EPL]);
770
do_merge_observed_event([], EventName, TimeStamp, StreamID, EPL) ->
771
#'ObservedEvent'{eventName = EventName,
772
timeNotation = TimeStamp,
774
eventParList = lists:reverse(EPL)}.
776
merge_eventSpec(OE) when record(OE, 'ObservedEvent'),
777
OE#'ObservedEvent'.timeNotation == asn1_NOVALUE ->
778
#'EventSpec'{eventName = OE#'ObservedEvent'.eventName,
779
streamID = OE#'ObservedEvent'.streamID,
780
eventParList = OE#'ObservedEvent'.eventParList};
781
merge_eventSpec(OE) ->
782
return_error(0, {bad_event_spec, OE}).
784
merge_eventParameters(Params) ->
785
StreamId = asn1_NOVALUE,
787
RA = #'RequestedActions'{},
789
do_merge_eventParameters(Params, StreamId, EPL, RA, HasA) .
791
do_merge_eventParameters([H | T], StreamId, EPL, RA, HasA) ->
793
keepActive when RA#'RequestedActions'.keepActive == asn1_NOVALUE ->
794
RA2 = RA#'RequestedActions'{keepActive = true},
795
do_merge_eventParameters(T, StreamId, EPL, RA2, yes);
796
{embed, SD, SED} when RA#'RequestedActions'.signalsDescriptor == asn1_NOVALUE ->
797
RA2 = RA#'RequestedActions'{signalsDescriptor = SD,
799
do_merge_eventParameters(T, StreamId, EPL, RA2, yes);
800
{eventDM, DM} when RA#'RequestedActions'.eventDM == asn1_NOVALUE ->
801
RA2 = RA#'RequestedActions'{eventDM = DM},
802
do_merge_eventParameters(T, StreamId, EPL, RA2, yes);
803
{stream, NewStreamId} when StreamId == asn1_NOVALUE ->
804
do_merge_eventParameters(T, NewStreamId, EPL, RA, HasA);
805
{other, PP} when record(PP, 'PropertyParm') ->
806
EP = #'EventParameter'{eventParameterName = PP#'PropertyParm'.name,
807
value = PP#'PropertyParm'.value,
808
extraInfo = PP#'PropertyParm'.extraInfo},
809
do_merge_eventParameters(T, StreamId, [EP | EPL], RA, HasA);
810
{other, EP} when record(EP, 'EventParameter') ->
811
do_merge_eventParameters(T, StreamId, [EP | EPL], RA, HasA);
813
return_error(0, {bad_eventParameter, H})
815
do_merge_eventParameters([], StreamId, EPL, RA, yes) ->
816
#'RequestedEvent'{streamID = StreamId,
818
evParList = lists:reverse(EPL)};
819
do_merge_eventParameters([], StreamId, EPL, _RA, no) ->
820
#'RequestedEvent'{streamID = StreamId,
821
eventAction = asn1_NOVALUE,
822
evParList = lists:reverse(EPL)}.
824
merge_secondEventParameters(Params) ->
825
StreamId = asn1_NOVALUE,
827
SRA = #'SecondRequestedActions'{},
829
do_merge_secondEventParameters(Params, StreamId, EPL, SRA, HasA) .
831
do_merge_secondEventParameters([H | T], StreamId, EPL, SRA, HasA) ->
833
keepActive when SRA#'SecondRequestedActions'.keepActive == asn1_NOVALUE ->
834
SRA2 = SRA#'SecondRequestedActions'{keepActive = true},
835
do_merge_secondEventParameters(T, StreamId, EPL, SRA2, yes);
836
{second_embed, SD} when SRA#'SecondRequestedActions'.signalsDescriptor == asn1_NOVALUE ->
837
SRA2 = SRA#'SecondRequestedActions'{signalsDescriptor = SD},
838
do_merge_secondEventParameters(T, StreamId, EPL, SRA2, yes);
839
{eventDM, DM} when SRA#'SecondRequestedActions'.eventDM == asn1_NOVALUE ->
840
SRA2 = SRA#'SecondRequestedActions'{eventDM = DM},
841
do_merge_secondEventParameters(T, StreamId, EPL, SRA2, yes);
842
{stream, NewStreamId} when StreamId == asn1_NOVALUE ->
843
do_merge_secondEventParameters(T, NewStreamId, EPL, SRA, HasA);
844
{other, PP} when record(PP, 'PropertyParm') ->
845
EP = #'EventParameter'{eventParameterName = PP#'PropertyParm'.name,
846
value = PP#'PropertyParm'.value,
847
extraInfo = PP#'PropertyParm'.extraInfo},
848
do_merge_secondEventParameters(T, StreamId, [EP | EPL], SRA, HasA);
849
{other, EP} when record(EP, 'EventParameter') ->
850
do_merge_secondEventParameters(T, StreamId, [EP | EPL], SRA, HasA);
852
return_error(0, {bad_secondEventParameter, H})
854
do_merge_secondEventParameters([], StreamId, EPL, SRA, yes) ->
855
#'SecondRequestedEvent'{streamID = StreamId,
857
evParList = lists:reverse(EPL)};
858
do_merge_secondEventParameters([], StreamId, EPL, _SRA, no) ->
859
#'SecondRequestedEvent'{streamID = StreamId,
860
eventAction = asn1_NOVALUE,
861
evParList = lists:reverse(EPL)}.
863
%% terminationID = "ROOT" / pathName / "$" / "*"
864
%% Total length of pathName must not exceed 64 chars.
865
%% pathName = ["*"] NAME *("/" / "*"/ ALPHA / DIGIT /"_" / "$" )
866
%% ["@" pathDomainName ]
867
%% ABNF allows two or more consecutive "." although it is meaningless
868
%% in a path domain name.
869
%% pathDomainName = (ALPHA / DIGIT / "*" )
870
%% *63(ALPHA / DIGIT / "-" / "*" / ".")
871
ensure_terminationID({safeToken, _Line, LowerText}) ->
872
%% terminationID = "ROOT" / pathName / "$" / "*"
873
decode_term_id(LowerText, false, [], []).
875
decode_term_id([H | T], Wild, Id, Component) ->
877
$/ -> decode_term_id(T, Wild, [lists:reverse(Component) | Id], []);
878
$* -> decode_term_id(T, true, Id, [?megaco_all | Component]);
879
$$ -> decode_term_id(T, true, Id, [?megaco_choose | Component]);
880
_ -> decode_term_id(T, Wild, Id, [H | Component])
882
decode_term_id([], Wild, Id, Component) ->
883
Id2 = [lists:reverse(Component) | Id],
884
#megaco_term_id{contains_wildcards = Wild, id = lists:reverse(Id2)}.
886
ensure_pathName({_TokenTag, _Line, Text}) ->
887
Text. %% BUGBUG: ensure values
889
%% TimeStamp = Date "T" Time ; per ISO 8601:1988
890
%% Date = 8(DIGIT) ; Date = yyyymmdd
891
%% Time = 8(DIGIT) ; Time = hhmmssss
892
ensure_timeStamp({'TimeStampToken', Line, Text}) ->
893
case string:tokens(Text, [$T, $t]) of
895
#'TimeNotation'{date = Date, time = Time};
897
return_error(Line, {bad_timeStamp, Text})
900
ensure_transactionID(TransId) ->
901
ensure_uint32(TransId).
903
%% transactionAck = transactionID / (transactionID "-" transactionID)
904
ensure_transactionAck({safeToken, _Line, Text}) ->
905
case string:tokens(Text, [$-]) of
907
#'TransactionAck'{firstAck = ensure_transactionID(Id)};
909
#'TransactionAck'{firstAck = ensure_transactionID(Id),
910
lastAck = ensure_transactionID(Id2)}
913
merge_context_request(asn1_NOVALUE, Prop) ->
914
merge_context_request(#'ContextRequest'{}, Prop);
916
merge_context_request(#'ContextRequest'{priority = asn1_NOVALUE} = CR,
918
CR#'ContextRequest'{priority = Int};
920
merge_context_request(#'ContextRequest'{emergency = asn1_NOVALUE} = CR,
921
{emergency, Bool}) ->
922
CR#'ContextRequest'{emergency = Bool};
924
merge_context_request(#'ContextRequest'{topologyReq = asn1_NOVALUE} = CR,
926
CR#'ContextRequest'{topologyReq = Desc};
928
merge_context_request(#'ContextRequest'{iepscallind = asn1_NOVALUE} = CR,
929
{iepsCallind, Ind}) ->
930
CR#'ContextRequest'{iepscallind = Ind};
932
merge_context_request(#'ContextRequest'{contextProp = asn1_NOVALUE} = CR,
933
{contextProp, Props}) ->
934
CR#'ContextRequest'{contextProp = Props};
936
%% The parser handles this, but we drop it in this version
937
%% merge_context_request(#'ContextRequest'{contextList = asn1_NOVALUE} = CR,
938
%% {contextList, _IDs}) ->
939
%% CR#'ContextRequest'{contextList = IDs};
940
merge_context_request(CR, {contextList, _IDs}) ->
943
merge_context_request(CR, {Tag, Val}) ->
946
priority -> CR#'ContextRequest'.priority;
947
emergency -> CR#'ContextRequest'.emergency;
948
topology -> CR#'ContextRequest'.topologyReq;
949
iepsCallind -> CR#'ContextRequest'.iepscallind;
950
contextProp -> CR#'ContextRequest'.contextProp%% ;
951
%% contextList -> CR#'ContextRequest'.contextList
953
exit({at_most_once_contextProperty, {Tag, Val, Val2}}).
956
merge_context_attr_audit_request(CAAR, []) ->
958
merge_context_attr_audit_request(CAAR, [H|T]) ->
960
priorityAudit when CAAR#'ContextAttrAuditRequest'.priority == asn1_NOVALUE ->
961
CAAR2 = CAAR#'ContextAttrAuditRequest'{priority = 'NULL'},
962
merge_context_attr_audit_request(CAAR2, T);
964
emergencyAudit when CAAR#'ContextAttrAuditRequest'.emergency == asn1_NOVALUE ->
965
CAAR2 = CAAR#'ContextAttrAuditRequest'{emergency = 'NULL'},
966
merge_context_attr_audit_request(CAAR2, T);
968
topologyAudit when CAAR#'ContextAttrAuditRequest'.topology == asn1_NOVALUE ->
969
CAAR2 = CAAR#'ContextAttrAuditRequest'{topology = 'NULL'},
970
merge_context_attr_audit_request(CAAR2, T);
972
iepsCallind when CAAR#'ContextAttrAuditRequest'.iepscallind == asn1_NOVALUE ->
973
CAAR2 = CAAR#'ContextAttrAuditRequest'{iepscallind = 'NULL'},
974
merge_context_attr_audit_request(CAAR2, T);
976
{prop, Name} when CAAR#'ContextAttrAuditRequest'.contextPropAud == asn1_NOVALUE ->
977
CPA = [#'IndAudPropertyParm'{name = Name}],
978
CAAR2 = CAAR#'ContextAttrAuditRequest'{contextPropAud = CPA},
979
merge_context_attr_audit_request(CAAR2, T);
982
CPA = CAAR#'ContextAttrAuditRequest'.contextPropAud,
983
CPA2 = [#'IndAudPropertyParm'{name = Name}|CPA],
984
CAAR2 = CAAR#'ContextAttrAuditRequest'{contextPropAud = CPA2},
985
merge_context_attr_audit_request(CAAR2, T)
989
merge_action_request(CtxId, Items) ->
990
do_merge_action_request(Items, [], asn1_NOVALUE, asn1_NOVALUE, CtxId).
992
do_merge_action_request([H|T], CmdReqs, CtxReq, CtxAuditReq, CtxId) ->
994
{commandRequest, CmdReq} ->
995
do_merge_action_request(T, [CmdReq|CmdReqs],
996
CtxReq, CtxAuditReq, CtxId);
998
{contextProp, ContextProp} ->
999
do_merge_action_request(T, CmdReqs,
1000
merge_context_request(CtxReq, ContextProp),
1001
CtxAuditReq, CtxId);
1003
{contextAudit, ContextAuditReq} when CtxAuditReq == asn1_NOVALUE ->
1004
do_merge_action_request(T, CmdReqs,
1005
CtxReq, ContextAuditReq, CtxId)
1007
do_merge_action_request([], CmdReqs, CtxReq, CtxAuditReq, CtxId) ->
1008
#'ActionRequest'{contextId = CtxId,
1009
contextRequest = strip_ContextRequest(CtxReq),
1010
contextAttrAuditReq = strip_ContextAttrAuditRequest(CtxAuditReq),
1011
commandRequests = lists:reverse(CmdReqs)}.
1015
%% In order to solve a problem in the parser, the error descriptor
1016
%% has been put last in the non-empty commandReplyList, if it is not
1018
merge_action_reply(Items) ->
1019
do_merge_action_reply(Items, asn1_NOVALUE, asn1_NOVALUE, []).
1021
do_merge_action_reply([], Err, Ctx, Cmds) ->
1022
#'ActionReply'{errorDescriptor = Err,
1023
contextReply = strip_ContextRequest(Ctx),
1024
commandReply = lists:reverse(Cmds)};
1025
do_merge_action_reply([H|T], Err0, CR, Cmds) ->
1027
{error, Err1} when Err0 == asn1_NOVALUE ->
1028
do_merge_action_reply(T, Err1, CR, Cmds);
1030
do_merge_action_reply(T, Err0, CR, [Cmd | Cmds]);
1031
{context, CtxProp} ->
1032
do_merge_action_reply(T, Err0,
1033
merge_context_request(CR, CtxProp), Cmds)
1036
strip_ContextRequest(#'ContextRequest'{priority = asn1_NOVALUE,
1037
emergency = asn1_NOVALUE,
1038
topologyReq = asn1_NOVALUE,
1039
iepscallind = asn1_NOVALUE,
1040
contextProp = asn1_NOVALUE}) ->
1042
strip_ContextRequest(#'ContextRequest'{priority = asn1_NOVALUE,
1043
emergency = asn1_NOVALUE,
1044
topologyReq = asn1_NOVALUE,
1045
iepscallind = asn1_NOVALUE,
1046
contextProp = []}) ->
1048
strip_ContextRequest(asn1_NOVALUE) ->
1050
strip_ContextRequest(R) ->
1053
strip_ContextAttrAuditRequest(asn1_NOVALUE) ->
1055
strip_ContextAttrAuditRequest(
1056
#'ContextAttrAuditRequest'{priority = asn1_NOVALUE,
1057
emergency = asn1_NOVALUE,
1058
topology = asn1_NOVALUE,
1059
iepscallind = asn1_NOVALUE,
1060
contextPropAud = asn1_NOVALUE}) ->
1062
strip_ContextAttrAuditRequest(
1063
#'ContextAttrAuditRequest'{priority = asn1_NOVALUE,
1064
emergency = asn1_NOVALUE,
1065
topology = asn1_NOVALUE,
1066
iepscallind = asn1_NOVALUE,
1067
contextPropAud = []}) ->
1069
strip_ContextAttrAuditRequest(R) ->
1072
merge_AmmRequest_descriptors([], Acc) ->
1074
merge_AmmRequest_descriptors([{_, deprecated}|Descs], Acc) ->
1075
merge_AmmRequest_descriptors(Descs, Acc);
1076
merge_AmmRequest_descriptors([Desc|Descs], Acc) ->
1077
merge_AmmRequest_descriptors(Descs, [Desc|Acc]).
1079
make_commandRequest({CmdTag, {_TokenTag, _Line, Text}}, Cmd) ->
1080
Req = #'CommandRequest'{command = {CmdTag, Cmd}},
1083
Req#'CommandRequest'{wildcardReturn = 'NULL'};
1084
[$o, $-, $w, $- | _] ->
1085
Req#'CommandRequest'{optional = 'NULL', wildcardReturn = 'NULL'};
1087
Req#'CommandRequest'{optional = 'NULL'};
1092
merge_terminationAudit(AuditReturnParameters) ->
1093
lists:reverse(do_merge_terminationAudit(AuditReturnParameters, [], [])).
1095
do_merge_terminationAudit([H| T], ARPs, AuditItems) ->
1097
{auditReturnItem, AuditItem} ->
1098
do_merge_terminationAudit(T, ARPs, [AuditItem | AuditItems]);
1099
AuditReturnParameter ->
1100
do_merge_terminationAudit(T, [AuditReturnParameter | ARPs], AuditItems)
1102
do_merge_terminationAudit([], AuditReturnParameters, []) ->
1103
AuditReturnParameters;
1104
do_merge_terminationAudit([], AuditReturnParameters, AuditItems) ->
1105
AuditDescriptor = #'AuditDescriptor'{auditToken = AuditItems},
1106
AuditReturnParameter = {emptyDescriptors, AuditDescriptor},
1107
[AuditReturnParameter | AuditReturnParameters].
1109
merge_mediaDescriptor(MediaParms) ->
1110
do_merge_mediaDescriptor(MediaParms, asn1_NOVALUE, [], []).
1112
do_merge_mediaDescriptor([H | T], TS, One, Multi) ->
1114
{streamParm, Parm} when Multi == [] ->
1115
do_merge_mediaDescriptor(T, TS, [Parm | One], Multi);
1116
{streamDescriptor, Desc} when One == [] ->
1117
do_merge_mediaDescriptor(T, TS, One, [Desc | Multi]);
1118
{termState, TS2} when TS == asn1_NOVALUE ->
1119
do_merge_mediaDescriptor(T, TS2, One, Multi);
1121
return_error(0, {bad_merge_mediaDescriptor, [H, TS, One, Multi]})
1123
do_merge_mediaDescriptor([], TS, One, Multi) ->
1125
One == [], Multi == [] ->
1126
#'MediaDescriptor'{streams = asn1_NOVALUE,
1127
termStateDescr = TS};
1128
One /= [], Multi == [] ->
1129
#'MediaDescriptor'{streams = {oneStream, merge_streamParms(One)},
1130
termStateDescr = TS};
1131
One == [], Multi /= [] ->
1132
#'MediaDescriptor'{streams = {multiStream, lists:reverse(Multi)},
1133
termStateDescr = TS}
1136
merge_streamParms(TaggedStreamParms) ->
1137
SP = #'StreamParms'{},
1138
do_merge_streamParms(TaggedStreamParms, SP).
1140
do_merge_streamParms([{Tag, D} | T] = All, SP) ->
1142
local when SP#'StreamParms'.localDescriptor == asn1_NOVALUE ->
1143
do_merge_streamParms(T, SP#'StreamParms'{localDescriptor = D});
1144
remote when SP#'StreamParms'.remoteDescriptor == asn1_NOVALUE ->
1145
do_merge_streamParms(T, SP#'StreamParms'{remoteDescriptor = D});
1148
case SP#'StreamParms'.localControlDescriptor of
1150
#'LocalControlDescriptor'{propertyParms = []};
1154
LCD2 = do_merge_control_streamParms(D, LCD),
1155
do_merge_streamParms(T, SP#'StreamParms'{localControlDescriptor = LCD2});
1156
statistics when SP#'StreamParms'.statisticsDescriptor == asn1_NOVALUE ->
1157
do_merge_streamParms(T, SP#'StreamParms'{statisticsDescriptor = D});
1159
return_error(0, {do_merge_streamParms, [All, SP]})
1161
do_merge_streamParms([], SP) when record(SP#'StreamParms'.localControlDescriptor, 'LocalControlDescriptor') ->
1162
LCD = SP#'StreamParms'.localControlDescriptor,
1163
PP = LCD#'LocalControlDescriptor'.propertyParms,
1164
LCD2 = LCD#'LocalControlDescriptor'{propertyParms = lists:reverse(PP)},
1165
SP#'StreamParms'{localControlDescriptor = LCD2};
1166
do_merge_streamParms([], SP) ->
1170
do_merge_control_streamParms([{SubTag, SD} | T] = All, LCD) ->
1172
group when LCD#'LocalControlDescriptor'.reserveGroup == asn1_NOVALUE ->
1173
LCD2 = LCD#'LocalControlDescriptor'{reserveGroup = SD},
1174
do_merge_control_streamParms(T, LCD2);
1175
value when LCD#'LocalControlDescriptor'.reserveValue == asn1_NOVALUE ->
1176
LCD2 = LCD#'LocalControlDescriptor'{reserveValue = SD},
1177
do_merge_control_streamParms(T, LCD2);
1178
mode when LCD#'LocalControlDescriptor'.streamMode == asn1_NOVALUE ->
1179
LCD2 = LCD#'LocalControlDescriptor'{streamMode = SD},
1180
do_merge_control_streamParms(T, LCD2);
1182
PP = LCD#'LocalControlDescriptor'.propertyParms,
1183
LCD2 = LCD#'LocalControlDescriptor'{propertyParms = [SD | PP]},
1184
do_merge_control_streamParms(T, LCD2);
1186
return_error(0, {do_merge_control_streamParms, [All, LCD]})
1188
do_merge_control_streamParms([], LCD) ->
1191
merge_terminationStateDescriptor(Parms) ->
1192
TSD = #'TerminationStateDescriptor'{propertyParms = []},
1193
do_merge_terminationStateDescriptor(Parms, TSD).
1195
do_merge_terminationStateDescriptor([{Tag, Val} | T], TSD) ->
1197
serviceState when TSD#'TerminationStateDescriptor'.serviceState == asn1_NOVALUE ->
1198
TSD2 = TSD#'TerminationStateDescriptor'{serviceState = Val},
1199
do_merge_terminationStateDescriptor(T, TSD2);
1200
eventBufferControl when TSD#'TerminationStateDescriptor'.eventBufferControl == asn1_NOVALUE->
1201
TSD2 = TSD#'TerminationStateDescriptor'{eventBufferControl = Val},
1202
do_merge_terminationStateDescriptor(T, TSD2);
1204
PP = TSD#'TerminationStateDescriptor'.propertyParms,
1205
TSD2 = TSD#'TerminationStateDescriptor'{propertyParms = [Val | PP]},
1206
do_merge_terminationStateDescriptor(T, TSD2)
1208
do_merge_terminationStateDescriptor([], TSD) ->
1209
PP = TSD#'TerminationStateDescriptor'.propertyParms,
1210
TSD#'TerminationStateDescriptor'{propertyParms = lists:reverse(PP)}.
1212
ensure_prop_groups({_TokenTag, _Line, Text}) ->
1215
parse_prop_name(Text, Group, Groups).
1217
parse_prop_name([Char | Rest] = All, Group, Groups) ->
1218
case ?classify_char(Char) of
1220
parse_prop_name(Rest, Group, Groups);
1222
parse_prop_name(Rest, Group, Groups);
1225
do_parse_prop_name(All, Name, Group, Groups)
1227
parse_prop_name([] = All, Group, Groups) ->
1229
do_parse_prop_name(All, Name, Group, Groups).
1231
do_parse_prop_name([Char | Rest], Name, Group, Groups) ->
1232
case ?classify_char(Char) of
1234
do_parse_prop_name(Rest, [Char | Name], Group, Groups);
1235
rest_char when Char == $=, Name /= [] ->
1236
%% Now we have a complete name
1238
Name == "v", Group /= [] ->
1239
%% v= is a property group delimiter,
1240
%% lets create yet another property group.
1241
Groups2 = [lists:reverse(Group) | Groups],
1243
parse_prop_value(Rest, Name, Group2, Groups2);
1245
%% Use current property group
1246
parse_prop_value(Rest, Name, Group, Groups)
1249
return_error(0, {bad_prop_name, lists:reverse(Name), Char})
1251
do_parse_prop_name([], [], [], Groups) ->
1252
lists:reverse(Groups);
1253
do_parse_prop_name([], [], Group, Groups) ->
1254
Group2 = lists:reverse(Group),
1255
lists:reverse([Group2 | Groups]);
1256
do_parse_prop_name([], Name, Group, Groups) when Name /= [] ->
1257
%% Assume end of line
1259
PP = make_prop_parm(Name, Value),
1260
Group2 = lists:reverse([PP | Group]),
1261
lists:reverse([Group2 | Groups]).
1263
parse_prop_value(Chars, Name, Group, Groups) ->
1265
do_parse_prop_value(Chars, Name, Value, Group, Groups).
1267
do_parse_prop_value([Char | Rest], Name, Value, Group, Groups) ->
1268
case ?classify_char(Char) of
1270
%% Now we have a complete "name=value" pair
1271
PP = make_prop_parm(Name, Value),
1272
parse_prop_name(Rest, [PP | Group], Groups);
1274
do_parse_prop_value(Rest, Name, [Char | Value], Group, Groups)
1276
do_parse_prop_value([], Name, Value, Group, Groups) ->
1277
%% Assume end of line
1278
PP = make_prop_parm(Name, Value),
1279
Group2 = lists:reverse([PP | Group]),
1280
lists:reverse([Group2 | Groups]).
1282
make_prop_parm(Name, Value) ->
1283
#'PropertyParm'{name = lists:reverse(Name),
1284
value = [lists:reverse(Value)]}.
1286
ensure_uint({_TokenTag, Line, Val}, Min, Max) when integer(Val) ->
1288
integer(Min), Val >= Min ->
1290
integer(Max), Val =< Max ->
1295
return_error(Line, {too_large_integer, Val, Max})
1298
return_error(Line, {too_small_integer, Val, Min})
1300
ensure_uint({TokenTag, Line, Text}, Min, Max) ->
1301
case catch list_to_integer(Text) of
1303
return_error(Line, {not_an_integer, Text});
1304
Val when integer(Val) ->
1305
ensure_uint({TokenTag, Line, Val}, Min, Max)
1307
ensure_uint(Val, Min, Max) ->
1308
ensure_uint({uint, 0, Val}, Min, Max).
1310
ensure_uint16(Int) ->
1311
ensure_uint(Int, 0, 65535).
1313
ensure_uint32(Int) ->
1314
ensure_uint(Int, 0, 4294967295) .
1317
ensure_hex({_TokenTag, _Line, [$0, $x |Chars]}, Min, Max) ->
1318
ensure_uint(length(Chars), Min, Max),
1319
hex_to_int(Chars, []);
1320
ensure_hex({_TokenTag, _Line, [$0, $X |Chars]}, Min, Max) ->
1321
ensure_uint(length(Chars), Min, Max),
1322
hex_to_int(Chars, []);
1323
ensure_hex([$0, $x |Chars], Min, Max) ->
1324
ensure_uint(length(Chars), Min, Max),
1325
hex_to_int(Chars, []);
1326
ensure_hex([$0, $X |Chars], Min, Max) ->
1327
ensure_uint(length(Chars), Min, Max),
1328
hex_to_int(Chars, []).
1331
hex_to_int([], Acc) ->
1333
hex_to_int([Char1,Char2|Tail], Acc) ->
1334
Int1 = hchar_to_int(Char1),
1335
Int2 = hchar_to_int(Char2),
1336
Val = Int2 bor (Int1 bsl 4),
1337
hex_to_int(Tail, [Val| Acc]);
1338
hex_to_int([Char], Acc) ->
1339
Int = hchar_to_int(Char),
1340
lists:reverse([Int|Acc]).
1342
hchar_to_int(Char) when $0 =< Char, Char =< $9 ->
1344
hchar_to_int(Char) when $A =< Char, Char =< $F ->
1345
Char - $A + 10; % OTP-4710
1346
hchar_to_int(Char) when $a =< Char, Char =< $f ->
1347
Char - $a + 10. % OTP-4710
1349
value_of({_TokenTag, _Line, Text}) ->
1353
%% -------------------------------------------------------------------
1358
%% %% d(true, F, A).
1359
%% d(get(dbg), F, A).
1362
%% io:format("DBG:~w:" ++ F ++ "~n", [?MODULE | A]);