/* Asterisk's AMI interface functions in TTCN-3
 * (C) 2024 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
 * Author: Pau Espin Pedrol <pespin@sysmocom.de>
 * All rights reserved.
 *
 * Released under the terms of GNU General Public License, Version 2 or
 * (at your option) any later version.
 *
 * SPDX-License-Identifier: GPL-2.0-or-later
 */

/*
 * https://docs.asterisk.org/Configuration/Interfaces/Asterisk-Manager-Interface-AMI/AMI-v2-Specification/
 */
module AMI_Functions {

import from Misc_Helpers all;
import from TELNETasp_PortType all;
import from Osmocom_Types all;
import from TCCConversion_Functions all;
import from Socket_API_Definitions all;

modulepar {
	float mp_ami_prompt_timeout := 10.0;
}

const charstring AMI_FIELD_ACTION := "Action";
const charstring AMI_FIELD_USERNAME := "Username";
const charstring AMI_FIELD_SECRET := "Secret";
const charstring AMI_FIELD_RESPONSE := "Response";

type record AMI_Field {
	charstring	key,
	charstring	val
};
type set of AMI_Field AMI_Msg;

template (value) AMI_Field
ts_AMI_Field(template (value) charstring key,
	     template (value) charstring val) := {
	key := key,
	val := val
};

template (present) AMI_Field
tr_AMI_Field(template (present) charstring key := ?,
	     template (present) charstring val := ?) := {
	key := key,
	val := val
};

/*
 * Field Templates:
 */

template (value) AMI_Field
ts_AMI_Field_Action(template (value) charstring val) := ts_AMI_Field(AMI_FIELD_ACTION, val);
template (value) AMI_Field
ts_AMI_Field_Username(template (value) charstring val) := ts_AMI_Field(AMI_FIELD_USERNAME, val);
template (value) AMI_Field
ts_AMI_Field_Secret(template (value) charstring val) := ts_AMI_Field(AMI_FIELD_SECRET, val);

template (present) AMI_Field
tr_AMI_Field_Action(template (present) charstring val := ?) := tr_AMI_Field(AMI_FIELD_ACTION, val);
template (present) AMI_Field
tr_AMI_Field_Username(template (present) charstring val := ?) := tr_AMI_Field(AMI_FIELD_USERNAME, val);
template (present) AMI_Field
tr_AMI_Field_Secret(template (present) charstring val := ?) := tr_AMI_Field(AMI_FIELD_SECRET, val);
template (present) AMI_Field
tr_AMI_Field_Response(template (present) charstring val := ?) := tr_AMI_Field(AMI_FIELD_RESPONSE, val);


template (present) AMI_Field
tr_AMI_Field_ResponseSuccess := tr_AMI_Field(AMI_FIELD_RESPONSE, "Success");


/*
 * Message Templates:
 */

template (value) AMI_Msg
ts_AMI_Action_Login(charstring username, charstring secret) := {
	ts_AMI_Field_Action("Login"),
	ts_AMI_Field_Username(username),
	ts_AMI_Field_Secret(secret)
};

template (present) AMI_Msg
tr_AMI_Action_Login(template(present) charstring username := ?,
		    template(present) charstring secret := ?) := superset(
	tr_AMI_Field_Action("Login"),
	tr_AMI_Field_Username(username),
	tr_AMI_Field_Secret(secret)
);

template (present) AMI_Msg
tr_AMI_Response_Success := superset(
	tr_AMI_Field_ResponseSuccess
);

/*
 * Functions:
 */

function f_AMI_Field_from_str(charstring str) return AMI_Field {
	var AMI_Field field;
	/* "each field is a key value pair delineated by a ':'.
	 * A single space MUST follow the ':' and precede the value. "*/
	var integer pos := f_strstr(str, ": ", 0);
	if (pos < 0) {
		Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
					log2str("Failed parsing AMI_Field: ", str));
	}
	field.key := substr(str, 0, pos);
	/* skip ": " */
	pos := pos + 2;
	field.val := substr(str, pos, lengthof(str) - pos);
	return field;
}

function f_AMI_Msg_from_str(charstring str) return AMI_Msg {
	var AMI_Msg msg := {};
	var Misc_Helpers.ro_charstring lines := f_str_split(str, "\n");

	for (var integer i := 0; i < lengthof(lines); i := i + 1) {
		var charstring line := lines[i];
		var AMI_Field field := f_AMI_Field_from_str(lines[i]);
		msg := msg & { field };
	}
	return msg;
}

function f_AMI_Field_to_str(AMI_Field field) return charstring {
	return field.key & ": " & field.val;
}

function f_AMI_Msg_to_str(AMI_Msg msg) return charstring {
	var charstring str := "";

	for (var integer i := 0; i < lengthof(msg); i := i + 1) {
		str := str & f_AMI_Field_to_str(msg[i]) & "\r\n";
	}

	str := str & "\r\n";
	return str;
}

private function f_ami_wait_for_prompt_str(TELNETasp_PT pt, charstring log_label := "(?)")
return charstring {
	var charstring rx, buf := "";
	var integer fd;
	timer T;

	T.start(mp_ami_prompt_timeout);
	alt {
	[] pt.receive(pattern "\n") { };
	[] pt.receive(charstring:?) -> value rx { buf := buf & rx; repeat };
	[] pt.receive(integer:?) -> value fd {
		if (fd == -1) {
			Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
						"AMI Telnet Connection Failure: " & log_label);
		} else {
			repeat; /* telnet connection succeeded */
		}
	}
	[] T.timeout {
		Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
					"AMI Timeout for prompt: " & log_label);
		};
	}
	T.stop;
	return buf;
}

function f_ami_wait_for_prompt(TELNETasp_PT pt, charstring log_label := "(?)") return AMI_Msg {
	var charstring buf := f_ami_wait_for_prompt_str(pt, log_label);
	var AMI_Msg msg := f_AMI_Msg_from_str(buf);
	return msg;
}

/* send a AMI command and obtain response until prompt is received */
private function f_ami_transceive_ret_str(TELNETasp_PT pt, charstring tx) return charstring {
	pt.send(tx);
	return f_ami_wait_for_prompt_str(pt, tx);
}

function f_ami_transceive_ret(TELNETasp_PT pt, template (value) AMI_Msg tx_msg) return AMI_Msg {
	var charstring tx_txt := f_AMI_Msg_to_str(valueof(tx_msg));
	var charstring resp_txt := f_ami_transceive_ret_str(pt, tx_txt);
	return f_AMI_Msg_from_str(resp_txt);
}

function f_ami_transceive_match(TELNETasp_PT pt,
				template (value) AMI_Msg tx_msg,
				template (present) AMI_Msg exp_ret := ?) {
	var AMI_Msg ret := f_ami_transceive_ret(pt, tx_msg);
	if (not match(ret, exp_ret)) {
		Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
			log2str("Non-matching AMI response: ", ret, " vs exp: ", exp_ret));
	}
}

function f_ami_transceive_match_response_success(TELNETasp_PT pt,
						 template (value) AMI_Msg tx_msg) {
	f_ami_transceive_match(pt, tx_msg, tr_AMI_Response_Success);
}

function f_ami_action_login(TELNETasp_PT pt, charstring username, charstring secret) {
	f_ami_transceive_match_response_success(pt, ts_AMI_Action_Login(username, secret));
}

}
