/*
 * iucvtty / iucvconn - IUCV Terminal Applications
 *
 * Processing of command line arguments
 *
 * Copyright IBM Corp. 2008, 2017
 *
 * s390-tools is free software; you can redistribute it and/or modify
 * it under the terms of the MIT license. See LICENSE for details.
 */
#include <ctype.h>
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "lib/zt_common.h"

#include "iucvterm/config.h"
#include "iucvterm/functions.h"
#include "iucvterm/gettext.h"

static const char iucvtty_usage[] = N_(
"Usage: %s [-h|--help] [-v|--version]\n"
"       %s [-a <regex>] <terminal id>  [-- <login program> [<args>]]\n\n"
"Options:\n"
"  -h, --help           Print this help, then exit.\n"
"  -v, --version        Print version information, then exit.\n"
"  -a, --allow-from     Permit connections from particular z/VM guests only.\n"
"                       A z/VM guest is permitted if regex matches its name.\n"
);

static const char iucvconn_usage[] = N_(
"Usage: %s [-h|--help] [-v|--version]\n"
"       %s [-e esc] [-s <file>] <vm guest> <terminal id>\n\n"
"Options:\n"
"  -h, --help           Print this help, then exit.\n"
"  -v, --version        Print version information, then exit.\n"
"  -s, --sessionlog     Write terminal session to file.\n"
"  -e, --escape-char    Escape character (can be one of: A-Y, ], ^ or _)\n"
"                       Characters C, D, Q, S, Z and [ are not allowed.\n"
);

static const struct option iucvterm_long_opts[] = {
	{ "help",	  no_argument, NULL, 'h' },
	{ "version",	  no_argument, NULL, 'v' },
	{ "allow-from",	  required_argument, NULL, 'a' },
	{ "sessionlog",   required_argument, NULL, 's' },
	{ "escape-char",  required_argument, NULL, 'e' },
	{  NULL,	  no_argument, NULL,  0  }
};

struct tool_info {
	char		name[10];
	char		optstring[10];
	const char	*usage;
	unsigned char	reqNonOpts;
};

/* program specific command line settings */
static const struct tool_info iucv_tool[2] = {
	{	.name = "iucvtty",
		.optstring = "-hva:",
		.usage = iucvtty_usage,
		.reqNonOpts = 1,
	},
	{	.name = "iucvconn",
		.optstring = "-hvs:e:",
		.usage = iucvconn_usage,
		.reqNonOpts = 2,
	}
};


static void __noreturn usage_exit(const struct tool_info *prg, int is_error,
				  const char *msg)
{
	FILE *file = is_error ? stderr : stdout;

	if (msg != NULL)
		fprintf(file, _("%s: %s\n"), prg->name, msg);
	fprintf(file, _(prg->usage), prg->name, prg->name);
	exit(is_error ? 1 : 0);	/* rc=1 .. invalid args */
}

static void __noreturn version_exit(const struct tool_info *prg)
{
	printf(_("%s: IUCV Terminal Applications, version %s\n"),
		prg->name, RELEASE_STRING);
	printf(_("Copyright IBM Corp. 2008, 2017\n"));
	exit(0);
}

static void cpy_or_exit(char *dest, const char *src, size_t size,
			const struct tool_info *prg, const char *param)
{
	if (strlen(src) >= size){
		fprintf(stderr,
			_("%s: %s exceeds the maximum of %zu characters\n"),
			prg->name, param, size - 1);
		exit(1);
	}
	strncpy(dest, src, size);
	dest[size - 1] = 0;
}

static void set_esc_or_exit(const struct tool_info *prg,
	                    const char val, unsigned char *esc)
{
	unsigned char upval = toupper(val);

	/* range of valid escape keys: A-Z [ \ ] ^ _ */
	if (upval < 'A' || upval > '_')
		usage_exit(prg, 1, _("The specified character is not a "
				     "valid escape character"));

	switch (upval) {
	case 'C':	/* interrupt (ISIG) */
	case 'D':	/* EoF / EoT */
	case 'Q':	/* XON */
	case 'S':	/* XOFF */
	case 'Z':	/* suspend (shell) */
	case '[':	/* ESC */
		usage_exit(prg, 1, _("The specified character is not a "
				     "valid escape character"));
	default:
		*esc = upval ^ 0100;	/* see ascii(7) */
		break;
	}
}


void parse_options(enum iucvterm_prg prg, struct iucvterm_cfg *config,
		   int argc, char **argv)
{
	int c;
	int index;
	int nonOpts = 0;

	config->cmd_parms = NULL;
	config->sessionlog = NULL;
	config->esc_char = '_' ^ 0100;		/* Ctrl-_ (0x1f) */
	config->flags = 0;

	while (1) {
		index = -1;
		c = getopt_long(argc, argv, iucv_tool[prg].optstring,
				iucvterm_long_opts, &index);
		if (c == -1)
			break;

		switch (c) {
		case 1:
			if (nonOpts >= iucv_tool[prg].reqNonOpts) {
				usage_exit(&iucv_tool[prg], 1, NULL);
				break;
			}
			switch (nonOpts) {
			case 0:
				if (prg == PROG_IUCV_CONN)
					cpy_or_exit(config->host, optarg,
						    sizeof(config->host),
						    &iucv_tool[prg],
						    _("<vm guest>"));
				else
					cpy_or_exit(config->service, optarg,
						    sizeof(config->service),
						    &iucv_tool[prg],
						    _("<terminal id>"));
				break;
			case 1:
				cpy_or_exit(config->service, optarg,
					    sizeof(config->service),
					    &iucv_tool[prg],
					    _("<terminal id>"));
				break;
			default:
				usage_exit(&iucv_tool[prg], 1, NULL);
				break;
			}
			++nonOpts;
			break;
		case 'a':/* max 80 */
			cpy_or_exit(config->client_re, optarg,
				    sizeof(config->client_re),
				    &iucv_tool[prg], _("<regex>"));
			if (is_regex_valid(config->client_re))
				exit(1);
			config->flags |= CFG_F_CHKCLNT;
			break;
		case 'e':
			switch (strlen(optarg)) {
			case 1:
				set_esc_or_exit(&iucv_tool[prg], optarg[0],
					        &config->esc_char);
				break;
			case 4:
				if (memcmp(optarg, "none", 4) == 0) {
					config->esc_char = 0;
					break;
				}
				/* fall through */
			default:
				usage_exit(&iucv_tool[prg], 1,
					   _("The escape character must be a "
					     "single character or 'none'"));
			}
			break;
		case 's':
			config->sessionlog = optarg;
			break;
		case 'h':
			usage_exit(&iucv_tool[prg], 0, NULL);
		case 'v':
			version_exit(&iucv_tool[prg]);
		case '?':
			printf(_("Try '%s --help' for more information.\n"),
				iucv_tool[prg].name);
			exit(1);
			break;
		}
	}

	if (optind < argc)	/* save additional parameters */
		config->cmd_parms = argv + optind;

	if (nonOpts < iucv_tool[prg].reqNonOpts)	/* not enough args */
		usage_exit(&iucv_tool[prg], 1,
			_("The command does not have enough arguments"));
}
