using System.IO; using Server.Accounting; using Server.Text; namespace Server.Commands { public static class CommandLogging { private static readonly char[] m_NotSafe = { '\\', '/', ':', '*', '?', '"', '<', '>', '|' }; public static bool Enabled { get; set; } = true; public static StreamWriter Output { get; private set; } public static void Initialize() { EventSink.Command += EventSink_Command; if (!Directory.Exists("Logs")) { Directory.CreateDirectory("Logs"); } var directory = "Logs/Commands"; if (!Directory.Exists(directory)) { Directory.CreateDirectory(directory); } try { Output = new StreamWriter(Path.Combine(directory, $"{Core.Now.ToLongDateString()}.log"), true); Output.AutoFlush = true; Output.WriteLine("##############################"); Output.WriteLine("Log started on {0}", Core.Now); Output.WriteLine(); } catch { // ignored } } public static object Format(object o) => o switch { Mobile m => m.Account == null ? $"{m} (no account)" : $"{m} ('{m.Account.Username}')", Item item => $"{item.Serial} ({item.GetType().Name})", _ => o }; public static void WriteLine(Mobile from, string text) { if (!Enabled) { return; } try { Output.WriteLine("{0}: {1}: {2}", Core.Now, from.NetState, text); var path = Core.BaseDirectory; var name = from.Account is not Account acct ? from.Name : acct.Username; AppendPath(ref path, "Logs"); AppendPath(ref path, "Commands"); AppendPath(ref path, from.AccessLevel.ToString()); path = Path.Combine(path, $"{name}.log"); using var sw = new StreamWriter(path, true); sw.WriteLine("{0}: {1}: {2}", Core.Now, from.NetState, text); } catch { // ignored } } public static void AppendPath(ref string path, string toAppend) { path = Path.Combine(path, toAppend); if (!Directory.Exists(path)) { Directory.CreateDirectory(path); } } public static string Safe(string ip) { if (ip == null) { return "null"; } ip = ip.Trim().DefaultIfNullOrEmpty("empty"); var isSafe = true; for (var i = 0; isSafe && i < m_NotSafe.Length; ++i) { isSafe = !ip.ContainsOrdinal(m_NotSafe[i]); } if (isSafe) { return ip; } using var sb = ValueStringBuilder.Create(ip.Length); sb.Append(ip); for (var i = 0; i < m_NotSafe.Length; ++i) { sb.Replace(m_NotSafe[i], '_', 0, sb.Length); } return sb.ToString(); } public static void EventSink_Command(CommandEventArgs e) { var from = e.Mobile; WriteLine(from, $"{from.AccessLevel} {Format(from)} used command '{e.Command} {e.ArgString}'"); } public static void LogChangeProperty(Mobile from, object o, string name, string value) { WriteLine(from, $"{from.AccessLevel} {Format(from)} set property '{name}' of {Format(o)} to '{value}'"); } } }