1stMUD4.0/bin/
1stMUD4.0/doc/MPDocs/
1stMUD4.0/player/
1stMUD4.0/win32/
1stMUD4.0/win32/rom/
/**************************************************************************
*  Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer,        *
*  Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe.   *
*                                                                         *
*  Merc Diku Mud improvements copyright (C) 1992, 1993 by Michael         *
*  Chastain, Michael Quan, and Mitchell Tse.                              *
*                                                                         *
*  In order to use any part of this Merc Diku Mud, you must comply with   *
*  both the original Diku license in 'license.doc' as well the Merc       *
*  license in 'license.txt'.  In particular, you may not remove either of *
*  these copyright notices.                                               *
*                                                                         *
*  Much time and thought has gone into this software and you are          *
*  benefiting.  We hope that you share your changes too.  What goes       *
*  around, comes around.                                                  *
***************************************************************************
*       ROM 2.4 is copyright 1993-1998 Russ Taylor                        *
*       ROM has been brought to you by the ROM consortium                 *
*           Russ Taylor (rtaylor@hypercube.org)                           *
*           Gabrielle Taylor (gtaylor@hypercube.org)                      *
*           Brian Moore (zump@rom.org)                                    *
*       By using this code, you have agreed to follow the terms of the    *
*       ROM license, in the file Rom24/doc/rom.license                    *
***************************************************************************
*       1stMUD ROM Derivative (c) 2001-2003 by Ryan Jennings              *
*            http://1stmud.dlmud.com/  <r-jenn@shaw.ca>                   *
***************************************************************************/
#include "merc.h"
#include "recycle.h"
#include "interp.h"
#include "tablesave.h"

/* The quoting character -- what overrides wildcards (do not undef)    */
#define QUOTE '\\'

/* The "matches ANYTHING" wildcard (do not undef)                      */
#define WILDS '*'

/* The "matches ANY NUMBER OF NON-SPACE CHARS" wildcard (do not undef) */
#define WILDP '%'

/* The "matches EXACTLY ONE CHARACTER" wildcard (do not undef)         */
#define WILDQ '?'

/* Changing these is probably counter-productive :) */
#define MATCH (match+saved+sofar)
#define NOMATCH 0

int wild_match(register unsigned char *m, register unsigned char *n)
{
	unsigned char *ma = m, *lsm = 0, *lsn = 0, *lpm = 0, *lpn = 0;
	int match = 1, saved = 0;
	register unsigned int sofar = 0;

	/* take care of null strings (should never match) */
	if ((m == 0) || (n == 0) || (!*n))
		return NOMATCH;

	/* (!*m) test used to be here, too, but I got rid of it.  After all,
	   If (!*n) was FALSE, there must be a character in the name (the
	   second string), so if the mask is empty it is a non-match.  Since
	   the algorithm handles this correctly without testing for it here
	   and this shouldn't be called with null masks anyway, it should be
	   a bit faster this way */

	while (*n)
	{
		/* Used to test for (!*m) here, but this scheme seems to work better */
		switch (*m)
		{
		case 0:
			do
				m--;			/* Search backwards      */
			while ((m > ma) && (*m == '?'));	/* For first non-? char  */
			if ((m > ma) ? ((*m == '*') && (m[-1] != QUOTE)) : (*m == '*'))
				return MATCH;	/* nonquoted * = match   */
			break;
		case WILDP:
			while (*(++m) == WILDP);	/* Zap redundant %s      */
			if (*m != WILDS)
			{					/* Don't both if next=*  */
				if (*n != ' ')
				{				/* WILDS can't match ' ' */
					lpm = m;
					lpn = n;	/* Save % fallback spot  */
					saved += sofar;
					sofar = 0;	/* And save tally count  */
				}
				continue;		/* Done with %           */
			}
			/* FALL THROUGH */
		case WILDS:
			do
				m++;			/* Zap redundant wilds   */
			while ((*m == WILDS) || (*m == WILDP));
			lsm = m;
			lsn = n;
			lpm = 0;			/* Save * fallback spot  */
			match += (saved + sofar);	/* Save tally count      */
			saved = sofar = 0;
			continue;			/* Done with *           */
		case WILDQ:
			m++;
			n++;
			continue;			/* Match one char        */
		case QUOTE:
			m++;				/* Handle quoting        */
		}

		if (tolower(*m) == tolower(*n))
		{						/* If matching           */
			m++;
			n++;
			sofar++;
			continue;			/* Tally the match       */
		}
		if (lpm)
		{						/* Try to fallback on %  */
			n = ++lpn;
			m = lpm;
			sofar = 0;			/* Restore position      */
			if ((*n | 32) == 32)
				lpm = 0;		/* Can't match 0 or ' '  */
			continue;			/* Next char, please     */
		}
		if (lsm)
		{						/* Try to fallback on *  */
			n = ++lsn;
			m = lsm;			/* Restore position      */
			/* Used to test for (!*n) here but it wasn't necessary so it's gone */
			saved = sofar = 0;
			continue;			/* Next char, please     */
		}
		return NOMATCH;			/* No fallbacks=No match */
	}
	while ((*m == WILDS) || (*m == WILDP))
		m++;					/* Zap leftover %s & *s  */
	return (*m) ? NOMATCH : MATCH;	/* End of both = match   */
}

BAN_DATA ban;

const struct savetable_type bansavetable[] = {
	{"name", FIELD_STRING, (void *) &ban.name, NULL, NULL},
	{"level", FIELD_INT, (void *) &ban.level, NULL, NULL},
	{"flags", FIELD_FLAGVECTOR, (void *) &ban.ban_flags, NULL, NULL},
	{NULL, 0, NULL, NULL, NULL}
};

TABLESAVE(rw_bans)
{
	rw_list(type, BAN_FILE, BAN_DATA, ban_first, ban_last, next, prev, new_ban,
			"BAN", ban, bansavetable);
}

bool check_ban(const char *site, int type)
{
	BAN_DATA *pban;
	char host[MAX_STRING_LENGTH];

	strcpy(host, capitalize(site));
	host[0] = LOWER(host[0]);

	for (pban = ban_first; pban != NULL; pban = pban->next)
	{
		if (!IS_SET(pban->ban_flags, type))
			continue;

		if (wild_match((unsigned char *) pban->name, (unsigned char *) host))
			return TRUE;
	}

	return FALSE;
}

void ban_site(CHAR_DATA * ch, const char *argument)
{
	char arg1[MAX_INPUT_LENGTH], arg2[MAX_INPUT_LENGTH];
	BUFFER *buffer;
	BAN_DATA *pban, *prev;
	int type;

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

	if (IS_NULLSTR(arg1))
	{
		if (ban_first == NULL)
		{
			chprintln(ch, "No sites banned at this time.");
			return;
		}
		buffer = new_buf();

		bprintln(buffer, "Banned sites  level  type");
		for (pban = ban_first; pban != NULL; pban = pban->next)
		{
			bprintlnf(buffer, "%-12s    %-3d  %s", pban->name,
					  pban->level, IS_SET(pban->ban_flags,
										  BAN_NEWBIES) ? "newbies" :
					  IS_SET(pban->ban_flags,
							 BAN_PERMIT) ? "permit" :
					  IS_SET(pban->ban_flags, BAN_ALL) ? "all" : "");
		}

		sendpage(ch, buf_string(buffer));
		free_buf(buffer);
		return;
	}

	/* find out what type of ban */
	if (IS_NULLSTR(arg2) || !str_prefix(arg2, "all"))
		type = BAN_ALL;
	else if (!str_prefix(arg2, "newbies"))
		type = BAN_NEWBIES;
	else if (!str_prefix(arg2, "permit"))
		type = BAN_PERMIT;
	else
	{
		chprintln(ch, "Acceptable ban types are all, newbies, and permit.");
		return;
	}

	if (strlen(arg1) == 0)
	{
		chprintln(ch, "You have to ban SOMETHING.");
		return;
	}

	prev = NULL;
	for (pban = ban_first; pban != NULL; pban = prev)
	{
		prev = pban->next;

		if (!str_cmp(arg1, pban->name))
		{
			if (pban->level > get_trust(ch))
			{
				chprintln(ch, "That ban was set by a higher power.");
				return;
			}
			else
			{
				UNLINK(pban, ban_first, ban_last, next, prev);
				free_ban(pban);
			}
		}
	}

	pban = new_ban();
	pban->name = str_dup(arg1);
	pban->level = get_trust(ch);

	/* set ban type */
	pban->ban_flags = type;

	LINK(pban, ban_first, ban_last, next, prev);
	rw_bans(action_write);
	chprintlnf(ch, "%s has been banned.", pban->name);
	return;
}

CH_CMD(do_ban)
{
	ban_site(ch, argument);
}

CH_CMD(do_allow)
{
	char arg[MAX_INPUT_LENGTH];
	BAN_DATA *prev;
	BAN_DATA *curr;

	one_argument(argument, arg);

	if (IS_NULLSTR(arg))
	{
		chprintln(ch, "Remove which site from the ban list?");
		return;
	}

	prev = NULL;
	for (curr = ban_first; curr != NULL; curr = prev)
	{
		prev = curr->next;

		if (!str_cmp(arg, curr->name))
		{
			if (curr->level > get_trust(ch))
			{
				chprintln(ch, "You are not powerful enough to lift that ban.");
				return;
			}
			UNLINK(curr, ban_first, ban_last, next, prev);

			free_ban(curr);
			chprintlnf(ch, "Ban on %s lifted.", arg);
			rw_bans(action_write);
			return;
		}
	}

	chprintln(ch, "Site is not banned.");
	return;
}