Don't convert percents to ampersands when part of url, fixes #420.

This commit is contained in:
UnknownShadow200 2017-09-01 14:25:22 +10:00
parent 5ee8c9c576
commit a933a360f8
3 changed files with 47 additions and 18 deletions

View File

@ -26,6 +26,8 @@ namespace MCGalaxy.Gui {
public static void Format(string message, Action<char, string> output) { public static void Format(string message, Action<char, string> output) {
int index = 0; int index = 0;
char col = 'S'; char col = 'S';
message = Colors.Escape(message);
while (index < message.Length) while (index < message.Length)
OutputPart(ref col, ref index, message, output); OutputPart(ref col, ref index, message, output);
} }
@ -47,7 +49,7 @@ namespace MCGalaxy.Gui {
static int Next(int start, string message) { static int Next(int start, string message) {
for (int i = start; i < message.Length; i++) { for (int i = start; i < message.Length; i++) {
if (!(message[i] == '&' || message[i] == '%')) continue; if (message[i] != '&') continue;
// No colour code follows this // No colour code follows this
if (i == message.Length - 1) return -1; if (i == message.Length - 1) return -1;

View File

@ -185,30 +185,57 @@ namespace MCGalaxy {
if (col == 'T') { col = ServerConfig.HelpSyntaxColor[1]; return true; } if (col == 'T') { col = ServerConfig.HelpSyntaxColor[1]; return true; }
if (col == 'I') { col = ServerConfig.IRCColor[1]; return true; } if (col == 'I') { col = ServerConfig.IRCColor[1]; return true; }
return IsDefined(col); return IsDefined(col);
} }
/// <summary> Converts percentage color codes to their actual/real color codes. </summary> /// <summary> Converts percentage color codes to their actual/real color codes. </summary>
/// <remarks> Does not escape percentage codes that are part of urls. </remarks>
public static string Escape(string value) { public static string Escape(string value) {
if (value.IndexOf('%') == -1) return value; if (value.IndexOf('%') == -1) return value;
char[] chars = new char[value.Length]; char[] chars = new char[value.Length];
for (int i = 0; i < chars.Length; i++) { chars[i] = value[i]; }
for (int i = 0; i < value.Length; i++ ) { for (int i = 0; i < chars.Length;) {
char c = value[i]; int end = value.IndexOf(' ', i);
bool validCode = c == '%' && i < value.Length - 1; if (end == -1) end = value.Length;
if (!validCode) { chars[i] = c; continue; }
char color = value[i + 1]; if (!IsUrlAt(chars, i, end - i)) Escape(chars, i, end);
if (Map(ref color)) { i = end + 1;
chars[i] = '&';
chars[i + 1] = color;
i++; continue;
}
chars[i] = '%';
} }
return new string(chars); return new string(chars);
} }
static bool IsUrlAt(char[] chars, int i, int len) {
const int prefixLen = 7; // "http://".Length
if (len < prefixLen) return false;
// skip color codes in url
while (len > 0 && chars[i] == '&') { len -= 2; i += 2; }
// Starts with "http" ?
if (len < prefixLen) return false;
if (chars[i] != 'h' || chars[i + 1] != 't' || chars[i + 2] != 't' || chars[i + 3] != 'p') return false;
len -= 4; i += 4;
// And then with "s://" or "://" ?
if (len >= 4 && chars[i] == 's' && chars[i + 1] == ':' && chars[i + 2] == '/' && chars[i + 3] == '/') return true;
if (len >= 3 && chars[i] == ':' && chars[i + 1] == '/' && chars[i + 2] == '/') return true;
return false;
}
static void Escape(char[] chars, int start, int end) {
for (int i = start; i < end; i++ ) {
char c = chars[i];
bool validCode = c == '%' && i < chars.Length - 1;
if (!validCode) continue;
char color = chars[i + 1];
if (!Map(ref color)) continue;
chars[i] = '&'; i++; // skip over color code
}
}
/// <summary> Removes all percentage and actual color codes from the given string. </summary> /// <summary> Removes all percentage and actual color codes from the given string. </summary>
public static string Strip(string value) { public static string Strip(string value) {
if (value.IndexOf('%') == -1 && value.IndexOf('&') == -1) return value; if (value.IndexOf('%') == -1 && value.IndexOf('&') == -1) return value;
@ -320,7 +347,7 @@ namespace MCGalaxy {
} }
} }
/// <summary> Describes information about a color code. </summary> /// <summary> Describes information about a color code. </summary>
public struct ColorDesc { public struct ColorDesc {
public char Code, Fallback; public char Code, Fallback;
public byte R, G, B, A; public byte R, G, B, A;

View File

@ -33,10 +33,10 @@ namespace MCGalaxy.Commands.Maintenance {
if (!Formatter.ValidName(p, args[1], "player")) return; if (!Formatter.ValidName(p, args[1], "player")) return;
if (PlayerInfo.FindExact(args[0]) != null) { if (PlayerInfo.FindExact(args[0]) != null) {
Player.Message(p, "\"{0}\" must be offline to use /infoswap.", args[0]); return; Player.Message(p, "\"{0}\" must be offline to use %T/InfoSwap", args[0]); return;
} }
if (PlayerInfo.FindExact(args[1]) != null) { if (PlayerInfo.FindExact(args[1]) != null) {
Player.Message(p, "\"{0}\" must be offline to use /infoswap.", args[1]); return; Player.Message(p, "\"{0}\" must be offline to use %T/InfoSwap", args[1]); return;
} }
string src = PlayerInfo.FindName(args[0]); string src = PlayerInfo.FindName(args[0]);
@ -51,10 +51,10 @@ namespace MCGalaxy.Commands.Maintenance {
Group srcGroup = Group.GroupIn(src); Group srcGroup = Group.GroupIn(src);
Group dstGroup = Group.GroupIn(dst); Group dstGroup = Group.GroupIn(dst);
if (p != null && srcGroup.Permission >= p.Rank) { if (p != null && srcGroup.Permission >= p.Rank) {
Player.Message(p, "Cannot /infoswap for a player ranked equal or higher to yours."); return; Player.Message(p, "Cannot %T/InfoSwap %Sfor a player ranked equal or higher to yours."); return;
} }
if (p != null && dstGroup.Permission >= p.Rank) { if (p != null && dstGroup.Permission >= p.Rank) {
Player.Message(p, "Cannot /infoswap for a player ranked equal or higher to yours."); return; Player.Message(p, "Cannot %T/InfoSwap %Sfor a player ranked equal or higher to yours."); return;
} }
SwapStats(src, dst); SwapStats(src, dst);