/
/*******************************************************************************\
|*      ARDENMORE 1.1 is copyright 1999-2000 Kirk Johnson                      *|
|*      Ardenmore has been brought to you by the ARDENMORE consortium          *|
|*         Kirk Johnson {Ammaross}	ammaross@crosswinds.net                    *|
|*         Brandon Neily  {Torhan}	torhan_sacras@crosswinds.net               *|
|*         Nathan Smith {Volgrath} volgrath@crosswinds.net                     *|
|*      By using this code, you have agreed to follow the terms of the         *|
|*      ARDENMORE license, in the file Ardenmore/ardenmore.licence             *|
|*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*|
|*    _____   ____     ____     _____  __    _  __ _     __     ____     _____ *|
|*   /@/   ) /@/  )   /@/  \   /@/    /@ \   / /@ V \   /@ \   /@/  )   /@/    *|
|*  /@/ --/ /@/ -<   /@/    | /@/--  /@/\ \ / /@/\_/ \ (@(  ) /@/ -<   /@/--   *|
|* (@(   ( (@(    \ (@(____/ (@(___ (@(  \_/ (@(     _\ \@_/ (@(    \ (@(___   *|
|*                                                                             *|
\*******************************************************************************/

#include "include.h"
#include "interp.h"
#include "tables.h"
#include "magic.h"
#include "lookup.h"
#include "olc.h"
#include "recycle.h"

extern bool		fBootDb;

#define SECEDIT( fun )	bool fun( CHAR_DATA *ch, char *argument )

int 	cmd_lookup			args( ( char *arg ) );
void	save_command_table	args( ( void ) );

SECURITY_DATA	*security_table;

#define	SEC_FILE	DATA_DIR "secgroup.dat"

const	struct	olc_comm_type	security_olc_comm_table	[]	=
{
 { "name",		NULL,			ed_olded,			secedit_name	},
 { "command",	NULL,			ed_olded,			secedit_cmd		},
 { "bit",		NULL,			ed_olded,			secedit_bit		},
 { "list",		NULL,			ed_olded,			secedit_list	},
 { "new",		NULL,			ed_olded,			secedit_new		},
 { "show",		NULL,			ed_olded,			secedit_show	},
 { "commands",	NULL,			ed_olded,			show_commands	},
 { "?",			NULL,			ed_olded,			show_help		},
 { NULL,		NULL,			NULL,				NULL			}
};

int secgroup_lookup( char *arg )
{
	int sec;
	
	for ( sec = 0; !IS_NULLSTR(security_table[sec].name); sec++ )
		if ( LOWER(arg[0]) == LOWER(security_table[sec].name[0])
		&&   !str_prefix( arg, security_table[sec].name ) )
			return sec;

	return -1;
}

int bit_value( char bit )
{ /* *sigh*. Anyone have a better way to do this? */
	switch (bit)
	{
	case 'A':	return A;
	case 'B':	return B;
	case 'C':	return C;
	case 'D':	return D;
	case 'E':	return E;
	case 'F':	return F;
	case 'G':	return G;
	case 'H':	return H;
	case 'I':	return I;
	case 'J':	return J;
	case 'K':	return K;
	case 'L':	return L;
	case 'M':	return M;
	case 'N':	return N;
	case 'O':	return O;
	case 'P':	return P;
	case 'Q':	return Q;
	case 'R':	return R;
	case 'S':	return S;
	case 'T':	return T;
	case 'U':	return U;
	case 'V':	return V;
	case 'W':	return W;
	case 'X':	return X;
	case 'Y':	return Y;
	case 'Z':	return Z;
	case 'a':	return aa;
	case 'b':	return bb;
	case 'c':	return cc;
	case 'd':	return dd;
	case 'e':	return ee;
	default: 	return 0;
	}

	return 0;
}

/* Mod to use instead of bit_value() ?
char *print_flags(int flag)
{
    int count, pos = 0;
    static char buf[52];


    for (count = 0; count < 32;  count++)
    {
        if (IS_SET(flag,1<<count))
        {
            if (count < 26)
                buf[pos] = 'A' + count;
            else
                buf[pos] = 'a' + (count - 26);
            pos++;
        }
    }

    if (pos == 0)
    {
        buf[pos] = '0';
        pos++;
    }

    buf[pos] = '\0';

    return buf;
}
*/

void do_secgroup( CHAR_DATA *ch, char *argument )
{
	CHAR_DATA *victim;
	char arg[MIL];
	int sec;

	if ( IS_NULLSTR( argument ) )
	{
		send_to_char( "Syntax: secgroup <victim> <group>\n\r", ch );
		return;
	}

	argument = one_argument( argument, arg );
	if ( (victim = get_char_world( ch, arg )) == NULL || IS_NPC(victim) )
	{
		send_to_char( "You do not see anyone by that name.\n\r", ch );
		return;
	}
	
	one_argument( argument, arg );
	if ( (sec = secgroup_lookup( arg )) == -1 )
	{
		send_to_char( "That is not a security group!\n\r", ch );
		return;
	}

	if ( !IS_SET( victim->pcdata->secgroups, security_table[sec].bit ) )
	{
		SET_BIT( victim->pcdata->secgroups, security_table[sec].bit );
		printf_to_char( ch, "%s added to security group: %s.\n\r", 
			victim->name, security_table[sec].name );
		printf_to_char( victim, "You were added to the security group: %s.\n\r",
			security_table[sec].name );
	}
	else
	{
		REMOVE_BIT( victim->pcdata->secgroups, security_table[sec].bit );
		printf_to_char( ch, "%s removed from security group: %s.\n\r", 
			victim->name, security_table[sec].name );
	}

	return;
}	
	
void secedit (CHAR_DATA * ch, char *argument)
{
	if ( ch->level < MAX_LEVEL )
	{
		send_to_char ("SPEdit : Insufficiant security to edit security groups.\n\r", ch);
		edit_done(ch);
		return;
	}

	if (!str_cmp (argument, "done"))
	{
		edit_done (ch);
		return;
	}

	if (!str_cmp (argument, "save"))
	{
		save_security_table();
		return;
	}

	if ( emptystring(argument) )
	{
		secedit_show(ch, argument);
		return;
	}

	/* Search Table and Dispatch Command. */
	if ( !process_olc_command(ch, argument, security_olc_comm_table) )
		interpret(ch, argument);

	return;
}

void do_secedit(CHAR_DATA *ch, char *argument)
{
    SECURITY_DATA *pSec;
    int sec;

    if ( IS_NPC(ch) )
    	return;

    if ( ch->level < MAX_LEVEL )
    {
    	send_to_char( "SecEdit: Insufficiant security to edit security groups.\n\r", ch );
    	return;
    }

    if ( IS_NULLSTR(argument) )
    {
    	send_to_char( "Syntax: SecEdit [group]\n\r", ch );
    	return;
    }

	if ( !str_cmp( argument, "list" ) )
	{
		secedit_list(ch,argument);
		return;
	}

    if ( !str_cmp( argument, "new" ) )
    {
    char command[MIL];
		argument = one_argument( argument, command );
		if ( secedit_new(ch, command) )
			save_security_table();
		return;
    }

    if ( (sec = secgroup_lookup(argument)) == -1 )
    {
    	send_to_char( "SecEdit: Security group does not exist.\n\r", ch );
    	return;
    }

    pSec = &security_table[sec];

    ch->desc->pEdit=(void *)pSec;
    ch->desc->editor= ED_SECURITY;

    return;
}

SECEDIT( secedit_list )
{
	BUFFER *pBuf;
	char buf[MSL];
	int i;

	pBuf = new_buf();

	sprintf( buf, "Num %-18.18s Num %-18.18s Num %-18.18s\n\r",
			"Name", "Name", "Name" );
	add_buf( pBuf, buf );

	for ( i = 0; !IS_NULLSTR(security_table[i].name); i++ )
	{
		sprintf( buf, "%3d %-18.18s", i+1,
		security_table[i].name );
		if ( i % 3 == 2 )
			strcat( buf, "\n\r" );
		else
			strcat( buf, " " );
		add_buf( pBuf, buf );
	}

	if ( i % 3 != 0 )
		add_buf( pBuf, "\n\r" );

	page_to_char( buf_string(pBuf), ch );
	free_buf(pBuf);
	return FALSE;
}


SECEDIT( secedit_show )
{
	SECURITY_DATA *pSec;
	BUFFER *pBuf;
	char buf[MSL];
	char buf2[MSL];
	int i,j;

	EDIT_SECURITY( ch, pSec );

	sprintf( buf,	"Name     : [%s]\n\r",		pSec->name );
	send_to_char( buf, ch );

	sprintf( buf,   "Bit      : [%s]\n\r", 		fwrite_flag( pSec->bit, buf2 ) );
	send_to_char( buf, ch );

	send_to_char(   "Commands:\n\r", ch );

	pBuf = new_buf();
	sprintf( buf, "Num %-12s Num %12s Num %-12s Num %12s\n\r",	"Name", "Name", "Name", "Name" );
	add_buf( pBuf, buf );
	for ( i = 0, j = 0; !IS_NULLSTR(cmd_table[i].name); i++ )
	{
		if ( IS_SET(cmd_table[i].secgroup, pSec->bit) )
		{
			sprintf( buf, "%3d %-12s", ++j, cmd_table[i].name );
			if ( j % 4 == 0 )
				strcat( buf, "\n\r" );
			else
				strcat( buf, " " );
			add_buf( pBuf, buf );
		}
	}

	if ( j % 4 != 0 )
		add_buf( pBuf, "\n\r" );
	page_to_char( buf_string(pBuf), ch );
	free_buf(pBuf);

	return FALSE;
}

SECEDIT( secedit_name )
{
	SECURITY_DATA *pSec;
	DESCRIPTOR_DATA *d;
	long bit;

	EDIT_SECURITY( ch, pSec );
	
	if ( IS_NULLSTR(argument) )
	{
		send_to_char( "Syntax: name [name]\n\r", ch );
		return FALSE;
	}
	
	if ( secgroup_lookup(argument) != -1 )
	{
		send_to_char( "A security group with that name already exists.\n\r", ch );
		return FALSE;
	}

	bit = pSec->bit;
	for ( d = descriptor_list; d; d = d->next )
	{
		if ( CH(d) != NULL && CH(d)->pcdata != NULL )
			REMOVE_BIT( CH(d)->pcdata->secgroups, bit );
	}

	free_string(pSec->name);
	pSec->name = str_dup(argument);

	send_to_char( "Ok.\n\r", ch );
	return TRUE;
}

SECEDIT( secedit_bit )
{
	SECURITY_DATA *pSec;
	long bit;
	int i;

	EDIT_SECURITY( ch, pSec );

//	one_argument( argument, arg );
	if ( IS_NULLSTR(argument) )
	{
		send_to_char( "Syntax: bit [bit letter]\n\r", ch );
		return FALSE;
	}

	bit = bit_value(argument[0]);

	if ( bit <= 0 || bit > ee )
	{
		send_to_char( "SecEdit: Invalid bit setting.\n\r", ch );
		return FALSE;
	}

	for ( i = 0; !IS_NULLSTR( security_table[i].name ); i++ )
	{
		if ( security_table[i].bit == bit )
		{
			send_to_char( "That bit is already being used.\n\r", ch );
			return FALSE;
		}
	}

	if (pSec->bit != 0)
	{
	DESCRIPTOR_DATA *d;
	CHAR_DATA *vict;
	
		for ( d = descriptor_list; d; d = d->next )
		{
			vict = CH(d);
			if ( vict != NULL && !IS_NPC(vict) && vict->pcdata != NULL )
			{
				REMOVE_BIT(vict->pcdata->secgroups, pSec->bit);
				save_char_obj( vict );
			}
		}
	}

	pSec->bit = bit;
	
	send_to_char( "Ok.\n\r", ch );
	return TRUE;
}


SECEDIT( secedit_cmd )
{
	SECURITY_DATA *pSec;
	char arg[MIL];
	int i;

	EDIT_SECURITY( ch, pSec );
	
	if ( IS_NULLSTR(argument) )
	{
		send_to_char( "Syntax: cmd [add/remove] [command]\n\r", ch );
		return FALSE;
	}

	argument = one_argument( argument, arg );
	if ( ( i = cmd_lookup(argument) ) == -1 )
	{
		send_to_char( "SecEdit: That command does not exist.\n\r", ch );
		return FALSE;
	}

	if ( !str_cmp( arg, "add" ) )
	{
		SET_BIT( cmd_table[i].secgroup, pSec->bit );
		cmd_table[i].level = MAX_LEVEL+1; // So no one can use it without permission.
	}
	else if ( !str_cmp( arg, "remove" ) )
	{
		REMOVE_BIT( cmd_table[i].secgroup, pSec->bit );
		cmd_table[i].level = 160;
	}
	else
	{
		send_to_char( "Syntax: command [add/remove] [command]\n\r", ch );
		return FALSE;
	}

	save_command_table();
	send_to_char( "Ok.\n\r", ch );
	return TRUE;
}


SECEDIT( secedit_new )
{
	DESCRIPTOR_DATA *d;
	CHAR_DATA *tch;
	SECURITY_DATA *new_table;
	int i;

	if ( IS_NULLSTR(argument) )
	{
		send_to_char( "Syntax: new [name-of-new-security-group]\n\r", ch );
		return FALSE;
	}

	if ( secgroup_lookup(argument) != -1 )
	{
		send_to_char ("SecEdit: A security group with that name already exists!\n\r",ch);
		return FALSE;
	}

	for ( d = descriptor_list; d; d = d->next )
	{
		if ( d->connected != CON_PLAYING || (tch = CH(d)) == NULL || tch->desc == NULL )
			continue;

		if ( tch->desc->editor == ED_SECURITY )
			edit_done(tch);
	}

	for ( i = 0; !IS_NULLSTR( security_table[i].name ); i++ )
		;

	if ( i >= 32 )
	{
		send_to_char( "SecEdit: Can not create any more security groups.\n\r", ch );
		return FALSE;
	}

	/* reallocate the table */
	new_table = realloc (security_table, sizeof(struct security_type) * ( i + 1 ) );

	if (!new_table) /* realloc failed */
	{
		send_to_char ("SecEdit: Failed to realloc(). Brace for impact.\n\r",ch);
		return FALSE;
	}

	security_table					= new_table;

	security_table[i].name			= str_dup (argument);
	security_table[i].bit			= 0;

	security_table[i+1].name		= NULL;

	ch->desc->editor	= ED_SECURITY;
	ch->desc->pEdit		= (void *) &security_table[i];

	send_to_char ("New security group created.\n\r",ch);
	return TRUE;
}

SECEDIT( secedit_delete )
{
	DESCRIPTOR_DATA *d;
	CHAR_DATA *tch;
	int i,j,iSec,temp;
	SECURITY_DATA *new_table;

	if ( IS_NULLSTR(argument) )
	{
		send_to_char( "Syntax: delete [name-of-security-group-to-delete]\n\r", ch );
		return FALSE;
	}

	if ( (iSec = secgroup_lookup(argument)) == -1)
	{
		send_to_char( "SecEdit: That command does not exist.\n\r", ch );
		return FALSE;
	}

	for ( d = descriptor_list; d; d = d->next )
	{
		if ( d->connected != CON_PLAYING || (tch = CH(d)) == NULL || tch->desc == NULL )
			continue;

		if ( tch->desc->editor == ED_SECURITY )
		  	edit_done(tch);
	}
	
	for ( d = descriptor_list; d; d = d->next )
	{
		tch = CH(d);
		if ( tch != NULL && !IS_NPC(tch) && tch->pcdata != NULL )
			REMOVE_BIT(tch->pcdata->secgroups, security_table[iSec].bit);
	}

	for ( i = 0; !IS_NULLSTR( security_table[i].name ); i++ )
		;

	new_table = malloc (sizeof(SECURITY_DATA) * i);

	if (!new_table)
	{
		send_to_char ("Memory allocation failed. Brace for impact...\n\r",ch);
		return FALSE;
	}

	temp = i;
	for (i = 0, j = 0; i < temp+1; i++)
		if (i != iSec) /* copy, increase only if copied */
		{
			new_table[j] = security_table[i];
			j++;
		}

	free (security_table);
	security_table = new_table;

	security_table[temp].name = NULL;

	send_to_char ("Security group deleted.\n\r",ch);
	return TRUE;
}