/********************************************************* * Bugblatter Whois Extension - V3.8 * ********************************************************* * * * This plug-in is linux & win32 friendly. * * * * Version history * * * * Version 3.7 * * * * - BUGFIX: All dates in August were recorded as being * * in June! * * * * Version 3.7 * * * * - Integration with cheating-death. Whois will report * * K:D ratios with/without c-d running, and can act * * as a c-d mediator if c-d is in optional mode * * - bbwhois report shortened, and bbwhois_full added * * to display the complete report. * * - Kicked and Banned messages in players console made * * more prominent. * * * * * * Version 3.6 * * * * - Reduced repetitions of some announcements * * - No warnings compiling on Adminmod 2.50.56 * * - Copes with SteamIDs and ValveIDs as well as WONIDs * * - Problems with case sensitive filenames on Linux * * fixed. No longer re-watches players unwatched and * * some broken detections fixed. * * - Remembers upto 5 old names used in this game for * * each player so if someone changes their name and * * you don't notice you can still whois them on their * * old name * * - Supports ban durations 1h,1d,1w,1m,1y etc. * * - Bug fix - used to report to other admins that a * * fellow admin had watched someone when they had * * actually kicked or banned them. * * * * Version 3.5 * * * * - No longer auto-watches a player who connects from * * the same IP as someone who has been temp banned. * * - Option to turn off team kill detection for non- * * team based games. * * - Within the same round reports if a player rejoins * * after being kicked, temp banned and/or rejoins * * with a different name to the one the left with. * * A single alert is sent to all ACCESS_WHOIS level * * admins. * * - Tells other admins in chat when another admin or * * hlguard uses note/watch/unwatch/kick/ban on a * * player that is (or was in the case of kick/ban ;)) * * connected to the server. * * * * Version 3.4 * * * * - Now detects are reports on team kills * * - Now alerts when two players connect from the same * * IP address * * - bbwhois_lan command added to recap who is lanning * * - Added CDATA tags around names to prevent problems * * with XML display * * - Corrected bug in GetTopName that returned the last * * name in the file as the top name all the time. * * This should may the admins top name appear in the * * whois reports and the correct Aka appear in the * * report title * * - Added first connection date to the report header * * - Ratios are now displayed as approximated ratios * * rather than percentages * * - IP address and access level line not included in * * report if the player isn't connected * * - bbwhois_watch and bbwhois_unwatch wouldn't work * * when require reason was turned on and you did * * supply a reason. * * - bbwhois_watch and bbwhois_unwatch now work on * * players that have left the server and on WONIDs * * of anyone connected or otherwise * * - bbwhois_note, bbwhois_watch and bbwhois_unwatch * * now return the player name match in the * * confirmation message to the admin using them * * - bbwhois now reports a usage message if called with * * no arguments. * * - when any ban/note/watch/unwatch is performed on a * * a player not connected, their most common name is * * written to the global notes file instead of * * "Unknown player not connected" * * * * Version 3.3 * * * * - Access level of ACCESS_WHOIS changed to the unused * * 1024 level. This allows you to give access to the * * bbwhois, bbwhois_note and bbwhois_watch commands * * to server regulars who are not admins to allow * * to alert you to cheats * * * * - bbwhois_admin command added to report who is admin * * * * - Names the player to watch if there is only one * * when an admin connects * * * * - hlguard integration - whois reports will now show * * actions / suspicions of hlguard * * * * Version 3.2 * * * * - Works correctly on linux * * - Uses the top admin name when recording their * * actions rather than their name at the time * * - Support for mods other than CS * * - Always creates the WONID.xml file for every player * * - WONID.xml now contains the players AuthID in the * * player tag * * - Records IP addresses * * - Writing data at end of round is now delayed 2 * * seconds so lag isn't during last death so players * * don't feel they were killed by the lag * * - Writes all notes to a global log file as well as * * the player specific notes files so server owner * * can review all admin actions. * * - XSL files are now located in the db folder so that * * "db" can be shared via HTTP to provide web based * * access to the XML files * * - Cross-refrences IP addresses to find other players * * from the same subnet * * - Automatically sets a watch on a player who connects* * from the same IP address/subnet as a banned player * * or a watched player unless they have been * * unwatched previously * * - BUGFIX: bbwhois_watch without a reason reported * * watches instead of adding one * * from the same subnet * * - Numerous fixes to admin_ban/admin_unban including * * using ban/banip correctly, telling the user the * * reason they were banned and giving the admin an * * error message if they supply a reason in the time * * field. * * - BUGFIX: cope with players having more than 10 * * notes correctly * * * * Version 3.1 alpha version: * * - Initial Version * ********************************************************* */ #pragma dynamic 8192 #define ROUND_TIME 600 #include <core> #include <console> #include <string> #include <admin> #include <adminlib> #include <plugin> #include "settings" #include "clientio" #include "ip" #include "language" #include "stringx" #include "time" #define ACCESS_WHOIS 1024 #define DEFAULT_REPORT 1 #define MIN_REPORT 0 #define MAX_REPORT 1 #define DEFAULT_REQUIREREASON 0 #define MIN_REQUIREREASON 0 #define MAX_REQUIREREASON 1 #define DEFAULT_TEAMKILL 1 #define MIN_TEAMKILL 0 #define MAX_TEAMKILL 1 #define DEFAULT_RCD_MINIMUM 15 #define MIN_RCD_MINIMUM 5 #define MAX_RCD_MINIMUM 10000 #define DEFAULT_RCD_MAXIMUM 60 #define MIN_RCD_MAXIMUM 5 #define MAX_RCD_MAXIMUM 10000 #define DEFAULT_RCD_RATIO 3 #define MIN_RCD_RATIO 1 #define MAX_RCD_RATIO 10 #define DEFAULT_RCD_ENABLED 0 #define MIN_RCD_ENABLED 0 #define MAX_RCD_ENABLED 1 #define MAX_OLD_PLAYERS 300 #define MAX_OLD_NAMES_PER_PLAYER 5 #define KD_NOCD_ADMIN 0 #define KD_NOCD_NOADMIN 1 #define KD_CD_ADMIN 2 #define KD_CD_NOADMIN 3 new g_Version[]="3.7"; new MSG_REPORTTITLE[]="Bugblatter Whois configuration:"; new MSG_RPT_REASONDISABLED[]=" - Providing a reason is optional (bbwhois_reqirereason)"; new MSG_RPT_REASONENABLED[]=" - Providing a reason is required (bbwhois_reqirereason)"; new MSG_RPT_TEAMKILL_ON[]=" - Logging of team kills is enabled (bbwhois_teamkills)"; new MSG_RPT_TEAMKILL_OFF[]=" - Logging of team kills is disabled (bbwhois_teamkills)"; new MSG_CDREPORTTITLE[]="\nBugblatter Whois <-> Cheating Death configuration: (bbwhois_cdrequired)"; new MSG_RPT_RCD_ON[] = " - CD Mediation enabled"; new MSG_RPT_RCD_OFF[] = " - CD Mediation disabled"; new MSG_RPT_RCD_MAXIMUM[] = " - Force players to use CD after %1i rounds"; new MSG_RPT_RCD_RATIO[] = " - Force players with a %1i:1 kills/deaths to use CD"; new MSG_RPT_RCD_MINIMUM[] = " - Ignore kills/deaths ratio for the first %1i rounds"; /* Config */ new g_RequireReason=DEFAULT_REQUIREREASON; new g_Report=DEFAULT_REPORT; new g_TeamKill=DEFAULT_TEAMKILL; /* State */ new g_Kills[MAX_PLAYERS][4]; /* Kills with admin connected */ new g_Deaths[MAX_PLAYERS][4]; /* Deaths with admin connected */ new g_IPs[MAX_PLAYERS]; /* Names of the currently conencted players */ new g_Connections[MAX_PLAYERS]; /* 1 for those slots that have a player connected but not logged as such */ new g_Rounds[MAX_PLAYERS]; /* Total rounds played */ new g_Watches[MAX_PLAYERS]; /* 1 for those slots where the connected player is watched */ new g_Registered=0; /* 1 indicates this plugin has initialised correctly */ new g_AuthIDs[MAX_PLAYERS][MAX_AUTHID_LENGTH]; /* AuthID cache for each connected player */ new g_Kicked[MAX_PLAYERS]; /* Flags a player has been kicked/banned so g_OldKicked can be set on disconnect */ new g_OldNames[MAX_OLD_PLAYERS][MAX_NAME_LENGTH]; /* Names of players that have disconnected in this game */ new g_OldAuthIDs[MAX_OLD_PLAYERS][MAX_AUTHID_LENGTH]; /* AuthIDs associated with each previous name */ new g_OldKicked[MAX_OLD_PLAYERS]; /* Flags if old players were kicked or banned */ new g_OldPtr=0; /* Indicates number of slots used in g_OldNames */ new g_TopNames[MAX_PLAYERS][MAX_NAME_LENGTH]; /* Records the top name of each connected player at the point they connected */ new g_TeamKills[MAX_PLAYERS]; /* Holds the index of the killer of each player if death was by team kill */ new g_TeamKillsLast[MAX_PLAYERS]; /* g_TeamKills from the last round */ new g_RoundStartTime=0; /* Seconds since 1/1/1970 00:00:00 when current round started */ new g_LanDetect[MAX_PLAYERS]; /* Used during processing bbwhois_lan to repeat duplicate reports */ new g_CheatingDeath=0; new g_CDRequiredMode=0; new g_CD_Status[MAX_PLAYERS]; new g_RcdMinimum = DEFAULT_RCD_MINIMUM; new g_RcdMaximum = DEFAULT_RCD_MAXIMUM; new g_RcdRatio = DEFAULT_RCD_RATIO; new g_RcdEnabled = DEFAULT_RCD_ENABLED; new g_AdminConnected=0; forward RegisterPlugin(); forward BBWhois(HLCommand,HLData,HLUserName,UserIndex); forward BBWhoisNote(HLCommand,HLData,HLUserName,UserIndex); forward BBWhoisWatch(HLCommand,HLData,HLUserName,UserIndex); forward BBWhoisUnWatch(HLCommand,HLData,HLUserName,UserIndex); forward BBWhoisAdmin(HLCommand,HLData,HLUserName,UserIndex); forward BBWhoisLan(HLCommand,HLData,HLUserName,UserIndex); forward BBWhoisReset(HLCommand,HLData,HLUserName,UserIndex); forward BBWhoisReport(HLCommand,HLData,HLUserName,UserIndex); forward BBWhoisRR(HLCommand,HLData,HLUserName,UserIndex); forward BBWhoisTeamKill(HLCommand,HLData,HLUserName,UserIndex); forward ShowConfig(UserIndex,Force); forward admin_ban(HLCommand,HLData,HLUserName,UserIndex); forward admin_kick(HLCommand,HLData,HLUserName,UserIndex); forward admin_unban(HLCommand,HLData,HLUserName,UserIndex); forward BBLogdWorldAction(HLCommand,HLData,HLUserName,UserIndex); forward BBLogdKill(HLCommand,HLData,HLUserName,UserIndex); forward OnEndOfRound(); forward BBWhoisHLGuard(HLCommand,HLData,HLUserName,UserIndex); forward LogWriteTimer(Timer,Repeat,HLUserName,HLParam); forward LogConnectionTimer(Timer,Repeat,HLUserName,HLParam); forward LogConnection(UserIndex); forward LookupConnectCount(Path[],strDate[],&nConnects); forward LookupNameCount(Path[],strName[],&nRounds); forward LookupIPCount(Path[],strIP[],&nRounds); forward LookupAddress(Path[],AuthID[]); forward LogEndOfRound(UserIndex,UserName[]); forward LogNames(UserName[],AuthID[]); forward LogIPs(UserIndex,AuthID[]); forward LogKills(UserIndex,AuthID[]); forward InitNotesFile(AuthID[]); forward LogNote(NoteType[],Target[],AdminIndex,AdminName[],Note[],Data[],Direct); forward WriteSettings(UserIndex); forward WriteSettingsByAuthID(AuthID[],Watch); forward ReadSettings(UserIndex); forward AnnounceWatches(Timer,Repeat,HLUserName,HLParam); forward AnnounceWatchme(Timer,Repeat,HLUserName,HLParam); forward ReportWatches(UserIndex); forward ReportLan(UserIndex); forward ReportAdmins(UserIndex); forward ReportHeader(UserIndex,AuthID[],Online,AKA[],fFull); forward ReportConnections(UserIndex,AuthID[]); forward ReportNames(Timer,Repeat,HLUserName,HLParam); forward ReportNamesShort(Timer,Repeat,HLUserName,HLParam); forward ReportIPs(Timer,Repeat,HLUserName,HLParam); forward ReportTop10(User[],AuthID[],strFile[],strPrompt[],nCount); forward ReportOtherIDs(Timer,Repeat,HLUserName,HLParam); forward ReportNotes(Timer,Repeat,HLUserName,HLParam); forward GetTopName(AuthID[],strCurName[],strTopName[],&Second); forward Resolve(Data[],AuthID[],&TargetIndex,TargetName[],AKA[]); forward IsAdminConnected(); forward Hash(strin[]); forward GetDate(strDate[]); forward GetAuthID(UserIndex,AuthID[MAX_AUTHID_LENGTH]); forward SplitDate(strDate[],&year,&month,&day); forward DaysDiff(year1,month1,day1,year2,month2,day2); forward CheckCrossReference(TargetIndex); forward CheckIPFile(TargetIndex,Path[],AuthID[]); forward CheckIPSetWatch(TargetIndex,AuthID[],DupAuthID[],Reason[]); forward HasBeenUnwatched(AuthID[]); forward CalcRatio(K,D,Ratio[]); forward CheckIP(UserIndex,AdminIndex); forward CheckSubnet(UserIndex,AdminIndex); forward CheckOldNames(NewName[],AuthID[]); forward GenerateFilename(Path[],ParsedAuthID[],&HashParsedAuthID,Base[],AuthID[],FileType[]); forward ParseAuthID(AuthID[],ParsedAuthID[]); forward RemoveCD(Name[]); public plugin_init() { plugin_registerinfo("Bugblatter's Whois plugin","Maintains a player information database",g_Version); /* Check server is configured properly */ new fOK = checkFileAccessRead(); fOK = checkFileAccessWrite() && fOK; fOK = checkVaultOK() && fOK; if (fOK == 0) { return PLUGIN_CONTINUE; } /* No need to abort if this one fails */ checkLanguage(); language_init(); readvaultnum("bbwhois_requirereason", g_RequireReason,DEFAULT_REQUIREREASON,MIN_REQUIREREASON,MAX_REQUIREREASON); readvaultnum("bbwhois_teamkill", g_TeamKill,DEFAULT_TEAMKILL,MIN_TEAMKILL,MAX_TEAMKILL); readvaultnum("bbwhois_rcdminimum", g_RcdMinimum,DEFAULT_RCD_MINIMUM,MIN_RCD_MINIMUM,MAX_RCD_MINIMUM); readvaultnum("bbwhois_rcdmaximum", g_RcdMaximum,DEFAULT_RCD_MAXIMUM,MIN_RCD_MAXIMUM,MAX_RCD_MAXIMUM); readvaultnum("bbwhois_rcdratio", g_RcdRatio,DEFAULT_RCD_RATIO,MIN_RCD_RATIO,MAX_RCD_RATIO); readvaultnum("bbwhois_rcdenabled", g_RcdEnabled,DEFAULT_RCD_ENABLED,MIN_RCD_ENABLED,MAX_RCD_ENABLED); RegisterPlugin(); set_timer("LogWriteTimer",ROUND_TIME,1,""); set_timer("LogConnectionTimer",15,99999,""); /* Check if cheating death is installed and not disabled */ new CDVersion[MAX_TEXT_LENGTH]; if (getstrvar("cdversion",CDVersion,MAX_TEXT_LENGTH)) { if (strlen(CDVersion)>0) { if (getvar("cdrequired")>=0) { g_CheatingDeath = 1; } if (getvar("cdrequired")==1) { g_CDRequiredMode = 1; } } } new i; for (i=0;i<MAX_PLAYERS;i++) { g_CD_Status[i]=3; } return PLUGIN_CONTINUE; } RegisterPlugin() { /* Logd callbacks */ plugin_registercmd("bbwhois_logdwa","BBLogdWorldAction",131072,""); exec("logd_reg 62 admin_command bbwhois_logdwa",0); plugin_registercmd("bbwhois_logdkill","BBLogdKill",131072,""); exec("logd_reg 57 admin_command bbwhois_logdkill",0); /* Cheating death callback to inform whois if player has validated */ plugin_registercmd("bbwhois_cdstatus","BBWhoisCDStatus",131072,""); /* HL Guard callback to report its actions / suspicions */ plugin_registercmd("bbwhois_hlguard","BBWhoisHLGuard",131072,""); /* Whois Player commands */ plugin_registercmd("bbwhois","BBWhois",ACCESS_WHOIS, "bbwhois <Player Name | WonID>: Displays a short on player's activities."); plugin_registercmd("bbwhois_full","BBWhois",ACCESS_WHOIS, "bbwhois_full <Player Name | WonID>: Displays a full on player's activities."); plugin_registercmd("bbwhois_note","BBWhoisNote",ACCESS_WHOIS, "bbwhois_note <Player Name | WonID> <Message>: Records a message against the player."); plugin_registercmd("bbwhois_watch","BBWhoisWatch",ACCESS_WHOIS, "bbwhois_watch <Player Name | WonID> <Reason>: Record player should be watched and logs reason."); plugin_registercmd("bbwhois_unwatch","BBWhoisUnWatch",ACCESS_WHOIS, "bbwhois_unwatch <Player Name | WonID> <Reason>: Record player should no longer be watched and logs reason."); plugin_registercmd("bbwhois_admin","BBWhoisAdmin",ACCESS_WHOIS, "bbwhois_admin: Lists those on the server with some level of admininstrator access"); plugin_registercmd("bbwhois_lan","BBWhoisLan",ACCESS_WHOIS, "bbwhois_lan: Lists those using the same IP address"); plugin_registercmd("bbwhois_report","BBWhoisReport",ACCESS_CONFIG, "bbwhois_report [ ^"on^" | ^"off^" ]: shows the whois config, and enables/disable report after every command"); plugin_registercmd("bbwhois_reset","BBWhoisReset",ACCESS_CONFIG, "bbwhois_reset: sets all whois settings to defaults"); plugin_registercmd("bbwhois_requirereason","BBWhoisRR",ACCESS_CONFIG, "bbwhois_requirereason ^"on^" | ^"off^": Sets whether reasons must be supplied for watches/gags/kicks/bans etc."); plugin_registercmd("bbwhois_teamkill","BBWhoisTeamKill",ACCESS_CONFIG, "bbwhois_teamkill ^"on^" | ^"off^": Enables / disables team kill logging."); plugin_registercmd("bbwhois_requirecd","BBWhoisRCD",ACCESS_CONFIG, "bbwhois_requirecd ^"on^" | ^"off^" | n ^"maximum^" | n ^"minimum^" | n ^"ratio^": Controls cheating death."); /* Reimplementations of standard player commands */ plugin_registercmd("admin_ban","admin_ban",ACCESS_BAN,"admin_ban <target or WONID or IP> [<minutes>] ['ip']: Bans target. 0 minutes is a permanent ban."); plugin_registercmd("admin_banip","admin_ban",ACCESS_BAN,"admin_banip <target or WONID or IP> [<minutes>]: Bans targets ip address. 0 minutes is a permanent ban. "); plugin_registercmd("admin_kick","admin_kick",ACCESS_KICK,"admin_kick <target> [<reason>]: Kicks target."); plugin_registercmd("admin_unban","admin_unban",ACCESS_BAN,"admin_unban <WONID or IP>: Unbans target."); g_Registered=1; } public plugin_connect(HLUserName, HLIP, UserIndex) { if (g_Registered ==0) { return PLUGIN_FAILURE; } new Data[MAX_DATA_LENGTH]; safe_convert(HLIP,Data,MAX_DATA_LENGTH); HLIPtoip(HLIP,g_IPs[UserIndex]); g_Connections[UserIndex]=1; g_AuthIDs[UserIndex][0]=0; g_CD_Status[UserIndex]=3; g_Rounds[UserIndex]=0; return PLUGIN_CONTINUE; } public plugin_disconnect(HLUserName, UserIndex) { if (g_Registered ==0) { return PLUGIN_FAILURE; } new UserName[MAX_NAME_LENGTH]; safe_convert(HLUserName, UserName, MAX_NAME_LENGTH); LogEndOfRound(UserIndex,UserName); RemoveCD(UserName); g_Connections[UserIndex]=0; g_Watches[UserIndex]=0; g_TopNames[UserIndex][0]=0; g_LanDetect[UserIndex]=0; if (g_OldPtr<MAX_OLD_PLAYERS) { strcpy(g_OldNames[g_OldPtr],UserName,MAX_NAME_LENGTH); strcpy(g_OldAuthIDs[g_OldPtr],g_AuthIDs[UserIndex],MAX_AUTHID_LENGTH); g_OldPtr++; new i=g_OldPtr-1; while (i>0) { if (streq(g_OldAuthIDs[g_OldPtr],g_AuthIDs[UserIndex])) { g_OldKicked[i]=g_Kicked[UserIndex]; } i--; } g_Kicked[UserIndex]=0; } g_AuthIDs[UserIndex][0]=0; return PLUGIN_CONTINUE; } public plugin_info(HLOldName, HLNewName, UserIndex) { if (g_Registered ==0) { return PLUGIN_FAILURE; } /* Ignore name changes before we have sussed their AuthID */ if (g_AuthIDs[UserIndex][0]==0) { return PLUGIN_CONTINUE; } new NewName[MAX_NAME_LENGTH]; new OldName[MAX_NAME_LENGTH]; safe_convert(HLNewName, NewName, MAX_NAME_LENGTH); safe_convert(HLOldName, OldName, MAX_NAME_LENGTH); RemoveCD(OldName); RemoveCD(NewName); /* Ignore calls when the name hasn't changed */ if (streq(NewName,OldName)) { return PLUGIN_CONTINUE; } /* Ignore calls with no old name specified */ if (strlen(OldName)==0) { return PLUGIN_CONTINUE; } /* Count the number of old names we already hold for this player */ new i=g_OldPtr-1; new c=0; while (i>0) { if (streq(g_AuthIDs[UserIndex],g_OldAuthIDs[i])) { /* Check the player hasn't changed their name back to one we already hold */ if (streq(g_OldNames[i],OldName)) { return PLUGIN_CONTINUE; } c=c+1; if (c==MAX_OLD_NAMES_PER_PLAYER) { break; } } i--; } /* Store old name so it can be resolved */ if (c==MAX_OLD_NAMES_PER_PLAYER) { /* Shuffle all the old names for this player along the list so it is the oldest old name that is removed */ new j=i+1; new k=i; while (j<g_OldPtr) { if (streq(g_AuthIDs[UserIndex],g_OldAuthIDs[i])) { strcpy(g_OldNames[k],g_OldNames[j],MAX_NAME_LENGTH); k=j; } j++; } strcpy(g_OldNames[k],OldName,MAX_NAME_LENGTH); } else { /* Append this old name to the list */ strcpy(g_OldNames[g_OldPtr],OldName,MAX_NAME_LENGTH); strcpy(g_OldAuthIDs[g_OldPtr],g_AuthIDs[UserIndex],MAX_AUTHID_LENGTH); g_OldKicked[g_OldPtr]=0; g_OldPtr++; } return PLUGIN_CONTINUE; } /* *************** Plugin commands ***************** */ public BBWhois(HLCommand,HLData,HLUserName,UserIndex) { new Command[MAX_COMMAND_LENGTH]; new Data[MAX_DATA_LENGTH]; new TargetIndex; new TargetName[MAX_NAME_LENGTH]; new AuthID[MAX_AUTHID_LENGTH]; new AKA[MAX_NAME_LENGTH]; safe_convert(HLCommand,Command,MAX_DATA_LENGTH); safe_convert(HLData,Data,MAX_DATA_LENGTH); if (strlen(Data)==0) { language_say(UserIndex,"Usage: bbwhois <playername or wonid>",print_type:print_console,0,0,0,0); } else { if (Resolve(Data,AuthID,TargetIndex,TargetName,AKA)) { ReportHeader(UserIndex,AuthID,TargetIndex,AKA,streq(Command,"bbwhois_full")); } else { language_sayf(UserIndex,"Unknown Player '%1s'",print_type:print_console,0,0,0,0,Data); } } return PLUGIN_HANDLED; } public BBWhoisNote(HLCommand,HLData,HLUserName,UserIndex) { new Data[MAX_DATA_LENGTH]; new User[MAX_NAME_LENGTH]; new Target[MAX_DATA_LENGTH]; new AuthID[MAX_AUTHID_LENGTH]; new TargetIndex; new TargetName[MAX_NAME_LENGTH]; new AKA[MAX_NAME_LENGTH]; safe_convert(HLData,Data,MAX_DATA_LENGTH); safe_convert(HLUserName,User,MAX_NAME_LENGTH); RemoveCD(User); strbreak(Data,Target,Data,MAX_DATA_LENGTH); if (Resolve(Target,AuthID,TargetIndex,TargetName,AKA)) { if (TargetIndex>0) { LogNote("Note",AuthID,UserIndex,User,Data,"",0); if (strlen(AKA) >0) { language_sayf(UserIndex,"Note added for player '%1s' now playing as '%2s'.",print_type:print_console,0,0,0,0,AKA,TargetName); } else { language_sayf(UserIndex,"Note added for player '%1s'.",print_type:print_console,0,0,0,0,TargetName); } new AdminMsg[MAX_TEXT_LENGTH]; snprintf(AdminMsg,MAX_DATA_LENGTH,"### %s has added a note for %s: %s",User,TargetName,Data); AnnounceToAdmins(AdminMsg,print_type:print_chat,UserIndex); } else { LogNote("Note",AuthID,UserIndex,User,Data,"",1); language_sayf(UserIndex,"Note added for disconnected player '%1s'.",print_type:print_console,0,0,0,0,TargetName); } } else { language_sayf(UserIndex,"Unknown Player '%1s'",print_type:print_console,0,0,0,0,Data); } return PLUGIN_HANDLED; } public BBWhoisWatch(HLCommand,HLData,HLUserName,UserIndex) { new Data[MAX_DATA_LENGTH]; new User[MAX_NAME_LENGTH]; new Target[MAX_DATA_LENGTH]; new TargetIndex; new TargetName[MAX_NAME_LENGTH]; new AuthID[MAX_AUTHID_LENGTH]; new AKA[MAX_NAME_LENGTH]; safe_convert(HLData,Data,MAX_DATA_LENGTH); safe_convert(HLUserName,User,MAX_NAME_LENGTH); RemoveCD(User); if (strlen(Data)==0) { /* Reporting on watches */ ReportWatches(UserIndex); return PLUGIN_HANDLED; } strbreak(Data,Target,Data,MAX_DATA_LENGTH); if ((strlen(Data)==0) && (g_RequireReason==1)) { language_say(UserIndex,"You must supply a reason when using bbwhois_watch",print_type:print_console,0,0,0,0); return PLUGIN_HANDLED; } /* Activating a watch */ if (Resolve(Target,AuthID,TargetIndex,TargetName,AKA)) { if (TargetIndex>0) { g_Watches[TargetIndex]=1; WriteSettings(TargetIndex); if (strlen(AKA) >0) { language_sayf(UserIndex,"Watch added for player '%1s' now playing as '%2s'.",print_type:print_console,0,0,0,0,AKA,TargetName); } else { language_sayf(UserIndex,"Watch added for player '%1s'.",print_type:print_console,0,0,0,0,TargetName); } LogNote("Watch",AuthID,UserIndex,User,Data,"",0); new AdminMsg[MAX_TEXT_LENGTH]; snprintf(AdminMsg,MAX_DATA_LENGTH,"### %s has watched %s, reason: %s",User,TargetName,Data); AnnounceToAdmins(AdminMsg,print_type:print_chat,UserIndex); } else { WriteSettingsByAuthID(AuthID,1); language_sayf(UserIndex,"Watch added for disconnected player '%1s'.",print_type:print_console,0,0,0,0,TargetName); LogNote("Watch",AuthID,UserIndex,User,Data,"",1); } } else { language_sayf(UserIndex,"Unknown player '%1s'",print_type:print_console,0,0,0,0,Target); } return PLUGIN_HANDLED; } public BBWhoisUnWatch(HLCommand,HLData,HLUserName,UserIndex) { new Data[MAX_DATA_LENGTH]; new User[MAX_NAME_LENGTH]; new Target[MAX_DATA_LENGTH]; new TargetIndex; new TargetName[MAX_DATA_LENGTH]; new AuthID[MAX_AUTHID_LENGTH]; new AKA[MAX_NAME_LENGTH]; safe_convert(HLData,Data,MAX_DATA_LENGTH); safe_convert(HLUserName,User,MAX_NAME_LENGTH); RemoveCD(User); strbreak(Data,Target,Data,MAX_DATA_LENGTH); if ((strlen(Data)==0) && (g_RequireReason==1)) { language_say(UserIndex,"You must supply a reason when using bbwhois_unwatch",print_type:print_console,0,0,0,0); return PLUGIN_HANDLED; } if (Resolve(Target,AuthID,TargetIndex,TargetName,AKA)) { if (TargetIndex>0) { g_Watches[TargetIndex]=0; WriteSettings(TargetIndex); LogNote("Unwatch",AuthID,UserIndex,User,Data,"",0); if (strlen(AKA) >0) { language_sayf(UserIndex,"Watch removed for player '%1s' now playing as '%2s'.",print_type:print_console,0,0,0,0,AKA,TargetName); } else { language_sayf(UserIndex,"Watch removed for player '%1s'.",print_type:print_console,0,0,0,0,TargetName); } new AdminMsg[MAX_TEXT_LENGTH]; snprintf(AdminMsg,MAX_DATA_LENGTH,"### %s has unwatched %s, reason: %s",User,TargetName,Data); AnnounceToAdmins(AdminMsg,print_type:print_chat,UserIndex); } else { WriteSettingsByAuthID(AuthID,0); language_sayf(UserIndex,"Watch removed for disconnected player '%1s'.",print_type:print_console,0,0,0,0,TargetName); LogNote("Unwatch",AuthID,UserIndex,User,Data,"",1); } } else { language_sayf(UserIndex,"Unknown player '%1s'",print_type:print_console,0,0,0,0,Target); } return PLUGIN_HANDLED; } public BBWhoisAdmin(HLCommand,HLData,HLUserName,UserIndex) { ReportAdmins(UserIndex); return PLUGIN_HANDLED; } public BBWhoisLan(HLCommand,HLData,HLUserName,UserIndex) { ReportLan(UserIndex); return PLUGIN_HANDLED; } public BBWhoisReset(HLCommand,HLData,HLUserName,UserIndex) { g_Report=DEFAULT_REPORT; g_RequireReason=DEFAULT_REQUIREREASON; writevaultnum("bbwhois_requirereason",g_RequireReason); writevaultnum("bbwhois_report",g_Report); return ShowConfig(UserIndex,0); } public BBWhoisReport(HLCommand,HLData,HLUserName,UserIndex) { if (readHLonoff(HLData,g_Report,DEFAULT_REPORT,MIN_REPORT,MAX_REPORT)) { writevaultnum("bbwhois_report",g_Report); ShowConfig(UserIndex,0); } else { ShowConfig(UserIndex,1); } return PLUGIN_HANDLED; } public BBWhoisRR(HLCommand,HLData,HLUserName,UserIndex) { if (readHLonoff(HLData,g_RequireReason,DEFAULT_REQUIREREASON,MIN_REQUIREREASON,MAX_REQUIREREASON)) { writevaultnum("bbwhois_requirereason",g_RequireReason); } return ShowConfig(UserIndex,0); } public BBWhoisTeamKill(HLCommand,HLData,HLUserName,UserIndex) { if (readHLonoff(HLData,g_TeamKill,DEFAULT_TEAMKILL,MIN_TEAMKILL,MAX_TEAMKILL)) { writevaultnum("bbwhois_teamkill",g_TeamKill); } return ShowConfig(UserIndex,0); } ShowConfig(UserIndex,Force) { if ((Force==0) && (g_Report==0)) { return PLUGIN_HANDLED; } language_say(UserIndex,MSG_REPORTTITLE,print_type:print_console,0,0,0,0); if (g_RequireReason==0) { language_say(UserIndex,MSG_RPT_REASONDISABLED,print_type:print_console,0,0,0,0); } else { language_say(UserIndex,MSG_RPT_REASONENABLED,print_type:print_console,0,0,0,0); } if (g_TeamKill==0) { language_say(UserIndex,MSG_RPT_TEAMKILL_OFF,print_type:print_console,0,0,0,0); } else { language_say(UserIndex,MSG_RPT_TEAMKILL_ON,print_type:print_console,0,0,0,0); } language_say(UserIndex,MSG_CDREPORTTITLE,print_type:print_console,0,0,0,0); if (g_RcdEnabled) { language_say(UserIndex,MSG_RPT_RCD_ON,print_type:print_console,0,0,0,0); } else { language_say(UserIndex,MSG_RPT_RCD_OFF,print_type:print_console,0,0,0,0); } language_sayf(UserIndex,MSG_RPT_RCD_MAXIMUM,print_type:print_console,0,0,0,0,g_RcdMaximum); language_sayf(UserIndex,MSG_RPT_RCD_RATIO,print_type:print_console,0,0,0,0,g_RcdRatio); language_sayf(UserIndex,MSG_RPT_RCD_MINIMUM,print_type:print_console,0,0,0,0,g_RcdMinimum); return PLUGIN_HANDLED; } public BBWhoisRCD(HLCommand,HLData,HLUserName,UserIndex) { new strData[MAX_DATA_LENGTH]; new strValue[MAX_DATA_LENGTH]; new strType[MAX_DATA_LENGTH]; new nValue=0; safe_convert(HLData,strData,MAX_DATA_LENGTH); new args=strsplit(strData," ",strValue,MAX_DATA_LENGTH,strType,MAX_DATA_LENGTH); nValue = strtonum(strValue); if ((args==2) && (strcasecmp(strType,"minimum")==0)) { if ( (nValue < MIN_RCD_MINIMUM) || (nValue > MAX_RCD_MINIMUM)) { g_RcdMinimum = DEFAULT_RCD_MINIMUM; } else { g_RcdMinimum = nValue; } writevaultnum("bbwhois_rcdminimum",g_RcdMinimum); ShowConfig(UserIndex,0); } else if ((args==2) && (strcasecmp(strType,"maximum")==0)) { if ( (nValue < MIN_RCD_MAXIMUM) || (nValue > MAX_RCD_MAXIMUM)) { g_RcdMaximum = DEFAULT_RCD_MAXIMUM; } else { g_RcdMaximum = nValue; } writevaultnum("bbwhois_rcdmaximum",g_RcdMaximum); ShowConfig(UserIndex,0); } else if ((args==2) && (strcasecmp(strType,"ratio")==0)) { if ( (nValue < MIN_RCD_RATIO) || (nValue > MAX_RCD_RATIO)) { g_RcdRatio = DEFAULT_RCD_RATIO; } else { g_RcdRatio = nValue; } writevaultnum("bbwhois_rcdratio",g_RcdRatio); ShowConfig(UserIndex,0); } else if ((args==1) && (strcasecmp(strValue,"on")==0)) { g_RcdEnabled = 1; writevaultnum("bbwhois_rcdenabled",g_RcdEnabled); ShowConfig(UserIndex,0); } else if ((args==1) && (strcasecmp(strValue,"off")==0)) { g_RcdEnabled = 0; writevaultnum("bbwhois_rcdenabled",g_RcdEnabled); ShowConfig(UserIndex,0); } else { /* TODO: Error message */ } return PLUGIN_HANDLED; } /* ************ Replacement Commands ************** */ /* admin_ban <target or WONID or IP> [<minutes>] [reason] admin_banip <target or WONID or IP> [<minutes>] */ public admin_ban(HLCommand,HLData,HLUserName,UserIndex) { new ban_user[MAX_DATA_LENGTH]; new BanTime = 0; new iBanType = bBanByID; new Command[MAX_COMMAND_LENGTH]; new Data[MAX_DATA_LENGTH]; new strTime[MAX_DATA_LENGTH]; new strReason[MAX_DATA_LENGTH]; new Text[MAX_TEXT_LENGTH]; new TargetName[MAX_NAME_LENGTH]; new TargetIndex; new User[MAX_NAME_LENGTH]; new strFormattedTime[MAX_TEXT_LENGTH]; convert_string(HLCommand,Command,MAX_COMMAND_LENGTH); convert_string(HLData,Data,MAX_DATA_LENGTH); convert_string(HLUserName,User,MAX_NAME_LENGTH); strbreak(Data,ban_user,strTime, MAX_DATA_LENGTH); strbreak(strTime, strTime, strReason, MAX_DATA_LENGTH); if (strlen(strReason)==0 && (g_RequireReason==1)) { language_say(UserIndex,"You must supply a reason when using admin_ban (use a time of 0 for a permanent ban)",print_type:print_console,0,0,0,0); return PLUGIN_HANDLED; } if (strlen(strTime) != 0) { BanTime = parseduration(strTime,strFormattedTime); if (BanTime == 0 && strTime[0]!='0') { language_say(UserIndex,"To supply a reason when using admin_ban supply a time period first (use a time of 0 for a permanent ban)",print_type:print_console,0,0,0,0); return PLUGIN_HANDLED; } } numtostr(BanTime,strTime); if((getvar("sv_lan") == 1) || (strcasecmp(Command, "admin_banip")==0)) iBanType = bBanByIP; if (check_user(ban_user)==1) { get_username(ban_user,TargetName,MAX_NAME_LENGTH); get_userindex(ban_user,TargetIndex); say_command(User,Command,TargetName); if(check_immunity(ban_user)==1) { snprintf(Text, MAX_TEXT_LENGTH, "Laf. You can't ban '%s', you silly bear.", TargetName); messageex(User,Text,print_type:print_chat); } else { if (iBanType == bBanByID) { LogNote("Ban",TargetName,UserIndex,User,strReason,strTime,0); } if (strlen(strReason)>0) { snprintf(Text,MAX_TEXT_LENGTH,"You have been banned from this server for %s^n^nReason for ban: %s",strFormattedTime,strReason); } else { snprintf(Text,MAX_TEXT_LENGTH,"You have been banned from this server for %s",strFormattedTime); } BigConsoleMessage(TargetIndex,Text); snprintf(Text,MAX_TEXT_LENGTH,"%i %i %s",iBanType,BanTime,ban_user); set_timer("DelayedBan",1,1,Text); g_Kicked[TargetIndex]=BanTime; new AdminMsg[MAX_TEXT_LENGTH]; RemoveCD(User); snprintf(AdminMsg,MAX_DATA_LENGTH,"### %s has banned %s, reason: %s",User,ban_user,strReason); AnnounceToAdmins(AdminMsg,print_type:print_chat,UserIndex); } } else { say_command(User,Command,ban_user); if (iBanType == bBanByID) { RemoveCD(User); LogNote("Ban",ban_user,UserIndex,User,strReason,strTime,1); } ban(ban_user,BanTime,iBanType); } return PLUGIN_HANDLED; } /* Delayed ban is to give time for the big console message to be sent */ public DelayedBan(Timer,Repeat,HLUserName,HLParam) { new strBanInfo[MAX_TEXT_LENGTH]; new strType[MAX_TEXT_LENGTH]; new strTime[MAX_TEXT_LENGTH]; convert_string(HLParam,strBanInfo,MAX_TEXT_LENGTH); strbreak(strBanInfo,strType,strBanInfo,MAX_TEXT_LENGTH); strbreak(strBanInfo,strTime,strBanInfo,MAX_TEXT_LENGTH); ban(strBanInfo,strtonum(strTime),strtonum(strType)); return PLUGIN_HANDLED; } /* admin_kick <target> [<reason>] */ public admin_kick(HLCommand,HLData,HLUserName,UserIndex) { new Command[MAX_COMMAND_LENGTH]; new Data[MAX_DATA_LENGTH]; new kick_user[MAX_DATA_LENGTH]; new Reason[MAX_DATA_LENGTH]; new Text[MAX_TEXT_LENGTH]; new User[MAX_NAME_LENGTH]; new TargetIndex; convert_string(HLCommand,Command,MAX_COMMAND_LENGTH); convert_string(HLData,Data,MAX_DATA_LENGTH); convert_string(HLUserName,User,MAX_NAME_LENGTH); strbreak(Data,kick_user,Reason,MAX_DATA_LENGTH); if (strlen(Reason)==0 && (g_RequireReason==1)) { language_say(UserIndex,"You must supply a reason when using admin_kick",print_type:print_console,0,0,0,0); return PLUGIN_HANDLED; } if ( check_user(kick_user) == 1) { new real_user[MAX_NAME_LENGTH]; get_username(kick_user,real_user,MAX_NAME_LENGTH); get_userindex(kick_user,TargetIndex); say_command(User,Command,real_user); if(check_immunity(kick_user)!=0) { snprintf(Text, MAX_TEXT_LENGTH, "Laf. You can't kick '%s', you silly bear.", real_user); messageex(User, Text, print_type:print_chat); } else { if (strlen(Reason) != 0) { snprintf(Text, MAX_TEXT_LENGTH, "You have been kicked from this server^n^nReason for kick: %s", Reason); } else { strcpy(Text, "You have been kicked from this server", MAX_TEXT_LENGTH); } BigConsoleMessage(TargetIndex,Text); RemoveCD(User); LogNote("Kick",real_user,UserIndex,User,Reason,"",0); set_timer("DelayedKick",2,1,real_user); g_Kicked[TargetIndex]=-12345678; new AdminMsg[MAX_TEXT_LENGTH]; snprintf(AdminMsg,MAX_DATA_LENGTH,"### %s has kicked %s, reason: %s",User,real_user,Reason); AnnounceToAdmins(AdminMsg,print_type:print_chat,UserIndex); } } else { selfmessage("Unrecognized player: "); selfmessage(kick_user); } return PLUGIN_HANDLED; } public DelayedKick(Timer,Repeat,HLUserName,HLParam) { new strUser[MAX_NAME_LENGTH]; convert_string(HLParam,strUser,MAX_NAME_LENGTH); kick(strUser); return PLUGIN_HANDLED; } /* admin_unban <WONID or IP> */ public admin_unban(HLCommand,HLData,HLUserName,UserIndex) { new Command[MAX_COMMAND_LENGTH]; new Data[MAX_DATA_LENGTH]; new User[MAX_NAME_LENGTH]; convert_string(HLCommand,Command,MAX_COMMAND_LENGTH); convert_string(HLData,Data,MAX_DATA_LENGTH); convert_string(HLUserName,User,MAX_NAME_LENGTH); new unban_user[MAX_DATA_LENGTH]; new Reason[MAX_DATA_LENGTH]; strbreak(Data,unban_user,Reason,MAX_DATA_LENGTH); if (strlen(Reason)==0 && (g_RequireReason==1)) { language_say(UserIndex,"You must supply a reason when using admin_unban",print_type:print_console,0,0,0,0); return PLUGIN_HANDLED; } unban(unban_user); log_command(User,Command,Data); RemoveCD(User); LogNote("Unban",unban_user,UserIndex,User,Reason,"",1); return PLUGIN_HANDLED; } /* *************** Event Capture ***************** */ public BBLogdWorldAction(HLCommand,HLData,HLUserName,UserIndex) { new Data[MAX_DATA_LENGTH]; safe_convert(HLData,Data,MAX_DATA_LENGTH); if (strmatch(Data,"Round_End",9)==1) { /*LogWriteTimer causes lag, so let the death animation of the last *player finish first then call it. Also set backup timer for next round *in case this isn't a round based mod */ set_timer("LogWriteTimer",2,1,""); set_timer("LogWriteTimer",ROUND_TIME,1,""); new i; for (i=0;i<MAX_PLAYERS;i++) { g_TeamKillsLast[i]=g_TeamKills[i]; g_TeamKills[i]=0; } } if (strmatch(Data,"Round_Start",11)==1) { g_RoundStartTime=get_unixtime(); } return PLUGIN_HANDLED; } public BBLogdKill(HLCommand,HLData,HLUserName,UserIndex) { new Data[MAX_DATA_LENGTH]; new strIndex[MAX_DATA_LENGTH]; new nKillerIndex; new nVictimIndex; new nKillerType; new nVictimType; safe_convert(HLData,Data,MAX_DATA_LENGTH); strbreak(Data,strIndex,Data,MAX_DATA_LENGTH); nKillerIndex=strtonum(strIndex); strbreak(Data,strIndex,Data,MAX_DATA_LENGTH); nVictimIndex=strtonum(strIndex); nKillerType = 1-g_AdminConnected; nVictimType = 1-g_AdminConnected; if (g_CheatingDeath) { if (g_CD_Status[nKillerIndex]==0) { nKillerType+=2; } if (g_CD_Status[nVictimIndex]==0) { nVictimType+=2; } } /* snprintf(Data,MAX_DATA_LENGTH,"Killer: %i/%i/%i, Vicitim: %i/%i/%i,CD: %i, Admin: %i",nKillerIndex,nKillerType,g_CD_Status[nKillerIndex],nVictimIndex,nVictimType,g_CD_Status[nVictimIndex],g_CheatingDeath,g_AdminConnected); log(Data);*/ if (nKillerIndex>0 && nKillerIndex<MAX_PLAYERS) { g_Kills[nKillerIndex][nKillerType]=g_Kills[nKillerIndex][nKillerType]+1; } if (nVictimIndex>0 && nVictimIndex<MAX_PLAYERS) { g_Deaths[nVictimIndex][nVictimType]=g_Deaths[nVictimIndex][nVictimType]+1; } if (g_TeamKill) { new nKillerTeam; new nVictimTeam; new KillerAuthID[MAX_AUTHID_LENGTH]; new VictimAuthID[MAX_AUTHID_LENGTH]; new VictimName[MAX_NAME_LENGTH]; new KillerName[MAX_NAME_LENGTH]; new Msg[MAX_DATA_LENGTH]; new nDummy; new i; new strKillTime[30]; if (nKillerIndex>0 && nKillerIndex<MAX_PLAYERS && nVictimIndex>0 && nVictimIndex<MAX_PLAYERS) { if (playerinfo(nKillerIndex,KillerName,MAX_NAME_LENGTH,nDummy,nDummy,nKillerTeam,nDummy,KillerAuthID)) { if (playerinfo(nVictimIndex,VictimName,MAX_NAME_LENGTH,nDummy,nDummy,nVictimTeam,nDummy,VictimAuthID)) { if (nKillerTeam == nVictimTeam) { snprintf(strKillTime,30,"%i seconds into round",get_unixtime() - g_RoundStartTime); RemoveCD(VictimName); if (g_TeamKillsLast[nKillerIndex]==nVictimIndex) { snprintf(Msg,MAX_DATA_LENGTH,"On %1s(%2s) who team killed him/her last round.",VictimName,VictimAuthID); LogNote("Team Kill",KillerAuthID,0,"Automatic",Msg,strKillTime,0); } if (g_TeamKillsLast[nVictimIndex]==nKillerIndex) { snprintf(Msg,MAX_DATA_LENGTH,"On %1s(%2s) twice on consecutive rounds.",VictimName,VictimAuthID); LogNote("Team Kill",KillerAuthID,0,"Automatic",Msg,strKillTime,0); } for (i=0;i<MAX_PLAYERS;i++) { if (g_TeamKills[i]==nKillerIndex) { LogNote("Team Kill",KillerAuthID,0,"Automatic","More than once in the same round",strKillTime,0); } } g_TeamKills[nVictimIndex]=nKillerIndex; } } } } } return PLUGIN_HANDLED; } OnEndOfRound() { new c = maxplayercount(); new i; new name[MAX_NAME_LENGTH]; for (i=1;i<=c;i++) { if (playerinfo(i,name,MAX_NAME_LENGTH)) { LogEndOfRound(i,name); } } } /* *************** HL Guard Callback ***************** */ public BBWhoisHLGuard(HLCommand,HLData,HLUserName,UserIndex) { new Data[MAX_DATA_LENGTH]; safe_convert(HLData,Data,MAX_DATA_LENGTH); new User[MAX_NAME_LENGTH]; safe_convert(HLUserName,User,MAX_DATA_LENGTH); if (streq(User,"Admin")==0) { snprintf(Data,MAX_DATA_LENGTH,"Attempt by %s to use HLGuard command.",User); log(Data); return PLUGIN_HANDLED; } new Event[MAX_DATA_LENGTH]; new EventUser[MAX_DATA_LENGTH]; new Msg[MAX_DATA_LENGTH]; new TargetIndex; new ui[2]; new AdminMsg[MAX_DATA_LENGTH]; strbreak(Data,Event,Data,MAX_DATA_LENGTH); strbreak(Data,EventUser,Data,MAX_DATA_LENGTH); /* Debug - can remove this */ snprintf(Msg,MAX_DATA_LENGTH,"HLGuard event %s for %s: #%s#",Event,EventUser,Data); plugin_message(Msg); /* Ensure we have recorded the connections of everyone connecting so hlguard doesn't try to watch players that we haven't read the fact we are already watching */ LogConnectionTimer(0,0,0,0); if (get_userindex(EventUser,TargetIndex)) { if (streq(Event,"tempban")) { snprintf(Msg,MAX_DATA_LENGTH,"Banned for: %s",Data); LogNote("Ban",EventUser,0,"HLGuard",Msg,"120",0); snprintf(AdminMsg,MAX_DATA_LENGTH,"### HLGuard has banned %s for 120 minutes for %s",EventUser,Data); AnnounceToAdmins(AdminMsg,print_type:print_chat,0); } else if (streq(Event,"name")) { if (g_Watches[TargetIndex]==0) { if (HasBeenUnwatched(EventUser)==0) { g_Watches[TargetIndex]=1; WriteSettings(TargetIndex); LogNote("Watch",EventUser,0,"HLGuard","Clan or player name on HLGuard cheat list","",0); ui[0]=TargetIndex; ui[1]=0; set_timer("AnnounceWatchme",6,4,ui); } } } else if (streq(Event,"ban")) { snprintf(Msg,MAX_DATA_LENGTH,"Banned for: %s",Data); LogNote("Ban",EventUser,0,"HLGuard",Msg,"",0); snprintf(AdminMsg,MAX_DATA_LENGTH,"### HLGuard has banned %s for %s",EventUser,Data); AnnounceToAdmins(AdminMsg,print_type:print_chat,0); } else if (streq(Event,"kick")) { snprintf(Msg,MAX_DATA_LENGTH,"Kicked for: %s",Data); LogNote("Kick",EventUser,0,"HLGuard",Msg,"",0); snprintf(AdminMsg,MAX_DATA_LENGTH,"### HLGuard has kicked %s for %s",EventUser,Data); AnnounceToAdmins(AdminMsg,print_type:print_chat,0); } else if (streq(Event,"suspect")) { if (g_Watches[TargetIndex]==0) { if (HasBeenUnwatched(EventUser)==0) { g_Watches[TargetIndex]=1; WriteSettings(TargetIndex); snprintf(Msg,MAX_DATA_LENGTH,"Suspected of use cheat: %s",Data); LogNote("Watch",EventUser,0,"HLGuard",Msg,"",0); ui[0]=TargetIndex; ui[1]=0; set_timer("AnnounceWatchme",6,4,ui); } } } /* Don't think we care about these two else if (streq(Event,"write")) { } else if (streq(Event,"say")) { } */ } return PLUGIN_HANDLED; } /* *************** HL Guard Callback ***************** */ public BBWhoisCDStatus(HLCommand,HLData,HLUserName,UserIndex) { new Data[MAX_DATA_LENGTH]; safe_convert(HLData,Data,MAX_DATA_LENGTH); new User[MAX_NAME_LENGTH]; safe_convert(HLUserName,User,MAX_DATA_LENGTH); if (streq(User,"Admin")==0) { snprintf(Data,MAX_DATA_LENGTH,"Attempt by %s to use CD status command.",User); log(Data); return PLUGIN_HANDLED; } new strSessionID[MAX_DATA_LENGTH]; strbreak(Data,strSessionID,Data,MAX_TEXT_LENGTH); new nSessionID = strtonum(strSessionID); new nStatus = strtonum(Data); if ((nStatus != 255) && (nStatus != 3)) { new nUserIndex = UserIndexFromSessionID(nSessionID); if (nUserIndex>0) { g_CD_Status[nUserIndex]=nStatus; new AuthID[MAX_AUTHID_LENGTH]; if (GetAuthID(UserIndex,AuthID)) { MediateCD(nUserIndex,AuthID); } } } return PLUGIN_HANDLED; } /* *************** Data Logging ***************** */ public LogWriteTimer(Timer,Repeat,HLUserName,HLParam) { OnEndOfRound(); return PLUGIN_HANDLED; } public LogConnectionTimer(Timer,Repeat,HLUserName,HLParam) { new c = maxplayercount(); new i; new Name[MAX_NAME_LENGTH]; new ui[2]; new wonid; new team; new dead; new sessionid; new AuthID[MAX_AUTHID_LENGTH]; for (i=1;i<=c;i++) { if (g_Connections[i]==1) { if (playerinfo(i,Name,MAX_NAME_LENGTH,sessionid,wonid,team,dead,AuthID)) { if (LogConnection(i)) { ReadSettings(i); g_Rounds[i]=LookupRoundCount(AuthID); if (g_Watches[i]==0) { CheckCrossReference(i); } g_Connections[i]=0; if (access(ACCESS_WHOIS,Name)) { ui[0]=i; ui[1]=0; set_timer("AnnounceWatches",5,2,ui); ReportLan(i); } if (g_Watches[i]) { ui[0]=i; ui[1]=0; set_timer("AnnounceWatchme",6,2,ui); } RemoveCD(Name); CheckOldNames(Name,AuthID); CheckIP(i,0); if (g_LanDetect[i]==0) { CheckSubnet(i,0); } } } } if (g_CheatingDeath) { if (g_CD_Status[i]==3) { if (playerinfo(i,Name,MAX_NAME_LENGTH,sessionid)) { new CDCmd[MAX_DATA_LENGTH]; snprintf(CDCmd,MAX_DATA_LENGTH,"cdstatus ^"admin_command BBWhois_CDStatus^" %i",sessionid); exec(CDCmd,0); } } } } g_AdminConnected=IsAdminConnected(); return PLUGIN_HANDLED; } LogConnection(UserIndex) { new AuthID[MAX_AUTHID_LENGTH]; new Buf[MAX_DATA_LENGTH]; if (GetAuthID(UserIndex,AuthID)==0) { return 0; } new Path[MAX_DATA_LENGTH]; new ParsedAuthID[MAX_AUTHID_LENGTH]; new HashParsedAuthID; GenerateFilename(Path,ParsedAuthID,HashParsedAuthID,"addons/whois/db",AuthID,"Connections.xml"); new nLine=-1; new nConnects=0; new strDate[MAX_DATE_LENGTH]; GetDate(strDate); new nMode=0; if (fileexists(Path)) { nMode=1; nLine=LookupConnectCount(Path,strDate,nConnects); if (nLine>0) { nMode=2; } } if (nMode==0) { writefile(Path,"<?xml version=^"1.0^"?>"); writefile(Path,"<?xml-stylesheet type=^"text/xsl^" href=^"../redirect.xsl^"?>"); snprintf(Buf,MAX_DATA_LENGTH,"<connections hash=^"%i^" authid=^"%s^">",HashParsedAuthID,ParsedAuthID); writefile(Path,Buf,-1); writefile(Path,"</connections>"); nMode=1; } if (nMode==1) { writefile(Path,"<connection>",filesize(Path)); writefile(Path,"<date>"); writefile(Path,strDate); writefile(Path,"</date>"); writefile(Path,"<count>"); numtostr(nConnects+1,Buf); writefile(Path,Buf); writefile(Path,"</count>"); writefile(Path,"</connection>"); writefile(Path,"</connections>"); } else { numtostr(nConnects+1,Buf); writefile(Path,Buf,nLine); } /* Now log to IP cross-referencing database * This works on actual AuthIDs rather than parsed AuthID's */ new IP[30]; iptostr(g_IPs[UserIndex],IP); GenerateFilename(Path,ParsedAuthID,HashParsedAuthID,"addons/whois/ips",IP,"address.txt"); if (LookupAddress(Path,AuthID)==0) { writefile(Path,AuthID); } /* And log subnet to cross-referencing database */ iptostr(g_IPs[UserIndex] & 4294967040,IP); /*4294967040 = 0xFFFFFF00 - masks out last octet */ GenerateFilename(Path,ParsedAuthID,HashParsedAuthID,"addons/whois/ips",IP,"subnet.txt"); if (LookupAddress(Path,AuthID)==0) { writefile(Path,AuthID); } return 1; } LookupConnectCount(Path[],strDate[],&nConnects) { new fs = filesize(Path); new i=4; new strFDate[MAX_DATE_LENGTH]; new strFConnects[MAX_NUMBER_LENGTH]; while(i<fs) { readfile(Path,strFDate,i+2,MAX_DATE_LENGTH); readfile(Path,strFConnects,i+5,MAX_NUMBER_LENGTH); if (streq(strDate,strFDate)) { nConnects=strtonum(strFConnects); return i+5; } i=i+8; } nConnects=0; return -1; } LookupNameCount(Path[],strName[],&nRounds) { new fs = filesize(Path); new i=4; new strFName[MAX_NAME_LENGTH]; new strFRounds[MAX_NUMBER_LENGTH]; while (i<fs) { readfile(Path,strFName,i+2,MAX_NAME_LENGTH); readfile(Path,strFRounds,i+5,MAX_NUMBER_LENGTH); if (streq(strName,strFName)) { nRounds=strtonum(strFRounds); return i+5; } i=i+8; } nRounds=0; return -1; } LookupIPCount(Path[],strIP[],&nRounds) { new fs = filesize(Path); new i=4; new strFIP[MAX_NAME_LENGTH]; new strFRounds[MAX_NUMBER_LENGTH]; while (i<fs) { readfile(Path,strFIP,i+2,MAX_NAME_LENGTH); readfile(Path,strFRounds,i+5,MAX_NUMBER_LENGTH); if (streq(strIP,strFIP)) { nRounds=strtonum(strFRounds); return i+5; } i=i+8; } nRounds=0; return -1; } LookupAddress(Path[],AuthID[]) { new fs = filesize(Path); new strFAuthID[MAX_AUTHID_LENGTH]; new i=1; while (i<=fs) { readfile(Path,strFAuthID,i,MAX_AUTHID_LENGTH); if (streq(strFAuthID,AuthID)) { return 1; } i++; } return 0; } LookupRoundCount(AuthID[]) { new Path[MAX_DATA_LENGTH]; new ParsedAuthID[MAX_AUTHID_LENGTH]; new HashParsedAuthID; new nCount=0; GenerateFilename(Path,ParsedAuthID,HashParsedAuthID,"addons/whois/db",AuthID,"Names.xml"); new fs = filesize(Path); new i=4; new strFRounds[MAX_NUMBER_LENGTH]; while (i<fs) { readfile(Path,strFRounds,i+5,MAX_NUMBER_LENGTH); nCount+=strtonum(strFRounds); i=i+8; } return nCount; } LogEndOfRound(UserIndex,UserName[]) { new AuthID[MAX_AUTHID_LENGTH]; if (GetAuthID(UserIndex,AuthID)==0) { /* Don't log failure here - it will occur for all empty slots! */ return; } g_Rounds[UserIndex]=g_Rounds[UserIndex]+1; LogKills(UserIndex,AuthID); RemoveCD(UserName); LogNames(UserName,AuthID); LogIPs(UserIndex,AuthID); MediateCD(UserIndex,AuthID); } LogNames(UserName[],AuthID[]) { new Buf[MAX_DATA_LENGTH]; new Path[MAX_DATA_LENGTH]; new ParsedAuthID[MAX_AUTHID_LENGTH]; new HashParsedAuthID; GenerateFilename(Path,ParsedAuthID,HashParsedAuthID,"addons/whois/db",AuthID,"Names.xml"); new nRounds=0; new nLine=-1; new nMode=0; if (fileexists(Path)) { nMode=1; nLine=LookupNameCount(Path,UserName,nRounds); if (nLine>0) { nMode=2; } } if (nMode==0) { writefile(Path,"<?xml version=^"1.0^"?>"); writefile(Path,"<?xml-stylesheet type=^"text/xsl^" href=^"../redirect.xsl^"?>"); snprintf(Buf,MAX_DATA_LENGTH,"<names hash=^"%i^" authid=^"%s^">",HashParsedAuthID, ParsedAuthID); writefile(Path,Buf,-1); writefile(Path,"</names>"); nMode=1; } if (nMode==1) { writefile(Path,"<name>",filesize(Path)); writefile(Path,"<alias><![CDATA["); writefile(Path,UserName); writefile(Path,"]]></alias>"); writefile(Path,"<count>"); numtostr(nRounds+1,Buf); writefile(Path,Buf); writefile(Path,"</count>"); writefile(Path,"</name>"); writefile(Path,"</names>"); } else { numtostr(nRounds+1,Buf); writefile(Path,Buf,nLine); } } LogIPs(UserIndex,AuthID[]) { new Buf[MAX_DATA_LENGTH]; new IP[30]; iptostr(g_IPs[UserIndex],IP); new Path[MAX_DATA_LENGTH]; new ParsedAuthID[MAX_DATA_LENGTH]; new HashParsedAuthID; GenerateFilename(Path,ParsedAuthID,HashParsedAuthID,"addons/whois/db",AuthID,"IPs.xml"); new nRounds=0; new nLine=-1; new nMode=0; if (fileexists(Path)) { nMode=1; nLine=LookupIPCount(Path,IP,nRounds); if (nLine>0) { nMode=2; } } if (nMode==0) { writefile(Path,"<?xml version=^"1.0^"?>"); writefile(Path,"<?xml-stylesheet type=^"text/xsl^" href=^"../redirect.xsl^"?>"); snprintf(Buf,MAX_DATA_LENGTH,"<ips hash=^"%i^" authid=^"%s^">",HashParsedAuthID, ParsedAuthID); writefile(Path,Buf,-1); writefile(Path,"</ips>"); nMode=1; } if (nMode==1) { writefile(Path,"<ip>",filesize(Path)); writefile(Path,"<address>"); writefile(Path,IP); writefile(Path,"</address>"); writefile(Path,"<count>"); numtostr(nRounds+1,Buf); writefile(Path,Buf); writefile(Path,"</count>"); writefile(Path,"</ip>"); writefile(Path,"</ips>"); } else { numtostr(nRounds+1,Buf); writefile(Path,Buf,nLine); } } LoadKillStatus(Path[],K[],D[]) { new Buf[MAX_TEXT_LENGTH]; new fOK=0; if (fileexists(Path)) { if (readfile(Path,Buf,6,MAX_DATA_LENGTH)) { K[KD_NOCD_ADMIN]=strtonum(Buf); if (readfile(Path,Buf,9,MAX_DATA_LENGTH)) { K[KD_NOCD_NOADMIN]=strtonum(Buf); if (readfile(Path,Buf,14,MAX_DATA_LENGTH)) { D[KD_NOCD_ADMIN]=strtonum(Buf); if (readfile(Path,Buf,17,MAX_DATA_LENGTH)) { D[KD_NOCD_NOADMIN]=strtonum(Buf); fOK=1; if (readfile(Path,Buf,22,MAX_DATA_LENGTH)) { K[KD_CD_ADMIN]=strtonum(Buf); if (readfile(Path,Buf,25,MAX_DATA_LENGTH)) { K[KD_CD_NOADMIN]=strtonum(Buf); if (readfile(Path,Buf,30,MAX_DATA_LENGTH)) { D[KD_CD_ADMIN]=strtonum(Buf); if (readfile(Path,Buf,33,MAX_DATA_LENGTH)) { D[KD_CD_NOADMIN]=strtonum(Buf); } } } } } } } } } if (fOK==0) { K[KD_NOCD_ADMIN]=0; K[KD_NOCD_NOADMIN]=0; K[KD_CD_ADMIN]=0; K[KD_CD_NOADMIN]=0; D[KD_NOCD_ADMIN]=0; D[KD_NOCD_NOADMIN]=0; D[KD_CD_ADMIN]=0; D[KD_CD_NOADMIN]=0; } return fOK; } LogKills(UserIndex,AuthID[]) { new K[4]; new D[4]; new Buf[MAX_DATA_LENGTH]; new Path[MAX_DATA_LENGTH]; new ParsedAuthID[MAX_AUTHID_LENGTH]; new HashParsedAuthID; GenerateFilename(Path,ParsedAuthID,HashParsedAuthID,"addons/whois/db",AuthID,"Kills.xml"); LoadKillStatus(Path,K,D); /* If file is corrupt, ignore it all */ K[KD_NOCD_ADMIN]+=g_Kills[UserIndex][KD_NOCD_ADMIN]; K[KD_NOCD_NOADMIN]+=g_Kills[UserIndex][KD_NOCD_NOADMIN]; K[KD_CD_ADMIN]+=g_Kills[UserIndex][KD_CD_ADMIN]; K[KD_CD_NOADMIN]+=g_Kills[UserIndex][KD_CD_NOADMIN]; D[KD_NOCD_ADMIN]+=g_Deaths[UserIndex][KD_NOCD_ADMIN]; D[KD_NOCD_NOADMIN]+=g_Deaths[UserIndex][KD_NOCD_NOADMIN]; D[KD_CD_ADMIN]+=g_Deaths[UserIndex][KD_CD_ADMIN]; D[KD_CD_NOADMIN]+=g_Deaths[UserIndex][KD_CD_NOADMIN]; resetfile(Path); resetfile(Path); writefile(Path,"<?xml version=^"1.0^"?>"); writefile(Path,"<?xml-stylesheet type=^"text/xsl^" href=^"../redirect.xsl^"?>"); snprintf(Buf,MAX_DATA_LENGTH,"<performance hash=^"%i^" authid=^"%s^">",HashParsedAuthID, ParsedAuthID); writefile(Path,Buf,-1); writefile(Path,"<kills>"); writefile(Path,"<administered>"); numtostr(K[KD_NOCD_ADMIN],Buf); writefile(Path,Buf,-1); writefile(Path,"</administered>"); writefile(Path,"<unmonitored>"); numtostr(K[KD_NOCD_NOADMIN],Buf); writefile(Path,Buf,-1); writefile(Path,"</unmonitored>"); writefile(Path,"</kills>"); writefile(Path,"<deaths>"); writefile(Path,"<administered>"); numtostr(D[KD_NOCD_ADMIN],Buf); writefile(Path,Buf,-1); writefile(Path,"</administered>"); writefile(Path,"<unmonitored>"); numtostr(D[KD_NOCD_NOADMIN],Buf); writefile(Path,Buf,-1); writefile(Path,"</unmonitored>"); writefile(Path,"</deaths>"); writefile(Path,"<cdkills>"); writefile(Path,"<administered>"); numtostr(K[KD_CD_ADMIN],Buf); writefile(Path,Buf,-1); writefile(Path,"</administered>"); writefile(Path,"<unmonitored>"); numtostr(K[KD_CD_NOADMIN],Buf); writefile(Path,Buf,-1); writefile(Path,"</unmonitored>"); writefile(Path,"</cdkills>"); writefile(Path,"<cddeaths>"); writefile(Path,"<administered>"); numtostr(D[KD_CD_ADMIN],Buf); writefile(Path,Buf,-1); writefile(Path,"</administered>"); writefile(Path,"<unmonitored>"); numtostr(D[KD_CD_NOADMIN],Buf); writefile(Path,Buf,-1); writefile(Path,"</unmonitored>"); writefile(Path,"</cddeaths>"); writefile(Path,"</performance>"); g_Kills[UserIndex][KD_NOCD_ADMIN]=0; g_Kills[UserIndex][KD_NOCD_NOADMIN]=0; g_Kills[UserIndex][KD_CD_ADMIN]=0; g_Kills[UserIndex][KD_CD_NOADMIN]=0; g_Deaths[UserIndex][KD_NOCD_ADMIN]=0; g_Deaths[UserIndex][KD_NOCD_NOADMIN]=0; g_Deaths[UserIndex][KD_CD_ADMIN]=0; g_Deaths[UserIndex][KD_CD_NOADMIN]=0;} InitNotesFile(AuthID[]) { new Msg[MAX_DATA_LENGTH]; new Path[MAX_DATA_LENGTH]; new ParsedAuthID[MAX_DATA_LENGTH]; new HashParsedAuthID; GenerateFilename(Path,ParsedAuthID,HashParsedAuthID,"addons/whois/db",AuthID,"Notes.xml"); if (fileexists(Path)==0) { writefile(Path,"<?xml version=^"1.0^"?>"); writefile(Path,"<?xml-stylesheet type=^"text/xsl^" href=^"../redirect.xsl^"?>"); snprintf(Msg,MAX_DATA_LENGTH,"<notes hash=^"%i^" authid=^"%s^">",HashParsedAuthID, ParsedAuthID); writefile(Path,Msg,-1); writefile(Path,"</notes>"); } } LogNote(NoteType[],Target[],AdminIndex,AdminName[],Note[],Data[],Direct) { new TargetIndex; new TargetName[MAX_DATA_LENGTH]; new AuthID[MAX_AUTHID_LENGTH]; if (Direct==0) { /* Target is playing - get their info from the game */ if (get_userindex(Target,TargetIndex)==0) { selfmessage("Unrecognised player."); return; } if (GetAuthID(TargetIndex,AuthID)==0) { /* log error */ log("Error getting target authid from target index"); return; } } else { /* Target isn't playing but Target variable contains their WONID * lookup their top name */ new dummy=0; GetTopName(Target,"",TargetName,dummy); if (TargetName[0]==0) { strcpy(TargetName,"[Unknown - Player Not connected]",MAX_DATA_LENGTH); } } new AdminAuth[MAX_AUTHID_LENGTH]; if (AdminIndex!=0) { if (GetAuthID(AdminIndex,AdminAuth)==0) { /* log error - todo handle console */ log("Error getting admin authid from admin index"); return; } } new Msg[MAX_DATA_LENGTH]; new Date[MAX_DATE_LENGTH]; get_timestamp(Date); /* Write to player-specific notes file */ new Path[MAX_DATA_LENGTH]; new ParsedAuthID[MAX_DATA_LENGTH]; new HashParsedAuthID; if (Direct) { GenerateFilename(Path,ParsedAuthID,HashParsedAuthID,"addons/whois/db",Target,"Notes.xml"); } else { GenerateFilename(Path,ParsedAuthID,HashParsedAuthID,"addons/whois/db",AuthID,"Notes.xml"); } if (fileexists(Path)) { new fs = filesize(Path); writefile(Path,"<note>",fs); } else { writefile(Path,"<?xml version=^"1.0^"?>"); writefile(Path,"<?xml-stylesheet type=^"text/xsl^" href=^"../redirect.xsl^"?>"); snprintf(Msg,MAX_DATA_LENGTH,"<notes hash=^"%i^" authid=^"%s^">",HashParsedAuthID, ParsedAuthID); writefile(Path,Msg,-1); writefile(Path,"<note>"); } writefile(Path,"<date>"); writefile(Path,Date); writefile(Path,"</date>"); writefile(Path,"<type>"); writefile(Path,NoteType); writefile(Path,"</type>"); if (AdminIndex==0) { writefile(Path,"<admin authid=^"^" hash=^"^" ><![CDATA["); writefile(Path,AdminName); } else { /*TODO: Parse AdminAuth */ snprintf(Msg,MAX_DATA_LENGTH,"<admin authid=^"%s^" hash=^"%i^"><![CDATA[", AdminAuth,Hash(AdminAuth)); writefile(Path,Msg,-1); /* record the admin's top name if we have loaded otherwise their current name */ if (g_TopNames[AdminIndex][0]==0) { writefile(Path,AdminName); } else { writefile(Path,g_TopNames[AdminIndex]); } } writefile(Path,"]]></admin>"); writefile(Path,"<message><![CDATA["); writefile(Path,Note); writefile(Path,"]]></message>"); writefile(Path,"<data>"); writefile(Path,Data); writefile(Path,"</data>"); writefile(Path,"</note>"); writefile(Path,"</notes>"); /* write same data to global notes file */ strcpy(Path,"addons/whois/db/GlobalNotes.xml",MAX_DATA_LENGTH); if (fileexists(Path)) { new fs = filesize(Path); writefile(Path,"<note>",fs); } else { writefile(Path,"<?xml version=^"1.0^"?>"); writefile(Path,"<?xml-stylesheet type=^"text/xsl^" href=^"player.xsl^"?>"); writefile(Path,"<notes>"); writefile(Path,"<note>"); } snprintf(Msg,MAX_DATA_LENGTH,"<target authid=^"%s^" hash=^"%i^"><![CDATA[", ParsedAuthID,HashParsedAuthID); writefile(Path,Msg,-1); if (Direct) { RemoveCD(TargetName); writefile(Path,TargetName); } else { writefile(Path,g_TopNames[TargetIndex]); } writefile(Path,"]]></target>"); writefile(Path,"<date>"); writefile(Path,Date); writefile(Path,"</date>"); writefile(Path,"<type>"); writefile(Path,NoteType); writefile(Path,"</type>"); if (AdminIndex==0) { writefile(Path,"<admin authid=^"^" hash=^"^"><![CDATA["); writefile(Path,AdminName); } else { snprintf(Msg,MAX_DATA_LENGTH,"<admin authid=^"%s^" hash=^"%i^"><![CDATA[", AdminAuth,Hash(AdminAuth)); writefile(Path,Msg,-1); /* record the admin's top name if we have loaded otherwise their current name */ if (g_TopNames[AdminIndex][0]==0) { writefile(Path,AdminName); } else { writefile(Path,g_TopNames[AdminIndex]); } } writefile(Path,"]]></admin>"); writefile(Path,"<message><![CDATA["); writefile(Path,Note); writefile(Path,"]]></message>"); writefile(Path,"<data>"); writefile(Path,Data); writefile(Path,"</data>"); writefile(Path,"</note>"); writefile(Path,"</notes>"); } WriteSettings(UserIndex) { new AuthID[MAX_AUTHID_LENGTH]; if (GetAuthID(UserIndex,AuthID)==0) { /* log error */ log("Error getting target authid from target index"); return; } /* Write to player-specific notes file */ new Path[MAX_DATA_LENGTH]; new ParsedAuthID[MAX_DATA_LENGTH]; new HashParsedAuthID; GenerateFilename(Path,ParsedAuthID,HashParsedAuthID,"addons/whois/db",AuthID,".xml"); new Msg[MAX_DATA_LENGTH]; resetfile(Path); writefile(Path,"<?xml version=^"1.0^"?>"); writefile(Path,"<?xml-stylesheet type=^"text/xsl^" href=^"../player.xsl^"?>"); snprintf(Msg,MAX_DATA_LENGTH,"<player hash=^"%i^" authid=^"%s^">",HashParsedAuthID,ParsedAuthID); writefile(Path,Msg,-1); writefile(Path,"<watch>"); snprintf(Msg,MAX_DATA_LENGTH,"%i",g_Watches[UserIndex]); writefile(Path,Msg); writefile(Path,"</watch>"); writefile(Path,"</player>"); } WriteSettingsByAuthID(AuthID[],Watch) { new Msg[MAX_DATA_LENGTH]; new Path[MAX_DATA_LENGTH]; new ParsedAuthID[MAX_DATA_LENGTH]; new HashParsedAuthID; GenerateFilename(Path,ParsedAuthID,HashParsedAuthID,"addons/whois/db",AuthID,".xml"); if (fileexists(Path)) { snprintf(Msg,MAX_DATA_LENGTH,"%i",Watch); writefile(Path,Msg,5); return 1; } return 0; } ReadSettings(UserIndex) { new AuthID[MAX_AUTHID_LENGTH]; if (GetAuthID(UserIndex,AuthID)==0) { /* log error */ log("Error getting target authid from target index"); return; } new Buf[MAX_DATA_LENGTH]; /* Write to player-specific notes file */ new Path[MAX_DATA_LENGTH]; new ParsedAuthID[MAX_DATA_LENGTH]; new HashParsedAuthID; GenerateFilename(Path,ParsedAuthID,HashParsedAuthID,"addons/whois/db",AuthID,".xml"); if (fileexists(Path)) { readfile(Path,Buf,5,MAX_DATA_LENGTH); g_Watches[UserIndex]=strtonum(Buf); } else { /* First ever connection - init xml files */ g_Watches[UserIndex]=0; InitNotesFile(AuthID); WriteSettings(UserIndex); } new TopName[MAX_NAME_LENGTH]; new Second; TopName[0]=0; GetTopName(AuthID,"",TopName,Second); if (TopName[0]==0) { g_TopNames[UserIndex][0]=0; } else { strcpy(g_TopNames[UserIndex],TopName,MAX_NAME_LENGTH); } } /* *************** Reporting ***************** */ /* This is called 3 times at 10 seconds intervals when an admin * connects to alert them that there are players to watch on the server */ public AnnounceWatches(Timer,Repeat,HLUserName,HLParam) { new c = maxplayercount(); new i; new w=0; new Name[MAX_NAME_LENGTH]; new ui[MAX_DATA_LENGTH]; new p; convert_string(HLParam,ui,MAX_DATA_LENGTH); for(i=1;i<c;i++) { w=w+g_Watches[i]; if (g_Watches[i]) { p=i; } } if (w>0) { if (w==1) { if (playerinfo(p,Name,MAX_NAME_LENGTH)) { language_sayf(ui[0],"%1s should be watched - type bbwhois %1s for details.",print_type:print_console,0,0,0,0,Name); language_sayf(ui[0],"%1s should be watched - type bbwhois %1s for details.",print_type:print_chat,0,0,0,0,Name); return; } } language_sayf(ui[0],"%1i players on the server should be watched. Type bbwhois_watch for a list.",print_type:print_console,0,0,0,0,w); language_sayf(ui[0],"%1i players on the server should be watched. Type bbwhois_watch for a list.",print_type:print_chat,0,0,0,0,w); } } public AnnounceWatchme(Timer,Repeat,HLUserName,HLParam) { new c = maxplayercount(); new i; new ui[MAX_DATA_LENGTH]; new Name[MAX_NAME_LENGTH]; new WatchName[MAX_NAME_LENGTH]; convert_string(HLParam,ui,MAX_DATA_LENGTH); if (playerinfo(ui[0],WatchName,MAX_NAME_LENGTH)) { for(i=1;i<c;i++) { if (playerinfo(i,Name,MAX_NAME_LENGTH)) { if (access(ACCESS_WHOIS,Name)) { language_saybynamef(Name,"%1s should be watched - type bbwhois %1s for details.",print_type:print_console,0,0,0,0,WatchName); language_saybynamef(Name,"%1s should be watched - type bbwhois %1s for details.",print_type:print_chat,0,0,0,0,WatchName); } } } } } ReportWatches(UserIndex) { new c=maxplayercount(); new i; new fFirst=1; new Name[MAX_NAME_LENGTH]; for(i=1;i<=c;i++) { if (g_Watches[i]) { if (playerinfo(i,Name,MAX_NAME_LENGTH)) { if (fFirst) { language_say(UserIndex,"### The following players should be watched:",print_type:print_console,0,0,0,0); fFirst=0; } language_sayf(UserIndex,"### - %1s",print_type:print_console,0,0,0,0,Name); } } } if (fFirst) { language_sayf(UserIndex,"### No players currently on the server need to be watched.",print_type:print_console,0,0,0,0); } } ReportLan(UserIndex) { new i; new c=maxplayercount(); new strName[MAX_NAME_LENGTH]; for (i=1;i<=c;i++) { g_LanDetect[i]=0; } for (i=1;i<=c;i++) { if (g_LanDetect[i]==0) { if (playerinfo(i,strName,MAX_NAME_LENGTH)) { CheckIP(i,UserIndex); } } } for (i=1;i<=c;i++) { if (g_LanDetect[i]==0) { if (playerinfo(i,strName,MAX_NAME_LENGTH)) { CheckSubnet(i,UserIndex); } } } for (i=1;i<=c;i++) { if (g_LanDetect[i]==1) { return; } } language_sayf(UserIndex,"### No players currently detected on the same IP address or subnet.",print_type:print_console,0,0,0,0); } ReportAdmins(UserIndex) { new c=maxplayercount(); new i; new j; new fFirst=1; new Name[MAX_NAME_LENGTH]; new level; new test; new def = getvar("default_access"); for(i=1;i<=c;i++) { if (playerinfo(i,Name,MAX_NAME_LENGTH)) { /* Cant report on the top-most access level because it goes negative! */ level=0; test=1; for (j=0;j<31;j++) { if (access(test,Name)) { level=level+test; } test=test*2; } if ((level>0) && (level!=def)) { if (fFirst) { language_say(UserIndex,"### The following players have administrator access:",print_type:print_console,0,0,0,0); fFirst=0; } language_sayf(UserIndex,"### - %1s (%2i)",print_type:print_console,0,0,0,0,Name,level); } } } if (fFirst) { language_sayf(UserIndex,"### No players currently on the server have administrator access.",print_type:print_console,0,0,0,0); } } ReportHeader(UserIndex,AuthID[],Online,AKA[],fFull) { /* Report the WONID and time connected */ /* Report the number of connections today, last 7 days, last 30 days, total */ /* Report the kills with/without admin */ /* Schedule rest of report to occur in a few seconds to prevent overflowing the admin's client */ if (fFull) { set_timer("ReportNames",1,1,AuthID); set_timer("ReportIPs",2,1,AuthID); set_timer("ReportOtherIDs",3,1,AuthID); set_timer("ReportNotes",4,1,AuthID); } else { set_timer("ReportNamesShort",1,1,AuthID); set_timer("ReportNotes",2,1,AuthID); } new TargetIndex=-1; if (Online>0) { TargetIndex=get_indexFromAuthID(AuthID); } new K[4]; new D[4]; new Path[MAX_DATA_LENGTH]; new ParsedAuthID[MAX_AUTHID_LENGTH]; new HashParsedAuthID; GenerateFilename(Path,ParsedAuthID,HashParsedAuthID,"addons/whois/db",AuthID,"Kills.xml"); LoadKillStatus(Path,K,D); if (Online>0) { K[KD_NOCD_ADMIN]+=g_Kills[TargetIndex][KD_NOCD_ADMIN]; K[KD_NOCD_NOADMIN]+=g_Kills[TargetIndex][KD_NOCD_NOADMIN]; K[KD_CD_ADMIN]+=g_Kills[TargetIndex][KD_CD_ADMIN]; K[KD_CD_NOADMIN]+=g_Kills[TargetIndex][KD_CD_NOADMIN]; D[KD_NOCD_ADMIN]+=g_Deaths[TargetIndex][KD_NOCD_ADMIN]; D[KD_NOCD_NOADMIN]+=g_Deaths[TargetIndex][KD_NOCD_NOADMIN]; D[KD_CD_ADMIN]+=g_Deaths[TargetIndex][KD_CD_ADMIN]; D[KD_CD_NOADMIN]+=g_Deaths[TargetIndex][KD_CD_NOADMIN]; } new Ratio1[20]; new Ratio2[20]; new Ratio3[20]; new Ratio4[20]; new Ratio5[20]; CalcRatio(K[KD_NOCD_ADMIN],D[KD_NOCD_ADMIN],Ratio1); CalcRatio(K[KD_NOCD_NOADMIN],D[KD_NOCD_NOADMIN],Ratio2); CalcRatio(K[KD_CD_ADMIN],D[KD_CD_ADMIN],Ratio3); CalcRatio(K[KD_CD_NOADMIN],D[KD_CD_NOADMIN],Ratio4); CalcRatio(K[KD_NOCD_NOADMIN]+K[KD_NOCD_ADMIN]+K[KD_CD_NOADMIN]+K[KD_CD_ADMIN], D[KD_NOCD_NOADMIN]+D[KD_NOCD_ADMIN]+D[KD_CD_NOADMIN]+D[KD_CD_ADMIN],Ratio5); new TopName[MAX_NAME_LENGTH]; new CurName[MAX_NAME_LENGTH]; new swap; new level=0; if (Online>0) { playerinfo(TargetIndex,CurName,MAX_NAME_LENGTH); new test=1; new i; for (i=0;i<31;i++) { if (access(test,CurName)) { level=level+test; } test=test*2; } RemoveCD(CurName); } else { CurName[0]=0; } if (strlen(AKA)==0) { GetTopName(AuthID,CurName,TopName,swap); } if (Online>0) { /* Cant report on the top-most access level because it goes negative! */ } new strIP[20]; if (Online>0) { iptostr(g_IPs[TargetIndex],strIP); } else { strcpy(strIP,"Not connected",20); } if (strlen(AKA)==0) { language_sayf(UserIndex,"### AuthID %1s - Name ^"%2s^" - Aka ^"%3s^"",print_type:print_console,0,0,0,0,AuthID,CurName,TopName); } else { language_sayf(UserIndex,"### AuthID %1s - Name ^"%2s^" - Aka ^"%3s^"",print_type:print_console,0,0,0,0,AuthID,CurName,AKA); } if (Online>0) { if (level==getvar("default_access")) { language_sayf(UserIndex,"### IP %1s - Admin Level %2i (default)",print_type:print_console,0,0,0,0,strIP,level); } else { language_sayf(UserIndex,"### IP %1s - Admin Level %2i",print_type:print_console,0,0,0,0,strIP,level); } } if (fFull) { if ((K[KD_NOCD_ADMIN]==0) || (D[KD_NOCD_ADMIN]==0)) { language_sayf(UserIndex,"### No C-D Administered: %1i kills, %2i deaths",print_type:print_console,0,0,0,0,K[KD_NOCD_ADMIN],D[KD_NOCD_ADMIN]); } else { language_sayf(UserIndex,"### No C-D Administered: %1i kills, %2i deaths, %3s ratio",print_type:print_console,0,0,0,0,K[KD_NOCD_ADMIN],D[KD_NOCD_ADMIN],Ratio1); } if ((K[KD_NOCD_NOADMIN]==0) || (D[KD_NOCD_NOADMIN]==0)) { language_sayf(UserIndex,"### No C-D Unmonitored: %1i kills, %2i deaths",print_type:print_console,0,0,0,0,K[KD_NOCD_NOADMIN],D[KD_NOCD_NOADMIN]); } else { language_sayf(UserIndex,"### No C-D Unmonitored: %1i kills, %2i deaths, %3s ratio",print_type:print_console,0,0,0,0,K[KD_NOCD_NOADMIN],D[KD_NOCD_NOADMIN],Ratio2); } if ((K[KD_CD_ADMIN]==0) || (D[KD_CD_ADMIN]==0)) { language_sayf(UserIndex,"### C-D Administered: %1i kills, %2i deaths",print_type:print_console,0,0,0,0,K[KD_CD_ADMIN],D[KD_CD_ADMIN]); } else { language_sayf(UserIndex,"### C-D Administered: %1i kills, %2i deaths, %3s ratio",print_type:print_console,0,0,0,0,K[KD_CD_ADMIN],D[KD_CD_ADMIN],Ratio3); } if ((K[KD_CD_NOADMIN]==0) || (D[KD_CD_NOADMIN]==0)) { language_sayf(UserIndex,"### C-D Unmonitored: %1i kills, %2i deaths",print_type:print_console,0,0,0,0,K[KD_CD_NOADMIN],D[KD_CD_NOADMIN]); } else { language_sayf(UserIndex,"### C-D Unmonitored: %1i kills, %2i deaths, %3s ratio",print_type:print_console,0,0,0,0,K[KD_CD_NOADMIN],D[KD_CD_NOADMIN],Ratio4); } } if ((K[KD_NOCD_NOADMIN]+K[KD_NOCD_ADMIN]+K[KD_CD_NOADMIN]+K[KD_CD_ADMIN]==0) || (D[KD_NOCD_NOADMIN]+D[KD_NOCD_ADMIN]+D[KD_CD_NOADMIN]+D[KD_CD_ADMIN]==0)) { language_sayf(UserIndex,"### Overall K:D ratio: %1i kills, %2i deaths",print_type:print_console,0,0,0,0,K[KD_NOCD_NOADMIN]+K[KD_NOCD_ADMIN]+K[KD_CD_NOADMIN]+K[KD_CD_ADMIN],D[KD_NOCD_NOADMIN]+D[KD_NOCD_ADMIN]+D[KD_CD_NOADMIN]+D[KD_CD_ADMIN]); } else { language_sayf(UserIndex,"### Overall K:D ratio: %1i kills, %2i deaths, %3s ratio",print_type:print_console,0,0,0,0,K[KD_NOCD_NOADMIN]+K[KD_NOCD_ADMIN]+K[KD_CD_NOADMIN]+K[KD_CD_ADMIN],D[KD_NOCD_NOADMIN]+D[KD_NOCD_ADMIN]+D[KD_CD_NOADMIN]+D[KD_CD_ADMIN],Ratio5); } ReportConnections(UserIndex,AuthID); } ReportConnections(UserIndex,AuthID[]) { new i=4; new strFDate[MAX_DATE_LENGTH]; new strFConnects[MAX_NUMBER_LENGTH]; new Path[MAX_DATA_LENGTH]; new ParsedAuthID[MAX_AUTHID_LENGTH]; new HashParsedAuthID; GenerateFilename(Path,ParsedAuthID,HashParsedAuthID,"addons/whois/db",AuthID,"Connections.xml"); new fs = filesize(Path); new year; new month; new day; new hour; new minute; new second; get_dateandtime(year,month,day,hour,minute,second); new fyear; new fmonth; new fday; new nDay=0; new nWeek=0; new nMonth=0; new nOverall=0; new nDiff; new nConnects; new fFirst=1; while(i<fs) { readfile(Path,strFDate,i+2,MAX_DATA_LENGTH); readfile(Path,strFConnects,i+5,MAX_NUMBER_LENGTH); SplitDate(strFDate,fyear,fmonth,fday); nDiff = DaysDiff(year,month,day,fyear,fmonth,fday); if (fFirst==1) { fFirst=0; language_sayf(UserIndex,"### Total Rounds Played %4i First Connection: %1i %2s %3i",print_type:print_console,0,0,0,0,fday,g_monthnames[fmonth-1],fyear,LookupRoundCount(AuthID)); } nConnects=strtonum(strFConnects); if (nDiff==0) { nDay+=nConnects; } if (nDiff <7) { nWeek+=nConnects; } if (nDiff <30) { nMonth+=nConnects; } nOverall+=nConnects; i=i+8; } language_sayf(UserIndex,"### Connections %4i (%1i today, %2i this week, %3i this month)",print_type:print_console,0,0,0,0,nDay,nWeek,nMonth,nOverall); } public ReportNames(Timer,Repeat,HLUserName,HLParam) { /* Report top 10 names in order of use */ new AuthID[MAX_DATA_LENGTH]; new User[MAX_NAME_LENGTH]; convert_string(HLUserName,User,MAX_NAME_LENGTH); convert_string(HLParam,AuthID,MAX_DATA_LENGTH); ReportTop10(User,AuthID,"Names","###^n### Known Aliases:",10); return PLUGIN_HANDLED; } public ReportNamesShort(Timer,Repeat,HLUserName,HLParam) { /* Report top 10 names in order of use */ new AuthID[MAX_DATA_LENGTH]; new User[MAX_NAME_LENGTH]; convert_string(HLUserName,User,MAX_NAME_LENGTH); convert_string(HLParam,AuthID,MAX_DATA_LENGTH); ReportTop10(User,AuthID,"Names","###^n### Known Aliases:",3); return PLUGIN_HANDLED; } public ReportIPs(Timer,Repeat,HLUserName,HLParam) { /* Report top 10 IP addresses in order of use */ new AuthID[MAX_DATA_LENGTH]; new User[MAX_NAME_LENGTH]; convert_string(HLUserName,User,MAX_NAME_LENGTH); convert_string(HLParam,AuthID,MAX_DATA_LENGTH); ReportTop10(User,AuthID,"IPs","###^n### Known IP Addresses:",10); return PLUGIN_HANDLED; } ReportTop10(User[],AuthID[],strFile[],strPrompt[],nCount) { /* Names & Rounds are a linked list. Head points to the first * element, and Next[e] points to the next element, with -1 * marking the end. alloc tracks how many rows are used for * the list * * This data structure means lines are sorted efficiently * as the file is loaded */ new Names[10][MAX_NAME_LENGTH]; new Rounds[10]; new Next[10]; new pos; new head=-1; new alloc=0; new last=-1; new i; for(i=0;i<nCount;i++) { Next[i]=-1; } new Path[MAX_DATA_LENGTH]; new ParsedAuthID[MAX_AUTHID_LENGTH]; new HashParsedAuthID; new strFullFile[MAX_DATA_LENGTH]; strcpy(strFullFile,strFile,MAX_DATA_LENGTH); strcat(strFullFile,".xml",MAX_DATA_LENGTH); GenerateFilename(Path,ParsedAuthID,HashParsedAuthID,"addons/whois/db",AuthID,strFullFile); new fs = filesize(Path); if (fs<=0) { return PLUGIN_HANDLED; } new strFName[MAX_NAME_LENGTH]; new strFRounds[MAX_NUMBER_LENGTH]; new nRounds; i=4; while(i<fs) { readfile(Path,strFName,i+2,MAX_NAME_LENGTH); readfile(Path,strFRounds,i+5,MAX_NUMBER_LENGTH); i=i+8; nRounds=strtonum(strFRounds); pos=head; last=-1; /* Try and find the right place for the new entry in the list */ while(pos!=-1) { if (Rounds[pos]<nRounds) { /* Insert before pos */ if (alloc<nCount) { /* There are free slots for an insert so do so. */ strcpy(Names[alloc],strFName,MAX_NAME_LENGTH); Rounds[alloc]=nRounds; Next[alloc]=pos; if (pos==head) { head=alloc; } else { Next[last]=alloc; } alloc++; break; } else { /* There are no free slots, so locate the end of the list and * overwrite it */ new pos2=pos; new pos3=pos; while (Next[pos2]!=-1) { pos3=pos2;pos2=Next[pos2]; } if (pos2!=pos3) { /* New line being inserted before some entry that isn't * the end one. pos = entry we are inserting before, * pos2 = end entry, pos3 = 2nd from end entry, * last = entry we are inserting after */ Next[pos3]=-1; strcpy(Names[pos2],strFName,MAX_NAME_LENGTH); Rounds[pos2]=nRounds; Next[pos2]=pos; if (pos==head) { head=pos2; } else { Next[last]=pos2; } } else { /* New line is being inserted before the end entry, therefore * simply overwrite the end entry with it */ strcpy(Names[pos],strFName,MAX_NAME_LENGTH); Rounds[pos]=nRounds; } break; } } else { /* New line has a smaller number of rounds than line pos - keep * looking */ last=pos; pos=Next[pos]; } } if (pos==-1) { /* the previous loop reached the end of the list without inserting * so append if there is room */ if (alloc<nCount) { strcpy(Names[alloc],strFName,MAX_NAME_LENGTH); Rounds[alloc]=nRounds; Next[alloc]=-1; if (last==-1) { head=alloc; } else { Next[last]=alloc; } alloc++; } else { /* list is full, loose this entry as it has a smaller number of * rounds than all those in the list */ } } } pos=head; language_saybynamef(User,strPrompt,print_type:print_console,0,0,0,0); while(pos!=-1) { language_saybynamef(User,"### %1s (%2i rounds)",print_type:print_console,0,0,0,0,Names[pos],Rounds[pos]); pos=Next[pos]; } return 0; } public ReportOtherIDs(Timer,Repeat,HLUserName,HLParam) { new AuthID[MAX_DATA_LENGTH]; new User[MAX_NAME_LENGTH]; convert_string(HLUserName,User,MAX_NAME_LENGTH); convert_string(HLParam,AuthID,MAX_DATA_LENGTH); new TargetIndex; get_userindex(AuthID,TargetIndex); new IP[30]; new Subnet[30]; iptostr(g_IPs[TargetIndex],IP); iptostr(g_IPs[TargetIndex] & 4294967040,Subnet); /*4294967040 = 0xFFFFFF00 - masks out last octet */ new Path[MAX_DATA_LENGTH]; new ParsedAuthID[MAX_AUTHID_LENGTH]; new HashParsedAuthID; GenerateFilename(Path,ParsedAuthID,HashParsedAuthID,"addons/whois/ips",IP,"address.txt"); new fPrompt=1; new fs = filesize(Path); new strFAuthID[MAX_AUTHID_LENGTH]; new i=1; while (i<fs) { readfile(Path,strFAuthID,i,MAX_AUTHID_LENGTH); if (streq(strFAuthID,AuthID)==0) { if (fPrompt==1) { fPrompt=0; language_saybyname(User,"###^n### Other players using this Subnet/IPAddress:",print_type:print_console,0,0,0,0); } new strTopName[MAX_NAME_LENGTH]; new dummy; GetTopName(strFAuthID,"",strTopName,dummy); language_saybynamef(User,"### %1s (%2s) played from the same address",print_type:print_console,0,0,0,0,strTopName,strFAuthID); } i++; } new SubnetPath[MAX_DATA_LENGTH]; GenerateFilename(Path,ParsedAuthID,HashParsedAuthID,"addons/whois/ips",Subnet,"_subnet.txt"); fs = filesize(SubnetPath); i=1; while (i<fs) { readfile(SubnetPath,strFAuthID,i,MAX_AUTHID_LENGTH); if (streq(strFAuthID,AuthID)==0) { if (LookupAddress(Path,strFAuthID)==0) { if (fPrompt==1) { fPrompt=0; language_saybyname(User,"###^n### Other players using this Subnet/IPAddress:",print_type:print_console,0,0,0,0); } new strTopName[MAX_NAME_LENGTH]; new dummy; GetTopName(strFAuthID,"",strTopName,dummy); language_saybynamef(User,"### %1s (%2s) played from the same subnet",print_type:print_console,0,0,0,0,strTopName,strFAuthID); } } i++; } return PLUGIN_HANDLED; } public ReportNotes(Timer,Repeat,HLUserName,HLParam) { new AuthID[MAX_DATA_LENGTH]; new User[MAX_NAME_LENGTH]; new strLine[MAX_DATA_LENGTH]; convert_string(HLUserName,User,MAX_NAME_LENGTH); convert_string(HLParam,AuthID,MAX_DATA_LENGTH); new Path[MAX_DATA_LENGTH]; new ParsedAuthID[MAX_AUTHID_LENGTH]; new HashParsedAuthID; GenerateFilename(Path,ParsedAuthID,HashParsedAuthID,"addons/whois/db",AuthID,"Notes.xml"); new date[MAX_DATE_LENGTH]; new type[MAX_DATA_LENGTH]; new adminauth[MAX_AUTHID_LENGTH]; new adminname[MAX_NAME_LENGTH]; new msg[MAX_DATA_LENGTH]; new data[MAX_DATA_LENGTH]; new dummy[MAX_DATA_LENGTH]; new fs = filesize(Path)-1; if (fs>0) { language_saybyname(User,"###^n### Recent notes / punishments:",print_type:print_console,0,0,0,0); new i=fs-169; if (i<4) { i=4; } while(i<=fs) { readfile(Path,date,i+2,MAX_DATE_LENGTH); readfile(Path,type,i+5,MAX_DATA_LENGTH); readfile(Path,strLine,i+7,MAX_DATA_LENGTH); readfile(Path,adminname,i+8,MAX_NAME_LENGTH); readfile(Path,msg,i+11,MAX_DATA_LENGTH); readfile(Path,data,i+14,MAX_DATA_LENGTH); strsplitx(strLine,'^"','|',dummy,MAX_DATA_LENGTH,adminauth,MAX_DATA_LENGTH,dummy,MAX_DATA_LENGTH); if (strlen(type)>0) { if (streq(type,"Ban")) { language_saybynamef(User,"### %1s: %2s by %3s(%4s) for %5s minutes - %6s",print_type:print_console,0,0,0,0,date,type,adminname,adminauth,data, msg); } else { if (streq(type,"Team Kill")) { language_saybynamef(User,"### %1s: %2s %3s - %4s",print_type:print_console,0,0,0,0,date,type,data,msg); } else { language_saybynamef(User,"### %1s: %2s by %3s(%4s) - %5s",print_type:print_console,0,0,0,0,date,type,adminname,adminauth,msg); } } } i=i+17; } } return PLUGIN_HANDLED; } /* If strCurName is the most commonly used name returns * the 2nd most commonly used or empty string and second is 1 * * If strCurName is not the most commonly used name, * returns the most commonly used and second is 0 */ GetTopName(AuthID[],strCurName[],strTopName[],&Second) { new i=4; new strFName[MAX_NAME_LENGTH]; new strFRounds[MAX_NUMBER_LENGTH]; new Path[MAX_DATA_LENGTH]; new ParsedAuthID[MAX_AUTHID_LENGTH]; new HashParsedAuthID; GenerateFilename(Path,ParsedAuthID,HashParsedAuthID,"addons/whois/db",AuthID,"Names.xml"); new fs = filesize(Path); new nRounds; new nTopRounds=0; new nCurRounds=0; strcpy(strTopName,strCurName,MAX_NAME_LENGTH); while(i<fs) { readfile(Path,strFName,i+2,MAX_DATA_LENGTH); readfile(Path,strFRounds,i+5,MAX_DATA_LENGTH); nRounds=strtonum(strFRounds); if (streq(strCurName,strFName)) { nCurRounds = nRounds; } else { if (nRounds > nTopRounds) { strcpy(strTopName,strFName,MAX_NAME_LENGTH); nTopRounds=nRounds; } } i=i+8; } if (nCurRounds>nTopRounds) { Second=1; } else { Second=0; } /* If we have no recorded name, and no current * name, get the name the user is currently playing as */ if ((strTopName[0]==0) && (strCurName[0]==0)) { get_username(AuthID,strTopName,MAX_NAME_LENGTH); RemoveCD(strTopName); } } /* *************** General Support ***************** */ Resolve(Data[],AuthID[],&TargetIndex,TargetName[],AKA[]) { new temp[MAX_NAME_LENGTH]; TargetIndex=0; AKA[0]=0; if (get_userAuthID(Data,AuthID,MAX_AUTHID_LENGTH)) { /* Player found, report on them */ get_userindex(Data,TargetIndex); get_username(Data,temp,MAX_NAME_LENGTH); RemoveCD(temp); strcpy(TargetName,temp,MAX_NAME_LENGTH); return 1; } else { /* Player not found, check on the last MAX_OLD_PLAYERS people to leave in this map * starting with the last to leave for a substring match */ new i=g_OldPtr-1; while (i>=0) { if (strcasestrx(g_OldNames[i],Data)>=0) { strcpy(AuthID,g_OldAuthIDs[i],MAX_AUTHID_LENGTH); strcpy(TargetName,g_OldNames[i],MAX_NAME_LENGTH); /* Player may still be connected and just changed their name * try and match the authid looked up against connected players */ new j; for(j=0;j<MAX_PLAYERS;j++) { if (streq(g_AuthIDs[j],AuthID)) { strcpy(AKA,g_OldNames[i],MAX_NAME_LENGTH); /* Have to use temp array due to compiler bug in writing direct to targetname */ TargetIndex=j; if (playerinfo(TargetIndex,temp,MAX_NAME_LENGTH)) { RemoveCD(temp); strcpy(TargetName,temp,MAX_NAME_LENGTH); } return 1; } } return 1; } i--; } /* OK, still no match - lets try and match it as an authid */ new Path[MAX_DATA_LENGTH]; new ParsedAuthID[MAX_AUTHID_LENGTH]; new HashParsedAuthID; GenerateFilename(Path,ParsedAuthID,HashParsedAuthID,"addons/whois/db",AuthID,"Kills.xml"); if (fileexists(Path)) { strcpy(AuthID,Data,MAX_AUTHID_LENGTH); new DummyName[MAX_NAME_LENGTH]; new Dummy; GetTopName(AuthID,DummyName,TargetName,Dummy); return 1; } } return 0; } IsAdminConnected() { new c=maxplayercount(); new i; new name[MAX_NAME_LENGTH]; for (i=1;i<=c;i++) { if (playerinfo(i,name,MAX_NAME_LENGTH)) { if (access(ACCESS_KICK,name)) { return 1; } } } return 0; } Hash(strin[]) { new c = strlen(strin); new h = 1; new i; for(i=0;i<c;i++) { h = ((h*strin[i]) % 99)+1; } return h; } GetDate(strDate[]) { new year; new month; new day; new hour; new minute; new second; get_dateandtime(year,month,day,hour,minute,second); snprintf(strDate,MAX_DATE_LENGTH,"%i-%i-%i",year,month,day); } GetAuthID(UserIndex,AuthID[MAX_AUTHID_LENGTH]) { new Name[MAX_NAME_LENGTH]; new Wonid; new Sessionid; new Team; new Deaths; if (g_AuthIDs[UserIndex][0]==0) { if (playerinfo(UserIndex,Name,MAX_NAME_LENGTH,Sessionid,Wonid,Team,Deaths,AuthID)==0) { return 0; } strcpy(g_AuthIDs[UserIndex],AuthID,MAX_AUTHID_LENGTH); } else { strcpy(AuthID,g_AuthIDs[UserIndex],MAX_AUTHID_LENGTH); } return 1; } SplitDate(strDate[],&year,&month,&day) { new strYear[MAX_NUMBER_LENGTH]; new strMonth[MAX_NUMBER_LENGTH]; new strDay[MAX_NUMBER_LENGTH]; strsplitx(strDate,'-','\',strYear,MAX_NUMBER_LENGTH,strMonth,MAX_NUMBER_LENGTH,strDay,MAX_NUMBER_LENGTH); year=strtonum(strYear); month=strtonum(strMonth); day=strtonum(strDay); } DaysDiff(year1,month1,day1,year2,month2,day2) { return getDaysSince1970(year1,month1,day1)-getDaysSince1970(year2,month2,day2); } CheckCrossReference(TargetIndex) { new AuthID[MAX_AUTHID_LENGTH]; GetAuthID(TargetIndex,AuthID); new IP[30]; new Subnet[30]; iptostr(g_IPs[TargetIndex],IP); iptostr(g_IPs[TargetIndex] & 4294967040,Subnet); /*4294967040 = 0xFFFFFF00 - masks out last octet */ new Path[MAX_DATA_LENGTH]; new ParsedAuthID[MAX_AUTHID_LENGTH]; new HashParsedAuthID; GenerateFilename(Path,ParsedAuthID,HashParsedAuthID,"addons/whois/ips",IP,"_address.txt"); if (CheckIPFile(TargetIndex,Path,AuthID)) { return 1; } GenerateFilename(Path,ParsedAuthID,HashParsedAuthID,"addons/whois/ips",Subnet,"_subnet.txt"); if (CheckIPFile(TargetIndex,Path,AuthID)) { return 1; } return 0; } CheckIPFile(TargetIndex,Path[],AuthID[]) { new fs = filesize(Path); new strFAuthID[MAX_AUTHID_LENGTH]; new i=1; while (i<fs) { readfile(Path,strFAuthID,i,MAX_AUTHID_LENGTH); if (streq(strFAuthID,AuthID)==0) { new Buf[MAX_DATA_LENGTH]; new WatchPath[MAX_DATA_LENGTH]; new ParsedAuthID[MAX_AUTHID_LENGTH]; new HashParsedAuthID; GenerateFilename(WatchPath,ParsedAuthID,HashParsedAuthID,"addons/whois/db",strFAuthID,"Notes.xml"); if (fileexists(WatchPath)) { new fs2= filesize(WatchPath)-1; if (fs2>0) { new j=4; new type[20]; while(j<=fs2) { readfile(WatchPath,type,j+5,MAX_DATA_LENGTH); if (streq(type,"Ban")) { readfile(WatchPath,type,i+14,MAX_DATA_LENGTH); if (streq(type,"0")) { CheckIPSetWatch(TargetIndex,AuthID,strFAuthID,"/has been banned"); } return 1; } j=j+17; } } } GenerateFilename(WatchPath,ParsedAuthID,HashParsedAuthID,"addons/whois/db",strFAuthID,".xml"); if (fileexists(WatchPath)) { readfile(WatchPath,Buf,5,MAX_DATA_LENGTH); if (strtonum(Buf)) { CheckIPSetWatch(TargetIndex,AuthID,strFAuthID,"watched"); return 1; } } } i++; } return 0; } CheckIPSetWatch(TargetIndex,AuthID[],DupAuthID[],Reason[]) { if (HasBeenUnwatched(AuthID)) { return 0; } /* Record connecting player as to-be-watched */ new strTopName[MAX_NAME_LENGTH]; new dummy; new msg[MAX_DATA_LENGTH]; GetTopName(DupAuthID,"",strTopName,dummy); g_Watches[TargetIndex]=1; WriteSettings(TargetIndex); snprintf(msg,MAX_DATA_LENGTH,"Playing from same IP/Subnet as %s(%s) who is %s",strTopName,DupAuthID,Reason); LogNote("Watch",AuthID,0,"Automatic",msg,"",0); return 1; } HasBeenUnwatched(AuthID[]) { /* Check if the connecting player has already been unwatched. If so * don't watch them again */ new type[20]; new Path[MAX_DATA_LENGTH]; new ParsedAuthID[MAX_DATA_LENGTH]; new HashParsedAuthID; GenerateFilename(Path,ParsedAuthID,HashParsedAuthID,"addons/whois/db",AuthID,"Notes.xml"); if (fileexists(Path)) { new fs= filesize(Path)-1; if (fs>0) { new i=4; while(i<=fs) { readfile(Path,type,i+5,MAX_DATA_LENGTH); if (streq(type,"Unwatch")) { return 1; } i=i+17; } } } return 0; } CalcRatio(K,D,Ratio[]) { new m; new n; if ((K==0) || (D==0)) { strcpy(Ratio,"N/A",4); } else { m = (((K * 10) / D) + 5) / 10; if (m>2) { n = 1; } else { n = (((D * 10) / K) + 5) / 10; if (n>2) { m=1; } else { if (K==D) { m = 1; n = 1; } else { if (K>D) { m = (K * 10) / D; n = 10; } else { n = (D * 10) / K; m = 10; } } } } snprintf(Ratio,20,"%i:%i",m,n); } } CheckIP(UserIndex,AdminIndex) { new j=0; new strUsers[MAX_DATA_LENGTH]; new strName[MAX_NAME_LENGTH]; new c=maxplayercount(); for (j=1;j<=c;j++) { if (j!=UserIndex) { if (playerinfo(j,strName,MAX_NAME_LENGTH)) { if (g_IPs[UserIndex]==g_IPs[j]) { if (strUsers[0]==0) { strcpy(strUsers,strName,MAX_DATA_LENGTH); } else { strcat(strUsers,", ",MAX_DATA_LENGTH); strcat(strUsers,strName,MAX_DATA_LENGTH); } g_LanDetect[UserIndex]=1; g_LanDetect[j]=1; } } } } if (strUsers[0]) { playerinfo(UserIndex,strName,MAX_NAME_LENGTH); new strAdmin[MAX_NAME_LENGTH]; if (AdminIndex==0) { /* Announce to all admins */ for(j=1;j<c;j++) { if (playerinfo(j,strAdmin,MAX_NAME_LENGTH)) { if (access(ACCESS_WHOIS,strAdmin)) { language_saybynamef(strAdmin,"### %1s and %2s are playing from the same IP address.",print_type:print_console,0,0,0,0,strUsers,strName); language_saybynamef(strAdmin,"### %1s and %2s are playing from the same IP address.",print_type:print_chat,0,0,0,0,strUsers,strName); } } } } else { language_sayf(AdminIndex,"### %1s and %2s are playing from the same IP address.",print_type:print_console,0,0,0,0,strUsers,strName); } } } CheckSubnet(UserIndex,AdminIndex) { new j=0; new strUsers[MAX_DATA_LENGTH]; new strName[MAX_NAME_LENGTH]; new c=maxplayercount(); for (j=1;j<=c;j++) { if (j!=UserIndex) { if (playerinfo(j,strName,MAX_NAME_LENGTH)) { if ((g_IPs[UserIndex] & 0xFFFFFF00) == (g_IPs[j] & 0xFFFFFF00)) { if (strUsers[0]==0) { strcpy(strUsers,strName,MAX_DATA_LENGTH); } else { strcat(strUsers,", ",MAX_DATA_LENGTH); strcat(strUsers,strName,MAX_DATA_LENGTH); } g_LanDetect[UserIndex]=1; g_LanDetect[j]=1; } } } } if (strUsers[0]) { playerinfo(UserIndex,strName,MAX_NAME_LENGTH); new strAdmin[MAX_NAME_LENGTH]; if (AdminIndex==0) { /* Announce to all admins */ for(j=1;j<c;j++) { if (playerinfo(j,strAdmin,MAX_NAME_LENGTH)) { if (access(ACCESS_WHOIS,strAdmin)) { language_saybynamef(strAdmin,"### %1s and %2s are playing from the same subnet.",print_type:print_console,0,0,0,0,strUsers,strName); language_saybynamef(strAdmin,"### %1s and %2s are playing from the same subnet.",print_type:print_chat,0,0,0,0,strUsers,strName); } } } } else { language_sayf(AdminIndex,"### %1s and %2s are playing from the same IP subnet.",print_type:print_console,0,0,0,0,strUsers,strName); } } } CheckOldNames(NewName[],AuthID[]) { new i=g_OldPtr-1; new msg[MAX_TEXT_LENGTH]; while (i>0) { if (streq(AuthID,g_OldAuthIDs[i])) { if (streq(NewName,g_OldNames[i])==0) { if (g_OldKicked[i]==-12345678) { snprintf(msg,MAX_TEXT_LENGTH,"### %s who was kicked earlier has rejoined as %s",g_OldNames[i],NewName); } else if (g_OldKicked[i]>0) { snprintf(msg,MAX_TEXT_LENGTH,"### %s who was banned earlier for %i minutes has rejoined as %s",g_OldNames[i],g_OldKicked[i],NewName); } else { snprintf(msg,MAX_TEXT_LENGTH,"### %s has rejoined and changed his name to %s",g_OldNames[i],NewName); } } else { if (g_OldKicked[i]==-12345678) { snprintf(msg,MAX_TEXT_LENGTH,"### %s who was kicked earlier has rejoined",g_OldNames[i]); } else if (g_OldKicked[i]>0) { snprintf(msg,MAX_TEXT_LENGTH,"### %s who was banned earlier for %i minutes has rejoined",g_OldNames[i],g_OldKicked[i]); } } if (msg[0]) { AnnounceToAdmins(msg,print_type:print_chat,0); } return; } i--; } } AnnounceToAdmins(msg[],print_type:location,Except) { new j; new strAdmin[MAX_NAME_LENGTH]; new c=maxplayercount(); for(j=1;j<c;j++) { if (j!=Except) { if (playerinfo(j,strAdmin,MAX_NAME_LENGTH)) { if (access(ACCESS_WHOIS,strAdmin)) { language_saybyname(strAdmin,msg,location,0,0,0,0); } } } } } GenerateFilename(Path[],ParsedAuthID[],&HashParsedAuthID,Base[],AuthID[],FileType[]) { ParseAuthID(AuthID,ParsedAuthID); HashParsedAuthID= Hash(ParsedAuthID); if (FileType[0]=='.') { snprintf(Path,MAX_DATA_LENGTH,"%s/%i/%s%s",Base,HashParsedAuthID,ParsedAuthID,FileType); } else { snprintf(Path,MAX_DATA_LENGTH,"%s/%i/%s_%s",Base,HashParsedAuthID,ParsedAuthID,FileType); } } ParseAuthID(AuthID[],ParsedAuthID[]) { new c=strlen(AuthID); new i; for(i=0;i<=c;i++) { if ( ((AuthID[i]>='a' && AuthID[i]<='z')) || ((AuthID[i]>='A' && AuthID[i]<='Z')) || ((AuthID[i]>='0' && AuthID[i]<='9')) || AuthID[i]==0 ) { ParsedAuthID[i]=AuthID[i]; } else { ParsedAuthID[i]='-'; } } } UserIndexFromSessionID(nSessionID) { new Name[MAX_NAME_LENGTH]; new i; new nTestSessionID; for (i=1;i<MAX_PLAYERS;i++) { if (playerinfo(i,Name,MAX_NAME_LENGTH,nTestSessionID)) { if (nSessionID == nTestSessionID) { return i; } } } return 0; } RemoveCD(Name[]) { if (strncmp(Name,"[No C-D]",8)==0) { strstrip(Name,8); } else if (strncmp(Name,"[Old C-D]",9)==0) { strstrip(Name,9); } } MediateCD(UserIndex,AuthID[]) { /* Check if mediation is enabled and CD is running on the server */ if ((g_RcdEnabled==0) || (g_CheatingDeath==0) || (g_CDRequiredMode == 1)) { return 0; } /* Check if player has failed CD authentication */ if ((g_CD_Status[UserIndex] != 1) && (g_CD_Status[UserIndex] != 2)) { return 0; } /* Watched players must use CD */ if (g_Watches[UserIndex]) { RequireCD(UserIndex); return 1; } /* Players with less than rcdminimum rounds played need not use CD */ if (g_Rounds[UserIndex] <= g_RcdMinimum) { return 0; } /* Players with more than rcdmaximum rounds played need CD */ if (g_Rounds[UserIndex] > g_RcdMaximum) { RequireCD(UserIndex); return 1; } /* Players with a non-cd K:D ratio higher than g_RcdMaximum need CD */ new Path[MAX_DATA_LENGTH]; new ParsedAuthID[MAX_AUTHID_LENGTH]; new HashParsedAuthID; GenerateFilename(Path,ParsedAuthID,HashParsedAuthID,"addons/whois/db",AuthID,"Kills.xml"); new K[4]; new D[4]; LoadKillStatus(Path,K,D); K[KD_NOCD_ADMIN]+=g_Kills[UserIndex][KD_NOCD_ADMIN]; K[KD_NOCD_NOADMIN]+=g_Kills[UserIndex][KD_NOCD_NOADMIN]; K[KD_CD_ADMIN]+=g_Kills[UserIndex][KD_CD_ADMIN]; K[KD_CD_NOADMIN]+=g_Kills[UserIndex][KD_CD_NOADMIN]; D[KD_NOCD_ADMIN]+=g_Deaths[UserIndex][KD_NOCD_ADMIN]; D[KD_NOCD_NOADMIN]+=g_Deaths[UserIndex][KD_NOCD_NOADMIN]; D[KD_CD_ADMIN]+=g_Deaths[UserIndex][KD_CD_ADMIN]; D[KD_CD_NOADMIN]+=g_Deaths[UserIndex][KD_CD_NOADMIN]; new KNoCD = K[KD_NOCD_ADMIN] + K[KD_NOCD_NOADMIN]; new DNoCD = D[KD_NOCD_ADMIN] + D[KD_NOCD_NOADMIN]; if (DNoCD == 0) { DNoCD = 1; } if (KNoCD >= DNoCD * g_RcdRatio) { RequireCD(UserIndex); return 1; } return 0; } RequireCD(UserIndex) { BigConsoleMessage(UserIndex,"You are required to use an up-to-date copy of^nCHEATING DEATH to continue to play on this server^n^nDownload it from www.unitedadmins.com"); new Name[MAX_NAME_LENGTH]; playerinfo(UserIndex,Name,MAX_NAME_LENGTH); set_timer("DelayedKick",2,1,Name); } BigConsoleMessage(UserIndex,Msg[]) { language_say(UserIndex,"^n^n^n*******************************************************",print_type:print_console,0,0,0,0); language_say(UserIndex,Msg,print_type:print_console,0,0,0,0); language_say(UserIndex,"*******************************************************^n^n",print_type:print_console,0,0,0,0); }