public inbox for ecos-discuss@sourceware.org
 help / color / mirror / Atom feed
* [ECOS] FIN is not sending on socket close()
@ 2007-06-25 13:49 srinivas naga vutukuri
  0 siblings, 0 replies; only message in thread
From: srinivas naga vutukuri @ 2007-06-25 13:49 UTC (permalink / raw)
  To: ecos-discuss

[-- Attachment #1: Type: text/plain, Size: 641 bytes --]

Dear All,

          Am just taken an example from
http://libcli.sourceforge.net
and integrated into my eCos application.

Am creating a thread, under that am calling TELNET_start() (can see in
clitest.c).
which is accepting the telnet sessions.
and after that its calling the cli_loop(). But when i issue quit,
which exits the while loop
in the cli_loop() function and tries to close the sockfd. But this is
not sending the FIN my
embedded system to my PC telnet client.  I also set the SO_LINGER socket option.


Could you please help me out.

My source code is attached here with the libcli.c for your reference.

best regards,
srinivas.

[-- Attachment #2: clitest.c --]
[-- Type: application/octet-stream, Size: 3925 bytes --]




#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include "libcli.h"

#include <netinet/in.h>

#define CLITEST_PORT		23
#define MODE_CONFIG_INT		10

#ifdef __GNUC__
# define UNUSED(d) d __attribute__ ((unused))
#else
# define UNUSED(d) d
#endif

int cmd_test(struct cli_def *cli, char *command, char *argv[], int argc)
{
    int i;
    cli_print(cli, "called %s with \"%s\"", __FUNCTION__, command);
    cli_print(cli, "%d arguments:", argc);
    for (i = 0; i < argc; i++)
	cli_print(cli, "	%s", argv[i]);

    return CLI_OK;
}

int cmd_set(struct cli_def *cli, UNUSED(char *command), char *argv[],
    int argc)
{
    if (argc < 2)
    {
	cli_print(cli, "Specify a variable to set");
	return CLI_OK;
    }

    cli_print(cli, "Setting \"%s\" to \"%s\"", argv[0], argv[1]);
    return CLI_OK;
}

int cmd_config_int(struct cli_def *cli, UNUSED(char *command), char *argv[],
    int argc)
{
    if (argc < 1)
    {
	cli_print(cli, "Specify an interface to configure");
	return CLI_OK;
    }

    if (strcmp(argv[0], "?") == 0)
	cli_print(cli, "  test0/0");

    else if (strcasecmp(argv[0], "test0/0") == 0)
	cli_set_configmode(cli, MODE_CONFIG_INT, "test");
    else
	cli_print(cli, "Unknown interface %s", argv[0]);

    return CLI_OK;
}

int cmd_config_int_exit(struct cli_def *cli, UNUSED(char *command),
    UNUSED(char *argv[]), UNUSED(int argc))
{
    cli_set_configmode(cli, MODE_CONFIG, NULL);
    return CLI_OK;
}

int check_auth(char *username, char *password)
{
    if (strcasecmp(username, "admin") != 0)
	return CLI_ERROR;
    if (strcasecmp(password, "admin") != 0)
	return CLI_ERROR;
    return CLI_OK;
}

int check_enable(char *password)
{
    return !strcasecmp(password, "topsecret");
}

void pc(UNUSED(struct cli_def *cli), char *string)
{
    printf("%s\n", string);
}



struct cli_def*  CLI_Init(void)
{
    struct cli_command *show=NULL, *set=NULL, *clear = NULL;
    struct cli_def *cli;

    cli = cli_init();
    cli_set_banner(cli, RELEASE);
    cli_set_hostname(cli, "Telsinex");

	
   show = cli_register_command(cli, NULL, "show", NULL, PRIVILEGE_UNPRIVILEGED,
	MODE_EXEC, NULL);

   set = cli_register_command(cli, NULL, "set", NULL, PRIVILEGE_UNPRIVILEGED,
	MODE_EXEC, NULL);
   
   clear = cli_register_command(cli, NULL, "clear", NULL, PRIVILEGE_UNPRIVILEGED,
	MODE_EXEC, NULL);


    cli_register_command(cli, NULL, "exit", cmd_config_int_exit,
	PRIVILEGE_PRIVILEGED, MODE_CONFIG_INT,
	"Exit from interface configuration");


    cli_set_auth_callback(cli, check_auth);
    cli_set_enable_callback(cli, check_enable);


    diag_printf("\n \n");

    return (cli);

}




void TELNET_start(void)
{
   int s, x;
   struct sockaddr_in servaddr;

    struct cli_def *cli;
    struct linger linger = {1,0};	

    //linger.l_onoff  = 1;
    //linger.l_linger   = 0;	

    int on = 1;

    cli = CLI_Init();	



    if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
	perror("socket");
	return 1;
    }
    setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));

    if (setsockopt(s, SOL_SOCKET, SO_LINGER, &linger,sizeof(linger)) < 0)
    	{
		perror("linger fail");
		return 1;
    	}


    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(CLITEST_PORT);
    if (bind(s, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0)
    {
	perror("bind");
	return 1;
    }

    if (listen(s, 50) < 0)
    {
	perror("listen");
	return 1;
    }


	
    printf("Listening on port %d\n", CLITEST_PORT);
    while ((x = accept(s, NULL, 0)))
    {
	cli_loop(cli, x);
	close(x);
    }
	
    cli_done(cli);
    return 0;

}

[-- Attachment #3: libcli.c --]
[-- Type: application/octet-stream, Size: 41683 bytes --]


#define _GNU_SOURCE
#include <stdio.h>
#include <errno.h>
#include <stdarg.h>
#include <stdlib.h>
//#include <memory.h>
//#include <malloc.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>

#ifdef REGEX_H
#include <regex.h>
#endif //REGEX_H

#include "libcli.h"

#include <sys/time.h>
#include <pkgconf/memalloc.h>
#include <sys/select.h>
#include <cyg/io/io.h>
#include <encrypt.h>

/* vim:sw=4 ts=8 */

#ifdef __GNUC__
# define UNUSED(d) d __attribute__ ((unused))
#else
# define UNUSED(d) d
#endif
extern char *
crypt (const char *wort, const char *salt);

enum cli_states {
    STATE_LOGIN,
    STATE_PASSWORD,
    STATE_NORMAL,
    STATE_ENABLE_PASSWORD,
    STATE_ENABLE
};

struct unp {
    char *username;
    char *password;
    struct unp *next;
};

/* free and zero (to avoid double-free) */
#define free_z(p) free(p), (p) = 0

void cli_set_auth_callback(struct cli_def *cli,
    int (*auth_callback)(char *, char *))
{
    cli->auth_callback = auth_callback;
}

void cli_set_enable_callback(struct cli_def *cli,
    int (*enable_callback)(char *))
{
    cli->enable_callback = enable_callback;
}

void cli_allow_user(struct cli_def *cli, char *username, char *password)
{
    struct unp *n = malloc(sizeof(struct unp));
    n->username = strdup(username);
    n->password = strdup(password);
    n->next = 0;

    if (cli->users)
    {
	struct unp *u = cli->users;
	while (u->next)
	    u = u->next;

	u->next = n;
    }
    else
	cli->users = n;
}

void cli_allow_enable(struct cli_def *cli, char *password)
{
    free(cli->enable_password);
    cli->enable_password = strdup(password);
}

void cli_deny_user(struct cli_def *cli, char *username)
{
    struct unp *u;
    struct unp *p;

    for (p = 0, u = cli->users; u; p = u, u = u->next)
    {
	if (strcmp(username, u->username))
	    continue;

	if (p)
	    p->next = u->next;
	else
	    cli->users = u->next;

	free(u->username);
	free(u->password);
	free(u);
	break;
    }
}

void cli_set_banner(struct cli_def *cli, char *banner)
{
    free_z(cli->banner);
    if (banner && *banner)
	cli->banner = strdup(banner);
}

void cli_set_hostname(struct cli_def *cli, char *hostname)
{
    free_z(cli->hostname);
    if (hostname && *hostname)
	cli->hostname = strdup(hostname);
}

void cli_set_promptchar(struct cli_def *cli, char *promptchar)
{
    free(cli->promptchar);
    cli->promptchar = strdup(promptchar);
}

int cli_set_privilege(struct cli_def *cli, int priv)
{
    int old = cli->privilege;
    cli->privilege = priv;

    if (priv != old)
	cli_set_promptchar(cli, priv == PRIVILEGE_PRIVILEGED ? "# " : "> ");

    return old;
}

static void set_modestring(struct cli_def *cli, char *modestring)
{
    free_z(cli->modestring);
    if (modestring)
	cli->modestring = strdup(modestring);
}

int cli_set_configmode(struct cli_def *cli, int mode, char *config_desc)
{
    int old = cli->mode;
    cli->mode = mode;

    if (mode != old)
    {
	if (!cli->mode)
	{
	    /* not config mode */
	    set_modestring(cli, 0);
	}
	else if (config_desc && *config_desc)
	{
	    char string[64];
	    snprintf(string, sizeof(string), "(config-%s)", config_desc);
	    set_modestring(cli, string);
	}
	else
	{
	    set_modestring(cli, "(config)");
	}
    }

    return old;
}

static int build_shortest(struct cli_def *cli, struct cli_command *commands)
{
    struct cli_command *c;

    for (c = commands; c; c = c->next)
    {
	int len = strlen(c->command);
	for (c->unique_len = 1; c->unique_len <= len; c->unique_len++)
	{
	    int foundmatch = 0;
	    struct cli_command *p;

	    for (p = commands; p; p = p->next)
	    {
		if (c == p)
		    continue;

		if (!strncmp(p->command, c->command, c->unique_len))
		    foundmatch++;
	    }

	    if (!foundmatch)
		break;
	}

	if (c->children)
	    build_shortest(cli, c->children);
    }

    return CLI_OK;
}

struct cli_command *cli_register_command(struct cli_def *cli,
    struct cli_command *parent, char *command,
    int (*callback)(struct cli_def *cli, char *, char **, int),
    int privilege, int mode, char *help)
{
    struct cli_command *c;
    struct cli_command *p;

    if (!command)
	return 0;

    if (!(c = calloc(sizeof(struct cli_command), 1)))
	return 0;

    c->callback = callback;
    c->next = 0;
    c->command = strdup(command);
    c->parent = parent;
    c->privilege = privilege;
    c->mode = mode;

    if (help)
	c->help = strdup(help);

    if (parent)
    {
	if (!parent->children)
	{
	    parent->children = c;
	}
	else
	{
	    for (p = parent->children; p && p->next; p = p->next)
		;

	    if (p)
		p->next = c;
	}
    }
    else
    {
	if (!cli->commands)
	{
	    cli->commands = c;
	}
	else
	{
	    for (p = cli->commands; p && p->next; p = p->next)
		;

	    if (p)
		p->next = c;
	}
    }

    build_shortest(cli, parent ? parent : cli->commands);
    return c;
}

int cli_unregister_command(struct cli_def *cli, char *command)
{
    struct cli_command *c;
    struct cli_command *p = 0;

    if (!(command && cli->commands))
	return CLI_ERROR;

    for (c = cli->commands; c; p = c, c = c->next)
    {
	if (strcmp(c->command, command))
	    continue;

	if (p)
	    p->next = c->next;
	else
	    cli->commands = c->next;

	free(c->command);
	free(c->help);
	free(c);
	return CLI_OK;
    }

    return CLI_ERROR;
}

static char *command_name(struct cli_def *cli, struct cli_command *command)
{
    free_z(cli->_name_buf);

    while (command)
    {
	char *o = cli->_name_buf;
	int sz = strlen(command->command) + 1;
	if (o)
	    sz += strlen(o) + 1;

	cli->_name_buf = malloc(sz);
	if (o)
	    sprintf(cli->_name_buf, "%s %s", command->command, o);
	else
	    strcpy(cli->_name_buf, command->command);

	command = command->parent;
	free(o);
    }

    return cli->_name_buf;
}

static int show_help(struct cli_def *cli, struct cli_command *c)
{
    struct cli_command *p;

    for (p = c; p; p = p->next)
    {
	if (p->command && p->callback && cli->privilege >= p->privilege &&
	    (p->mode == cli->mode || p->mode == MODE_ANY))
	{
	    cli_error(cli, "  %-20s %s", command_name(cli, p), p->help ? : "");
	}

	if (p->children)
	    show_help(cli, p->children);
    }

    return CLI_OK;
}

static int cmd_enable(struct cli_def *cli, UNUSED(char *command),
    UNUSED(char *argv[]), UNUSED(int argc))
{
    if (cli->privilege == PRIVILEGE_PRIVILEGED)
	return CLI_OK;

    if (!cli->enable_password && !cli->enable_callback)
    {
	/* no password required, set privilege immediately */
	cli_set_privilege(cli, PRIVILEGE_PRIVILEGED);
	cli_set_configmode(cli, MODE_EXEC, 0);
    }
    else
    {
	/* require password entry */
	cli->state = STATE_ENABLE_PASSWORD;
    }

    return CLI_OK;
}

static int cmd_disable(struct cli_def *cli, UNUSED(char *command),
    UNUSED(char *argv[]), UNUSED(int argc))
{
    cli_set_privilege(cli, PRIVILEGE_UNPRIVILEGED);
    cli_set_configmode(cli, MODE_EXEC, 0);
    return CLI_OK;
}

static int cmd_help(struct cli_def *cli, UNUSED(char *command),
    UNUSED(char *argv[]), UNUSED(int argc))
{
    cli_error(cli, "\nCommands available:");
    show_help(cli, cli->commands);
    return CLI_OK;
}

static int cmd_history(struct cli_def *cli, UNUSED(char *command),
    UNUSED(char *argv[]), UNUSED(int argc))
{
    int i;

    cli_error(cli, "\nCommand history:");
    for (i = 0; i < MAX_HISTORY; i++)
	if (cli->history[i])
	    cli_error(cli, "%3d. %s", i, cli->history[i]);

    return CLI_OK;
}

static int cmd_quit(struct cli_def *cli, UNUSED(char *command),
    UNUSED(char *argv[]), UNUSED(int argc))
{
    cli_set_privilege(cli, PRIVILEGE_UNPRIVILEGED);
    cli_set_configmode(cli, MODE_EXEC, 0);
    return CLI_QUIT;
}

static int cmd_exit(struct cli_def *cli, char *command, char *argv[], int argc)
{
    if (cli->mode == MODE_EXEC)
	return cmd_quit(cli, command, argv, argc);

    if (cli->mode > MODE_CONFIG)
	cli_set_configmode(cli, MODE_CONFIG, 0);
    else
	cli_set_configmode(cli, MODE_EXEC, 0);

    return CLI_OK;
}

static int cmd_configure_terminal(struct cli_def *cli, UNUSED(char *command),
    UNUSED(char *argv[]), UNUSED(int argc))
{
    cli_set_configmode(cli, MODE_CONFIG, 0);
    return CLI_OK;
}

struct cli_def *cli_init()
{
    struct cli_def *cli;
    struct cli_command *c;

    if (!(cli = calloc(sizeof(struct cli_def), 1)))
	return 0;

    cli_register_command(cli, 0, "help", cmd_help, PRIVILEGE_UNPRIVILEGED,
    			 MODE_ANY, "Show available commands");

    cli_register_command(cli, 0, "quit", cmd_quit, PRIVILEGE_UNPRIVILEGED,
    			 MODE_ANY, "Disconnect");

 //   cli_register_command(cli, 0, "logout", cmd_quit, PRIVILEGE_UNPRIVILEGED,
 //   			 MODE_ANY, "Disconnect");

    cli_register_command(cli, 0, "exit", cmd_exit, PRIVILEGE_UNPRIVILEGED,
    			 MODE_ANY, "Exit from current mode");

    cli_register_command(cli, 0, "history", cmd_history, PRIVILEGE_UNPRIVILEGED,
    			 MODE_ANY, "Show a list of previously run commands");

    cli_register_command(cli, 0, "enable", cmd_enable, PRIVILEGE_UNPRIVILEGED,
    			 MODE_EXEC, "Turn on privileged commands");

    cli_register_command(cli, 0, "disable", cmd_disable, PRIVILEGE_PRIVILEGED,
    			 MODE_EXEC, "Turn off privileged commands");

    c = cli_register_command(cli, 0, "configure", 0, PRIVILEGE_PRIVILEGED,
			     MODE_EXEC, "Enter configuration mode");

    cli_register_command(cli, c, "terminal", cmd_configure_terminal,
			 PRIVILEGE_PRIVILEGED, MODE_EXEC,
			 "Configure from the terminal");

    cli->privilege = cli->mode = -1;
    cli_set_privilege(cli, PRIVILEGE_UNPRIVILEGED);
    cli_set_configmode(cli, MODE_EXEC, 0);
    return cli;
}

static void unregister_all(struct cli_def *cli, struct cli_command *command)
{
    struct cli_command *c;

    if (!command)
	command = cli->commands;

    if (!command)
	return;

    for (c = command; c; )
    {
	struct cli_command *p = c->next;

	/* unregister all child commands */
	if (c->children)
	    unregister_all(cli, c->children);

	free(c->command);
	free(c->help);
	free(c);
	c = p;
    }
}

int cli_done(struct cli_def *cli)
{
    struct unp *u = cli->users;

    /* free all users */
    while (u)
    {
	struct unp *n = u->next;
	free(u->username);
	free(u->password);
	free(u);
	u = n;
    }

    /* free all commands */
    unregister_all(cli, 0);

    free(cli->banner);
    free(cli->promptchar);
    free(cli->hostname);
    free_z(cli);

    return CLI_OK;
}

static int add_history(struct cli_def *cli, char *cmd)
{
    int i = 0;

    /* table full */
    if (cli->history[MAX_HISTORY-1])
    {
	free(cli->history[0]);
	for (; i < MAX_HISTORY-1; i++)
	    cli->history[i] = cli->history[i+1];

	cli->history[i] = 0;
    }

    while (cli->history[i])
	i++;

    cli->history[i] = strdup(cmd);
    return i + 1;
}

static int parse_line(char *line, char *words[], int max_words)
{
    int nwords = 0;
    char *p = line;
    char *word_start = line;
    int inquote = 0;

    while (nwords < max_words - 1)
    {
	if (!*p || *p == inquote ||
	    (word_start && !inquote && (isspace(*p) || *p == '|')))
	{
	    if (word_start)
	    {
		int len = p - word_start;

		memcpy(words[nwords] = malloc(len + 1), word_start, len);
		words[nwords++][len] = 0;
	    }

	    if (!*p)
		break;

	    if (inquote)
		p++; /* skip over trailing quote */

	    inquote = 0;
	    word_start = 0;
	}
	else if (*p == '"' || *p == '\'')
	{
	    inquote = *p++;
	    word_start = p;
	}
	else
	{
	    if (!word_start)
	    {
		if (*p == '|')
		    words[nwords++] = strdup("|");
		else if (!isspace(*p))
		    word_start = p;
	    }

	    p++;
	}
    }

    return nwords;
}

static char *join_words(int argc, char **argv)
{
    char *p;
    int len = 0;
    int i;

    for (i = 0; i < argc; i++)
    {
	if (i)
	    len += 1;

	len += strlen(argv[i]);
    }

    p = malloc(len + 1);
    p[0] = 0;

    for (i = 0; i < argc; i++)
    {
	if (i)
	    strcat(p, " ");

	strcat(p, argv[i]);
    }

    return p;
}
#ifdef REGEX_H
struct match_filter_state {
    int flags;
#define MATCH_REGEX		1
#define MATCH_INVERT		2
    union {
	char *string;
	regex_t re;
    } match;
};

static int match_filter(UNUSED(struct cli_def *cli), char *string, void *data)
{
    struct match_filter_state *state = data;
    int r = CLI_ERROR;

    if (!string) /* clean up */
    {
	if (state->flags & MATCH_REGEX)
	    regfree(&state->match.re);
	else
	    free(state->match.string);

	free(state);
	return CLI_OK;
    }

    if (state->flags & MATCH_REGEX)
    {
	if (!regexec(&state->match.re, string, 0, 0, 0))
	    r = CLI_OK;
    }
    else
    {
	if (strstr(string, state->match.string))
	    r = CLI_OK;
    }

    if (state->flags & MATCH_INVERT)
    {
	if (r == CLI_OK)
	    r = CLI_ERROR;
	else
	    r = CLI_OK;
    }

    return r;
}

static int match_filter_init(struct cli_def *cli, int argc, char **argv,
    struct cli_filter *filt)
{
    struct match_filter_state *state;
    int rflags;
    int i;
    char *p;

    if (argc < 2)
    {
	if (cli->client)
	    fprintf(cli->client, "Match filter requires an argument\r\n");

	return CLI_ERROR;
    }

    filt->filter = match_filter;
    filt->data = state = calloc(sizeof(struct match_filter_state), 1);

    if (argv[0][0] == 'i' || /* include/exclude */
	(argv[0][0] == 'e' && argv[0][1] == 'x'))
    {
	if (argv[0][0] == 'e')
	    state->flags = MATCH_INVERT;

	state->match.string = join_words(argc-1, argv+1);
	return CLI_OK;
    }

    state->flags = MATCH_REGEX;

    /* grep/egrep */
    rflags = REG_NOSUB;
    if (argv[0][0] == 'e') /* egrep */
	rflags |= REG_EXTENDED;

    i = 1;
    while (i < argc - 1 && argv[i][0] == '-' && argv[i][1])
    {
	int last = 0;
	p = &argv[i][1];

	if (strspn(p, "vie") != strlen(p))
	    break;

	while (*p)
	{
	    switch (*p++)
	    {
	    case 'v':
		state->flags |= MATCH_INVERT;
		break;

	    case 'i':
		rflags |= REG_ICASE;
		break;

	    case 'e':
		last++;
		break;
	    }
	}

	i++;
	if (last)
	    break;
    }

    p = join_words(argc-i, argv+i);
    if ((i = regcomp(&state->match.re, p, rflags)))
    {
	if (cli->client)
	    fprintf(cli->client, "Invalid pattern \"%s\"\r\n", p);

	free(p);
	return CLI_ERROR;
    }

    free(p);
    return CLI_OK;
}
#endif //REGEX_H
struct range_filter_state {
    int matched;
    char *from;
    char *to;
};

static int range_filter(UNUSED(struct cli_def *cli), char *string, void *data)
{
    struct range_filter_state *state = data;
    int r = CLI_ERROR;

    if (!string) /* clean up */
    {
	free(state->from);
	free(state->to);
	free(state);
	return CLI_OK;
    }

    if (!state->matched)
	state->matched = !!strstr(string, state->from);

    if (state->matched)
    {
	r = CLI_OK;
	if (state->to && strstr(string, state->to))
	    state->matched = 0;
    }

    return r;
}

static int range_filter_init(struct cli_def *cli, int argc, char **argv,
    struct cli_filter *filt)
{
    struct range_filter_state *state;
    char *from = 0;
    char *to = 0;

    if (!strncmp(argv[0], "bet", 3)) /* between */
    {
	if (argc < 3)
	{
	    if (cli->client)
		fprintf(cli->client, "Between filter requires 2 arguments\r\n");

	    return CLI_ERROR;
	}

	from = strdup(argv[1]);
	to = join_words(argc-2, argv+2);
    }
    else /* begin */
    {
	if (argc < 2)
	{
	    if (cli->client)
		fprintf(cli->client, "Begin filter requires an argument\r\n");

	    return CLI_ERROR;
	}

	from = join_words(argc-1, argv+1);
    }

    filt->filter = range_filter;
    filt->data = state = calloc(sizeof(struct range_filter_state), 1);

    state->from = from;
    state->to = to;

    return CLI_OK;
}

static int count_filter(struct cli_def *cli, char *string, void *data)
{
    int *count = data;

    if (!string) /* clean up */
    {
	/* print count */
	if (cli->client)
	    fprintf(cli->client, "%d\r\n", *count);

	free(count);
	return CLI_OK;
    }

    while (isspace(*string))
	string++;

    if (*string)
	(*count)++;  /* only count non-blank lines */

    return CLI_ERROR; /* no output */
}

static int count_filter_init(struct cli_def *cli, int argc,
    UNUSED(char **argv), struct cli_filter *filt)
{
    if (argc > 1)
    {
	if (cli->client)
	    fprintf(cli->client, "Count filter does not take arguments\r\n");

	return CLI_ERROR;
    }

    filt->filter = count_filter;
    filt->data = calloc(sizeof(int), 1);

    return CLI_OK;
}

static int find_command(struct cli_def *cli, struct cli_command *commands,
    int num_words, char *words[], int start_word, int filters[])
{
    struct cli_command *c;
    int c_words = num_words;

    if (filters[0])
	c_words = filters[0];

    /* deal with ? for help */
    if (!words[start_word])
	return CLI_ERROR;

    if (words[start_word][strlen(words[start_word])-1] == '?')
    {
	int l = strlen(words[start_word])-1;

	for (c = commands; c; c = c->next)
	{
	    if (!strncasecmp(c->command, words[start_word], l) &&
		(c->callback || c->children) &&
		cli->privilege >= c->privilege &&
		(c->mode == cli->mode || c->mode == MODE_ANY))
	    {
		cli_error(cli, "  %-20s %s", c->command, c->help ? : "");
	    }
	}

	return CLI_OK;
    }

    for (c = commands; c; c = c->next)
    {
	if (cli->privilege < c->privilege)
	    continue;

	if (strncasecmp(c->command, words[start_word], c->unique_len))
	    continue;
	    
	if (strncasecmp(c->command, words[start_word],
			strlen(words[start_word])))
	    continue;

	/* drop out of config submode */
	if (cli->mode > MODE_CONFIG && c->mode == MODE_CONFIG)
	    cli_set_configmode(cli, MODE_CONFIG, 0);

	if (c->mode == cli->mode || c->mode == MODE_ANY)
	{
	    int rc = CLI_OK;
	    int f;
	    struct cli_filter **filt = &cli->filters;

	    /* found a word! */
	    if (!c->children)
	    {
		/* last word */
		if (!c->callback)
		{
		    cli_error(cli, "No callback for \"%s\"",
			      command_name(cli, c));

		    return CLI_ERROR;
		}
	    }
	    else
	    {
		if (start_word == c_words - 1)
		{
		    cli_error(cli, "Incomplete command");
		    return CLI_ERROR;
		}

		return find_command(cli, c->children, num_words, words,
				    start_word + 1, filters);
	    }

	    if (!c->callback)
	    {
		cli_error(cli, "Internal server error processing \"%s\"",
			  command_name(cli, c));

		return CLI_ERROR;
	    }

	    for (f = 0; rc == CLI_OK && filters[f]; f++)
	    {
		int n = num_words;
		char **argv;
		int argc;
		int len;

		if (filters[f+1])
		    n = filters[f+1];

		if (filters[f] == n - 1)
		{
		    cli_error(cli, "Missing filter");
		    return CLI_ERROR;
		}

		argv = words + filters[f] + 1;
		argc = n - (filters[f] + 1);
		len = strlen(argv[0]);
		if (argv[argc-1][strlen(argv[argc-1])-1] == '?')
		{
		    if (argc == 1)
		    {
			cli_error(cli, "  %-20s %s", "begin",
				  "Begin with lines that match");

			cli_error(cli, "  %-20s %s", "between",
				  "Between lines that match");

			cli_error(cli, "  %-20s %s", "count",
			          "Count of lines");

			cli_error(cli, "  %-20s %s", "exclude",
			          "Exclude lines that match");

			cli_error(cli, "  %-20s %s", "include",
			          "Include lines that match");

			cli_error(cli, "  %-20s %s", "grep",
			          "Include lines that match regex "
				  "(options: -v, -i, -e)");

			cli_error(cli, "  %-20s %s", "egrep",
				  "Include lines that match extended regex");
		    }
		    else
		    {
			if (argv[0][0] != 'c') /* count */
			    cli_error(cli, "  WORD");

			if (argc > 2 || argv[0][0] == 'c') /* count */
			    cli_error(cli, "  <cr>");
		    }

		    return CLI_OK;
		}

		if (argv[0][0] == 'b' && len < 3) /* [beg]in, [bet]ween */
		{
		    cli_error(cli, "Ambiguous filter \"%s\" (begin, between)",
			      argv[0]);

		    return CLI_ERROR;
		}

		if (argv[0][0] == 'e' && len < 2) /* [eg]rep, [ex]clude */
		{
		    cli_error(cli, "Ambiguous filter \"%s\" (egrep, exclude)",
			      argv[0]);

		    return CLI_ERROR;
		}

		*filt = calloc(sizeof(struct cli_filter), 1);

		if (!strncmp("include", argv[0], len) ||
		    !strncmp("exclude", argv[0], len) ||
		    !strncmp("grep", argv[0], len) ||
		    !strncmp("egrep", argv[0], len))
		#ifdef REGEX_H	
		    rc = match_filter_init(cli, argc, argv, *filt);
		#endif
		 	;
		else if (!strncmp("begin", argv[0], len) ||
		    !strncmp("between", argv[0], len))
		    rc = range_filter_init(cli, argc, argv, *filt);
		else if (!strncmp("count", argv[0], len))
		    rc = count_filter_init(cli, argc, argv, *filt);
		else
		{
		    cli_error(cli, "Invalid filter \"%s\"", argv[0]);
		    rc = CLI_ERROR;
		}

		if (rc == CLI_OK)
		    filt = &(*filt)->next;
		else
		    free_z(*filt);
	    }

	    if (rc == CLI_OK)
	    {
		rc = c->callback(cli, command_name(cli, c),
				 words + start_word + 1,
				 c_words - start_word - 1);
	    }

	    while (cli->filters)
	    {
		struct cli_filter *filt = cli->filters;

		/* call one last time to clean up */
		filt->filter(cli, 0, filt->data);
		cli->filters = filt->next;
		free(filt);
	    }

	    return rc;
	}
    }

    cli_error(cli, "Invalid %s \"%s\"",
	      commands->parent ? "argument" : "command", words[start_word]);

    return CLI_ERROR;
}

static int run_command(struct cli_def *cli, char *command)
{
#define MAX_WORD 128
#define MAX_FILT 128
    char *words[MAX_WORD] = { 0 };
    int filters[MAX_FILT] = { 0 };
    int num_words;
    int r;
    int i;
    int f;

    if (!command)
	return CLI_ERROR;

    while (isspace(*command))
	command++;

    if (!*command)
	return CLI_OK;

    num_words = parse_line(command, words, MAX_WORD);
    for (i = f = 0; i < num_words && f < MAX_FILT-1; i++)
    {
	if (words[i][0] == '|')
	    filters[f++] = i;
    }

    filters[f] = 0;

    if (num_words)
	r = find_command(cli, cli->commands, num_words, words, 0, filters);
    else
	r = CLI_ERROR;

    for (i = 0; i < num_words; i++)
	free(words[i]);

    if (r == CLI_QUIT)
	return r;

    return CLI_OK;
}

static int get_completions(struct cli_def * cli,char *command, char **completions,
   int max_completions)
{
#define MAX_WORD 128
#define MAX_FILT 128
    char *words[MAX_WORD] = { 0 };
    char *twords[MAX_WORD] = { 0 };
#if 0	
    int filters[MAX_FILT] = { 0 };
    int f;
#endif	
    int num_words;
    int i,k;


    int num_completions = 0;	
    struct cli_command *c;
    struct cli_command *ch;

    if (!command)
	return CLI_ERROR;

    while (isspace(*command))
	command++;

    if (!*command)
	return CLI_OK;

    num_words = parse_line(command, words, MAX_WORD);
#if 0	
    for (i = f = 0; i < num_words && f < MAX_FILT-1; i++)
    {
	if (words[i][0] == '|')
	    filters[f++] = i;
    }

    filters[f] = 0;
#endif

    if (num_words >= 1)
    {
		c = cli->commands;

		for (i=0; i < num_words; i++)
		{
			while (c)
			{
				if (strncasecmp(c->command, words[i],strlen(words[i])) == 0)
				{
					if ( (i+1) == num_words)
					{							
						num_completions++;

						for (k = 0; k < i; k++)
						{
							twords[k] = words[k];
						}

						twords[i] = c->command;  //which is 'i' th word (k+1)
									
						completions[num_completions-1] = join_words(num_words, twords);

						ch = c->children;
						
						next:
						if (ch)
						{
							if (ch->command)
							{
								num_completions++;
								twords[i+1] = ch->command;  //which is 'i+1' th word (k+2)
								completions[num_completions-1] = join_words(num_words+1, twords);
								ch = ch->next;
								goto next;
							}

						}
					}
					else
					{
						c = c->children;
						break; //break from while loop
					}
				}
				c = c->next;				
			}
		}
    }

    return num_completions;
}
#if 0
static int get_completions(UNUSED(char *command), UNUSED(char **completions),
    UNUSED(int max_completions))
{
    return 0;
}
#endif
static void clear_line(int sockfd, char *cmd, int l, int cursor)
{
    int i;
    if (cursor < l)
	for (i = 0; i < (l - cursor); i++)
	    write(sockfd, " ", 1);

    for (i = 0; i < l; i++)
	cmd[i] = '\b';

    for (; i < l * 2; i++)
	cmd[i] = ' ';

    for (; i < l * 3; i++)
	cmd[i] = '\b';

    write(sockfd, cmd, i);
    memset(cmd, 0, i);
    l = cursor = 0;
}

void cli_reprompt(struct cli_def *cli)
{
    cli->showprompt = 1;
}

void cli_regular(struct cli_def *cli, int (*callback)(struct cli_def *cli))
{
    cli->regular_callback = callback;
}

#define DES_PREFIX "{crypt}"	/* to distinguish clear text from DES crypted */
#define MD5_PREFIX "$1$"

static int pass_matches(char *pass, char *try)
{
    int des;
    if ((des = !strncasecmp(pass, DES_PREFIX, sizeof(DES_PREFIX)-1)))
	pass += sizeof(DES_PREFIX)-1;

    if (des || !strncmp(pass, MD5_PREFIX, sizeof(MD5_PREFIX)-1))
//	try = crypt(try, pass);
 		;

    return !strcmp(pass, try);
}

#define CTRL(c) (c - '@')

static int show_prompt(struct cli_def *cli, int sockfd)
{
    int len = 0;

    if (cli->hostname)
	len += write(sockfd, cli->hostname, strlen(cli->hostname));

    if (cli->modestring)
	len += write(sockfd, cli->modestring, strlen(cli->modestring));

    return len + write(sockfd, cli->promptchar, strlen(cli->promptchar));
}

extern int _fd_filetype (int fd);

int cli_loop(struct cli_def *cli, int sockfd)
{
    int n;
    unsigned char c;
    char *cmd = 0;
    char *oldcmd = 0;
    int l;
    int oldl = 0;
    int is_telnet_option = 0;
    int skip = 0;
    int esc = 0;
    int cursor = 0;
    int hist_sz = 0;
    char *username = 0;
    char *password = 0;

    char *negotiate =
	"\xFF\xFB\x03"
	"\xFF\xFB\x01"
	"\xFF\xFD\x03"
	"\xFF\xFD\x01";

    cli->state = STATE_LOGIN;

    memset(cli->history, 0, MAX_HISTORY);
    if (_fd_filetype (sockfd)== 2)  /*CYG_FILE_TYPE_SOCKET	  2,  communications endpoint */
    {
	write(sockfd, negotiate, strlen(negotiate));
    }
    if ((cmd = malloc(4096)) == 0)
	return CLI_ERROR;

    if (!(cli->client = fdopen(sockfd, "w+")))
	return CLI_ERROR;


    setbuf(cli->client, 0);
	
    if (cli->banner)
	cli_error(cli, "%s", cli->banner);

    /* start off in unprivileged mode */
    cli_set_privilege(cli, PRIVILEGE_UNPRIVILEGED);
    cli_set_configmode(cli, MODE_EXEC, 0);

    /* no auth required? */
    if (!cli->users && !cli->auth_callback)
	cli->state = STATE_NORMAL;

    while (1)
    {
	int hist = -1;
	int lastchar = 0;
	struct timeval tm;

	cli->showprompt = 1;

	if (oldcmd)
	{
	    l = cursor = oldl;
	    oldcmd[l] = 0;
	    cli->showprompt = 1;
	    oldcmd = 0;
	    oldl = 0;
	}
	else
	{
	    memset(cmd, 0, 4096);
	    l = 0;
	    cursor = 0;
	}

	tm.tv_sec = 1;
	tm.tv_usec = 0;

	while (1)
	{
	    int sr;
	    fd_set r;
	    if (cli->showprompt)
	    {
		if (cli->state != STATE_PASSWORD &&
		    cli->state != STATE_ENABLE_PASSWORD)
		    write(sockfd, "\r\n", 2);

		switch (cli->state)
		{
		    case STATE_LOGIN:
			write(sockfd, "Username: ", strlen("Username: "));
			break;

		    case STATE_PASSWORD:
			write(sockfd, "Password: ", strlen("Password: "));
			break;

		    case STATE_NORMAL:
		    case STATE_ENABLE:
			show_prompt(cli, sockfd);
			write(sockfd, cmd, l);
			if (cursor < l)
			{
			    int n = l - cursor;
			    while (n--)
				write(sockfd, "\b", 1);
			}

			break;

		    case STATE_ENABLE_PASSWORD:
			write(sockfd, "Password: ", strlen("Password: "));
			break;

		}

		cli->showprompt = 0;
	    }

	    if (_fd_filetype (sockfd)== 2)  /*CYG_FILE_TYPE_SOCKET	  2,  communications endpoint */
	    {
		    FD_ZERO(&r);
		    FD_SET(sockfd, &r);

		    if ((sr = select(sockfd + 1, &r, 0, 0, &tm)) < 0)
		    {
			/* select error */
			if (errno == EINTR)
			    continue;

			perror("read");
			l = -1;
			break;
		    }

		    if (sr == 0)
		    {
			/* timeout every second */
			if (cli->regular_callback &&
			    cli->regular_callback(cli) != CLI_OK)
			    break;

			tm.tv_sec = 1;
			tm.tv_usec = 0;
			continue;
		    }
	    }
	    if ((n = read(sockfd, &c, 1)) < 0)
	    {
		if (errno == EINTR)
		    continue;

		perror("read");
		l = -1;
		break;
	    }

	    if (n == 0)
	    {
		l = -1;
		break;
	    }

	    if (skip)
	    {
		skip--;
		continue;
	    }

	    if (c == 255 && !is_telnet_option)
	    {
		is_telnet_option++;
		continue;
	    }

	    if (is_telnet_option)
	    {
		if (c >= 251 && c <= 254)
		{
		    is_telnet_option = c;
		    continue;
		}

		if (c != 255)
		{
		    is_telnet_option = 0;
		    continue;
		}

		is_telnet_option = 0;
	    }

	    /* handle ANSI arrows */
	    if (esc)
	    {
		if (esc == '[')
		{
		    /* remap to readline control codes */
		    switch (c)
		    {
			case 'A': /* Up */
			    c = CTRL('P');
			    break;

			case 'B': /* Down */
			    c = CTRL('N');
			    break;

			case 'C': /* Right */
			    c = CTRL('F');
			    break;

			case 'D': /* Left */
			    c = CTRL('B');
			    break;

			default:
			    c = 0;
		    }

		    esc = 0;
		}
		else
		{
		    esc = (c == '[') ? c : 0;
		    continue;
		}
	    }

	    if (c == 0)
		continue;

	    if (c == '\n')
		continue;

	    if (c == '\r')
	    {
		if (cli->state != STATE_PASSWORD &&
		    cli->state != STATE_ENABLE_PASSWORD)
		    write(sockfd, "\r\n", 2);

		break;
	    }

	    if (c == 27)
	    {
		esc = 1;
		continue;
	    }

	    if (c == CTRL('C'))
	    {
		write(sockfd, "\a", 1);
		continue;
	    }

	    /* back word, backspace/delete */
	    if (c == CTRL('W') || c == CTRL('H') || c == 0x7f)
	    {
		int back = 0;

		if (c == CTRL('W')) /* word */
		{
		    int nc = cursor;

		    if (l == 0 || cursor == 0)
			continue;

		    while (nc && cmd[nc - 1] == ' ')
		    {
			nc--;
			back++;
		    }

		    while (nc && cmd[nc - 1] != ' ')
		    {
			nc--;
			back++;
		    }
		}
		else /* char */
		{
		    if (l == 0 || cursor == 0)
		    {
			write(sockfd, "\a", 1);
			continue;
		    }

		    back = 1;
		}

		if (back)
		{
		    while (back--)
		    {
			if (l == cursor)
			{
			    cmd[--cursor] = 0;
			    if (cli->state != STATE_PASSWORD &&
				cli->state != STATE_ENABLE_PASSWORD)
				write(sockfd, "\b \b", 3);
			}
			else
			{
			    int i;
			    cursor--;
			    if (cli->state != STATE_PASSWORD &&
				cli->state != STATE_ENABLE_PASSWORD)
			    {
				int len;
				for (i = cursor; i <= l; i++)
				    cmd[i] = cmd[i+1];

				len = strlen(cmd + cursor);
				write(sockfd, "\b", 1);
				write(sockfd, cmd + cursor, len);
				write(sockfd, " ", 1);
				for (i = 0; i <= len; i++)
				    write(sockfd, "\b", 1);
			    }
			}

			l--;
		    }

		    continue;
		}
	    }

	    /* redraw */
	    if (c == CTRL('L'))
	    {
		int i;
		int cursorback = l - cursor;

		if (cli->state == STATE_PASSWORD ||
		    cli->state == STATE_ENABLE_PASSWORD)
		    continue;

		write(sockfd, "\r\n", 2);
		show_prompt(cli, sockfd);
		write(sockfd, cmd, l);

		for (i = 0; i < cursorback; i++)
		    write(sockfd, "\b", 1);

		continue;
	    }

	    /* clear line */
	    if (c == CTRL('U'))
	    {
		if (cli->state == STATE_PASSWORD ||
		    cli->state == STATE_ENABLE_PASSWORD)
		    memset(cmd, 0, l);
		else
		    clear_line(sockfd, cmd, l, cursor);

		l = cursor = 0;
		continue;
	    }

	    /* kill to EOL */
	    if (c == CTRL('K'))
	    {
		if (cursor == l)
		    continue;

		if (cli->state != STATE_PASSWORD &&
		    cli->state != STATE_ENABLE_PASSWORD)
		{
		    int c;
		    for (c = cursor; c < l; c++)
			write(sockfd, " ", 1);

		    for (c = cursor; c < l; c++)
			write(sockfd, "\b", 1);
		}

		memset(cmd + cursor, 0, l - cursor);
		l = cursor;
		continue;
	    }

	    /* EOT */
	    if (c == CTRL('D'))
	    {
		if (cli->state == STATE_PASSWORD ||
		    cli->state == STATE_ENABLE_PASSWORD)
		    break;

		if (l)
		    continue;

		strcpy(cmd, "quit");
		l = cursor = strlen(cmd);
		write(sockfd, "quit\r\n", l + 2);
		break;
	    }

	    /* disable */
	    if (c == CTRL('Z'))
	    {
		if (cli->mode != MODE_EXEC)
		{
		    clear_line(sockfd, cmd, l, cursor);
		    cli_set_configmode(cli, MODE_EXEC, 0);
		    cli->showprompt = 1;
		}

		continue;
	    }

	    /* TAB completion */
	    if (c == CTRL('I'))
	    {
		char *completions[128];
		int num_completions = 0;

		if (cli->state == STATE_PASSWORD ||
		    cli->state == STATE_ENABLE_PASSWORD)
		    continue;

		if (cursor != l)
		    continue;

		if (l > 0)
		    num_completions = get_completions(cli, cmd, completions, 128);

		if (num_completions == 0)
		{
		    write(sockfd, "\a", 1);
		}
		else if (num_completions == 1)
		{
			if (lastchar != CTRL('I'))
				{
				    /* single completion */
				    int i;
				    for (i = l; i > 0; i--, cursor--)
				    {
					write(sockfd, "\b", 1);
					if (i == ' ') break;
				    }

				    strcpy((cmd + i), completions[0]);
				    l += strlen(completions[0]);
				    cursor = l;
				    write(sockfd, completions[0], strlen(completions[0]));

				   lastchar = c;	
				}			
		}
		else if (lastchar == CTRL('I'))
		{
		    /* double tab */
		    int i;
		    write(sockfd, "\r\n", 2);
		    for (i = 0; i < num_completions; i++)
		    {
			write(sockfd, completions[i], strlen(completions[i]));
			if (i % 4 == 3)
			    write(sockfd, "\r\n", 2);
			else
			    write(sockfd, "		", 1);
		    }

		    if (i % 4 != 3)
			write(sockfd, "\r\n", 2);

		    cli->showprompt = 1;
		}
		else
		{
		    /* more than one completion */
		    lastchar = c;
		    write(sockfd, "\a", 1);
		}
		continue;
	    }

	    /* history */
	    if (c == CTRL('P') || c == CTRL('N'))
	    {
		if (cli->state == STATE_PASSWORD ||
		    cli->state == STATE_ENABLE_PASSWORD)
		    continue;

		if (!hist_sz) /* empty */
		    continue;

		if (c == CTRL('P')) /* Up */
		{
		    if (hist == -1 /* inital */ || --hist < 0 /* wrap */) 
		    	hist = hist_sz - 1;
		}
		else /* Down */
		{
		    if (hist == -1 || ++hist > hist_sz - 1)
		    	hist = 0;
		}

		/* show history item */
		clear_line(sockfd, cmd, l, cursor);
		memset(cmd, 0, 4096);
		strncpy(cmd, cli->history[hist], 4095);
		l = cursor = strlen(cmd);
		write(sockfd, cmd, l);
		continue;
	    }

	    /* left/right cursor motion */
	    if (c == CTRL('B') || c == CTRL('F'))
	    {
		if (c == CTRL('B')) /* Left */
		{
		    if (cursor)
		    {
			if (cli->state != STATE_PASSWORD &&
			    cli->state != STATE_ENABLE_PASSWORD)
			    write(sockfd, "\b", 1);

			cursor--;
		    }
		}
		else /* Right */
		{
		    if (cursor < l)
		    {
			if (cli->state != STATE_PASSWORD &&
			    cli->state != STATE_ENABLE_PASSWORD)
			    write(sockfd, &cmd[cursor], 1);

			cursor++;
		    }
		}

		continue;
	    }

	    /* start of line */
	    if (c == CTRL('A'))
	    {
		if (cursor)
		{
		    if (cli->state != STATE_PASSWORD &&
			cli->state != STATE_ENABLE_PASSWORD)
		    {
			write(sockfd, "\r", 1);
			show_prompt(cli, sockfd);
		    }

		    cursor = 0;
		}

		continue;
	    }

	    /* end of line */
	    if (c == CTRL('E'))
	    {
		if (cursor < l)
		{
		    if (cli->state != STATE_PASSWORD &&
			cli->state != STATE_ENABLE_PASSWORD)
			write(sockfd, &cmd[cursor], l - cursor);

		    cursor = l;
		}

		continue;
	    }

	    /* normal character typed */
	    if (cursor == l) /* append to end of line */
	    {
		cmd[cursor] = c;
		if (l < 4095)
		{
		    l++;
		    cursor++;
		}
		else
		{
		    write(sockfd, "\a", 1);
		    continue;
		}
	    }
	    else /* insert */
	    {
		int i;
		/* move everything one character to the right */
		if (l >= 4094) l--;
		for (i = l; i >= cursor; i--)
		    cmd[i + 1] = cmd[i];

		/* write what we've just added */
		cmd[cursor] = c;

		write(sockfd, &cmd[cursor], l - cursor + 1);
		for (i = 0; i < (l - cursor + 1); i++)
		    write(sockfd, "\b", 1);

		l++;
		cursor++;
	    }

	    if (cli->state != STATE_PASSWORD &&
	    	cli->state != STATE_ENABLE_PASSWORD)
	    {
		if (c == '?' && cursor == l)
		{
		    write(sockfd, "\r\n", 2);
		    oldcmd = cmd;
		    oldl = cursor = l - 1;
		    break;
		}
		write(sockfd, &c, 1);
	    }

	    oldcmd = 0;
	    oldl = 0;
	    lastchar = c;
	}

	if (l < 0)
	    break;

	if (!strcasecmp(cmd, "quit"))
	    break;

	if (cli->state == STATE_LOGIN)
	{
	    if (l == 0)
		continue;

	    /* require login */
	    free(username);
	    username = strdup(cmd);
	    cli->state = STATE_PASSWORD;
	    cli->showprompt = 1;
	}
	else if (cli->state == STATE_PASSWORD)
	{
	    /* require password */
	    int allowed = 0;

	    free(password);
	    password = strdup(cmd);
	    if (cli->auth_callback && cli->auth_callback(username, password) == CLI_OK)
		allowed++;

	    if (!allowed)
	    {
		struct unp *u;
		for (u = cli->users; u; u = u->next)
		{
		    if (!strcmp(u->username, username) &&
			pass_matches(u->password, password))
		    {
			allowed++;
			break;
		    }
		}
	    }

	    if (allowed)
	    {
		cli_error(cli, "");
		cli->state = STATE_NORMAL;
	    }
	    else
	    {
		cli_error(cli, "\n\nAccess denied");
		free_z(username);
		free_z(password);
		cli->state = STATE_LOGIN;
	    }

	    cli->showprompt = 1;
	}
	else if (cli->state == STATE_ENABLE_PASSWORD)
	{
	    int allowed = 0;
	    if (cli->enable_password)
	    {
		/* check stored static enable password */
		if (pass_matches(cli->enable_password, cmd))
		    allowed++;
	    }

	    if (!allowed && cli->enable_callback)
	    {
		/* check callback */
		if (cli->enable_callback(cmd))
		    allowed++;
	    }

	    if (allowed)
	    {
		cli->state = STATE_ENABLE;
		cli_set_privilege(cli, PRIVILEGE_PRIVILEGED);
	    }
	    else
	    {
		cli_error(cli, "\n\nAccess denied");
		cli->state = STATE_NORMAL;
	    }
	}
	else
	{
	    if (!l)
	    	continue;

	    if (cmd[l - 1] != '?')
	    	hist_sz = add_history(cli, cmd);

	    if (run_command(cli, cmd) == CLI_QUIT)
		break;
	}
    }

    {
	/* cleanup */
	int i;
	for (i = 0; i < MAX_HISTORY; i++)
	    free_z(cli->history[i]);

	free(username);
	free(password);
	free(cmd);
    }

    fclose(cli->client);
    cli->client = 0;
    return CLI_OK;
}

int cli_file(struct cli_def *cli, FILE *fh, int privilege, int mode)
{
    int oldpriv = cli_set_privilege(cli, privilege);
    int oldmode = cli_set_configmode(cli, mode, 0);
    char buf[4096];

    while (1)
    {
	char *p;
	char *cmd;
	char *end;

	if (!fgets(buf, sizeof(buf), fh))
	    break; /* end of file */

	if ((p = strpbrk(buf, "#!\r\n")))
	    *p = 0;

	cmd = buf;
	while (isspace(*cmd))
	    cmd++;

	if (!*cmd)
	    continue;

	for (p = end = cmd; *p; p++)
	    if (!isspace(*p))
		end = p;

	*++end = 0;
	if (!strcasecmp(cmd, "quit"))
	    break;

	if (run_command(cli, cmd) == CLI_QUIT)
	    break;
    }

    cli_set_privilege(cli, oldpriv);
    cli_set_configmode(cli, oldmode, 0 /* didn't save desc */);

    return CLI_OK;
}

static void do_print(struct cli_def *cli, int filter, char *format, va_list ap)
{
    char **buf = &cli->_print_buf;
    int *sz = &cli->_print_bufsz;
    char *p;
    int n;

    while (!*buf || (n = vsnprintf(*buf, *sz, format, ap)) >= *sz)
    {
	if (!(p = realloc(*buf, *sz += 4096)))
	{
	    free_z(*buf);
	    *sz = 0;
	    return;
	}

	*buf = p;
    }

    if (n < 0) /* vsnprintf failed */
	return;

    p = *buf;
    do {
	char *next = strchr(p, '\n');
	struct cli_filter *f = filter ? cli->filters : 0;
	int print = 1;

	if (next)
	    *next++ = 0;

	while (print && f)
	{
	    print = (f->filter(cli, p, f->data) == CLI_OK);
	    f = f->next;
	}

	if (print)
	{
	    if (cli->print_callback)
		cli->print_callback(cli, p);
	    else if (cli->client)
		fprintf(cli->client, "%s\r\n", p);
	}

	p = next;
    } while (p);
}

void cli_print(struct cli_def *cli, char *format, ...)
{
    va_list ap;

    va_start(ap, format);
    do_print(cli, 1, format, ap);
    va_end(ap);
}

void cli_error(struct cli_def *cli, char *format, ...)
{
    va_list ap;

    va_start(ap, format);
    do_print(cli, 0, format, ap);
    va_end(ap);
}

void cli_print_callback(struct cli_def *cli,
    void (*callback)(struct cli_def *, char *))
{
    cli->print_callback = callback;
}

[-- Attachment #4: Type: text/plain, Size: 148 bytes --]

-- 
Before posting, please read the FAQ: http://ecos.sourceware.org/fom/ecos
and search the list archive: http://ecos.sourceware.org/ml/ecos-discuss

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2007-06-25  5:42 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-06-25 13:49 [ECOS] FIN is not sending on socket close() srinivas naga vutukuri

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).