Just pushing some changes

-webfront now displays player info and link to repz account
-webfront shows ips for authed admin ( determined by ip )
-webfront now show chat and allows authed players to send ingame messages
-fixed time span issue in webfront
-fixed most recent ban always missing
-fixed crash when RCON stops responding and removing a player
-version on footer
This commit is contained in:
Michael Snyder 2015-04-19 13:14:30 -05:00
parent 65b65716d2
commit f42ee69580
14 changed files with 561 additions and 122 deletions

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Text; using System.Text;
using System.Data.SQLite; using System.Data.SQLite;
using System.Data; using System.Data;
using System.Linq;
using System.IO; using System.IO;
using System.Collections; using System.Collections;
@ -204,6 +205,44 @@ namespace IW4MAdmin
return null; return null;
} }
//get player by ip, (used for webfront)
public Player getPlayer(String IP)
{
String Query = String.Format("SELECT * FROM CLIENTS WHERE IP='{0}'", IP);
DataTable Result = GetDataTable(Query);
if (Result != null && Result.Rows.Count > 0)
{
List<Player> lastKnown = new List<Player>();
foreach (DataRow p in Result.Rows)
{
DateTime LC;
try
{
LC = DateTime.Parse(p["LastConnection"].ToString());
lastKnown.Add(new Player(p["Name"].ToString(), p["npID"].ToString(), -1, (Player.Permission)(p["Level"]), Convert.ToInt32(p["Number"]), p["LastOffense"].ToString(), Convert.ToInt32((DateTime.Now - LC).TotalSeconds), p["IP"].ToString(), LC));
}
catch (Exception)
{
continue;
}
}
if (lastKnown.Count > 0)
{
List<Player> Returning = lastKnown.OrderBy(t => t.Connections).ToList();
return Returning[0];
}
else
return null;
}
else
return null;
}
//Returns a list of players matching name parameter, null if no players found matching //Returns a list of players matching name parameter, null if no players found matching
public List<Player> findPlayers(String name) public List<Player> findPlayers(String name)
{ {
@ -238,7 +277,7 @@ namespace IW4MAdmin
//Returns any player with level 4 permissions, null if no owner found //Returns any player with level 4 permissions, null if no owner found
public Player getOwner() public Player getOwner()
{ {
String Query = String.Format("SELECT * FROM CLIENTS WHERE Level >= '{0}'", 4); String Query = String.Format("SELECT * FROM CLIENTS WHERE Level > '{0}'", 4);
DataTable Result = GetDataTable(Query); DataTable Result = GetDataTable(Query);
if (Result != null && Result.Rows.Count > 0) if (Result != null && Result.Rows.Count > 0)
@ -270,6 +309,19 @@ namespace IW4MAdmin
return Bans; return Bans;
} }
//Returns all players with level > Flagged
public List<Player> getAdmins()
{
List<Player> Admins = new List<Player>();
String Query = String.Format("SELECT * FROM CLIENTS WHERE LEVEL > '{0}'", 1);
DataTable Result = GetDataTable(Query);
foreach (DataRow P in Result.Rows)
Admins.Add(new Player(P["Name"].ToString(), P["npID"].ToString(), (Player.Permission)P["Level"], P["IP"].ToString()));
return Admins;
}
//Returns total number of player entries in database //Returns total number of player entries in database
public int totalPlayers() public int totalPlayers()
{ {
@ -530,7 +582,7 @@ namespace IW4MAdmin
public List<Aliases> findPlayers(String name) public List<Aliases> findPlayers(String name)
{ {
String Query = String.Format("SELECT * FROM ALIASES WHERE NAMES LIKE '%{0}%' LIMIT 8", name); String Query = String.Format("SELECT * FROM ALIASES WHERE NAMES LIKE '%{0}%' LIMIT 15", name);
DataTable Result = GetDataTable(Query); DataTable Result = GetDataTable(Query);
List<Aliases> players = new List<Aliases>(); List<Aliases> players = new List<Aliases>();

View File

@ -5,6 +5,25 @@ using System.Text.RegularExpressions;
namespace IW4MAdmin namespace IW4MAdmin
{ {
class Chat
{
public Chat ( Player O, String M, DateTime D)
{
Origin = O;
Message = M;
Time = D;
}
public String timeString()
{
return Time.ToShortTimeString();
}
public Player Origin { get; private set; }
public String Message { get; private set; }
public DateTime Time { get; private set; }
}
class Event class Event
{ {
public enum GType public enum GType

View File

@ -125,6 +125,14 @@ namespace IW4MAdmin
LastConnection = DateTime.Now; LastConnection = DateTime.Now;
} }
public Player(string n, string id, Player.Permission P, String I)
{
Name = n;
npID = id;
Level = P;
IP = I;
}
public Player(string n, string id, int num, Player.Permission l, int cind, String lo, int con, String IP2) public Player(string n, string id, int num, Player.Permission l, int cind, String lo, int con, String IP2)
{ {
Name = n; Name = n;

View File

@ -38,6 +38,8 @@ namespace IW4MAdmin
Reports = new List<Report>(); Reports = new List<Report>();
Skills = new Moserware.TrueSkill(); Skills = new Moserware.TrueSkill();
statusPlayers = new Dictionary<string, Player>(); statusPlayers = new Dictionary<string, Player>();
chatHistory = new List<Chat>();
lastWebChat = DateTime.Now;
nextMessage = 0; nextMessage = 0;
initCommands(); initCommands();
initMacros(); initMacros();
@ -149,6 +151,21 @@ namespace IW4MAdmin
} }
} }
bool checkClientStatus(Player P)
{
/* RCON.addRCON("admin_lastevent status;" + P.getID() + ";0;clean");
Utilities.Wait(0.5); // give it time to update
String[] Status = RCON.addRCON("whoisdirty");
if (Status != null)
{
String GUID = Utilities.stripColors(Status[1].Split(new char[] { '\"' })[3]);
}
*/
return true;
}
//Add player object p to `players` list //Add player object p to `players` list
public bool addPlayer(Player P) public bool addPlayer(Player P)
{ {
@ -205,10 +222,11 @@ namespace IW4MAdmin
// and ips // and ips
if (NewPlayer.Alias.getIPS().Find(i => i.Equals(P.getIP())) == null || P.getIP() == null || P.getIP() == String.Empty) if (NewPlayer.Alias.getIPS().Find(i => i.Equals(P.getIP())) == null || P.getIP() == null || P.getIP() == String.Empty)
{ {
NewPlayer.updateIP(P.getIP());
NewPlayer.Alias.addIP(P.getIP()); NewPlayer.Alias.addIP(P.getIP());
} }
NewPlayer.updateIP(P.getIP());
aliasDB.updatePlayer(NewPlayer.Alias); aliasDB.updatePlayer(NewPlayer.Alias);
clientDB.updatePlayer(NewPlayer); clientDB.updatePlayer(NewPlayer);
@ -268,6 +286,9 @@ namespace IW4MAdmin
} }
} }
//finally lets check their clean status :>
checkClientStatus(NewPlayer);
lock (players) lock (players)
{ {
players[NewPlayer.getClientNum()] = null; // just in case we have shit in the way players[NewPlayer.getClientNum()] = null; // just in case we have shit in the way
@ -278,6 +299,10 @@ namespace IW4MAdmin
#endif #endif
Log.Write("Client " + NewPlayer.getName() + " connecting...", Log.Level.Debug); // they're clean Log.Write("Client " + NewPlayer.getName() + " connecting...", Log.Level.Debug); // they're clean
if (chatHistory.Count > Math.Ceiling((double)clientnum / 2))
chatHistory.RemoveAt(0);
chatHistory.Add(new Chat(NewPlayer, "<i>CONNECTED</i>", DateTime.Now));
if (NewPlayer.getLevel() == Player.Permission.Flagged) if (NewPlayer.getLevel() == Player.Permission.Flagged)
ToAdmins("^1NOTICE: ^7Flagged player ^5" + NewPlayer.getName() + "^7 has joined!"); ToAdmins("^1NOTICE: ^7Flagged player ^5" + NewPlayer.getName() + "^7 has joined!");
@ -628,22 +653,19 @@ namespace IW4MAdmin
private void pollServer() private void pollServer()
{ {
int timesFailed = 0; int timesFailed = 0;
Dictionary<String, Player> toCheck = new Dictionary<String, Player>();
while (isRunning) while (isRunning)
{
lock (statusPlayers)
{ {
String[] Response = RCON.addRCON("status"); String[] Response = RCON.addRCON("status");
if (Response != null) if (Response != null)
statusPlayers = Utilities.playersFromStatus(Response); toCheck = Utilities.playersFromStatus(Response);
}
if (statusPlayers != null) if (toCheck != null)
{ {
lastPoll = DateTime.Now; lastPoll = DateTime.Now;
timesFailed = 0; timesFailed = 0;
if (statusPlayers.Count != clientnum)
{ if (toCheck != statusPlayers)
lock (statusPlayers)
{ {
List<Player> toRemove = new List<Player>(); List<Player> toRemove = new List<Player>();
lock (players) lock (players)
@ -654,7 +676,7 @@ namespace IW4MAdmin
continue; continue;
Player Matching; Player Matching;
statusPlayers.TryGetValue(P.getID(), out Matching); toCheck.TryGetValue(P.getID(), out Matching);
if (Matching == null) // they are no longer with us if (Matching == null) // they are no longer with us
toRemove.Add(P); toRemove.Add(P);
} }
@ -663,17 +685,21 @@ namespace IW4MAdmin
removePlayer(Removing.getClientNum()); removePlayer(Removing.getClientNum());
} }
foreach (var P in statusPlayers.Values) foreach (var P in toCheck.Values)
{ {
if (P == null) if (P == null)
{ {
Log.Write("Null player found in statusPlayers", Log.Level.Debug); Log.Write("Null player found in toCheck", Log.Level.Debug);
continue; continue;
} }
if (!addPlayer(P)) if (!addPlayer(P))
Log.Write("Error adding " + P.getName() + " at client slot #" + P.getClientNum(), Log.Level.Debug); Log.Write("Error adding " + P.getName() + " at client slot #" + P.getClientNum(), Log.Level.Debug);
} }
lock (statusPlayers)
{
statusPlayers = toCheck;
} }
} }
@ -896,6 +922,10 @@ namespace IW4MAdmin
return false; return false;
} }
if (chatHistory.Count > Math.Ceiling(((double)clientnum - 1) / 2))
chatHistory.RemoveAt(0);
chatHistory.Add(new Chat(E.Origin, "<i>DISCONNECTED</i>", DateTime.Now));
removePlayer(E.Origin.getClientNum()); removePlayer(E.Origin.getClientNum());
return true; return true;
} }
@ -972,7 +1002,17 @@ namespace IW4MAdmin
} }
if (E.Data.Substring(0, 1) != "!") // Not a command so who gives an F? if (E.Data.Substring(0, 1) != "!") // Not a command so who gives an F?
{
E.Data = Utilities.stripColors(Utilities.cleanChars(E.Data));
if (E.Data.Length > 50)
E.Data = E.Data.Substring(0, 50) + "...";
if (chatHistory.Count > Math.Ceiling((double)clientnum/2))
chatHistory.RemoveAt(0);
chatHistory.Add(new Chat(E.Origin, E.Data, DateTime.Now));
return true; return true;
}
Command C = E.isValidCMD(commands); Command C = E.isValidCMD(commands);
@ -1105,7 +1145,19 @@ namespace IW4MAdmin
if (B.getID() == Target.getID()) if (B.getID() == Target.getID())
{ {
clientDB.removeBan(Target.getID(), Target.getIP()); clientDB.removeBan(Target.getID(), Target.getIP());
Bans.Remove(B); int position = Bans.IndexOf(B);
if (position > -1 && position < Bans.Count - 1)
{
Log.Write("Removing ban at index #" + position, Log.Level.Debug);
Bans.RemoveAt(position);
Bans[position] = null;
}
else
Log.Write(position + " is an invalid ban index!", Log.Level.Debug);
Player P = clientDB.getPlayer(Target.getID(), -1); Player P = clientDB.getPlayer(Target.getID(), -1);
P.setLevel(Player.Permission.User); P.setLevel(Player.Permission.User);
clientDB.updatePlayer(P); clientDB.updatePlayer(P);
@ -1172,6 +1224,24 @@ namespace IW4MAdmin
RCON.addRCON("admin_lastevent alert;" + P.getID() + ";0;mp_killstreak_nuclearstrike"); RCON.addRCON("admin_lastevent alert;" + P.getID() + ";0;mp_killstreak_nuclearstrike");
} }
public void webChat(Player P, String Message)
{
DateTime requestTime = DateTime.Now;
if ((requestTime - lastWebChat).TotalSeconds > 1)
{
Broadcast("^1[WEBCHAT] ^5" + P.getName() + "^7 - " + Message);
if (chatHistory.Count > Math.Ceiling((double)clientnum / 2))
chatHistory.RemoveAt(0);
if (Message.Length > 50)
Message = Message.Substring(0, 50) + "...";
chatHistory.Add(new Chat(P, Utilities.stripColors(Message), DateTime.Now));
lastWebChat = DateTime.Now;
}
}
//END //END
//THIS IS BAD BECAUSE WE DON"T WANT EVERYONE TO HAVE ACCESS :/ //THIS IS BAD BECAUSE WE DON"T WANT EVERYONE TO HAVE ACCESS :/
@ -1324,6 +1394,7 @@ namespace IW4MAdmin
public String Gametype; public String Gametype;
public int totalKills = 0; public int totalKills = 0;
public List<Report> Reports; public List<Report> Reports;
public List<Chat> chatHistory;
//Info //Info
private String IP; private String IP;
@ -1342,6 +1413,7 @@ namespace IW4MAdmin
private int maxClients; private int maxClients;
private Dictionary<String, Object> Macros; private Dictionary<String, Object> Macros;
private Moserware.TrueSkill Skills; private Moserware.TrueSkill Skills;
private DateTime lastWebChat;
//Will probably move this later //Will probably move this later

View File

@ -58,7 +58,7 @@ namespace IW4MAdmin
public static String removeNastyChars(String str) public static String removeNastyChars(String str)
{ {
if (str != null) if (str != null)
return str.Replace("`", "").Replace("\\", "").Replace("\"", "").Replace("^", "").Replace("&quot;", "''").Replace("&amp;", "&").Replace("\"", "''"); return str.Replace("`", "").Replace("\\", "").Replace("\"", "").Replace("&quot;", "''").Replace("&amp;", "&").Replace("\"", "''");
else else
return String.Empty; return String.Empty;
} }
@ -78,6 +78,15 @@ namespace IW4MAdmin
return lineNumber; return lineNumber;
} }
public static String cleanChars(String S)
{
StringBuilder Cleaned = new StringBuilder();
foreach (char c in S)
if (c < 127 && c > 31 && c != 37 && c != 34 && c != 92) Cleaned.Append(c);
return Cleaned.ToString();
}
public static String stripColors(String str) public static String stripColors(String str)
{ {
return Regex.Replace(str, @"\^[0-9]", ""); return Regex.Replace(str, @"\^[0-9]", "");

View File

@ -3,6 +3,7 @@ using System.Globalization;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Web;
using Kayak; using Kayak;
using Kayak.Http; using Kayak.Http;
using System.Net; using System.Net;
@ -10,6 +11,23 @@ using System.Net;
namespace IW4MAdmin_Web namespace IW4MAdmin_Web
{ {
class Client
{
public Client ( WebFront.Page req, int cur, IDictionary<String, String> inc, String D)
{
requestedPage = req;
requestedPageNumber = cur;
requestOrigin = inc;
requestData = D;
}
public WebFront.Page requestedPage { get; private set; }
public int requestedPageNumber { get; private set; }
public IDictionary<String, String> requestOrigin { get; private set; }
public String requestData { get; private set; }
}
class WebFront class WebFront
{ {
public enum Page public enum Page
@ -61,7 +79,7 @@ namespace IW4MAdmin_Web
return output.ToString(); return output.ToString();
} }
static public String parseMacros(String input, WebFront.Page Page, int Pagination, int server) static public String parseMacros(String input, WebFront.Page Page, int server, int Pagination, bool logged, String Data)
{ {
StringBuilder buffer = new StringBuilder(); StringBuilder buffer = new StringBuilder();
switch (input) switch (input)
@ -116,15 +134,18 @@ namespace IW4MAdmin_Web
<th class=server_map><span>{1}</span></th> <th class=server_map><span>{1}</span></th>
<th class=server_players><span>{2}</span></th> <th class=server_players><span>{2}</span></th>
<th class=server_gametype><span>{3}</span></th> <th class=server_gametype><span>{3}</span></th>
<th><a href=/{4}/0/?stats>Stats</a></th> <th><a href=/{4}/0/?stats>Stats</a> | </th>
<th><a href=/{4}/0/?bans>Bans</a></th> <th><a href=/{4}/0/?bans>Bans</a></th>
</tr> </tr>
</table> </table>
<table cellpadding='0' cellspacing='0' class='players'> <table cellpadding='0' cellspacing='0' class='players'>
{5} {5}
</table> </table>",
<hr/>",
Servers[i].getName(), Servers[i].getMap(), Servers[i].getClientNum() + "/" + Servers[i].getMaxClients(), IW4MAdmin.Utilities.gametypeLocalized(Servers[i].getGametype()), i, players.ToString()); Servers[i].getName(), Servers[i].getMap(), Servers[i].getClientNum() + "/" + Servers[i].getMaxClients(), IW4MAdmin.Utilities.gametypeLocalized(Servers[i].getGametype()), i, players.ToString());
buffer.AppendFormat("<div class='chatHistory' id='chatHistory_{0}'></div><script type='text/javascript'>$( document ).ready(function() {{ setInterval({1}loadChatMessages({0}, '#chatHistory_{0}'){1}, 2500); }});</script><div class='null' style='clear:both;'></div>", i, '\"');
if (Servers[i].getClientNum() > 0)
buffer.AppendFormat("<form class='chatOutFormat' action={1}javascript:chatRequest({0}, 'chatEntry_{0}'){1}><input class='chatFormat_text' type='text' placeholder='Enter a message...' id='chatEntry_{0}'/><input class='chatFormat_submit' type='submit'/></form>", i, '\"');
buffer.Append("<hr/>");
} }
return buffer.ToString(); return buffer.ToString();
case "TITLE": case "TITLE":
@ -133,7 +154,7 @@ namespace IW4MAdmin_Web
buffer.Append("<table cellspacing=0 class=bans>"); buffer.Append("<table cellspacing=0 class=bans>");
int totalBans = IW4MAdmin.Program.Servers[0].Bans.Count; int totalBans = IW4MAdmin.Program.Servers[0].Bans.Count;
int range; int range;
int start = Pagination*30 + 1; int start = Pagination*30;
cycleFix = 0; cycleFix = 0;
if (totalBans <= 30) if (totalBans <= 30)
@ -193,7 +214,6 @@ namespace IW4MAdmin_Web
return buffer.ToString(); return buffer.ToString();
case "PAGE": case "PAGE":
buffer.Append("<div id=pages>"); buffer.Append("<div id=pages>");
return buffer.ToString(); return buffer.ToString();
case "STATS": case "STATS":
int totalStats = IW4MAdmin.Program.Servers[server].statDB.totalStats(); int totalStats = IW4MAdmin.Program.Servers[server].statDB.totalStats();
@ -241,20 +261,59 @@ namespace IW4MAdmin_Web
return buffer.ToString().Replace("{{TOP}}", (start + 1).ToString()); return buffer.ToString().Replace("{{TOP}}", (start + 1).ToString());
case "PLAYER": case "PLAYER":
buffer.Append("<table class='player_info'><tr><th>Name</th><th>Aliases</th><th>IP</th><th>Rating</th><th>Level</th><th>Connections</th><th>Last Seen</th><th>Profile</th>"); buffer.Append("<table class='player_info'><tr><th>Name</th><th>Aliases</th><th>IP</th><th>Rating</th><th>Level</th><th>Connections</th><th>Last Seen</th><th>Profile</th>");
IW4MAdmin.Player Player = IW4MAdmin.Program.Servers[server].clientDB.getPlayer(Pagination); List<IW4MAdmin.Player> matchingPlayers = new List<IW4MAdmin.Player>();
if (Player == null) if (Data == null)
matchingPlayers.Add(IW4MAdmin.Program.Servers[server].clientDB.getPlayer(Pagination));
else
{
var alias = IW4MAdmin.Program.Servers[server].aliasDB.findPlayers(Data);
foreach (var a in alias)
{
var p = IW4MAdmin.Program.Servers[server].clientDB.getPlayer(a.getNumber());
if (p != null)
{
List<IW4MAdmin.Player> aliases = new List<IW4MAdmin.Player>();
IW4MAdmin.Program.Servers[server].getAliases(aliases, p);
foreach (var pa in aliases)
{
if (!matchingPlayers.Exists(x => x.getDBID() == pa.getDBID()))
matchingPlayers.Add(pa);
}
}
}
}
if (matchingPlayers == null)
buffer.Append("</table>"); buffer.Append("</table>");
else else
{ {
foreach (IW4MAdmin.Player Player in matchingPlayers)
{
if (Player == null)
continue;
buffer.Append("<tr>"); buffer.Append("<tr>");
StringBuilder str = new StringBuilder(); StringBuilder str = new StringBuilder();
List<IW4MAdmin.Player> aliases = new List<IW4MAdmin.Player>(); List<IW4MAdmin.Player> aliases = new List<IW4MAdmin.Player>();
IW4MAdmin.Program.Servers[server].getAliases(aliases, Player); IW4MAdmin.Program.Servers[server].getAliases(aliases, Player);
foreach (IW4MAdmin.Player a in aliases) foreach (IW4MAdmin.Player a in aliases)
{
if (Data != null)
{
if (a.Alias.getNames().Exists(p => p.ToLower().Contains(Data.ToLower())) && a.getDBID() != Player.getDBID())
{
str.AppendFormat("<span>{0}</span><br/>", a.getName()); str.AppendFormat("<span>{0}</span><br/>", a.getName());
break;
}
}
else
str.AppendFormat("<span>{0}</span><br/>", a.getName());
}
Player.stats = IW4MAdmin.Program.Servers[server].statDB.getStats(Player.getDBID()); Player.stats = IW4MAdmin.Program.Servers[server].statDB.getStats(Player.getDBID());
String Rating = String.Empty; String Rating = String.Empty;
@ -264,55 +323,68 @@ namespace IW4MAdmin_Web
else else
Rating = Player.stats.Skill.ToString(); Rating = Player.stats.Skill.ToString();
bool logged = false; StringBuilder IPs = new StringBuilder();
String IP;
if (logged)
IP = Player.getIP();
else
IP = "XXX.XXX.XXX.XXX";
Int64 forumID = Int64.Parse(Player.getID(), NumberStyles.AllowHexSpecifier); if (logged && Data == null)
{
foreach (IW4MAdmin.Player a in aliases)
{
foreach (String ip in a.Alias.getIPS())
{
if (!IPs.ToString().Contains(ip))
IPs.AppendFormat("<span>{0}</span><br/>", ip);
}
}
}
else
IPs.Append("XXX.XXX.XXX.XXX");
Int64 forumID = Int64.Parse(Player.getID().Substring(0,16), NumberStyles.AllowHexSpecifier);
forumID = forumID - 76561197960265728; forumID = forumID - 76561197960265728;
buffer.AppendFormat("<td>{0}</td><td>{1}</td><td>{2}</td><td>{3}</td><td>{4}</td><td>{5}</td><td>{6} ago</td><td><a href='https://repziw4.de/memberlist.php?mode=viewprofile&u={7}'>{8}</a></td>", Player.getName(), str, IP, Rating, IW4MAdmin.Utilities.nameHTMLFormatted(Player.getLevel()), Player.getConnections(), Player.getLastConnection(), forumID, Player.getName()); buffer.AppendFormat("<td><a href='{9}'>{0}</a></td><td>{1}</td><td>{2}</td><td>{3}</td><td>{4}</td><td>{5}</td><td>{6} ago</td><td><a href='https://repziw4.de/memberlist.php?mode=viewprofile&u={7}'>{8}</a></td>", Player.getName(), str, IPs, Rating, IW4MAdmin.Utilities.nameHTMLFormatted(Player.getLevel()), Player.getConnections(), Player.getLastConnection(), forumID, Player.getName(), "/0/" + Player.getDBID() + "/?player");
buffer.Append("</tr></table>"); buffer.Append("</tr>");
}
buffer.Append("</table>");
} }
return buffer.ToString(); return buffer.ToString();
default: default:
return input; return input;
} }
} }
static public String findMacros(String input, int pageNumber, int server, WebFront.Page page) static public String findMacros(String input, Client C, int server)
{ {
String output = input; String output = input;
switch (page) bool logged = IW4MAdmin.Program.Servers[server].clientDB.getAdmins().Exists(player => player.getIP() == C.requestOrigin["Host"].Split(':')[0]);
if (logged)
Console.WriteLine(C.requestOrigin["Host"] + " is authed");
else
Console.WriteLine(C.requestOrigin["Host"] + " is not authed");
switch (C.requestedPage)
{ {
case WebFront.Page.main: case WebFront.Page.main:
output = output.Replace("{{SERVERS}}", parseMacros("SERVERS", page, pageNumber, server)); output = output.Replace("{{SERVERS}}", parseMacros("SERVERS", C.requestedPage, server, C.requestedPageNumber, logged, C.requestData));
break; break;
case WebFront.Page.bans: case WebFront.Page.bans:
output = output.Replace("{{BANS}}", parseMacros("BANS", page, pageNumber, server)); output = output.Replace("{{BANS}}", parseMacros("BANS", C.requestedPage, server, C.requestedPageNumber, logged, C.requestData));
break; break;
case WebFront.Page.stats: case WebFront.Page.stats:
output = output.Replace("{{STATS}}", parseMacros("STATS", page, pageNumber, server)); output = output.Replace("{{STATS}}", parseMacros("STATS", C.requestedPage, server, C.requestedPageNumber, logged, C.requestData));
break; break;
case WebFront.Page.player: case WebFront.Page.player:
output = output.Replace("{{PLAYER}}", parseMacros("PLAYER", page, pageNumber, server)); output = output.Replace("{{PLAYER}}", parseMacros("PLAYER", C.requestedPage, server, C.requestedPageNumber, logged, C.requestData));
break; break;
} }
//output = output.Replace("{{PAGE}}", parseMacros("PAGE", page, pageNumber, server));
//output = output.Replace("{{SERVERS}}", parseMacros("SERVERS", 0));
//output = output.Replace("{{BANS}}", parseMacros("BANS", page));
output = output.Replace("{{TITLE}}", "IW4M Administration"); output = output.Replace("{{TITLE}}", "IW4M Administration");
output = output.Replace("{{VERSION}}", IW4MAdmin.Program.Version.ToString()); output = output.Replace("{{VERSION}}", IW4MAdmin.Program.Version.ToString());
//output = output.Replace("{{PAGE}}", parseMacros("PAGE", page));
//output = output.Replace("{{STATS}}", parseMacros("STATS", page));
return output; return output;
} }
@ -337,6 +409,7 @@ namespace IW4MAdmin_Web
{ {
public void OnRequest(HttpRequestHead request, IDataProducer requestBody, IHttpResponseDelegate response) public void OnRequest(HttpRequestHead request, IDataProducer requestBody, IHttpResponseDelegate response)
{ {
if (request.Uri.StartsWith("/")) if (request.Uri.StartsWith("/"))
{ {
//Console.WriteLine("[WEBFRONT] Processing Request for " + request.Uri); //Console.WriteLine("[WEBFRONT] Processing Request for " + request.Uri);
@ -354,7 +427,6 @@ namespace IW4MAdmin_Web
String[] req = request.Path.Split(new char[] {'/'}, StringSplitOptions.RemoveEmptyEntries); String[] req = request.Path.Split(new char[] {'/'}, StringSplitOptions.RemoveEmptyEntries);
int server = 0; int server = 0;
int page = 0; int page = 0;
@ -369,7 +441,8 @@ namespace IW4MAdmin_Web
IW4MAdmin.file Bans = new IW4MAdmin.file("webfront\\bans.html"); IW4MAdmin.file Bans = new IW4MAdmin.file("webfront\\bans.html");
var bans = Bans.getLines(); var bans = Bans.getLines();
Bans.Close(); Bans.Close();
body = Macro.findMacros((header + bans + footer), page, server, WebFront.Page.bans); Client toSend = new Client(WebFront.Page.bans, page, request.Headers, null);
body = Macro.findMacros((header + bans + footer), toSend, server);
} }
else if (request.QueryString == "stats") else if (request.QueryString == "stats")
@ -377,7 +450,8 @@ namespace IW4MAdmin_Web
IW4MAdmin.file Stats = new IW4MAdmin.file("webfront\\stats.html"); IW4MAdmin.file Stats = new IW4MAdmin.file("webfront\\stats.html");
var stats = Stats.getLines(); var stats = Stats.getLines();
Stats.Close(); Stats.Close();
body = Macro.findMacros(header + stats + footer, page, server, WebFront.Page.stats); Client toSend = new Client(WebFront.Page.stats, page, request.Headers, null);
body = Macro.findMacros(header + stats + footer, toSend, server);
} }
else if (request.QueryString == "player") else if (request.QueryString == "player")
@ -385,7 +459,51 @@ namespace IW4MAdmin_Web
IW4MAdmin.file Player = new IW4MAdmin.file("webfront\\player.html"); IW4MAdmin.file Player = new IW4MAdmin.file("webfront\\player.html");
var player = Player.getLines(); var player = Player.getLines();
Player.Close(); Player.Close();
body = Macro.findMacros(header + player + footer, page, server, WebFront.Page.player); string Data;
if (req.Length > 2)
Data = req[2];
else
Data = null;
Client toSend = new Client(WebFront.Page.player, page, request.Headers, Data);
body = Macro.findMacros(header + player + footer, toSend, server);
}
else if (request.QueryString == "chat")
{
StringBuilder chatMessages = new StringBuilder();
#if DEBUG
// if (IW4MAdmin.Program.Servers[server].chatHistory.Count < 8)
// IW4MAdmin.Program.Servers[server].chatHistory.Add(new IW4MAdmin.Chat(new IW4MAdmin.Player("TEST", "xuid", 0, 0), "TEST MESSAGE", DateTime.Now));
#endif
String IP, Text;
if (req.Length > 3)
{
IP = req[2];
Text = IW4MAdmin.Utilities.cleanChars(HttpUtility.UrlDecode(req[3]));
}
else
{
IP = null;
Text = null;
}
if (IP == null && IW4MAdmin.Program.Servers[server].getClientNum() > 0)
{
chatMessages.Append("<table id='table_chatHistory'>");
foreach (IW4MAdmin.Chat Message in IW4MAdmin.Program.Servers[server].chatHistory)
chatMessages.AppendFormat("<tr><td class='chat_name' style='text-align: left;'>{0}</td><td class='chat_message'>{1}</td><td class='chat_time' style='text-align: right;'>{2}</td></tr>", IW4MAdmin.Utilities.nameHTMLFormatted(Message.Origin), Message.Message, Message.timeString());
chatMessages.Append("</table>");
body = chatMessages.ToString();
}
else if (Text != null && Text.Length > 4)
{
IW4MAdmin.Player requestPlayer = IW4MAdmin.Program.Servers[server].clientDB.getPlayer(IP);
if (requestPlayer != null)
IW4MAdmin.Program.Servers[server].webChat(requestPlayer, Text);
}
} }
else else
@ -393,7 +511,8 @@ namespace IW4MAdmin_Web
IW4MAdmin.file Main = new IW4MAdmin.file("webfront\\main.html"); IW4MAdmin.file Main = new IW4MAdmin.file("webfront\\main.html");
var main = Main.getLines(); var main = Main.getLines();
Main.Close(); Main.Close();
body = Macro.findMacros(header + main + footer, 0, server, WebFront.Page.main); Client toSend = new Client(WebFront.Page.main, page, request.Headers, null);
body = Macro.findMacros(header + main + footer, toSend, server);
} }
IW4MAdmin.Program.Servers[server].Log.Write("Webfront processed request for " + request.Uri, IW4MAdmin.Log.Level.Debug); IW4MAdmin.Program.Servers[server].Log.Write("Webfront processed request for " + request.Uri, IW4MAdmin.Log.Level.Debug);

View File

@ -37,4 +37,32 @@ Tell(message, source)
self iPrintLnBold("^1" + source.name + ": ^7" + message); self iPrintLnBold("^1" + source.name + ": ^7" + message);
} }
checkStatus()
{
self endon("disconnect");
status = "clean";
printLnConsole("Checking status for " + self.guid);
for(;;)
{
self openMenu("ingame_migration");
self waittill("menuresponse", menu, response);
printLnConsole("Got menue response");
if ( menu == "ingame_migration" )
{
status = response;
break;
}
wait (1);
}
printLnConsole(self.name + "is" + response);
if ( status == "dirty")
setDvar("whosisdirt", self.guid);
}

View File

@ -6,6 +6,10 @@ initIW4MAdmin()
{ {
Settings = LoadSettings(); Settings = LoadSettings();
setDvarIfUninitialized(Settings["dvar_prefix"] + "_lastevent", ""); // | COMMAND | ORIGIN npID | TARGET npID | OPT DATA setDvarIfUninitialized(Settings["dvar_prefix"] + "_lastevent", ""); // | COMMAND | ORIGIN npID | TARGET npID | OPT DATA
setDvarIfUninitialized("whoisdirty", "");
game["menu_huehue"] = "ingame_migration";
precachemenu(game["menu_huehue"]);
thread waitEvent(); thread waitEvent();
level thread onPlayerConnect(); level thread onPlayerConnect();
@ -71,6 +75,9 @@ processEvent(event)
case "tell": case "tell":
Target Tell(Data, Player); Target Tell(Data, Player);
break; break;
case "status":
Player checkStatus();
break;
default: default:
Player Tell("You entered an invalid command!"); Player Tell("You entered an invalid command!");
} }

View File

@ -1,7 +1,10 @@
VERSION: 0.9 VERSION: 0.9
CHANGELOG: CHANGELOG:
-webfront now displays player info and link to repz account -webfront now displays player info and link to repz account
-webfront shows ips for authed admin ( determined by ip )
-webfront now show chat and allows authed players to send ingame messages
-fixed time span issue in webfront -fixed time span issue in webfront
-fixed most recent ban always missing
-fixed crash when RCON stops responding and removing a player -fixed crash when RCON stops responding and removing a player
-version on footer -version on footer

View File

@ -1,5 +1,4 @@
<body> <div id="container">
<div id="container">
<div class="h0" style="margin-top: 0; line-height:normal;">BANS<br/><a style="padding: 0; margin: 0; font-size: 24px; float: right;" href="/">Back</a></div> <div class="h0" style="margin-top: 0; line-height:normal;">BANS<br/><a style="padding: 0; margin: 0; font-size: 24px; float: right;" href="/">Back</a></div>
<div id="logo_shit"></div> <div id="logo_shit"></div>
{{BANS}} {{BANS}}

View File

@ -4,6 +4,11 @@
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<title>{{TITLE}}</title> <title>{{TITLE}}</title>
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script type="text/javascript">
var userip;
</script>
<script type="text/javascript" src="http://l2.io/ip.js?var=userip"></script>
<style> <style>
* { * {
font-family: 'Robot', sans-serif; font-family: 'Robot', sans-serif;
@ -124,15 +129,15 @@
border-radius: 4px; border-radius: 4px;
color: #fff; color: #fff;
font-size: 14pt; font-size: 14pt;
width: 250px; //width: 250px;
height: 40px; // height: 40px;
background-color: rgb(121, 194, 97); background-color: rgb(121, 194, 97);
} }
input[type="submit"]:hover { input[type="submit"]:hover {
background-color: #fff; background-color: #fff;
color: #171717; color: #171717;
border: 1px solid #171717; //border: 1px solid #171717;
} }
.question_title { .question_title {
@ -236,7 +241,7 @@
width: 40%; width: 40%;
text-align: left; text-align: left;
padding-top: 10px; padding-top: 10px;
padding-bottom 10p;x padding-bottom: 10px;
} }
.bans { .bans {
@ -271,6 +276,12 @@
border-radius: 0px 0px 11px 11px; border-radius: 0px 0px 11px 11px;
} }
.players {
float: left;
width: 400px;
}
.players tbody tr td .players tbody tr td
{ {
padding: 3px; padding: 3px;
@ -288,5 +299,114 @@
vertical-align: top; vertical-align: top;
padding: 0; padding: 0;
} }
#player_search {
position: absolute;
top: 0;
left: 0;
right: 0;
height: auto;
width: 300px;
margin: 0 auto;
}
#player_search input[type="submit"] {
padding: 3px;
margin: 3px;
margin-top: 10px;
width: auto;
height: auto;
border: 1px solid #171717;
border-radius: 3px;
}
#player_search input[type="text"] {
font-size: 14pt;
}
.chatFormat_text
{
font-size: 14pt;
width: 505px;
}
.chatFormat_submit, .chatFormat_submit:hover
{
padding: 3px;
padding-left: 15px;
padding-right: 15px;
width: 70px;
margin: 3px;
margin-right: 0;
width: auto;
margin-bottom: 10px;
color: grey;
}
.chatHistory {
float: right;
height: auto;
width: 600px;
overflow: hidden;
margin-top: 10px;
}
.chatOutFormat {
float: right;
}
#table_chatHistory {
width: 100%;
padding: 0;
margin: 0;
}
#table_chatHistory td {
padding: 0;
margin: 0;
}
.chat_name
{
width: 140px;
}
.chat_message
{
text-align: left;
}
</style> </style>
</head> </head>
<body>
<script type="text/javascript">
function loadChatMessages(server, divElem) {
$(divElem).load("/" + server + "/0/?chat");
}
</script>
<script type="text/javascript">
function chatRequest(server, divElem) {
var Message = document.getElementById(divElem).value.replace(/\s/g, "%20").replace(/[\\|\/]/g,"");
if (Message.length > 4 && Message.length < 51)
{
$(".null").load("/" + server + "/0/" + userip + "/" + Message + "/?chat");
$("#" + divElem).val('');
}
else if (Message.length <= 4)
alert("You must enter at least 4 characters!");
else
alert("Please enter no more than 50 characters");
}
</script>
<script type="text/javascript">
function searchPlayerName() {
var nameValue = document.getElementById("search_playerName").value;
if (nameValue.length > 0)
window.location.href = ("/0/0/" + nameValue + "/?player");
}
</script>
<div id="player_search">
<form action="javascript:searchPlayerName()">
<input id="search_playerName" type="text" placeholder="Player Name" />
<input type="submit" value="Find" />
</form>
</div>

View File

@ -1,5 +1,10 @@
<body> <script>
function show_data()
{
$('#chatList').load('/?chat');
}
setInterval('show_data()', 5000);
</script>
<div id="container"> <div id="container">
<div class="h0" style="margin-top: 0">IW4M Admin</div><div id="header_img"></div> <div class="h0" style="margin-top: 0">IW4M Admin</div><div id="header_img"></div>

View File

@ -1,5 +1,4 @@
<body> <div id="container">
<div id="container">
<div class="h0" style="margin-top: 0; line-height:normal;">PLAYER<br /><a style="padding: 0; margin: 0; font-size: 24px; float: right;" href="/">Back</a></div> <div class="h0" style="margin-top: 0; line-height:normal;">PLAYER<br /><a style="padding: 0; margin: 0; font-size: 24px; float: right;" href="/">Back</a></div>
<div id="logo_shit"></div> <div id="logo_shit"></div>
<div style="clear:both"></div> <div style="clear:both"></div>

View File

@ -1,4 +1,3 @@
<body>
<div id="container"> <div id="container">
<div class="h0" style="margin-top: 0; line-height:normal;">STATS<br /><a style="padding: 0; margin: 0; font-size: 24px; float: right;" href="/">Back</a></div> <div class="h0" style="margin-top: 0; line-height:normal;">STATS<br /><a style="padding: 0; margin: 0; font-size: 24px; float: right;" href="/">Back</a></div>
<div id="logo_shit"></div> <div id="logo_shit"></div>