#include <stdio.h> #include <string.h> #include <stdlib.h> #include <ctype.h> #include <time.h> #include "merc.h" #include "leader.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 :) * */ void load_bans ( ) { char buf[MAX_STRING_LENGTH]; char *word; FILE *fp; bool fMatch = FALSE; if (!(fp = fopen(DATA_DIR BAN_LIST, "r"))) { bug ("load_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 '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 ); fread_to_eol(fp); } /* 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; pban = alloc_mem(sizeof( BAN_DATA ) ); pban->name = fread_string ( fp ); pban->level = fread_number( fp ); pban->duration = fread_number( fp ); pban->unban_date = fread_number( fp ); if ( type == BAN_SITE ) { pban->prefix = fread_number( fp ); pban->suffix = fread_number( fp ); } pban->warn = fread_number( fp ); pban->ban_by = fread_string( fp ); pban->ban_time = fread_string( 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; class_table[i].class_name[0] != '\0'; i++ ) { if ( !str_cmp( class_table[i].class_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]; free_string( pban->name ); pban->name = str_dup( temp2 ); break; } } if ( 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_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 */ void save_banlist ( void ) { BAN_DATA *pban; FILE *fp; fclose (fpReserve); if (!(fp = fopen (DATA_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 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. */ 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, time; 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; } 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 ) ) time = atoi( arg4 ); else time = -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 ( time != -1 && ( time < 1 || time > 1000 ) ) { send_to_char("Time value is -1 (forever) or from 1 to 1000.\n\r", ch); return; } if ( arg1[0] == '\0' ) { send_to_char("Syntax: ban site <address> <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; } if ( !str_cmp ( arg1, "site" ) ) { if ( arg2[0] == '\0' ) { show_bans( ch, BAN_SITE ); return; } 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' ) { do_ban(ch,""); return; } if ( !add_ban ( ch, arg2, arg3, time, BAN_SITE ) ) 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' ) { do_ban(ch,""); return; } if ( !add_ban(ch, arg2, arg3, time, BAN_CLASS ) ) return; } else if ( !str_cmp ( arg1, "show" ) ) { if ( arg2[0] == '\0' || arg3[0] == '\0' ) { do_ban(ch,""); return; } 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 { do_ban(ch,""); return; } 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; } do_ban(ch,""); return; } /* * Allow a already banned site/class */ 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 ); if ( arg1[0] == '\0' || arg2[0] == '\0') { send_to_char ("Syntax: allow site <address>\n\r", ch ); send_to_char ("Syntax: allow class <class>\n\r", ch ); return; } 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 ) { if ( value == 1 || !str_cmp ( pban->name, temp ) ) { fMatch = TRUE; wiznetf( ch, WIZ_MISC, get_trust( ch ), "%s allowing site %s.", ch->name, pban->name ); dispose_ban( pban, BAN_SITE ); 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 ) { if ( value == 1 || !str_cmp ( pban->name, arg2 ) ) { fMatch = TRUE; wiznetf( ch, WIZ_MISC, get_trust( ch ), "%s allowing class %s.", ch->name, pban->name ); dispose_ban( pban, BAN_CLASS ); break; } if ( value > 1 ) value--; } } else { do_allow(ch,""); return; } 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; } /* * 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; 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' ) { send_to_char ("Syntax: warn class <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; } if ( arg2[0] == '#' ) { name = arg2; name++; if ( !is_number( name ) ) { do_warn(ch,""); return; } count = atoi( name ); if ( count < 1 ) { send_to_char("The number has to be above 0.\n\r", ch ); return; } } if ( !str_cmp( arg1, "class") ) type = BAN_CLASS; 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_SITE ) { pban = first_ban; start = first_ban; end = last_ban; } else { do_warn(ch,""); return; } for ( ; pban && count != 0; count--, pban = pban->next ) if ( count == -1 && !str_cmp(pban->name, arg2 ) ) break; if ( pban ) { 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; } /* * This actually puts the new ban into the proper linked list and * initializes its data. */ int add_ban( CHAR_DATA *ch, char *arg1, char *arg2, int time, int type ) { char arg[MAX_STRING_LENGTH]; char buf[MAX_STRING_LENGTH]; BAN_DATA *pban, *temp; struct tm *tms; char *name; int level, 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. */ 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_IMPLEMENTOR ) { ch_printf(ch,"Level range is from 0 to %d.\n\r", LEVEL_IMPLEMENTOR ); return 0; } } else if ( !str_cmp( arg2, "all" ) ) level = LEVEL_IMPLEMENTOR; 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("Bad string for flag in add_ban.", 0 ); return 0; } switch ( type ) { case BAN_CLASS: if ( arg[0] == '\0' ) return 0; if ( is_number( arg ) ) value = atoi( arg ); else value = class_lookupn(arg); 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 (¤t_time)); temp->ban_time = str_dup (buf); if ( temp->ban_by ) free_string( temp->ban_by ); temp->ban_by = str_dup ( ch->name ); send_to_char("Updated entry.\n\r", ch); return 1; } } } pban = alloc_mem( sizeof( BAN_DATA) ); pban->name = str_dup ( class_table[value].class_name ); pban->flag = value; pban->level = level; pban->ban_by = str_dup ( ch->name ); LINK( pban, first_ban_class, last_ban_class, next, prev ); wiznetf( ch, WIZ_MISC, get_trust( ch ), "%s setting class ban on %s", ch->name, pban->name ); break; case BAN_SITE: { bool prefix = FALSE, suffix = FALSE; name = arg; 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 ) ) { 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 (¤t_time)); temp->ban_time = str_dup (buf); if ( temp->ban_by ) free_string( temp->ban_by ); temp->ban_by = str_dup ( ch->name ); send_to_char("Updated entry.\n\r", ch); return 1; } } } pban = alloc_mem( sizeof( BAN_DATA ) ); pban->ban_by = str_dup ( ch->name ); pban->suffix = suffix; pban->prefix = prefix; pban->name = str_dup( name ); pban->level = level; LINK( pban, first_ban, last_ban, next, prev ); wiznetf( ch, WIZ_MISC, get_trust( ch ), "%s setting class ban on %s", ch->name, pban->name ); break; } default: bug("Bad type in add_ban: %d.", type ); return 0; } sprintf (buf, "%24.24s", ctime (¤t_time)); pban->ban_time = str_dup (buf); if ( time > 0 ) { pban->duration = time; tms = localtime(¤t_time); tms->tm_mday += time; pban->unban_date = mktime(tms); } else { pban->duration = -1; pban->unban_date = -1; } if ( pban->level == BAN_WARN ) pban->warn = TRUE; string_append( ch, &pban->note ); 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; } /* * Print the bans out to the screen */ void show_bans ( CHAR_DATA *ch, int type ) { BAN_DATA *pban; int bnum; switch ( type ) { case BAN_SITE: page_to_char("Banned sites:\n\r", ch); page_to_char("[ ##] Warn (Lv) Time By For Site\n\r",ch); page_to_char("---- ---- ---- ------------------------ --------------- ---- ---------------\n\r", ch); pban = first_ban; 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_CLASS: page_to_char("Banned classes:\n\r", ch); page_to_char("[ #] Warn (Lv) Time By For Class\n\r",ch); pban = first_ban_class; break; default: bug ("Bad type in show_bans: %d", type ); return; } page_to_char("---- ---- ---- ------------------------ --------------- ---- ---------------\n\r", 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 */ 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_IMPLEMENTOR ) 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 */ 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_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( buf ); } 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( buf ); } 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( buf ); return TRUE; } return FALSE; } void dispose_ban ( BAN_DATA *pban , int type) { if ( !pban ) return; if ( type != BAN_SITE && type != BAN_CLASS ) { 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; } free_ban( pban ); return; } void free_ban( BAN_DATA *pban ) { if ( pban->name ) free_string( pban->name ); if ( pban->ban_time ) free_string( pban->ban_time ); if ( pban->note ) free_string( pban->note ); if ( pban->ban_by ) free_string( pban->ban_by ); if ( pban->ban_time ) free_string( pban->ban_time ); free_mem( pban, sizeof( *pban ) ); }