blob: c05403ef5e337beda5f1fa1b60ac87c30e637fe1 [file] [log] [blame]
Pau Espin Pedrol54b614a2024-04-17 18:58:36 +02001/* Asterisk's AMI interface functions in TTCN-3
2 * (C) 2024 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
3 * Author: Pau Espin Pedrol <pespin@sysmocom.de>
4 * All rights reserved.
5 *
6 * Released under the terms of GNU General Public License, Version 2 or
7 * (at your option) any later version.
8 *
9 * SPDX-License-Identifier: GPL-2.0-or-later
10 */
11
12/*
13 * https://docs.asterisk.org/Configuration/Interfaces/Asterisk-Manager-Interface-AMI/AMI-v2-Specification/
14 */
15module AMI_Functions {
16
17import from Misc_Helpers all;
Pau Espin Pedrol54b614a2024-04-17 18:58:36 +020018import from Osmocom_Types all;
Pau Espin Pedrol01f1df82024-05-08 16:55:55 +020019import from IPL4asp_Types all;
20import from IPL4asp_PortType all;
Pau Espin Pedrol54b614a2024-04-17 18:58:36 +020021import from Socket_API_Definitions all;
Pau Espin Pedrol01f1df82024-05-08 16:55:55 +020022import from TCCConversion_Functions all;
Pau Espin Pedrol54b614a2024-04-17 18:58:36 +020023
24modulepar {
25 float mp_ami_prompt_timeout := 10.0;
26}
27
28const charstring AMI_FIELD_ACTION := "Action";
Pau Espin Pedrol941ca3c2024-05-09 16:46:58 +020029const charstring AMI_FIELD_ACTION_ID := "ActionID";
Pau Espin Pedrol54b614a2024-04-17 18:58:36 +020030const charstring AMI_FIELD_USERNAME := "Username";
31const charstring AMI_FIELD_SECRET := "Secret";
32const charstring AMI_FIELD_RESPONSE := "Response";
33
Pau Espin Pedrol4362dbd2024-04-26 19:31:27 +020034/* Extensions: */
35const charstring AMI_FIELD_REGISTRATION := "Registration";
36
Pau Espin Pedrol54b614a2024-04-17 18:58:36 +020037type record AMI_Field {
38 charstring key,
39 charstring val
Pau Espin Pedrolde7a4852024-04-19 16:20:45 +020040} with {
41 encode "TEXT"
42 variant "SEPARATOR(': ', ':\s+')"
Pau Espin Pedrol54b614a2024-04-17 18:58:36 +020043};
Pau Espin Pedrolde7a4852024-04-19 16:20:45 +020044
45type set of AMI_Field AMI_Msg with {
46 encode "TEXT"
47 variant "SEPARATOR('\r\n', '(\r\n)|[\n]')"
48 variant "END('\r\n', '(\r\n)|[\n]')"
49};
50
51external function enc_AMI_Msg(in AMI_Msg msg) return charstring
52 with { extension "prototype(convert) encode(TEXT)" }
53external function dec_AMI_Msg(in charstring stream) return AMI_Msg
54 with { extension "prototype(convert) decode(TEXT)" }
Pau Espin Pedrol54b614a2024-04-17 18:58:36 +020055
56template (value) AMI_Field
57ts_AMI_Field(template (value) charstring key,
58 template (value) charstring val) := {
59 key := key,
60 val := val
61};
62
63template (present) AMI_Field
64tr_AMI_Field(template (present) charstring key := ?,
65 template (present) charstring val := ?) := {
66 key := key,
67 val := val
68};
69
70/*
71 * Field Templates:
72 */
73
74template (value) AMI_Field
75ts_AMI_Field_Action(template (value) charstring val) := ts_AMI_Field(AMI_FIELD_ACTION, val);
76template (value) AMI_Field
Pau Espin Pedrol4362dbd2024-04-26 19:31:27 +020077ts_AMI_Field_ActionId(template (value) charstring val) := ts_AMI_Field(AMI_FIELD_ACTION_ID, val);
78template (value) AMI_Field
Pau Espin Pedrol54b614a2024-04-17 18:58:36 +020079ts_AMI_Field_Username(template (value) charstring val) := ts_AMI_Field(AMI_FIELD_USERNAME, val);
80template (value) AMI_Field
81ts_AMI_Field_Secret(template (value) charstring val) := ts_AMI_Field(AMI_FIELD_SECRET, val);
Pau Espin Pedrol4362dbd2024-04-26 19:31:27 +020082/* Extensions: */
83template (value) AMI_Field
84ts_AMI_Field_Registration(template (value) charstring val) := ts_AMI_Field(AMI_FIELD_REGISTRATION, val);
Pau Espin Pedrol54b614a2024-04-17 18:58:36 +020085
86template (present) AMI_Field
Pau Espin Pedrol21c084f2024-05-09 16:42:16 +020087tr_AMI_Field_Action(template (present) charstring val := ?) := tr_AMI_Field(pattern @nocase AMI_FIELD_ACTION, val);
Pau Espin Pedrol54b614a2024-04-17 18:58:36 +020088template (present) AMI_Field
Pau Espin Pedrol21c084f2024-05-09 16:42:16 +020089tr_AMI_Field_ActionId(template (present) charstring val := ?) := tr_AMI_Field(pattern @nocase AMI_FIELD_ACTION_ID, val);
Pau Espin Pedrol4362dbd2024-04-26 19:31:27 +020090template (present) AMI_Field
Pau Espin Pedrol21c084f2024-05-09 16:42:16 +020091tr_AMI_Field_Username(template (present) charstring val := ?) := tr_AMI_Field(pattern @nocase AMI_FIELD_USERNAME, val);
Pau Espin Pedrol54b614a2024-04-17 18:58:36 +020092template (present) AMI_Field
Pau Espin Pedrol21c084f2024-05-09 16:42:16 +020093tr_AMI_Field_Secret(template (present) charstring val := ?) := tr_AMI_Field(pattern @nocase AMI_FIELD_SECRET, val);
Pau Espin Pedrol54b614a2024-04-17 18:58:36 +020094template (present) AMI_Field
Pau Espin Pedrol21c084f2024-05-09 16:42:16 +020095tr_AMI_Field_Response(template (present) charstring val := ?) := tr_AMI_Field(pattern @nocase AMI_FIELD_RESPONSE, val);
Pau Espin Pedrol4362dbd2024-04-26 19:31:27 +020096/* Extensions: */
97template (present) AMI_Field
Pau Espin Pedrol21c084f2024-05-09 16:42:16 +020098tr_AMI_Field_Registration(template (present) charstring val := ?) := tr_AMI_Field(pattern @nocase AMI_FIELD_REGISTRATION, val);
Pau Espin Pedrol54b614a2024-04-17 18:58:36 +020099
100
101template (present) AMI_Field
Pau Espin Pedrol21c084f2024-05-09 16:42:16 +0200102tr_AMI_Field_ResponseSuccess := tr_AMI_Field(pattern @nocase AMI_FIELD_RESPONSE, "Success");
Pau Espin Pedrol54b614a2024-04-17 18:58:36 +0200103
104
Pau Espin Pedrol4362dbd2024-04-26 19:31:27 +0200105/***********************
Pau Espin Pedrol54b614a2024-04-17 18:58:36 +0200106 * Message Templates:
Pau Espin Pedrol4362dbd2024-04-26 19:31:27 +0200107 ***********************/
108
109/*
110 * ACTIONS
Pau Espin Pedrol54b614a2024-04-17 18:58:36 +0200111 */
112
Pau Espin Pedrol4362dbd2024-04-26 19:31:27 +0200113/* Action: Login
114 * Username: <value>
115 * Secret: <value>
116 */
Pau Espin Pedrol54b614a2024-04-17 18:58:36 +0200117template (value) AMI_Msg
Pau Espin Pedrol77976a62024-05-08 21:17:38 +0200118ts_AMI_Action_Login(charstring username,
119 charstring secret,
120 template (value) charstring action_id := "0001") := {
Pau Espin Pedrol54b614a2024-04-17 18:58:36 +0200121 ts_AMI_Field_Action("Login"),
Pau Espin Pedrol77976a62024-05-08 21:17:38 +0200122 ts_AMI_Field_ActionId(action_id),
Pau Espin Pedrol54b614a2024-04-17 18:58:36 +0200123 ts_AMI_Field_Username(username),
124 ts_AMI_Field_Secret(secret)
125};
126
127template (present) AMI_Msg
128tr_AMI_Action_Login(template(present) charstring username := ?,
Pau Espin Pedrol77976a62024-05-08 21:17:38 +0200129 template(present) charstring secret := ?,
130 template (present) charstring action_id := ?) := superset(
Pau Espin Pedrol54b614a2024-04-17 18:58:36 +0200131 tr_AMI_Field_Action("Login"),
Pau Espin Pedrol77976a62024-05-08 21:17:38 +0200132 tr_AMI_Field_ActionId(action_id),
Pau Espin Pedrol54b614a2024-04-17 18:58:36 +0200133 tr_AMI_Field_Username(username),
134 tr_AMI_Field_Secret(secret)
135);
136
Pau Espin Pedrol4362dbd2024-04-26 19:31:27 +0200137/* Action: PJSIPRegister
138 * ActionID: <value>
139 * Registration: volte_ims
140 */
141template (value) AMI_Msg
142ts_AMI_Action_PJSIPRegister(template (value) charstring registration := "volte_ims",
143 template (value) charstring action_id := "0001") := {
144 ts_AMI_Field_Action("PJSIPRegister"),
145 ts_AMI_Field_ActionId(action_id),
146 ts_AMI_Field_Registration(registration)
147};
148template (present) AMI_Msg
149tr_AMI_Action_PJSIPRegister(template (present) charstring registration := ?,
150 template (present) charstring action_id := ?) := {
151 tr_AMI_Field_Action("PJSIPRegister"),
152 tr_AMI_Field_ActionId(action_id),
153 tr_AMI_Field_Registration(registration)
154};
155
156/*
157 * RESPONSES
158 */
159
160/* Response: Success
161 */
Pau Espin Pedrol54b614a2024-04-17 18:58:36 +0200162template (present) AMI_Msg
163tr_AMI_Response_Success := superset(
164 tr_AMI_Field_ResponseSuccess
165);
166
Pau Espin Pedrol4362dbd2024-04-26 19:31:27 +0200167/* Response: Success
168 * ActionId: <value>
169 */
170template (present) AMI_Msg
171tr_AMI_Response_Success_ActionId(template (present) charstring action_id := ?) := superset(
172 tr_AMI_Field_ResponseSuccess,
173 tr_AMI_Field_ActionId(action_id)
174);
175
Pau Espin Pedrolbcb4e822024-04-26 20:16:47 +0200176
177/***********************
178 * Adapter:
179 ***********************/
180
Pau Espin Pedrol01f1df82024-05-08 16:55:55 +0200181type record AMI_Adapter_Parameters {
182 charstring remote_host,
183 IPL4asp_Types.PortNumber remote_port,
184 charstring local_host,
185 IPL4asp_Types.PortNumber local_port,
186 charstring welcome_str
187}
188
189const AMI_Adapter_Parameters c_default_AMI_Adapter_pars := {
190 remote_host := "127.0.0.1",
191 remote_port := 5038,
192 local_host := "0.0.0.0",
193 local_port := 0,
194 welcome_str := "Asterisk Call Manager/9.0.0\r\n"
195};
196
Pau Espin Pedrolbcb4e822024-04-26 20:16:47 +0200197type port AMI_Msg_PT message {
198 inout AMI_Msg;
199} with { extension "internal" };
200
201type component AMI_Adapter_CT {
Pau Espin Pedrol01f1df82024-05-08 16:55:55 +0200202 port IPL4asp_PT IPL4;
Pau Espin Pedrolbcb4e822024-04-26 20:16:47 +0200203 port AMI_Msg_PT CLIENT;
Pau Espin Pedrol01f1df82024-05-08 16:55:55 +0200204 var AMI_Adapter_Parameters g_pars;
205
206 /* Connection identifier of the client itself */
207 var IPL4asp_Types.ConnectionId g_self_conn_id := -1;
Pau Espin Pedrolbcb4e822024-04-26 20:16:47 +0200208}
209
Pau Espin Pedrol01f1df82024-05-08 16:55:55 +0200210/* Function to use to connect as client to a remote IPA Server */
211private function f_AMI_Adapter_connect() runs on AMI_Adapter_CT {
212 var IPL4asp_Types.Result res;
213 map(self:IPL4, system:IPL4);
214 res := IPL4asp_PortType.f_IPL4_connect(IPL4, g_pars.remote_host, g_pars.remote_port,
215 g_pars.local_host, g_pars.local_port, 0, { tcp:={} });
216 if (not ispresent(res.connId)) {
217 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
218 log2str("Could not connect AMI socket from ", g_pars.local_host, " port ",
219 g_pars.local_port, " to ", g_pars.remote_host, " port ", g_pars.remote_port,
220 "; check your configuration"));
221 }
222 g_self_conn_id := res.connId;
223 log("AMI connected, ConnId=", g_self_conn_id)
224}
Pau Espin Pedrolbcb4e822024-04-26 20:16:47 +0200225
Pau Espin Pedrol01f1df82024-05-08 16:55:55 +0200226private function f_ASP_RecvFrom_msg_to_charstring(ASP_RecvFrom rx_rf) return charstring {
227 return oct2char(rx_rf.msg);
228}
229
230/* Function to use to connect as client to a remote IPA Server */
231private function f_AMI_Adapter_wait_rx_welcome_str() runs on AMI_Adapter_CT {
232 var ASP_RecvFrom rx_rf;
233 var charstring rx_str;
234 timer Twelcome := 3.0;
235
236 Twelcome.start;
237 alt {
238 [] IPL4.receive(ASP_RecvFrom:?) -> value rx_rf {
239 rx_str := f_ASP_RecvFrom_msg_to_charstring(rx_rf);
240 if (g_pars.welcome_str != rx_str) {
241 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
242 log2str("AMI Welcome message mismatch: '", rx_str,
243 "' vs exp '", g_pars.welcome_str, "'"));
244 }
245 }
246 [] Twelcome.timeout {
247 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
248 log2str("AMI Welcome timeout"));
249 }
250 }
251 Twelcome.stop;
252 log("AMI Welcome message received: '", rx_str, "'");
253}
254
255private function dec_AMI_Msg_ext(charstring txt) return AMI_Msg {
256 log("AMI dec: '", txt, "'");
257 /* TEXT Enc/dec is not happy with empty values, workaround it: */
258 var charstring patched_txt := f_str_replace(txt, "Challenge: \r\n", "");
259 patched_txt := f_str_replace(patched_txt, "AccountCode: \r\n", "");
260 patched_txt := f_str_replace(patched_txt, "Value: \r\n", "");
261 patched_txt := f_str_replace(patched_txt, "DestExten: \r\n", "");
262 patched_txt := f_str_replace(patched_txt, "Exten: \r\n", "");
263 patched_txt := f_str_replace(patched_txt, "Extension: \r\n", "");
Pau Espin Pedrolbf0e14d2024-05-16 18:34:13 +0200264 patched_txt := f_str_replace(patched_txt, "Hint: \r\n", "");
Pau Espin Pedrol01f1df82024-05-08 16:55:55 +0200265
266 /* "AppData" field sometimes has a value containing separator ": ", which makes
267 * TEXT dec not happy. Workaround it for now by removing the whole field line:
268 * "AppData: 5,0502: Call pjsip endpoint from 0501\r\n"
269 */
270 var integer pos := f_strstr(patched_txt, "AppData: ", 0);
271 if (pos >= 0) {
272 var integer pos_end := f_strstr(patched_txt, "\r\n", pos) + lengthof("\r\n");
273 var charstring to_remove := substr(patched_txt, pos, pos_end - pos);
274 patched_txt := f_str_replace(patched_txt, to_remove, "");
275 }
276
277 log("AMI patched dec: '", patched_txt, "'");
278 return dec_AMI_Msg(patched_txt);
279}
280
281function f_AMI_Adapter_main(AMI_Adapter_Parameters pars := c_default_AMI_Adapter_pars)
282 runs on AMI_Adapter_CT {
283 var AMI_Msg msg;
Pau Espin Pedrolbcb4e822024-04-26 20:16:47 +0200284 var charstring rx, buf := "";
285 var integer fd;
Pau Espin Pedrol01f1df82024-05-08 16:55:55 +0200286 var ASP_RecvFrom rx_rf;
287 var ASP_Event rx_ev;
Pau Espin Pedrolbcb4e822024-04-26 20:16:47 +0200288
Pau Espin Pedrol01f1df82024-05-08 16:55:55 +0200289 g_pars := pars;
290
291 f_AMI_Adapter_connect();
292
293 f_AMI_Adapter_wait_rx_welcome_str();
Pau Espin Pedrolbcb4e822024-04-26 20:16:47 +0200294
295 while (true) {
296
297 alt {
Pau Espin Pedrol01f1df82024-05-08 16:55:55 +0200298 [] IPL4.receive(ASP_RecvFrom:?) -> value rx_rf {
299 var charstring rx_str := f_ASP_RecvFrom_msg_to_charstring(rx_rf);
300 log("AMI rx: '", rx_str, "'");
301 buf := buf & rx_str;
302 log("AMI buf: '", buf, "'");
303
304 /* If several messages come together */
305 var boolean last_is_complete := f_str_endswith(buf, "\r\n\r\n");
306 var Misc_Helpers.ro_charstring msgs := f_str_split(buf, "\r\n\r\n");
307 log("AMI split: ", msgs);
308 if (lengthof(msgs) > 0) {
309 for (var integer i := 0; i < lengthof(msgs) - 1; i := i + 1) {
310 var charstring txt := msgs[i] & "\r\n";
311 msg := dec_AMI_Msg_ext(txt);
312 CLIENT.send(msg);
313 }
314 if (last_is_complete) {
315 var charstring txt := msgs[lengthof(msgs) - 1] & "\r\n";
316 msg := dec_AMI_Msg_ext(txt);
317 CLIENT.send(msg);
318 buf := "";
319 } else {
320 buf := msgs[lengthof(msgs) - 1];
321 }
Pau Espin Pedrolbcb4e822024-04-26 20:16:47 +0200322 }
Pau Espin Pedrol01f1df82024-05-08 16:55:55 +0200323 log("AMI remain buf: '", buf, "'");
324 }
325 [] IPL4.receive(ASP_ConnId_ReadyToRelease:?) {
326 }
327
328 [] IPL4.receive(ASP_Event:?) -> value rx_ev {
329 log("Rx AMI ASP_Event: ", rx_ev);
Pau Espin Pedrolbcb4e822024-04-26 20:16:47 +0200330 }
331 [] CLIENT.receive(AMI_Msg:?) -> value msg {
332 /* TODO: in the future, queue Action if there's already one Action in transit, to fullfill AMI requirements. */
Pau Espin Pedrol01f1df82024-05-08 16:55:55 +0200333 var charstring tx_txt := enc_AMI_Msg(msg) & "\r\n";
334
335 var ASP_SendTo tx := {
336 connId := g_self_conn_id,
337 remName := g_pars.remote_host,
338 remPort := g_pars.remote_port,
339 proto := { tcp := {} },
340 msg := char2oct(tx_txt)
341 };
342 IPL4.send(tx);
Pau Espin Pedrolbcb4e822024-04-26 20:16:47 +0200343 }
344 }
345 }
346}
347
348
Pau Espin Pedrol54b614a2024-04-17 18:58:36 +0200349/*
350 * Functions:
351 */
352
Pau Espin Pedrol4362dbd2024-04-26 19:31:27 +0200353/* Generate a random "ActionId" value: */
354function f_gen_action_id() return charstring {
355 return hex2str(f_rnd_hexstring(16));
356}
357
358function f_ami_msg_find(AMI_Msg msg,
359 template (present) charstring key := ?)
360return template (omit) AMI_Field {
361 var integer i;
362
363 for (i := 0; i < lengthof(msg); i := i + 1) {
364 if (not ispresent(msg[i])) {
365 continue;
366 }
367 if (match(msg[i].key, key)) {
368 return msg[i];
369 }
370 }
371 return omit;
372}
373
374function f_ami_msg_find_or_fail(AMI_Msg msg,
375 template (present) charstring key := ?)
376return AMI_Field {
377 var template (omit) AMI_Field field;
378 field := f_ami_msg_find(msg, key);
379 if (istemplatekind(field, "omit")) {
380 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
381 log2str("Key ", key, " not found in ", msg));
382 }
383 return valueof(field);
384}
385
386function f_ami_msg_get_value(AMI_Msg msg,
387 template (present) charstring key := ?)
388return template (omit) charstring {
389 var template (omit) AMI_Field field;
390 field := f_ami_msg_find(msg, key);
391 if (istemplatekind(field, "omit")) {
392 return omit;
393 }
394 return field.val;
395}
396
397function f_ami_msg_get_value_or_fail(AMI_Msg msg,
398 template (present) charstring key := ?)
399return template charstring {
400 var AMI_Field field;
401 field := f_ami_msg_find_or_fail(msg, key);
402 return field.val;
403}
404
Pau Espin Pedrolbcb4e822024-04-26 20:16:47 +0200405function f_ami_transceive_ret(AMI_Msg_PT pt, template (value) AMI_Msg tx_msg, float rx_timeout := 10.0) return AMI_Msg {
406 var AMI_Msg rx_msg;
Pau Espin Pedrol54b614a2024-04-17 18:58:36 +0200407 timer T;
408
Pau Espin Pedrolbcb4e822024-04-26 20:16:47 +0200409 T.start(rx_timeout);
410 pt.send(tx_msg);
Pau Espin Pedrol54b614a2024-04-17 18:58:36 +0200411 alt {
Pau Espin Pedrolbcb4e822024-04-26 20:16:47 +0200412 [] pt.receive(AMI_Msg:?) -> value rx_msg;
Pau Espin Pedrol54b614a2024-04-17 18:58:36 +0200413 [] T.timeout {
414 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
Pau Espin Pedrolbcb4e822024-04-26 20:16:47 +0200415 log2str("AMI Response timeout: ", tx_msg));
416 }
Pau Espin Pedrol54b614a2024-04-17 18:58:36 +0200417 }
418 T.stop;
Pau Espin Pedrolbcb4e822024-04-26 20:16:47 +0200419 return rx_msg;
420
Pau Espin Pedrol54b614a2024-04-17 18:58:36 +0200421}
422
Pau Espin Pedrolbcb4e822024-04-26 20:16:47 +0200423private altstep as_ami_rx_fail(AMI_Msg_PT pt, template AMI_Msg exp_msg := *)
424{
425 var AMI_Msg msg;
426 [] pt.receive(AMI_Msg:?) -> value msg {
Pau Espin Pedrol54b614a2024-04-17 18:58:36 +0200427 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
Pau Espin Pedrolbcb4e822024-04-26 20:16:47 +0200428 log2str("Received unexpected AMI message := ", msg, "\nvs exp := ", exp_msg));
Pau Espin Pedrol54b614a2024-04-17 18:58:36 +0200429 }
430}
431
Pau Espin Pedrolbcb4e822024-04-26 20:16:47 +0200432altstep as_ami_expect_msg(AMI_Msg_PT pt, template (present) AMI_Msg msg_expect, boolean fail_others := true)
433{
434 [] pt.receive(msg_expect);
435 [fail_others] as_ami_rx_fail(pt, msg_expect);
436}
437
438function f_ami_transceive_match(AMI_Msg_PT pt,
439 template (value) AMI_Msg tx_msg,
440 template (present) AMI_Msg exp_ret := ?,
441 boolean fail_others := true,
442 float rx_timeout := 10.0) return AMI_Msg {
443 var AMI_Msg rx_msg;
444 timer T;
445
446 T.start(rx_timeout);
447 pt.send(tx_msg);
448 alt {
449 [] pt.receive(exp_ret) -> value rx_msg;
450 [not fail_others] pt.receive(AMI_Msg:?) -> value rx_msg {
451 log("AMI: Ignoring Rx msg ", rx_msg);
452 repeat;
453 }
454 [fail_others] as_ami_rx_fail(pt, exp_ret);
455 [] T.timeout {
456 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
457 log2str("AMI Response timeout: ", tx_msg));
458 }
459 }
460 T.stop;
461 return rx_msg;
462}
463
464function f_ami_transceive_match_response_success(AMI_Msg_PT pt,
Pau Espin Pedrol54b614a2024-04-17 18:58:36 +0200465 template (value) AMI_Msg tx_msg) {
Pau Espin Pedrol4362dbd2024-04-26 19:31:27 +0200466 var template (present) AMI_Msg exp_resp;
467 var template (omit) charstring action_id := f_ami_msg_get_value(valueof(tx_msg), AMI_FIELD_ACTION_ID);
468 if (isvalue(action_id)) {
469 exp_resp := tr_AMI_Response_Success_ActionId(action_id);
470 } else {
471 exp_resp := tr_AMI_Response_Success;
472 }
473 f_ami_transceive_match(pt, tx_msg, exp_resp);
Pau Espin Pedrol54b614a2024-04-17 18:58:36 +0200474}
475
Pau Espin Pedrolbcb4e822024-04-26 20:16:47 +0200476function f_ami_action_login(AMI_Msg_PT pt, charstring username, charstring secret) {
Pau Espin Pedrol77976a62024-05-08 21:17:38 +0200477 var charstring reg_action_id := f_gen_action_id();
478 f_ami_transceive_match_response_success(pt, ts_AMI_Action_Login(username, secret, reg_action_id));
Pau Espin Pedrol54b614a2024-04-17 18:58:36 +0200479}
480
Pau Espin Pedrolbcb4e822024-04-26 20:16:47 +0200481function f_ami_action_PJSIPRegister(AMI_Msg_PT pt, charstring register) {
Pau Espin Pedrol4362dbd2024-04-26 19:31:27 +0200482 var charstring reg_action_id := f_gen_action_id();
483 f_ami_transceive_match_response_success(pt, ts_AMI_Action_PJSIPRegister(register, reg_action_id));
484}
485
Pau Espin Pedrol01f1df82024-05-08 16:55:55 +0200486private function f_ami_selftest_decode(charstring txt) {
487 log("Text to decode: '", txt, "'");
488 var AMI_Msg msg := dec_AMI_Msg(txt);
489 log("AMI_Msg decoded: ", msg);
490}
491
492function f_ami_selftest() {
493 f_ami_selftest_decode("AppData: 5,0502: Call pjsip endpoint from 0501\r\n");
494}
495
Pau Espin Pedrol54b614a2024-04-17 18:58:36 +0200496}