eldhamud/boards/
eldhamud/clans/
eldhamud/classes/
eldhamud/councils/
eldhamud/deity/
eldhamud/doc/
eldhamud/doc/DIKU/
eldhamud/doc/MERC/
eldhamud/doc/mudprogs/
eldhamud/houses/
/****************************************************************************
 *   _______  _        ______            _______  _______           ______   *
 *  (  ____ \( \      (  __  \ |\     /|(  ___  )(       )|\     /|(  __  \  *
 *  | (    \/| (      | (  \  )| )   ( || (   ) || () () || )   ( || (  \  ) *
 *  | (__    | |      | |   ) || (___) || (___) || || || || |   | || |   ) | *
 *  |  __)   | |      | |   | ||  ___  ||  ___  || |(_)| || |   | || |   | | *
 *  | (      | |      | |   ) || (   ) || (   ) || |   | || |   | || |   ) | *
 *  | (____/\| (____/\| (__/  )| )   ( || )   ( || )   ( || (___) || (__/  ) *
 *  (_______/(_______/(______/ |/     \||/     \||/     \|(_______)(______/  *
 *              +-+-+-+  +-+-+-+-+-+-+-+  +-+-+-+-+-+-+-+-+-+-+              *
 *              |T|h|e|  |O|a|k|l|a|n|d|  |C|h|r|o|n|i|c|l|e|s|              *
 *              +-+-+-+  +-+-+-+-+-+-+-+  +-+-+-+-+-+-+-+-+-+-+              *
 * ------------------------------------------------------------------------- *
 * EldhaMUD code (C) 2003-2005 by Robert Powell (Tommi)                      *
 * EldhaMUD Team: Celest, Altere and Krelowyn                                *
 * ------------------------------------------------------------------------- *
 *                                                                           *
 ****************************************************************************/
/****************************************************************************
 * [S]imulated [M]edieval [A]dventure multi[U]ser [G]ame      |   \\._.//   *
 * -----------------------------------------------------------|   (0...0)   *
 * SMAUG 1.4 (C) 1994, 1995, 1996, 1998  by Derek Snider      |    ).:.(    *
 * -----------------------------------------------------------|    {o o}    *
 * SMAUG code team: Thoric, Altrag, Blodkai, Narn, Haus,      |   / ' ' \   *
 * Scryn, Rennard, Swordbearer, Gorog, Grishnakh, Nivek,      |~'~.VxvxV.~'~*
 * Tricops and Fireblade                                      |             *
 * ------------------------------------------------------------------------ *
 * Merc 2.1 Diku Mud improvments copyright (C) 1992, 1993 by Michael        *
 * Chastain, Michael Quan, and Mitchell Tse.                                *
 * Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer,          *
 * Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe.     *
 * ------------------------------------------------------------------------ *
 *                            Ban module by Shaddai                         *
 ****************************************************************************/



#include <string.h>
#include <ctype.h>
#include <stdio.h>
#include <time.h>
#include "mud.h"


/* Local functions */
void fread_ban args ( ( FILE *fp, int type ) );
bool check_expire args ( ( BAN_DATA *ban ) );
void dispose_ban args ( ( BAN_DATA *ban, int type ) );
void free_ban args ( ( BAN_DATA *pban ) );

/* Global Variables */

BAN_DATA *first_ban;
BAN_DATA *last_ban;
BAN_DATA *first_ban_class;
BAN_DATA *last_ban_class;
BAN_DATA *first_ban_race;
BAN_DATA *last_ban_race;


/*
 * Load all those nasty bans up :)
 * 	Shaddai
 */
void
load_banlist ( void )
{
  char buf[MAX_STRING_LENGTH];
  char *word;
  FILE *fp;
  bool fMatch = FALSE;

  if (!(fp = fopen (SYSTEM_DIR BAN_LIST, "r")))
    {
      bug ("Save_banlist: Cannot open " BAN_LIST, 0);
      perror (BAN_LIST);
      return;
    }
    for ( ; ; )
    {
	word = feof (fp) ? "END" : fread_word ( fp );
	fMatch = FALSE;
	switch ( UPPER ( word[0] ) )
	{
	   case 'C':
		if ( !str_cmp ( word, "CLASS" ) )
		{
			fread_ban ( fp, BAN_CLASS );
			fMatch = TRUE;
		}
		break;
	   case 'E':
		if ( !str_cmp ( word, "END"))/*File should always contain END*/
		{
			fclose ( fp );
			log_string ( "Done." );
			return;
		}
           case 'R':
		if ( !str_cmp ( word, "RACE" ) )
		{
			fread_ban ( fp, BAN_RACE );
			fMatch = TRUE;
		}
		break;
	   case 'S':
		if ( !str_cmp ( word, "SITE" ) )
		{
			fread_ban ( fp, BAN_SITE );
			fMatch = TRUE;
		}
		break;
	}
	if ( !fMatch )
     	{
        	sprintf ( buf, "Load_banlist: no match: %s", word );
        	bug ( buf, 0 );
     	} /* End of switch statement */
   } /* End of for loop */
}

/*
 * Load up one class or one race ban structure.
 */

void
fread_ban ( FILE *fp, int type )
{
  BAN_DATA *pban;
  int i = 0;
  bool fMatch = FALSE;
  
  CREATE ( pban, BAN_DATA, 1 );

  pban->name = fread_string_nohash ( fp );
  pban->level = fread_number( fp );
  pban->duration = fread_number( fp );
  pban->unban_date = fread_number( fp );
  if ( type == BAN_SITE ) { /* Sites have 2 extra numbers written out */
	pban->prefix = fread_number( fp );
	pban->suffix = fread_number( fp );
  }
  pban->warn = fread_number( fp );
  pban->ban_by = fread_string_nohash( fp );
  pban->ban_time = fread_string_nohash( fp );
  pban->note = fread_string( fp );

  /* Need to lookup the class or race number if it is of that type */

  if ( type == BAN_CLASS )
  	for ( i = 0; i < MAX_CLASS; i++ )
  	{
		if ( !str_cmp( class_table[i]->who_name, pban->name ) )
		{
			fMatch = TRUE;
			break;
		}
  	}
  else if ( type == BAN_RACE )
  	for ( i = 0; i < MAX_RACE; i++ )
  	{
		if ( !str_cmp( race_table[i]->race_name, pban->name ) )
		{
			fMatch = TRUE;
			break;
		}
  	}
  else if ( type == BAN_SITE )
	for ( i = 0; i < strlen( pban->name); i ++ )
	{
	  if ( pban->name[i] == '@' )
	  {
		char *temp;
		char *temp2;

		temp = str_dup( pban->name );
		temp[i] = '\0';
		temp2 = &pban->name[i+1];
                DISPOSE( pban->name );
		pban->name = str_dup( temp2 );
		DISPOSE( temp );
		break;
	  }
	}

  if ( type == BAN_RACE || type == BAN_CLASS ) {
  	if ( fMatch )
		pban->flag = i;
  	else /* The file is corupted throw out this ban structure */
  	{
		bug("Bad class structure %d.\n\r", i );
		free_ban( pban );
		return;
  	}
  }
  if ( type == BAN_CLASS )
  	LINK( pban, first_ban_class, last_ban_class, next, prev );
  else if ( type == BAN_RACE )
  	LINK( pban, first_ban_race, last_ban_race, next, prev );
  else if ( type == BAN_SITE )
	LINK( pban, first_ban, last_ban, next, prev );
  else /* Bad type throw out the ban structure */
  {
	bug("Fread_ban: Bad type %d", type );
	free_ban( pban );
  }
  return;
}

/*
 * Saves all bans, for sites, classes and races.
 * 	Shaddai
 */

void
save_banlist ( void )
{
  BAN_DATA *pban;
  FILE *fp;

  fclose (fpReserve);
  if (!(fp = fopen (SYSTEM_DIR BAN_LIST, "w")))
    {
      bug ("Save_banlist: Cannot open " BAN_LIST, 0);
      perror (BAN_LIST);
      fpReserve = fopen (NULL_FILE, "r");
      return;
    }

  /* Print out all the site bans */

  for (pban = first_ban; pban; pban = pban->next) {
  	fprintf (fp, "SITE\n" );
	fprintf (fp, "%s~\n", pban->name );
	fprintf (fp, "%d %d %d %d %d %d\n", pban->level, pban->duration,
		pban->unban_date, pban->prefix, pban->suffix, pban->warn );
	fprintf (fp, "%s~\n%s~\n%s~\n", pban->ban_by, pban->ban_time,
		pban->note );
    }
  
  /* Print out all the race bans */

  for (pban = first_ban_race; pban; pban = pban->next ) {
	fprintf (fp, "RACE\n" );
	fprintf (fp, "%s~\n", pban->name );
	fprintf (fp, "%d %d %d %d\n", pban->level, pban->duration,
		pban->unban_date, pban->warn );
	fprintf (fp, "%s~\n%s~\n%s~\n", pban->ban_by, pban->ban_time,
		pban->note );
    }

  /* Print out all the class bans */

  for (pban = first_ban_class; pban; pban = pban->next ) {
	fprintf (fp, "CLASS\n" );
	fprintf (fp, "%s~\n", pban->name );
	fprintf (fp, "%d %d %d %d\n", pban->level, pban->duration,
		pban->unban_date, pban->warn );
	fprintf (fp, "%s~\n%s~\n%s~\n", pban->ban_by, pban->ban_time,
		pban->note );
    }
  fprintf (fp, "END\n"); /* File must have an END even if empty */
  fclose (fp);
  fpReserve = fopen (NULL_FILE, "r");
  return;
}

/*
 * The main command for ban, lots of arguments so be carefull what you
 * change here.		Shaddai
 */

void
do_ban ( CHAR_DATA *ch, char *argument )
{
  char arg1[MAX_INPUT_LENGTH];
  char arg2[MAX_INPUT_LENGTH];
  char arg3[MAX_INPUT_LENGTH];
  char arg4[MAX_INPUT_LENGTH];
  char *temp;
  BAN_DATA *pban;
  int value = 0, btime;

  if (IS_NPC (ch)) /* Don't want mobs banning sites ;) */
  {
      send_to_char ("Monsters are too dumb to do that!\n\r", ch);
      return;
  }

  if (!ch->desc) /* No desc means no go :) */
  {
      bug ("do_ban: no descriptor", 0);
      return;
  }

  set_char_color( AT_IMMORT, ch );
  argument = one_argument( argument, arg1 );
  argument = one_argument( argument, arg2 );
  argument = one_argument( argument, arg3 );
  argument = one_argument( argument, arg4 );

  /* Do we have a time duration for the ban? */

  if ( arg4[0] != '\0' && is_number( arg4 ) )
	btime = atoi( arg4 );
  else
	btime = -1;

  
  /* -1 is default, but no reason the time should be greater than 1000
   * or less than 1, after all if it is greater than 1000 you are talking
   * around 3 years.
   */

  if ( btime != -1 &&  ( btime < 1 || btime > 1000 ) )
  {
      send_to_char("Time value is -1 (forever) or from 1 to 1000.\n\r", ch);
      return;
  }

  /*
   * Need to be carefull with sub-states or everything will get messed up.
   */

  switch ( ch->substate ) {
  default:
      bug ("do_ban: illegal substate", 0);
      return;
  case SUB_RESTRICTED:
      send_to_char ("You cannot use this command from within another command.\n\r", ch);
      return;
  case SUB_NONE:
	ch->tempnum = SUB_NONE;
	break;

   /* Returning to end the editing of the note */

   case SUB_BAN_DESC:
	add_ban( ch, "", "",0, 0 );
	return;
  }
  if ( arg1[0] == '\0' )
	goto syntax_message;

  /* If no args are sent after the class/site/race, show the current banned
   * items.  Shaddai
   */

  if ( !str_cmp ( arg1, "site" ) ) {
	if ( arg2[0] == '\0' )
	{
		show_bans( ch, BAN_SITE );
		return;
	}

	/* Are they high enough to ban sites? */

	if ( get_trust(ch) < sysdata.ban_site_level ) {
		ch_printf(ch,"You must be %d level to add bans.\n\r",sysdata.ban_site_level);
		return;
	}
	if ( arg3[0] == '\0' )
		goto syntax_message;
	if ( !add_ban ( ch, arg2, arg3, btime, BAN_SITE ) )
		return;
  }
  else if ( !str_cmp ( arg1, "race" ) ) {
	if ( arg2[0] == '\0' )
	{
		show_bans( ch, BAN_RACE );
		return;
	}

	/* Are they high enough level to ban races? */

	if ( get_trust(ch)  < sysdata.ban_race_level ) {
		ch_printf(ch,"You must be %d level to add bans.\n\r",sysdata.ban_race_level);
		return;
	}
	if ( arg3[0] == '\0' )
		goto syntax_message;
	if ( !add_ban(ch, arg2, arg3, btime, BAN_RACE ) )
		return;
  }
  else if ( !str_cmp ( arg1, "class" ) ) {
	if ( arg2[0] == '\0' )
	{
		show_bans( ch, BAN_CLASS );
		return;
	}

        /* Are they high enough to ban classes? */

	if ( get_trust(ch) < sysdata.ban_class_level ) {
		ch_printf(ch,"You must be %d level to add bans.\n\r",sysdata.ban_class_level);
		return;
	}
	if ( arg3[0] == '\0' )
		goto syntax_message;
	if ( !add_ban(ch, arg2, arg3, btime, BAN_CLASS ) )
		return;
  }
  else if ( !str_cmp ( arg1, "show" ) ) {
	
	/* This will show the note attached to a ban */

	if ( arg2[0] == '\0' || arg3[0] == '\0' )
		goto syntax_message;
        temp = arg3;
  	if ( arg3[0] == '#' ) /* Use #1 to show the first ban*/
  	{
        	temp = arg3;
        	temp++;
        	if ( !is_number( temp ) )
        	{
                	send_to_char("Which ban # to show?\n\r", ch);
                	return;
        	}
        	value = atoi(temp);
               if ( value < 1 )
        	{
			send_to_char ("You must specify a number greater than 0.\n\r",ch);
			return;
		}
	  }
	if ( !str_cmp ( arg2, "site" ) ) 
        {
		pban = first_ban;
		if ( temp[0] == '*' )
			temp++;
		if ( temp[strlen(temp)-1] == '*' )
			temp[strlen(temp)-1] = '\0';
	}
	else if ( !str_cmp ( arg2, "class" ) )
		pban = first_ban_class;
	else if ( !str_cmp ( arg2, "race" ) )
		pban = first_ban_race;
	else 
		goto syntax_message;
	for ( ; pban; pban = pban->next ) 
	  if ( value == 1 || !str_cmp ( pban->name, temp ) )
		break;
	  else if ( value > 1 )
		value--;
		
	if ( !pban ) {
		send_to_char ("No such ban.\n\r", ch);
		return;
	}	
	ch_printf(ch, "Banned by: %s\n\r", pban->ban_by );
	send_to_char ( pban->note, ch );
	return;
  }
  else
	goto syntax_message;
  return;

/* Catch all syntax message, make sure that return stays above this or you
 * will get the syntax message everytime you issue the command even if it
 * is a valid one.  Shaddai
 */

syntax_message:
        send_to_char("Syntax: ban site  <address> <type> <duration>\n\r", ch );
        send_to_char("Syntax: ban race  <race>    <type> <duration>\n\r", ch );
        send_to_char("Syntax: ban class <class>   <type> <duration>\n\r", ch );
	send_to_char("Syntax: ban show  <field>   <number>\n\r", ch );
	send_to_char("Ban site lists current bans.\n\r", ch );
	send_to_char("Duration is the length of the ban in days.\n\r", ch );
	send_to_char("Type can be:  newbie, mortal, all, warn or level.\n\r", ch );
	send_to_char("In ban show, the <field> is site, race or class,", ch);
	send_to_char("  and the <number> is the ban number.\n\r", ch );
        return;
}


/*
 * Allow a already banned site/class or race.  Shaddai
 */

void
do_allow ( CHAR_DATA *ch, char * argument )
{
  BAN_DATA *pban;
  char arg1[MAX_INPUT_LENGTH];
  char arg2[MAX_INPUT_LENGTH];
  char *temp = NULL;
  bool fMatch = FALSE;
  int	value = 0;

  if (IS_NPC (ch)) /* No mobs allowing sites */
  {
      send_to_char ("Monsters are too dumb to do that!\n\r", ch);
      return;
  }

  if (!ch->desc) /* No desc is a bad thing */
  {
      bug ("do_allow: no descriptor", 0);
      return;
  }

  argument = one_argument( argument, arg1 );
  argument = one_argument( argument, arg2 );

  set_char_color (AT_IMMORT, ch);

  if ( arg1[0] == '\0' || arg2[0] == '\0')
	goto syntax_message;
  if ( arg2[0] == '#' ) /* Use #1 to ban the first ban in the list specified */
  {
	temp = arg2;
	temp++;
	if ( !is_number( temp ) )
	{
		send_to_char("Which ban # to allow?\n\r", ch);
		return;
	}
	value = atoi(temp);
  }
  if ( !str_cmp( arg1, "site" ) ) {
	if ( !value ) {
	  if ( strlen(arg2) < 2 )
	  {
	    send_to_char("You have to have at least 2 chars for a ban\n\r", ch);
	    send_to_char("If you are trying to allow by number use #\n\r",ch);
	    return;
	  }

	  temp = arg2;
	  if ( arg2[0] == '*' )
		  temp++;		
	  if ( temp[strlen(temp) - 1] == '*' )
		  temp[ strlen(temp) -1] = '\0';
 	}
	
	for ( pban = first_ban; pban; pban = pban->next )
	{
		/* Need to make sure we dispose properly of the ban_data 
                 * Or memory problems will be created.
		 * Shaddai
		 */

		if ( value == 1 || !str_cmp ( pban->name, temp ) )
		{
			fMatch = TRUE;
			dispose_ban( pban, BAN_SITE );
			break;
		}
		if ( value > 1 )
			value--;
	}
  }
  else if ( !str_cmp( arg1, "race" ) ) {

	arg2[0] = toupper( arg2[0] );
	for ( pban = first_ban_race; pban; pban = pban->next )
	{
		/* Need to make sure we dispose properly of the ban_data 
                 * Or memory problems will be created.
		 * Shaddai
		 */

		if ( value == 1 || !str_cmp ( pban->name, arg2 ) )
		{
			fMatch = TRUE;
			dispose_ban( pban, BAN_RACE );
			break;
		}
		if ( value > 1 )
			value--;
	}
  }
  else if ( !str_cmp( arg1, "class" ) ) {

	arg2[0] = toupper( arg2[0] );
	for ( pban = first_ban_class; pban; pban = pban->next )
	{
		/* Need to make sure we dispose properly of the ban_data 
                 * Or memory problems will be created.
		 * Shaddai
		 */

		if ( value == 1 || !str_cmp ( pban->name, arg2 ) )
		{
			fMatch = TRUE;
			dispose_ban( pban, BAN_CLASS );
			break;
		}
		if ( value > 1 )
			value--;
	}
  }
  else
	goto syntax_message;

  if ( fMatch )
  {
	save_banlist();
  	ch_printf(ch, "%s is now allowed.\n\r", arg2 );
  }
  else
	ch_printf(ch, "%s was not banned.\n\r", arg2 );
  return;

/*
 *  Make sure that return above stays in!
 */

syntax_message:
	send_to_char ("Syntax: allow site  <address>\n\r", ch );
	send_to_char ("Syntax: allow race  <race>\n\r", ch );
	send_to_char ("Syntax: allow class <class>\n\r", ch );
	return;
}

/* 
 *  Sets the warn flag on bans.
 */
void
do_warn ( CHAR_DATA *ch, char *argument )
{
  char arg1[MAX_STRING_LENGTH];
  char arg2[MAX_STRING_LENGTH];
  char *name;
  int  count = -1, type;
  BAN_DATA *pban, *start, *end;

  /* 
   * Don't want mobs or link-deads doing this.
   */

  if (IS_NPC (ch))
  {
      send_to_char ("Monsters are too dumb to do that!\n\r", ch);
      return;
  }

  if (!ch->desc)
  {
      bug ("do_warn: no descriptor", 0);
      return;
  }

  argument = one_argument( argument, arg1 );
  argument = one_argument( argument, arg2 );

  if ( arg1[0] == '\0' || arg2[0] == '\0' )
	goto syntax_message;

  if ( arg2[0] == '#' ) {
  	name = arg2;
	name++;
	if ( !is_number( name ) )
		goto syntax_message;
	count = atoi( name );
	if ( count < 1 ) {
		send_to_char("The number has to be above 0.\n\r", ch );
		return;
	}
  }
 
  /*
   *  We simply set up which ban list we will be looking at here.
   */
  if ( !str_cmp( arg1, "class") )
        type = BAN_CLASS;
  else if ( !str_cmp( arg1, "race" ) )
        type = BAN_RACE;
  else if ( !str_cmp( arg1, "site" ) )
        type = BAN_SITE;
  else
        type = -1;
 

  if ( type == BAN_CLASS ) {
	pban = first_ban_class;
	start = first_ban_class;
	end = last_ban_class;
	arg2[0] = toupper( arg2[0] );
  }
  else if ( type == BAN_RACE ) {
	pban = first_ban_race;
	start = first_ban_race;
	end = last_ban_race;
	arg2[0] = toupper( arg2[0] );
  }
  else if ( type == BAN_SITE ) {
	pban = first_ban;
	start = first_ban;
	end = last_ban;
  }
  else 
	goto syntax_message;
  for ( ; pban && count != 0; count--, pban = pban->next )
	if ( count == -1 && !str_cmp(pban->name, arg2 ) )
		break;
  if ( pban )
  {
	/* If it is just a warn delete it, otherwise remove the warn flag. */
       
	if ( pban->warn ){
		if ( pban->level == BAN_WARN ) {
			dispose_ban( pban, type );
		send_to_char("Warn has been deleted.\n\r", ch );
		}
		else {
			pban->warn = FALSE;
			send_to_char("Warn turned off.\n\r", ch);
		}
	}
	else {
		pban->warn = TRUE;
		send_to_char("Warn turned on.\n\r", ch );
	}
	save_banlist( );
  }
  else {
        ch_printf(ch, "%s was not found in the ban list.\n\r", arg2 );
	return;
  }
  return;
 /* The above return has to stay in! */
syntax_message:
	send_to_char ("Syntax: warn class <field>\n\r", ch );
	send_to_char ("Syntax: warn race  <field>\n\r", ch );
	send_to_char ("Syntax: warn site  <field>\n\r", ch );
	send_to_char ("Field is either #(ban_number) or the site/class/race.\n\r", ch);
	send_to_char ("Example:  warn class #1\n\r", ch );
	return;
}

/*
 *  This actually puts the new ban into the proper linked list and
 *  initializes its data.  Shaddai
 */

int add_ban( CHAR_DATA * ch, char *arg1, char *arg2, int btime, int type )
{
   char arg[MAX_STRING_LENGTH];
   char buf[MAX_STRING_LENGTH];
   BAN_DATA *pban, *temp;
   struct tm *tms;
   char *name;
   int level, i, value;

   /*
    * Should we check to see if they have dropped link sometime in between 
    * * writing the note and now?  Not sure but for right now we won't since
    * * do_ban checks for that.  Shaddai
    */

   switch ( ch->substate )
   {
      default:
         bug( "%s", "add_ban: illegal substate" );
         return 0;
      case SUB_RESTRICTED:
         send_to_char( "You cannot use this command from within another command.\n\r", ch );
         return 0;
      case SUB_NONE:
      {
         one_argument( arg1, arg );
         smash_tilde( arg );  /* Make sure the immortals don't put a ~ in it. */

         if( arg[0] == '\0' || arg2[0] == '\0' )
            return 0;

         if( is_number( arg2 ) )
         {
            level = atoi( arg2 );
            if( level < 0 || level > LEVEL_SUPREME )
            {
               ch_printf( ch, "Level range is from 0 to %d.\n\r", LEVEL_SUPREME );
               return 0;
            }
         }
         else if( !str_cmp( arg2, "all" ) )
            level = LEVEL_SUPREME;
         else if( !str_cmp( arg2, "newbie" ) )
            level = 1;
         else if( !str_cmp( arg2, "mortal" ) )
            level = LEVEL_AVATAR;
         else if( !str_cmp( arg2, "warn" ) )
            level = BAN_WARN;
         else
         {
            bug( "%s", "Bad string for flag in add_ban." );
            return 0;
         }

         switch ( type )
         {
            case BAN_CLASS:
               if( arg[0] == '\0' )
                  return 0;
               if( is_number( arg ) )
                  value = atoi( arg );
               else
               {
                  for( i = 0; i < MAX_CLASS; i++ )
                     if( !str_cmp( class_table[i]->who_name, arg ) )
                        break;
                  value = i;
               }
               if( value < 0 || value >= MAX_CLASS )
               {
                  send_to_char( "Unknown class.\n\r", ch );
                  return 0;
               }
               for( temp = first_ban_class; temp; temp = temp->next )
               {
                  if( temp->flag == value )
                  {
                     if( temp->level == level )
                     {
                        send_to_char( "That entry already exists.\n\r", ch );
                        return 0;
                     }
                     else
                     {
                        temp->level = level;
                        if( temp->level == BAN_WARN )
                           temp->warn = TRUE;
                        sprintf( buf, "%24.24s", ctime( &current_time ) );
                        temp->ban_time = str_dup( buf );
                        if( btime > 0 )
                        {
                           temp->duration = btime;
                           tms = localtime( &current_time );
                           tms->tm_mday += btime;
                           temp->unban_date = mktime( tms );
                        }
                        else
                        {
                           temp->duration = -1;
                           temp->unban_date = -1;
                        }
                        if( temp->ban_by )
                           DISPOSE( temp->ban_by );
                        temp->ban_by = str_dup( ch->name );
                        send_to_char( "Updated entry.\n\r", ch );
                        return 1;
                     }
                  }
               }
               CREATE( pban, BAN_DATA, 1 );
               pban->name = str_dup( class_table[value]->who_name );
               pban->flag = value;
               pban->level = level;
               pban->ban_by = str_dup( ch->name );
               LINK( pban, first_ban_class, last_ban_class, next, prev );
               break;
            case BAN_RACE:
               if( is_number( arg ) )
                  value = atoi( arg );
               else
               {
                  for( i = 0; i < MAX_RACE; i++ )
                     if( !str_cmp( race_table[i]->race_name, arg ) )
                        break;
                  value = i;
               }
               if( value < 0 || value >= MAX_RACE )
               {
                  send_to_char( "Unknown race.\n\r", ch );
                  return 0;
               }
               for( temp = first_ban_race; temp; temp = temp->next )
               {
                  if( temp->flag == value )
                  {
                     if( temp->level == level )
                     {
                        send_to_char( "That entry already exists.\n\r", ch );
                        return 0;
                     }
                     else
                     {
                        temp->level = level;
                        if( temp->level == BAN_WARN )
                           temp->warn = TRUE;
                        sprintf( buf, "%24.24s", ctime( &current_time ) );
                        temp->ban_time = str_dup( buf );
                        if( btime > 0 )
                        {
                           temp->duration = btime;
                           tms = localtime( &current_time );
                           tms->tm_mday += btime;
                           temp->unban_date = mktime( tms );
                        }
                        else
                        {
                           temp->duration = -1;
                           temp->unban_date = -1;
                        }
                        if( temp->ban_by )
                           DISPOSE( temp->ban_by );
                        temp->ban_by = str_dup( ch->name );
                        send_to_char( "Updated entry.\n\r", ch );
                        return 1;
                     }
                  }
               }
               CREATE( pban, BAN_DATA, 1 );
               pban->name = str_dup( race_table[value]->race_name );
               pban->flag = value;
               pban->level = level;
               pban->ban_by = str_dup( ch->name );
               LINK( pban, first_ban_race, last_ban_race, next, prev );
               break;
            case BAN_SITE:
            {
               bool prefix = FALSE, suffix = FALSE, user_name = FALSE;
               char *temp_host = NULL, *temp_user = NULL;
               int x;

               for( x = 0; x < strlen( arg ); x++ )
               {
                  if( arg[x] == '@' )
                  {
                     user_name = TRUE;
                     temp_host = str_dup( &arg[x + 1] );
                     arg[x] = '\0';
                     temp_user = str_dup( arg );
                     break;
                  }
               }
               if( !user_name )
                  name = arg;
               else
                  name = temp_host;

               if( !name ) /* Double check to make sure name isnt null */
               {
                  /* Free this stuff if its there */
                  if( user_name )
                  {
                     DISPOSE( temp_host );
                     DISPOSE( temp_user );
                  }
                  send_to_char( "Name was null.\n\r", ch );
                  return 0;
               }

               if( name[0] == '*' )
               {
                  prefix = TRUE;
                  name++;
               }

               if( name[strlen( name ) - 1] == '*' )
               {
                  suffix = TRUE;
                  name[strlen( name ) - 1] = '\0';
               }
               for( temp = first_ban; temp; temp = temp->next )
               {
                  if( !str_cmp( temp->name, name ) )
                  {
                     if( temp->level == level && ( prefix && temp->prefix ) && ( suffix && temp->suffix ) )
                     {
                        /* Free this stuff if its there */
                        if( user_name )
                        {
                           DISPOSE( temp_host );
                           DISPOSE( temp_user );
                        }
                        send_to_char( "That entry already exists.\n\r", ch );
                        return 0;
                     }
                     else
                     {
                        temp->suffix = suffix;
                        temp->prefix = prefix;
                        if( temp->level == BAN_WARN )
                           temp->warn = TRUE;
                        temp->level = level;
                        sprintf( buf, "%24.24s", ctime( &current_time ) );
                        temp->ban_time = str_dup( buf );
                        if( btime > 0 )
                        {
                           temp->duration = btime;
                           tms = localtime( &current_time );
                           tms->tm_mday += btime;
                           temp->unban_date = mktime( tms );
                        }
                        else
                        {
                           temp->duration = -1;
                           temp->unban_date = -1;
                        }
                        if( temp->ban_by )
                           DISPOSE( temp->ban_by );
                        if( user_name )
                        {
                           DISPOSE( temp_host );
                           DISPOSE( temp_user );
                        }
                        temp->ban_by = str_dup( ch->name );
                        send_to_char( "Updated entry.\n\r", ch );
                        return 1;
                     }
                  }
               }
               CREATE( pban, BAN_DATA, 1 );
               pban->ban_by = str_dup( ch->name );
               pban->suffix = suffix;
               pban->prefix = prefix;
               pban->name = str_dup( name );
               pban->level = level;
               if( user_name )
               {
                  DISPOSE( temp_host );
                  DISPOSE( temp_user );
               }
               break;
            }
            default:
               bug( "Bad type in add_ban: %d.", type );
               return 0;
         }
         sprintf( buf, "%24.24s", ctime( &current_time ) );
         pban->ban_time = str_dup( buf );
         if( btime > 0 )
         {
            pban->duration = btime;
            tms = localtime( &current_time );
            tms->tm_mday += btime;
            pban->unban_date = mktime( tms );
         }
         else
         {
            pban->duration = -1;
            pban->unban_date = -1;
         }
         if( pban->level == BAN_WARN )
            pban->warn = TRUE;
         ch->substate = SUB_BAN_DESC;
         ch->dest_buf = pban;
         if( !pban->note )
            pban->note = STRALLOC( "" );;
         start_editing( ch, pban->note );
         return 1;
      }
      case SUB_BAN_DESC:
         pban = ( BAN_DATA * ) ch->dest_buf;
         if( !pban )
         {
            bug( "%s", "do_ban: sub_ban_desc: NULL ch->dest_buf" );
            ch->substate = SUB_NONE;
            return 0;
         }
         if( pban->note )
            STRFREE( pban->note );
         pban->note = copy_buffer( ch );
         stop_editing( ch );
         ch->substate = ch->tempnum;
         save_banlist(  );
         if( pban->duration > 0 )
         {
            ch_printf( ch, "%s banned for %d days.\n\r", pban->name, pban->duration );
         }
         else
         {
            ch_printf( ch, "%s banned forever.\n\r", pban->name );
         }
         return 1;
   }
   return 1;
}


 

/*
 * Print the bans out to the screen.  Shaddai
 */

void show_bans ( CHAR_DATA *ch, int type )
{
  BAN_DATA *pban;
  int bnum;

  set_pager_color (AT_IMMORT, ch);

  switch ( type ) {
	case BAN_SITE:
		send_to_pager("Banned sites:\n\r", ch);
      		send_to_pager("[ #] Warn (Lv) Time                     By              For   Site\n\r",ch);
 send_to_pager("---- ---- ---- ------------------------ --------------- ----  ---------------\n\r", ch);
		pban = first_ban;
		set_pager_color( AT_PLAIN, ch );
 		for ( bnum=1; pban; pban=pban->next, bnum++)
		{
     		   pager_printf (ch, "[%2d] %-4s (%2d) %-24s %-15s %4d  %c%s%c\n\r", 
			     bnum, (pban->warn)?"YES":"no", pban->level, 
			     pban->ban_time, pban->ban_by, pban->duration,
				(pban->prefix)?'*':' ',
				pban->name, (pban->suffix)?'*':' ');
		}
 		return;
	case BAN_RACE:
		send_to_pager("Banned races:\n\r", ch);
      		send_to_pager("[ #] Warn (Lv) Time                     By              For   Race\n\r",ch);
		pban = first_ban_race;
		break;
	case BAN_CLASS:
		send_to_pager("Banned classes:\n\r", ch);
      		send_to_pager("[ #] Warn (Lv) Time                     By              For   Class\n\r",ch);
		pban = first_ban_class;
		break;
	default:
		bug ("Bad type in show_bans: %d", type );
		return;
	}
 send_to_pager("---- ---- ---- ------------------------ --------------- ----  ---------------\n\r", ch);
 set_pager_color( AT_PLAIN, ch );
 for ( bnum=1; pban; pban=pban->next, bnum++)
      pager_printf (ch, "[%2d] %-4s (%2d) %-24s %-15s %4d  %s\n\r", bnum,
         (pban->warn)?"YES":"no", pban->level, pban->ban_time, pban->ban_by, 
	 pban->duration, pban->name);
 return;
}

/*
 * Check for totally banned sites.  Need this because we don't have a
 * char struct yet.  Shaddai
 */

bool
check_total_bans ( DESCRIPTOR_DATA *d )
{
  BAN_DATA *pban;
  char new_host[MAX_STRING_LENGTH];
  int i;

  for ( i = 0; i < (int) strlen( d->host ) ; i++ )
	new_host[i] = LOWER( d->host[i] );
  new_host[i] = '\0';

  for ( pban = first_ban; pban; pban = pban->next ) {
  	if ( pban->level != LEVEL_SUPREME )
		continue;
	if ( pban->prefix && pban->suffix  && strstr( pban->name, new_host ) )
	{
		if ( check_expire( pban ) )
		{
			dispose_ban( pban, BAN_SITE );
			save_banlist( );
			return FALSE;
		}
		else
			return TRUE;
	}
	/*
	 *   Bug of switched checks noticed by Cronel
	 */
	if ( pban->suffix && !str_prefix( pban->name, new_host ) )
	{
		if ( check_expire( pban ) )
		{
			dispose_ban( pban, BAN_SITE );
			save_banlist( );
			return FALSE;
		}
		else
			return TRUE;
	}
	if ( pban->prefix && !str_suffix( pban->name, new_host ) )
	{
		if ( check_expire( pban ) )
		{
			dispose_ban( pban, BAN_SITE );
			save_banlist( );
			return FALSE;
		}
		else
			return TRUE;
	}
	if ( !str_cmp( pban->name, new_host ) )
	{
		if ( check_expire( pban ) )
		{
			dispose_ban( pban, BAN_SITE );
			save_banlist( );
			return FALSE;
		}
		else
			return TRUE;
	}
  }
  return FALSE;
}

/*
 * The workhose, checks for bans on sites/classes and races. Shaddai
 */
	
bool
check_bans( CHAR_DATA *ch, int type )
{
  char buf[MAX_STRING_LENGTH];
  BAN_DATA *pban;
  char new_host[MAX_STRING_LENGTH];
  int i;
  bool fMatch = FALSE;

  switch ( type )
  {
	case BAN_RACE:
		pban = first_ban_race;		
		break;
	case BAN_CLASS:
		pban = first_ban_class;		
		break;
	case BAN_SITE:	
		pban = first_ban;		
		for ( i = 0; i < (int) ( strlen( ch->desc->host ) ); i++ )
			new_host[i] = LOWER( ch->desc->host[i] );
                new_host[i] = '\0';
		break;
	default:
		bug ( "Ban type in check_bans: %d.", type );
		return FALSE;
  }
  for ( ; pban; pban = pban->next ) {
	if ( type == BAN_CLASS &&  pban->flag == ch->class )
	{
		if ( check_expire( pban ) )
		{
			    dispose_ban( pban, BAN_CLASS );
			    save_banlist( );
			    return FALSE;
		}
		if ( ch->level > pban->level )
		{
			if ( pban->warn ) {
			   sprintf( buf, "%s class logging in from %s.",
				pban->name, ch->desc->host );
			   log_string_plus( buf, LOG_WARN, sysdata.log_level );
			}
			return FALSE;
		}			
		else
			return TRUE;
	}
	if ( type == BAN_RACE && pban->flag == ch->race )
	{
		if ( check_expire( pban ) )
		{
			    dispose_ban( pban, BAN_RACE );
			    save_banlist( );
			    return FALSE;
		}
		if ( ch->level > pban->level )
		{
			if ( pban->warn ) {
			   sprintf( buf, "%s race logging in from %s.",
				pban->name, ch->desc->host );
			   log_string_plus( buf, LOG_WARN, sysdata.log_level );
			}
			return FALSE;
		}			
		else
			return TRUE;
	}
 	if ( type == BAN_SITE ) 
	{
		if ( pban->prefix && pban->suffix  && 
			strstr( pban->name, new_host ) )
			fMatch = TRUE;
		else if ( pban->prefix && !str_suffix( pban->name, new_host ) )
			fMatch = TRUE;
		else if ( pban->suffix && !str_prefix( pban->name, new_host ) )
			fMatch = TRUE;
		else if ( !str_cmp( pban->name, new_host ) )
			fMatch = TRUE;
		if ( fMatch )
		{
		        if ( check_expire( pban ) )
                        {
			    dispose_ban( pban, BAN_SITE );
			    save_banlist( );
			    return FALSE;
                        }
			if ( ch->level > pban->level )
			{
			 if ( pban->warn ) {
			    sprintf( buf, "%s logging in from site %s.",
				ch->name, ch->desc->host );
			    log_string_plus( buf, LOG_WARN, sysdata.log_level );
  			 }
			 return FALSE;
			}
			else
				return TRUE;
		}	
	}
  }
  return FALSE;
}

bool check_expire( BAN_DATA *pban )
{
  char buf[MAX_STRING_LENGTH];

  if ( pban->unban_date < 0 )
	return FALSE;
  if ( pban->unban_date <= current_time )
  {
  	sprintf( buf, "%s ban has expired.", pban->name );
  	log_string_plus( buf, LOG_WARN, sysdata.log_level );
	return TRUE;
  }
  return FALSE;
}

void dispose_ban ( BAN_DATA *pban , int type)
{
  if ( !pban )
        return;

  if ( type != BAN_SITE && type != BAN_CLASS && type != BAN_RACE )
  {
        bug("Dispose_ban: Unknown Ban Type %d.", type );
        return;
  }

  switch ( type )
  {
  	case BAN_SITE:  UNLINK(pban, first_ban, last_ban, next, prev); break;
	case BAN_CLASS: UNLINK(pban, first_ban_class, last_ban_class, next,
				prev ); break;
	case BAN_RACE:  UNLINK(pban, first_ban_race, last_ban_race, next,
				prev);  break;
  }
  free_ban( pban );
  return;
}

void free_ban( BAN_DATA *pban )
{
  if ( pban->name )
     DISPOSE( pban->name );
  if ( pban->ban_time )
     DISPOSE( pban->ban_time );
  if ( pban->note )
        STRFREE( pban->note );
  if ( pban->ban_by )
     DISPOSE( pban->ban_by );                               
  if ( pban->ban_time )
     DISPOSE( pban->ban_time );
  DISPOSE( pban );                                          
}