/* blacklist.c  --  eurephiadm blacklist command:
 *                  Show/edit blacklist
 *
 *  GPLv2 only - Copyright (C) 2009 - 2012
 *               David Sommerseth <dazo@users.sourceforge.net>
 *
 *  This program is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU General Public License
 *  as published by the Free Software Foundation; version 2
 *  of the License.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 *
 */

/**
 * @file   eurephiadm/commands/blacklist.c
 * @author David Sommerseth <dazo@users.sourceforge.net>
 * @date   2009-05-09
 *
 * @brief  eurephiadm blacklist command.  Show and edit the eurephia blacklists
 *
 */

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

#ifdef HAVE_LIBXML2
#include <libxml/tree.h>
#endif

#define MODULE "eurephia::Blacklist" /**< Need to define the active module before including argparser.h */
#include <eurephia_nullsafe.h>
#include <eurephia_context.h>
#include <eurephia_log.h>
#include <eurephia_xml.h>
#include <eurephia_values_struct.h>
#include <eurephiadb_session_struct.h>
#include <eurephiadb_mapping.h>
#include <eurephiadb_driver.h>
#include <eurephia_values.h>

#include "../argparser.h"
#include "../xsltparser.h"


/**
 * Help screens for the blacklist command
 *
 * @param page which help screen to display
 */
void display_blacklist_help(int page)
{
        switch( page ) {
        case 'l':
                printf("The blacklist list mode will show registered entries in the blacklist.\n"
                       "\n"
                       "     -v | --verbose               Show more details\n"
                       "\n"
                       "Filters:\n"
                       "     -u | --username <username>   User name\n"
                       "     -d | --digest <SHA1 digest>  Certificate SHA1 digest\n"
                       "     -i | --ipaddr <ip address>   IP address\n\n");
                break;

        case 'D':
                printf("The blacklist delete mode will remove a blacklisted entry.\n"
                       "\n"
                       "One of the following parameters must be given (only one):\n"
                       "     -u | --username <username>   User name\n"
                       "     -d | --digest <SHA1 digest>  Certificate SHA1 digest\n"
                       "     -i | --ipaddr <ip address>   IP address\n"
                       "     -b | --blid <ID>             Blacklist record ID\n"
                       "\n"
                       );
                break;

        case 'A':
                printf("The blacklist add mode will register a new entry to be blacklisted.\n"
                       "\n"
                       "One of the following parameters must be given (only one):\n"
                       "     -u | --username <username>   User name\n"
                       "     -d | --digest <SHA1 digest>  Certificate SHA1 digest\n"
                       "     -i | --ipaddr <ip address>   IP address\n"
                       "\n"
                       );
                break;

        default:
                printf("Available modes for the blacklist command are:\n\n"
                       "     -l | --list         List all entries on theblacklist\n"
                       "     -A | --add          Add an entry to the blacklist\n"
                       "     -D | --delete       Delete an entry from the blacklist\n"
                       "     -h | --help <mode>  Show help\n\n");
                break;
        }
}


/**
 * Help screen wrapper.  Used by cmd_Help()
 */
void help_Blacklist()
{
        display_blacklist_help(0);
}


/**
 * Help screen wrapper for the blacklist help function.
 *
 * @param ctx   eurephiaCTX
 * @param sess  eurephiaSESSION of the current logged in user
 * @param cfg   eurephiaVALUES struct of the current configuration
 * @param argc  argument count for the eurephiadm command
 * @param argv  argument table for the eurephiadm command
 *
 * @return returns 0 on success, otherwise 1.
 */
int help_Blacklist2(eurephiaCTX *ctx, eurephiaSESSION *sess, eurephiaVALUES *cfg, int argc, char **argv)
{
        e_options modeargs[] = {
                {"--list", "-l", 0},
                {"--add", "-A", 0},
                {"--delete", "-D", 0},
                {NULL, NULL, 0}
        };
        int i = 1;
        display_blacklist_help(eurephia_getopt(&i, argc, argv, modeargs));
        return 0;
}


/**
 * blacklist list mode.  Lists all blacklisted certificates, user account and/or IP addresses.
 *
 * @param ctx   eurephiaCTX
 * @param sess  eurephiaSESSION of the current logged in user
 * @param cfg   eurephiaVALUES struct of the current configuration
 * @param argc  argument count for the eurephiadm command
 * @param argv  argument table for the eurephiadm command
 *
 * @return returns 0 on success, otherwise 1.
 */
int list_blacklist(eurephiaCTX *ctx, eurephiaSESSION *sess, eurephiaVALUES *cfg, int argc, char **argv)
{
        xmlDoc *blst_xml = NULL, *srch_xml = NULL;
        xmlNode *fmap_n = NULL, *srch_n = NULL;
        char *xsltparams[] = {"view", "'list'", NULL};
        int i = 0;

        e_options modeargs[] = {
                {"--verbose", "-v", 0},
                {"--help", "-h", 0},
                {"--username", "-u", 1},
                {"--digest", "-d", 1},
                {"--ipaddr", "-i", 1},
                {NULL, NULL, 0}
        };

        eurephiaXML_CreateDoc(ctx, 1, "blacklist", &srch_xml, &srch_n);
        xmlNewProp(srch_n, (xmlChar *) "mode", (xmlChar *) "list");

        fmap_n = xmlNewChild(srch_n, NULL, (xmlChar *) "fieldMapping", NULL);
        xmlNewProp(fmap_n, (xmlChar *) "table", (xmlChar *) "blacklist");

        for( i = 1; i < argc; i++ ) {
                switch( eurephia_getopt(&i, argc, argv, modeargs) ) {
                case 'v':
                        xsltparams[1] = "'details'";
                        break;

                case 'u':
                        xmlNewChild(fmap_n, NULL, (xmlChar *) "username", (xmlChar *) optargs[0]);
                        break;

                case 'd':
                        xmlNewChild(fmap_n, NULL, (xmlChar *) "digest", (xmlChar *) optargs[0]);
                        break;

                case 'i':
                        xmlNewChild(fmap_n, NULL, (xmlChar *) "ip", (xmlChar *) optargs[0]);
                        break;

                case 'h':
                        display_blacklist_help('l');
                        xmlFreeDoc(srch_xml);
                        return 0;

                default:
                        xmlFreeDoc(srch_xml);
                        return 1;
                }
        }

        blst_xml = eDBadminBlacklist(ctx, srch_xml);
        xmlFreeDoc(srch_xml);
        if( blst_xml == NULL ) {
                fprintf(stderr, "%s: Error retrieving the blacklist.\n", MODULE);
                return 1;
        }
        xslt_print_xmldoc(stdout, cfg, blst_xml, "blacklist.xsl", (const char **) xsltparams);
        xmlFreeDoc(blst_xml);
        return 0;
}


/**
 * Function for modifying the blacklists
 *
 * @param ctx   eurephiaCTX
 * @param sess  eurephiaSESSION of the current logged in user
 * @param cfg   eurephiaVALUES struct of the current configuration
 * @param argc  argument count for the eurephiadm command
 * @param argv  argument table for the eurephiadm command
 *
 * @return returns 0 on success, otherwise 1.
 */
int modify_blacklist(eurephiaCTX *ctx, eurephiaSESSION *sess, eurephiaVALUES *cfg, int argc, char **argv)
{
        xmlDoc *result_xml = NULL, *upd_xml = NULL;
        xmlNode *fmap_n = NULL, *upd_n = NULL;
        eurephiaRESULT *res = NULL;
        int i = 0, rc = 1, mode = 0;

        e_options modeargs[] = {
                {"--help", "-h", 0},
                {"--username", "-u", 1},
                {"--digest", "-d", 1},
                {"--ipaddr", "-i", 1},
                {"--blid", "-b", 1},
                {NULL, NULL, 0}
        };

        eurephiaXML_CreateDoc(ctx, 1, "blacklist", &upd_xml, &upd_n);
        if( (strcmp(argv[0], "--add") == 0) || (strcmp(argv[0], "-A") == 0) ) {
                xmlNewProp(upd_n, (xmlChar *) "mode", (xmlChar *) "add");
                mode = 'A';
        } else if( (strcmp(argv[0], "--delete") == 0) || (strcmp(argv[0], "-D") == 0) ) {
                xmlNewProp(upd_n, (xmlChar *) "mode", (xmlChar *) "delete");
                mode = 'D';
        } else {
                fprintf(stderr, "%s: Invalid mode\n", MODULE);
                xmlFreeDoc(upd_xml);
                return 1;
        }

        fmap_n = xmlNewChild(upd_n, NULL, (xmlChar *) "fieldMapping", NULL);
        xmlNewProp(fmap_n, (xmlChar *) "table", (xmlChar *) "blacklist");

        for( i = 1; i < argc; i++ ) {
                switch( eurephia_getopt(&i, argc, argv, modeargs) ) {
                case 'u':
                        xmlNewChild(fmap_n, NULL, (xmlChar *) "username", (xmlChar *) optargs[0]);
                        break;

                case 'd':
                        xmlNewChild(fmap_n, NULL, (xmlChar *) "digest", (xmlChar *) optargs[0]);
                        break;

                case 'i':
                        xmlNewChild(fmap_n, NULL, (xmlChar *) "ip", (xmlChar *) optargs[0]);
                        break;

                case 'b':
                        xmlNewChild(fmap_n, NULL, (xmlChar *) "id", (xmlChar *) optargs[0]);
                        break;

                case 'h':
                        display_blacklist_help(mode);
                        xmlFreeDoc(upd_xml);
                        return 0;

                default:
                        xmlFreeDoc(upd_xml);
                        return 1;
                }
        }

        result_xml = eDBadminBlacklist(ctx, upd_xml);
        xmlFreeDoc(upd_xml);
        if( result_xml == NULL ) {
                fprintf(stderr, "%s: Could not modify the blacklist\n", MODULE);
                return 1;
        }

        res = eurephiaXML_ParseResultMsg(ctx, result_xml);
        if( res == NULL ) {
                fprintf(stderr, "%s: Error updating the blacklist. No results returned.\n", MODULE);
                return 1;

        }

        if( res->resultType == exmlERROR ) {
                fprintf(stderr, "%s: %s\n", MODULE, res->message);
                rc = 1;
        } else {
                fprintf(stdout, "%s: %s\n", MODULE, res->message);
                rc = 0;
        }
        free_nullsafe(ctx, res);
        xmlFreeDoc(result_xml);

        return rc;
}


/**
 * Main function for the the blacklist command
 *
 * @param ctx   eurephiaCTX
 * @param sess  eurephiaSESSION of the current logged in user
 * @param cfg   eurephiaVALUES struct of the current configuration
 * @param argc  argument count for the eurephiadm command
 * @param argv  argument table for the eurephiadm command
 *
 * @return returns 0 on success, otherwise 1.
*/
int cmd_Blacklist(eurephiaCTX *ctx, eurephiaSESSION *sess, eurephiaVALUES *cfg, int argc, char **argv)
{
        char **mode_argv;
        int rc = 0, i = 0, mode_argc = 0;
        e_options cmdargs[] = {
                {"--list", "-l", 0},
                {"--add", "-A", 0},
                {"--delete", "-D", 0},
                {"--help", "-h", 0},
                {NULL, NULL, 0}
        };
        int (*mode_fnc) (eurephiaCTX *ctx, eurephiaSESSION *sess, eurephiaVALUES *cfg, int argc, char **argv);

        assert((ctx != NULL) && (ctx->dbc != NULL));

        mode_fnc = NULL;
        for( i = 1; i < argc; i++ ) {
                switch( eurephia_getopt(&i, argc, argv, cmdargs) ) {
                case 'l':
                        mode_fnc = list_blacklist;
                        break;

                case 'A':
                case 'D':
                        mode_fnc = modify_blacklist;
                        break;

                case 'h':
                        mode_fnc = help_Blacklist2;

                default:
                        break;
                }
                if( mode_fnc != NULL ) {
                        break;
                }
        }

        // If we do not have any known mode defined, exit with error
        if( mode_fnc == NULL )  {
                fprintf(stderr, "%s: Unknown argument.  No mode given\n", MODULE);
                return 1;
        }

        // Allocate memory for our arguments being sent to the mode function
        mode_argv = (char **) calloc(sizeof(char *), (argc - i)+2);
        assert(mode_argv != NULL);

        // Copy over only the arguments needed for the mode
        mode_argc = eurephia_arraycp(i, argc, argv, mode_argv, (argc - i));

        // Call the mode function
        rc = mode_fnc(ctx, sess, cfg, mode_argc, mode_argv);
        free_nullsafe(ctx, mode_argv);

        return rc;

}
