/*
 * Copyright (c) 2004-2009, Luiz Otavio O Souza <loos.br@gmail.com>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

static const char rcsid[] = "$Id: check-cmd.c 112 2009-03-15 17:30:28Z loos-br $";

#include <errno.h>
#include <stdio.h>
#include <string.h>

#include "io.h"
#include "sb.h"
#include "client.h"
#include "server.h"
#include "return.h"
#include "syslog.h"
#include "protocol.h"
#include "msn-proxy.h"

CMD	PRE_CMDS[] = {
	{ "VER", 0, msn_get_ver },
	{ NULL, 0, NULL }
	};

int check_ok(struct user_ *user, command *cmd, int args) { return(ROK); }

int _check_args(command *cmd, int args) {

    if (args != cmd->args_len) {
        io_printf(1, "numero de args: [%d] != [%d]\n", args, cmd->args_len);
	print_command(cmd);
        return(RFAIL);
    }
    return(ROK);
}

int check_args(struct user_ *user, command *cmd, int args) {
    return(_check_args(cmd, args));
}

int check_sb_args(struct sb_ *sb, command *cmd, int args) {
    return(_check_args(cmd, args));
}

int
check_cmd(struct user_ *user, command *cmd, int type) {
 unsigned long	erro	= 0;
 log_		*log    = &config.log;
 CMDS_		*cmds_  = (CMDS_ *)0;
 CMD		*cmds   = (CMD *)0;
 char		*label  = "";
 char		*ep;

    /* get the right command type */
    cmds_ = user->cmds;
    for ( ; cmds_ && cmds_->type && cmds_->cmd; cmds_++) {
	if (cmds_->type == type) {
	    label = cmds_->label;
	    cmds = cmds_->cmd;
	    break;
	}
    }

    if (user->version == 0)
	cmds = PRE_CMDS;

    if (cmds == (CMD *)0) {
	log->debug("unknown protocol type [%d] / version [%d]\n", type,
		   user->version);
	return(RFAIL);
    }

    /* check for protocol errors */
    errno = 0;
    erro = strtoul((char *)cmd->cmd.s, &ep, 10);
    if (errno == 0 && *cmd->cmd.s && (ep && *ep == 0)) {

	/* ignore the 241, 508, 509 and 511 commands */
	if (erro != 511 && erro != 509 && erro != 508 && erro != 241) {
	    log->debug("===> warning error received\n");
	    return(ROK);
	}
    }

    /* dispatch command */
    for ( ; (cmds && cmds->cmd); cmds++) {
	/* XXX - remove */
	//io_printf(1, "%S: [%S] == [%s]\n", label, cmds->cmd, &cmd->cmd);
	if (strncmp(cmds->cmd, (char *)cmd->cmd.s, cmd->cmd.len) == 0) {
	    //print_command(cmd);
	    return(cmds->func(user, cmd, cmds->args));
	}
    }

    /* post commands cannot drop connection */
    switch (type) {
	case SERVER_POST_CMD:
	case CLIENT_POST_CMD:
	    return(ROK);
    }

    log->debug("debug: %S command blocked: ", label);
    print_command(cmd);
    return(RFAIL);
}

int
check_sb_cmd(struct sb_ *sb, command *cmd, int type) {
 unsigned long	erro   = 0;
 SBCMDS_	*cmds_ = (SBCMDS_ *)0;
 SBCMD		*cmds  = (SBCMD *)0;
 log_		*log   = &config.log;
 char		*label = "";
 char		*ep;

    /* get the right command type */
    cmds_ = sb->user->sbcmds;
    for ( ; cmds_ && cmds_->type && cmds_->sbcmd; cmds_++) {
	if (cmds_->type == type) {
	    label = cmds_->label;
	    cmds = cmds_->sbcmd;
	    break;
	}
    }

    if (cmds == (SBCMD *)0) {
	log->debug("unknown protocol type [%d] / version [%d]\n", type,
		   sb->user->version);
	return(RFAIL);
    }

    /* check for errors */
    errno = 0;
    erro = strtoul((char *)cmd->cmd.s, &ep, 10);
    if (errno == 0 && *cmd->cmd.s && (ep && *ep == 0)) {
	log->debug("warning: error received\n");
	return(ROK);
    }

    /* dispatch command */
    for ( ; (cmds && cmds->cmd); cmds++) {
	//io_printf(1, "%S: [%S] == [%s]\n", label, cmds->cmd, &cmd->cmd);
	if (strncmp(cmds->cmd, (char *)cmd->cmd.s, cmd->cmd.len) == 0) {
	    //print_command(cmd);
	    return(cmds->func(sb, cmd, cmds->args));
	}
    }

    /* post commands cannot drop connection */
    switch (type) {
	case SERVER_SB_POST_CMD:
	case CLIENT_SB_POST_CMD:
	    return(ROK);
    }

    log->debug("debug: %S command blocked: ", label);
    print_command(cmd);
    return(RFAIL);
}
