initial import of incomplete project to record E1 lines
diff --git a/src/vty.c b/src/vty.c
new file mode 100644
index 0000000..694dab1
--- /dev/null
+++ b/src/vty.c
@@ -0,0 +1,195 @@
+
+#include <osmocom/abis/e1_input.h>
+#include <osmocom/vty/command.h>
+#include <osmocom/vty/vty.h>
+
+#include "recorder.h"
+
+#define LINE_STR "Configure Recording for given Line\nE1/T1 Line Number\n"
+
+DEFUN(cfg_recorder, cfg_recorder_cmd,
+	"recorder",
+	"Configuration of E1 Recorder\n")
+{
+	vty->node = RECORDER_NODE;
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_rec_line_ts_mode, cfg_rec_line_ts_mode_cmd,
+	"line <0-255> ts <0-31> mode (none|signalling|trau|raw)",
+	LINE_STR
+	"E1/T1 Timeslot Number\n"
+	"E1/T1 Timeslot Number\n"
+	"Recording Mode\n"
+	"No recording\n"
+	"Signalling Data (HDLC)\n"
+	"TRAU Frames\n"
+	"Raw Data\n")
+{
+	int line_nr = atoi(argv[0]);
+	int ts_nr = atoi(argv[1]);
+	int mode = get_string_value(e1inp_ts_type_names, argv[2]);
+	struct e1inp_line *line;
+	struct e1inp_ts *ts;
+
+	if (mode < 0) {
+		vty_out(vty, "Cannot parse mode %s%s", argv[2], VTY_NEWLINE);
+		return CMD_WARNING;
+	}
+
+	line = e1inp_line_find(line_nr);
+	if (!line) {
+		vty_out(vty, "Cannot find line %d%s", line_nr, VTY_NEWLINE);
+		return CMD_WARNING;
+	}
+	if (ts_nr >= line->num_ts) {
+		vty_out(vty, "Timeslot %d is too large%s", ts_nr, VTY_NEWLINE);
+		return CMD_WARNING;
+	}
+	ts = &line->ts[ts_nr];
+
+	switch (mode) {
+	case E1INP_TS_TYPE_NONE:
+		/* TOOD: have eqinp_ts_config_none ? */
+		ts->type = E1INP_TS_TYPE_NONE;
+		break;
+	case E1INP_TS_TYPE_SIGN:
+		e1inp_ts_config_sign(ts, line);
+		break;
+	case E1INP_TS_TYPE_RAW:
+		e1inp_ts_config_raw(ts, line, &e1ts_raw_recv);
+		break;
+	}
+
+	/* notify driver of change */
+	e1inp_line_update(line);
+
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_rec_line_mirror, cfg_rec_line_mirror_cmd,
+	"line <0-255> mirror <0-255>",
+	LINE_STR "Mirror this line to another line\n"
+	"E1/T1 Line Number\n")
+{
+	uint8_t line_nr = atoi(argv[0]);
+	uint8_t peer_nr = atoi(argv[1]);
+	struct e1_recorder_line *line = &g_recorder.line[line_nr];
+	struct e1_recorder_line *peer = &g_recorder.line[peer_nr];
+	/* look up morror peer and enable mirror flag on peer */
+	if (peer->mirror.enabled &&
+	    peer->mirror.line_nr != line_nr) {
+		vty_out(vty, "Peer line %u already part of another mirror%s",
+			peer_nr, VTY_NEWLINE);
+		return CMD_WARNING;
+	}
+	peer->mirror.enabled = true;
+	peer->mirror.line_nr = line_nr;
+	/* enable mirror flag of current line */
+	if (line->mirror.enabled &&
+	    line->mirror.line_nr != peer_nr) {
+		vty_out(vty, "Line %u already part of another mirror%s",
+			line_nr, VTY_NEWLINE);
+		return CMD_WARNING;
+	}
+	line->mirror.enabled = true;
+	line->mirror.line_nr = peer_nr;
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_rec_no_line_mirror, cfg_rec_no_line_mirror_cmd,
+	"no line <0-255> mirror",
+	LINE_STR "Mirror this line to another line\n"
+	"E1/T1 Line Number\n")
+{
+	uint8_t line_nr = atoi(argv[0]);
+	struct e1_recorder_line *line = &g_recorder.line[line_nr];
+	struct e1_recorder_line *peer;
+
+	if (!line->mirror.enabled)
+		return CMD_WARNING;
+	/* look up morror peer (if any) and disable mirror flag on peer */
+	peer = &g_recorder.line[line->mirror.line_nr];
+	if (peer->mirror.enabled) {
+		peer->mirror.enabled = false;
+		peer->mirror.line_nr = 0;
+	}
+	/* dsiable mirror flag of current line */
+	if (line->mirror.enabled){
+		line->mirror.enabled = false;
+		line->mirror.line_nr = 0;
+	}
+	return CMD_SUCCESS;
+}
+
+
+DEFUN(cfg_rec_save_path, cfg_rec_save_path_cmd,
+	"storage-path PATH",
+	"Configure the directory for storing recordings\n"
+	"Directory to which recordings are stored\n")
+{
+	osmo_talloc_replace_string(NULL, &g_recorder.storage_path, argv[0]);
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_rec_file_size, cfg_rec_file_size_cmd,
+	"file-size-mb <1-9999999>",
+	"Configure the maximum file size before starting new file\n"
+	"Megabytes\n")
+{
+	g_recorder.max_file_size_mb = atoi(argv[0]);
+	return CMD_SUCCESS;
+}
+
+static void config_write_recorder_line(struct vty *vty, unsigned int lnr)
+{
+	struct e1inp_line *line = e1inp_line_find(lnr);
+	struct e1_recorder_line *rline = &g_recorder.line[lnr];
+	unsigned int i;
+
+	if (rline->mirror.enabled) {
+		vty_out(vty, " line %u mirror %u%s",
+			lnr, rline->mirror.line_nr, VTY_NEWLINE);
+	}
+
+	if (!line)
+		return;
+
+	for (i = 0; i < line->num_ts; i++) {
+		struct e1inp_ts *ts = &line->ts[i];
+	}
+}
+
+static int config_write_recorder(struct vty *vty)
+{
+	unsigned int i;
+
+	vty_out(vty, "recorder%s", VTY_NEWLINE);
+	vty_out(vty, " file-size-mb %u%s", g_recorder.max_file_size_mb,
+		VTY_NEWLINE);
+	vty_out(vty, " storage-path %s%s", g_recorder.storage_path,
+		VTY_NEWLINE);
+	for (i = 0; i < 255; i++) {
+		config_write_recorder_line(vty, i);
+	}
+
+	return 0;
+}
+
+static struct cmd_node cfg_recorder_node = {
+	RECORDER_NODE,
+	"%s(config-recorder)# ",
+	1,
+};
+
+void recorder_vty_init(void)
+{
+	install_element(CONFIG_NODE, &cfg_recorder_cmd);
+
+	install_node(&cfg_recorder_node, config_write_recorder);
+	install_element(RECORDER_NODE, &cfg_rec_line_ts_mode_cmd);
+	install_element(RECORDER_NODE, &cfg_rec_line_mirror_cmd);
+	install_element(RECORDER_NODE, &cfg_rec_no_line_mirror_cmd);
+	install_element(RECORDER_NODE, &cfg_rec_save_path_cmd);
+	install_element(RECORDER_NODE, &cfg_rec_file_size_cmd);
+}