/*
**  Copyright 2000-2004 University of Illinois Board of Trustees
**  Copyright 2000-2004 Mark D. Roth
**  All rights reserved.
**
**  commands.c - nph command vector code
**
**  Mark D. Roth <roth@feep.net>
*/

#include <nph.h>

#include <errno.h>

#ifdef STDC_HEADERS
# include <string.h>
# include <stdlib.h>
#endif

#include <strings.h>

#ifdef HAVE_READLINE_READLINE_H
# include <readline/readline.h>
#endif


typedef int (*cmd_func_t)(int, char **);

struct command
{
	char *command;
	int pager;
	cmd_func_t function;
	char *helptext;
};

const struct command cmds[] = {
  { "connect",	0,	nph_connect,
		"connect host[:port]\tConnect to a new PH server" },
  { "source",	0,	nph_source,
		"source file\t\tRead commands from a file" },
  {".",		0,	nph_source,
		". file\t\t\t(same as source command)" },
  { "<",	0,	nph_source,
		"< file\t\t\t(same as source command)" },
  { "id",	0,	nph_id,
		"id text\t\t\tIdentify yourself for the server's logs" },
  { "external",	0,	nph_external,
		"external\t\tSet session to be non-local" },
  { "suser",	0,	nph_suser,
		"suser alias\t\tBecome user alias (heros only)" },
  { "login",	0,	nph_login,
		"login alias\t\tLog in to the server" },
  { "logout",	0,	nph_logout,
		"logout\t\t\tLog out of the server" },
  { "passwd",	0,	nph_passwd,
		"passwd\t\t\tChange your PH password" },
  { "password",	0,	nph_passwd,
		"password\t\t(same as passwd command)" },
  { "option",	0,	nph_option,
		"option [opt[=val]]\tShow or set nph client options" },
  { "switch",	0,	nph_option,
		"switch [opt[=val]]\t(same as option command)" },
  { "help",	0,	nph_help,
		"help [command]\t\tShow help for nph commands" },
  { "?",	0,	nph_help,
		"?\t\t\t(same as help command)" },
  { "quit",	0,	nph_quit,
		"quit\t\t\tEnd PH session" },
  { "bye",	0,	nph_quit,
		"bye\t\t\t(same as quit command)" },
  { "exit",	0,	nph_quit,
		"exit\t\t\t(same as quit command)" },
  { "stop",	0,	nph_quit,
		"stop\t\t\t(same as quit command)" },
  { "whoami",	0,	nph_whoami,
		"whoami\t\t\tDisplays the currently logged-in username" },
  { "status",	1,	nph_status,
		"status\t\t\tView the server's message of the day" },
  { "motd",	1,	nph_status,
		"motd\t\t\t(same as status command)" },
  { "serveradd", 0,	nph_serveradd,
		"serveradd server [sitename]\n\t\t\t"
		"Add a server to the list of known servers" },
  { "listservers", 1,	nph_listservers,
		"listservers [domain]\tView list of other known PH servers" },
  { "set",	0,	nph_set,
		"set [option[=setting]]\tShow or set server options" },
  { "siteinfo",	0,	nph_siteinfo,
		"siteinfo\t\tRetrieve site-specific settings from server" },
  { "fields",	1,	nph_fields,
		"fields [field]\t\tView the fields supported by the server" },
  { "edit",	0,	nph_edit,
		"edit field [alias]\tEdit a given field (once logged in)" },
  { "change",	0,	nph_change,
		"change selectors... make|force changes...\n\t\t\t"
		"Change data on server" },
  { "make",	0,	nph_change,
		"make changes...\t\t"
		"Change data of currently logged-in user on server" },
  { "delete",	0,	nph_delete,
		"delete selectors...\tDelete entries on server (heros only)" },
  { "add",	0,	nph_add,
		"add fields...\t\tAdd an entry on the server (heros only)" },
  { "me",	1,	nph_me,
		"me\t\t\tView your PH entry (once logged in)" },
  { "query",	1,	nph_query,
		"query selectors [return fields...] [@domain]\n\t\t\t"
		"Retrieve data from the server" },
  { "ph",	1,	nph_query,
		"ph selectors [return fields...] [@domain]\n\t\t\t"
		"(same as query command)" },
#if 0
  { "select",	0,	nph_select,
		"select [selectors]\t\t\t"
		"Select entries for further processing" },
#endif
  { "resolve_email", 0,	nph_resolvemail,
		"resolve_email [keyfields=field1:field2:...] user\n\t\t\t"
		"Resolve email address for user" },
  { "public_email", 0,	nph_publicemail,
		"public_email alias\t"
		"Determine the advertised email address for alias" },
  { "resolve_www", 0,	nph_resolvewww,
		"resolve_www user\tResolve URL for user" },
  { "public_www", 0,	nph_publicwww,
		"public_www alias\tDetermine the advertised URL for alias" },
  { NULL,	0,	NULL,
		NULL }
};


/* parse a command vector and call the appropriate function */
int
nph_command(char *command)
{
	char *p, *q;
	char *wordp, *nextp;
	char **cmdv = NULL;
	int i, j, cmdc = 0;
	int redirected = 0;

#ifdef DEBUG
	printf("==> nph_command(\"%s\")\n", command);
#endif

	/* now parse actual command */
	nextp = command;
	do
	{
		/* skip leading spaces */
		wordp = nextp + strspn(nextp, " ");
		if (*nextp == '\0')
			break;

		/* if wordp starts with '>', output to a file */
		if (wordp[0] == '>')
		{
			q = wordp + 1;

			/* append if ">>" */
			if (wordp[1] == '>')
			{
				i = 1;
				q++;
			}
			else
				i = 0;

			/* open the file */
			q += strspn(q, " ");
			if (output_file(q, i) == -1)
				return -1;

			/* done parsing command */
			redirected = 1;
			break;
		}

		/* if wordp starts with '|', pipe to program */
		if (wordp[0] == '|')
		{
			q = wordp + 1;
			q += strspn(q, " ");

			if (output_pipe(q) == -1)
				return -1;

			/* done parsing command */
			redirected = 1;
			break;
		}

		/* find a non-escaped quote */
		p = strchr(wordp, '"');
		if (p != NULL
		    && p != wordp
		    && *(p - 1) == '\\')
			p = NULL;

		/* find a non-escaped space */
		q = strchr(wordp, ' ');
		if (q != NULL
		    && *(q - 1) == '\\')
			q = NULL;

		/*
		** quoted string - word ends at first non-escaped space
		** after next non-escaped quote
		*/
		if (p != NULL
		    && (p - q) < 0)
		{
			for (q = strchr(p + 1, '"');
			     q != NULL;
			     q = strchr(q + 1, '"'))
				if (*(q - 1) != '\\')
					break;
			if (q == NULL)
			{
				nph_printf(1, "parse error - unmatched '\"'\n");
				return -1;
			}
			for (q = strchr(q + 1, ' ');
			     q != NULL;
			     q = strchr(q + 1, ' '))
				if (*(q - 1) != '\\')
					break;
		}

		/* set the word delimiter */
		if (q != NULL)
			*q++ = '\0';
		nextp = q;

		cmdv = (char **)realloc(cmdv, (cmdc + 2) * sizeof(char *));
		cmdv[cmdc] = wordp;
		cmdv[++cmdc] = NULL;
	}
	while (nextp != NULL);

#ifdef DEBUG
	for (i = 0; i < cmdc; i++)
		printf("cmdv[%d] = \"%s\"\n", i, cmdv[i]);
#endif

	/* find command function */
	for (i = 0; cmds[i].command != NULL; i++)
		if (strcasecmp(cmds[i].command, cmdv[0]) == 0)
			break;

	/*
	** if the command wasn't redirected and is set for paging,
	** use the pager
	*/
	get_option("usepager", &j);
	if (j && !redirected && cmds[i].pager)
	{
		get_option("pager", &q);

		if (output_pipe(q) == -1)
			return -1;
	}

	/* call command */
	if (cmds[i].function != NULL)
	{
		if (!sigsetjmp(command_env, 1))
		{
			sighandler_state = HANDLER_COMMAND;
			i = (*(cmds[i].function))(cmdc, cmdv);
		}
	}
	else
	{
		nph_printf(1, "unknown command \"%s\"\n", cmdv[0]);
		i = -1;
	}

	/* reset output */
	reset_output(0);
	free(cmdv);
	return i;
}


/* prints the help text for command */
int
nph_help(int cmdc, char **cmdv)
{
	int i;

	/* if no argument, print all help */
	if (cmdv[1] == NULL)
	{
		for (i = 0; cmds[i].helptext != NULL; i++)
			nph_printf(0, "%s\n", cmds[i].helptext);
		return 0;
	}

	/* print help for the specified command only */
	if (cmdv[2] != NULL)
	{
		nph_printf(1, "help: too many arguments\n");
		print_help("help");
	}
	else
		print_help(cmdv[1]);

	return 0;
}


/* prints the help text for command */
void
print_help(char *command)
{
	int i;

	for (i = 0; cmds[i].command != NULL; i++)
		if (strcasecmp(cmds[i].command, command) == 0)
			break;

	if (cmds[i].helptext != NULL)
		nph_printf(0, "%s\n", cmds[i].helptext);
	else
		nph_printf(1, "unknown command \"%s\"\n", command);
}


#ifdef HAVE_LIBREADLINE

/* command completion function */
char *
rl_complete_command(char *text, int state)
{
	static int i;
	static int textlen;

	if (!state)
	{
		i = 0;
		textlen = strlen(text);
	}
	else
		i++;

	for (; cmds[i].command != NULL; i++)
		if (strncasecmp(cmds[i].command, text, textlen) == 0)
			return strdup(cmds[i].command);

	return NULL;
}

#endif /* HAVE_LIBREADLINE */


/* quit */
int
nph_quit(int cmdc, char **cmdv)
{
	if (cmdv[1] != NULL)
	{
		print_help(cmdv[0]);
		return -1;
	}

#ifdef HAVE_LIBREADLINE
	rl_callback_handler_remove();
#endif

	sighandler_state = HANDLER_DEFAULT;

	if (ph_close(ph, 0) == -1)
	{
		nph_printf(1, "ph_close(): %s\n", strerror(errno));
		exit(1);
	}
	exit(0);
}


/* whoami */
int
nph_whoami(int cmdc, char **cmdv)
{
	char *user;

	if (cmdv[1] != NULL)
	{
		print_help(cmdv[0]);
		return -1;
	}

	user = ph_whoami(ph);
	if (user == NULL)
		user = "(anonymous)";

	nph_printf(0, "user %s on server %s\n", user, ph_server);
	return 0;
}




syntax highlighted by Code2HTML, v. 0.9.1