Drew the rest of the fucking owl.

This commit is contained in:
flash 2024-05-14 22:17:25 +00:00
parent 7bcf5acb7e
commit a6a7e56bd1
52 changed files with 504 additions and 215 deletions

View file

@ -28,7 +28,7 @@ namespace SharpChat {
public void DispatchEvent(IChatEvent eventInfo) {
if(eventInfo is MessageCreateEvent mce) {
if(mce.IsBroadcast) {
Send(new BroadcastPacket(mce.MessageText));
Send(new MessageBroadcastPacket(mce.MessageText));
} else if(mce.IsPrivate) {
// The channel name returned by GetDMChannelName should not be exposed to the user, instead @<Target User> should be displayed
// e.g. nook sees @Arysil and Arysil sees @nook
@ -47,7 +47,7 @@ namespace SharpChat {
return;
foreach(ChatUser user in users)
SendTo(user, new ChatMessageAddPacket(
SendTo(user, new MessageAddPacket(
mce.MessageId,
DateTimeOffset.Now,
mce.SenderId,
@ -58,7 +58,7 @@ namespace SharpChat {
} else {
ChatChannel? channel = Channels.FirstOrDefault(c => c.NameEquals(mce.ChannelName));
if(channel != null)
SendTo(channel, new ChatMessageAddPacket(
SendTo(channel, new MessageAddPacket(
mce.MessageId,
DateTimeOffset.Now,
mce.SenderId,
@ -242,15 +242,15 @@ namespace SharpChat {
chan.Name,
maxMsgLength
));
conn.Send(new ContextUsersPacket(GetChannelUsers(chan).Except(new[] { user }).Select(
user => new ContextUsersPacket.ListEntry(user.UserId, user.LegacyNameWithStatus, user.Colour, user.Rank, user.Permissions, true)
conn.Send(new UsersPopulatePacket(GetChannelUsers(chan).Except(new[] { user }).Select(
user => new UsersPopulatePacket.ListEntry(user.UserId, user.LegacyNameWithStatus, user.Colour, user.Rank, user.Permissions, true)
).OrderByDescending(user => user.Rank).ToArray()));
foreach(StoredEventInfo msg in Events.GetChannelEventLog(chan.Name))
conn.Send(new ContextMessagePacket(msg));
conn.Send(new MessagePopulatePacket(msg));
conn.Send(new ContextChannelsPacket(Channels.Where(c => c.Rank <= user.Rank).Select(
channel => new ContextChannelsPacket.ListEntry(channel.Name, channel.HasPassword, channel.IsTemporary)
conn.Send(new ChannelsPopulatePacket(Channels.Where(c => c.Rank <= user.Rank).Select(
channel => new ChannelsPopulatePacket.ListEntry(channel.Name, channel.HasPassword, channel.IsTemporary)
).ToArray()));
Users.Add(user);
@ -285,13 +285,13 @@ namespace SharpChat {
if(!user.Can(ChatUserPermissions.JoinAnyChannel) && chan.IsOwner(user)) {
if(chan.Rank > user.Rank) {
SendTo(user, new LegacyCommandResponse(LCR.CHANNEL_INSUFFICIENT_RANK, true, chan.Name));
SendTo(user, new ChannelRankTooLowErrorPacket(chan.Name));
ForceChannel(user);
return;
}
if(!string.IsNullOrEmpty(chan.Password) && chan.Password != password) {
SendTo(user, new LegacyCommandResponse(LCR.CHANNEL_INVALID_PASSWORD, true, chan.Name));
if(!string.IsNullOrEmpty(chan.Password) && chan.Password.Equals(password)) {
SendTo(user, new ChannelPasswordWrongErrorPacket(chan.Name));
ForceChannel(user);
return;
}
@ -312,12 +312,12 @@ namespace SharpChat {
Events.AddEvent("chan:join", user, oldChan, flags: StoredEventFlags.Log);
SendTo(user, new ContextClearPacket(ContextClearPacket.ClearMode.MessagesUsers));
SendTo(user, new ContextUsersPacket(GetChannelUsers(chan).Except(new[] { user }).Select(
user => new ContextUsersPacket.ListEntry(user.UserId, user.LegacyNameWithStatus, user.Colour, user.Rank, user.Permissions, true)
SendTo(user, new UsersPopulatePacket(GetChannelUsers(chan).Except(new[] { user }).Select(
user => new UsersPopulatePacket.ListEntry(user.UserId, user.LegacyNameWithStatus, user.Colour, user.Rank, user.Permissions, true)
).OrderByDescending(u => u.Rank).ToArray()));
foreach(StoredEventInfo msg in Events.GetChannelEventLog(chan.Name))
SendTo(user, new ContextMessagePacket(msg));
SendTo(user, new MessagePopulatePacket(msg));
ForceChannel(user, chan);

View file

@ -24,7 +24,7 @@ namespace SharpChat.Commands {
}
Task.Run(async () => {
ctx.Chat.SendTo(ctx.User, new BanListPacket(
ctx.Chat.SendTo(ctx.User, new BanListResponsePacket(
(await Misuzu.GetBanListAsync() ?? Array.Empty<MisuzuBanInfo>()).Select(
ban => string.IsNullOrEmpty(ban.UserName) ? (string.IsNullOrEmpty(ban.RemoteAddress) ? string.Empty : ban.RemoteAddress) : ban.UserName
).ToArray()

View file

@ -2,7 +2,7 @@
using System.Linq;
namespace SharpChat.Commands {
public class CreateChannelCommand : IChatCommand {
public class ChannelCreateCommand : IChatCommand {
public bool IsMatch(ChatCommandContext ctx) {
return ctx.NameEquals("create");
}
@ -27,19 +27,19 @@ namespace SharpChat.Commands {
createChanHierarchy = 0;
if(createChanHierarchy > ctx.User.Rank) {
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.INSUFFICIENT_RANK));
ctx.Chat.SendTo(ctx.User, new ChannelRankTooHighErrorPacket());
return;
}
string createChanName = string.Join('_', ctx.Args.Skip(createChanHasHierarchy ? 1 : 0));
if(!ChatChannel.CheckName(createChanName)) {
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.CHANNEL_NAME_INVALID));
ctx.Chat.SendTo(ctx.User, new ChannelNameFormatErrorPacket());
return;
}
if(ctx.Chat.Channels.Any(c => c.NameEquals(createChanName))) {
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.CHANNEL_ALREADY_EXISTS, true, createChanName));
ctx.Chat.SendTo(ctx.User, new ChannelNameInUseErrorPacket(createChanName));
return;
}
@ -58,7 +58,7 @@ namespace SharpChat.Commands {
));
ctx.Chat.SwitchChannel(ctx.User, createChan, createChan.Password);
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.CHANNEL_CREATED, false, createChan.Name));
ctx.Chat.SendTo(ctx.User, new ChannelCreateResponsePacket(createChan.Name));
}
}
}

View file

@ -2,7 +2,7 @@
using System.Linq;
namespace SharpChat.Commands {
public class DeleteChannelCommand : IChatCommand {
public class ChannelDeleteCommand : IChatCommand {
public bool IsMatch(ChatCommandContext ctx) {
return ctx.NameEquals("delchan") || (
ctx.NameEquals("delete")
@ -20,17 +20,17 @@ namespace SharpChat.Commands {
ChatChannel? delChan = ctx.Chat.Channels.FirstOrDefault(c => c.NameEquals(delChanName));
if(delChan == null) {
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.CHANNEL_NOT_FOUND, true, delChanName));
ctx.Chat.SendTo(ctx.User, new ChannelNotFoundErrorPacket(delChanName));
return;
}
if(!ctx.User.Can(ChatUserPermissions.DeleteChannel) && delChan.IsOwner(ctx.User)) {
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.CHANNEL_DELETE_FAILED, true, delChan.Name));
ctx.Chat.SendTo(ctx.User, new ChannelDeleteNotAllowedErrorPacket(delChan.Name));
return;
}
ctx.Chat.RemoveChannel(delChan);
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.CHANNEL_DELETED, false, delChan.Name));
ctx.Chat.SendTo(ctx.User, new ChannelDeleteResponsePacket(delChan.Name));
}
}
}

View file

@ -2,17 +2,17 @@
using System.Linq;
namespace SharpChat.Commands {
public class JoinChannelCommand : IChatCommand {
public class ChannelJoinCommand : IChatCommand {
public bool IsMatch(ChatCommandContext ctx) {
return ctx.NameEquals("join");
}
public void Dispatch(ChatCommandContext ctx) {
string? joinChanStr = ctx.Args.FirstOrDefault();
string joinChanStr = ctx.Args.FirstOrDefault() ?? string.Empty;
ChatChannel? joinChan = ctx.Chat.Channels.FirstOrDefault(c => c.NameEquals(joinChanStr));
if(joinChan == null) {
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.CHANNEL_NOT_FOUND, true, joinChanStr ?? string.Empty));
ctx.Chat.SendTo(ctx.User, new ChannelNotFoundErrorPacket(joinChanStr));
ctx.Chat.ForceChannel(ctx.User);
return;
}

View file

@ -1,7 +1,7 @@
using SharpChat.Packet;
namespace SharpChat.Commands {
public class PasswordChannelCommand : IChatCommand {
public class ChannelPasswordCommand : IChatCommand {
public bool IsMatch(ChatCommandContext ctx) {
return ctx.NameEquals("pwd")
|| ctx.NameEquals("password");
@ -19,7 +19,7 @@ namespace SharpChat.Commands {
chanPass = string.Empty;
ctx.Chat.UpdateChannel(ctx.Channel, password: chanPass);
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.CHANNEL_PASSWORD_CHANGED, false));
ctx.Chat.SendTo(ctx.User, new ChannelPasswordChangedResponsePacket());
}
}
}

View file

@ -2,7 +2,7 @@
using System.Linq;
namespace SharpChat.Commands {
public class RankChannelCommand : IChatCommand {
public class ChannelRankCommand : IChatCommand {
public bool IsMatch(ChatCommandContext ctx) {
return ctx.NameEquals("rank")
|| ctx.NameEquals("privilege")
@ -16,12 +16,12 @@ namespace SharpChat.Commands {
}
if(!ctx.Args.Any() || !int.TryParse(ctx.Args.First(), out int chanHierarchy) || chanHierarchy > ctx.User.Rank) {
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.INSUFFICIENT_RANK));
ctx.Chat.SendTo(ctx.User, new ChannelRankTooHighErrorPacket());
return;
}
ctx.Chat.UpdateChannel(ctx.Channel, minRank: chanHierarchy);
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.CHANNEL_RANK_CHANGED, false));
ctx.Chat.SendTo(ctx.User, new ChannelRankChangedResponsePacket());
}
}
}

View file

@ -25,18 +25,18 @@ namespace SharpChat.Commands {
return;
}
string? banUserTarget = ctx.Args.ElementAtOrDefault(0);
string banUserTarget = ctx.Args.ElementAtOrDefault(0) ?? string.Empty;
string? banDurationStr = ctx.Args.ElementAtOrDefault(1);
int banReasonIndex = 1;
ChatUser? banUser = null;
if(banUserTarget == null || (banUser = ctx.Chat.Users.FirstOrDefault(u => u.NameEquals(banUserTarget))) == null) {
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.USER_NOT_FOUND, true, banUserTarget ?? string.Empty));
if(string.IsNullOrEmpty(banUserTarget) || (banUser = ctx.Chat.Users.FirstOrDefault(u => u.NameEquals(banUserTarget))) == null) {
ctx.Chat.SendTo(ctx.User, new UserNotFoundErrorPacket(banUserTarget));
return;
}
if(!ctx.User.IsSuper && banUser.Rank >= ctx.User.Rank && banUser != ctx.User) {
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.KICK_NOT_ALLOWED, true, banUser.LegacyName));
ctx.Chat.SendTo(ctx.User, new KickBanNotAllowedErrorPacket(banUser.LegacyName));
return;
}
@ -66,7 +66,7 @@ namespace SharpChat.Commands {
MisuzuBanInfo? fbi = await Misuzu.CheckBanAsync(userId, userIp);
if(fbi != null && fbi.IsBanned && !fbi.HasExpired) {
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.KICK_NOT_ALLOWED, true, banUser.LegacyName));
ctx.Chat.SendTo(ctx.User, new KickBanNotAllowedErrorPacket(banUser.LegacyName));
return;
}

View file

@ -3,7 +3,7 @@ using System;
using System.Linq;
namespace SharpChat.Commands {
public class ActionCommand : IChatCommand {
public class MessageActionCommand : IChatCommand {
public bool IsMatch(ChatCommandContext ctx) {
return ctx.NameEquals("action")
|| ctx.NameEquals("me");

View file

@ -3,7 +3,7 @@ using SharpChat.Packet;
using System;
namespace SharpChat.Commands {
public class BroadcastCommand : IChatCommand {
public class MessageBroadcastCommand : IChatCommand {
public bool IsMatch(ChatCommandContext ctx) {
return ctx.NameEquals("say")
|| ctx.NameEquals("broadcast");

View file

@ -4,7 +4,7 @@ using System.Linq;
namespace SharpChat.Commands
{
public class DeleteMessageCommand : IChatCommand {
public class MessageDeleteCommand : IChatCommand {
public bool IsMatch(ChatCommandContext ctx) {
return ctx.NameEquals("delmsg") || (
ctx.NameEquals("delete")
@ -30,12 +30,12 @@ namespace SharpChat.Commands
StoredEventInfo? delMsg = ctx.Chat.Events.GetEvent(delSeqId);
if(delMsg == null || delMsg.Sender?.Rank > ctx.User.Rank || (!deleteAnyMessage && delMsg.Sender?.UserId != ctx.User.UserId)) {
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.MESSAGE_DELETE_ERROR));
ctx.Chat.SendTo(ctx.User, new MessageDeleteNotAllowedErrorPacket());
return;
}
ctx.Chat.Events.RemoveEvent(delMsg);
ctx.Chat.Send(new ChatMessageDeletePacket(delMsg.Id));
ctx.Chat.Send(new MessageDeletePacket(delMsg.Id));
}
}
}

View file

@ -4,7 +4,7 @@ using System;
using System.Linq;
namespace SharpChat.Commands {
public class WhisperCommand : IChatCommand {
public class MessageWhisperCommand : IChatCommand {
public bool IsMatch(ChatCommandContext ctx) {
return ctx.NameEquals("whisper")
|| ctx.NameEquals("msg");
@ -16,11 +16,11 @@ namespace SharpChat.Commands {
return;
}
string? whisperUserStr = ctx.Args.FirstOrDefault();
string whisperUserStr = ctx.Args.FirstOrDefault() ?? string.Empty;
ChatUser? whisperUser = ctx.Chat.Users.FirstOrDefault(u => u.NameEquals(whisperUserStr));
if(whisperUser == null) {
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.USER_NOT_FOUND, true, whisperUserStr ?? string.Empty));
ctx.Chat.SendTo(ctx.User, new UserNotFoundErrorPacket(whisperUserStr));
return;
}

View file

@ -36,15 +36,15 @@ namespace SharpChat.Commands {
MisuzuBanInfo? banInfo = await Misuzu.CheckBanAsync(ipAddr: unbanAddrTarget);
if(banInfo?.IsBanned != true || banInfo.HasExpired) {
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.USER_NOT_BANNED, true, unbanAddrTarget));
ctx.Chat.SendTo(ctx.User, new KickBanNoRecordErrorPacket(unbanAddrTarget));
return;
}
bool wasBanned = await Misuzu.RevokeBanAsync(banInfo, MisuzuClient.BanRevokeKind.RemoteAddress);
if(wasBanned)
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.USER_UNBANNED, false, unbanAddrTarget));
ctx.Chat.SendTo(ctx.User, new PardonResponsePacket(unbanAddrTarget));
else
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.USER_NOT_BANNED, true, unbanAddrTarget));
ctx.Chat.SendTo(ctx.User, new KickBanNoRecordErrorPacket(unbanAddrTarget));
}).Wait();
}
}

View file

@ -43,15 +43,15 @@ namespace SharpChat.Commands {
MisuzuBanInfo? banInfo = await Misuzu.CheckBanAsync(unbanUserTarget, userIdIsName: unbanUserTargetIsName);
if(banInfo?.IsBanned != true || banInfo.HasExpired) {
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.USER_NOT_BANNED, true, unbanUserTarget));
ctx.Chat.SendTo(ctx.User, new KickBanNoRecordErrorPacket(unbanUserTarget));
return;
}
bool wasBanned = await Misuzu.RevokeBanAsync(banInfo, MisuzuClient.BanRevokeKind.UserId);
if(wasBanned)
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.USER_UNBANNED, false, unbanUserTarget));
ctx.Chat.SendTo(ctx.User, new PardonResponsePacket(unbanUserTarget));
else
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.USER_NOT_BANNED, true, unbanUserTarget));
ctx.Chat.SendTo(ctx.User, new KickBanNoRecordErrorPacket(unbanUserTarget));
}).Wait();
}
}

View file

@ -2,7 +2,7 @@
using System.Linq;
namespace SharpChat.Commands {
public class AFKCommand : IChatCommand {
public class UserAFKCommand : IChatCommand {
private const string DEFAULT = "AFK";
private const int MAX_LENGTH = 5;

View file

@ -2,7 +2,7 @@
using System.Linq;
namespace SharpChat.Commands {
public class NickCommand : IChatCommand {
public class UserNickCommand : IChatCommand {
public bool IsMatch(ChatCommandContext ctx) {
return ctx.NameEquals("nick");
}
@ -43,7 +43,7 @@ namespace SharpChat.Commands {
nickStr = string.Empty;
if(!string.IsNullOrWhiteSpace(nickStr) && ctx.Chat.Users.Any(u => u.NameEquals(nickStr))) {
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.NAME_IN_USE, true, nickStr));
ctx.Chat.SendTo(ctx.User, new UserNameInUseErrorPacket(nickStr));
return;
}

View file

@ -1,6 +1,5 @@
using SharpChat.Packet;
using System.Linq;
using System.Text;
namespace SharpChat.Commands {
public class WhoCommand : IChatCommand {
@ -9,50 +8,33 @@ namespace SharpChat.Commands {
}
public void Dispatch(ChatCommandContext ctx) {
StringBuilder whoChanSB = new();
string? whoChanStr = ctx.Args.FirstOrDefault();
string? channelName = ctx.Args.FirstOrDefault();
if(string.IsNullOrEmpty(whoChanStr)) {
foreach(ChatUser whoUser in ctx.Chat.Users) {
whoChanSB.Append(@"<a href=""javascript:void(0);"" onclick=""UI.InsertChatText(this.innerHTML);""");
if(whoUser == ctx.User)
whoChanSB.Append(@" style=""font-weight: bold;""");
whoChanSB.AppendFormat(@">{0}</a>, ", whoUser.LegacyName);
}
if(whoChanSB.Length > 2)
whoChanSB.Length -= 2;
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.USERS_LISTING_SERVER, false, whoChanSB));
} else {
ChatChannel? whoChan = ctx.Chat.Channels.FirstOrDefault(c => c.NameEquals(whoChanStr));
if(whoChan == null) {
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.CHANNEL_NOT_FOUND, true, whoChanStr));
return;
}
if(whoChan.Rank > ctx.User.Rank || (whoChan.HasPassword && !ctx.User.Can(ChatUserPermissions.JoinAnyChannel))) {
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.USERS_LISTING_ERROR, true, whoChanStr));
return;
}
foreach(ChatUser whoUser in ctx.Chat.GetChannelUsers(whoChan)) {
whoChanSB.Append(@"<a href=""javascript:void(0);"" onclick=""UI.InsertChatText(this.innerHTML);""");
if(whoUser == ctx.User)
whoChanSB.Append(@" style=""font-weight: bold;""");
whoChanSB.AppendFormat(@">{0}</a>, ", whoUser.LegacyName);
}
if(whoChanSB.Length > 2)
whoChanSB.Length -= 2;
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.USERS_LISTING_CHANNEL, false, whoChan.Name, whoChanSB));
if(string.IsNullOrEmpty(channelName)) {
ctx.Chat.SendTo(ctx.User, new WhoServerResponsePacket(
ctx.Chat.Users.Select(u => u.LegacyName).ToArray(),
ctx.User.LegacyName
));
return;
}
ChatChannel? channel = ctx.Chat.Channels.FirstOrDefault(c => c.NameEquals(channelName));
if(channel == null) {
ctx.Chat.SendTo(ctx.User, new ChannelNotFoundErrorPacket(channelName));
return;
}
if(channel.Rank > ctx.User.Rank || (channel.HasPassword && !ctx.User.Can(ChatUserPermissions.JoinAnyChannel))) {
ctx.Chat.SendTo(ctx.User, new WhoChannelNotFoundErrorPacket(channelName));
return;
}
ctx.Chat.SendTo(ctx.User, new WhoChannelResponsePacket(
channel.Name,
ctx.Chat.GetChannelUsers(channel).Select(user => user.LegacyName).ToArray(),
ctx.User.LegacyName
));
}
}
}

View file

@ -15,11 +15,11 @@ namespace SharpChat.Commands {
return;
}
string? ipUserStr = ctx.Args.FirstOrDefault();
string ipUserStr = ctx.Args.FirstOrDefault() ?? string.Empty;
ChatUser? ipUser;
if(string.IsNullOrWhiteSpace(ipUserStr) || (ipUser = ctx.Chat.Users.FirstOrDefault(u => u.NameEquals(ipUserStr))) == null) {
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.USER_NOT_FOUND, true, ipUserStr ?? string.Empty));
ctx.Chat.SendTo(ctx.User, new UserNotFoundErrorPacket(ipUserStr));
return;
}

View file

@ -10,7 +10,7 @@ namespace SharpChat.Packet {
}
private readonly FailReason Reason;
private readonly DateTimeOffset Expires;
private readonly long Expires;
public AuthFailPacket(FailReason reason) {
Reason = reason;
@ -18,7 +18,7 @@ namespace SharpChat.Packet {
public AuthFailPacket(DateTimeOffset expires) {
Reason = FailReason.Banned;
Expires = expires;
Expires = expires.Year >= 2100 ? -1 : expires.ToUnixTimeSeconds();
}
public override string Pack() {
@ -30,7 +30,7 @@ namespace SharpChat.Packet {
});
if(Reason == FailReason.Banned)
packet += string.Format("\t{0}", Expires.Year >= 2100 ? -1 : Expires.ToUnixTimeSeconds());
packet += string.Format("\t{0}", Expires);
return packet;
}

View file

@ -1,24 +1,25 @@
using System;
using System.Linq;
using System.Text;
namespace SharpChat.Packet {
public class BanListPacket : ServerPacket {
public class BanListResponsePacket : ServerPacket {
private readonly long Timestamp;
private readonly string[] Bans;
public BanListPacket(string[] bans) {
Bans = bans ?? throw new ArgumentNullException(nameof(bans));
public BanListResponsePacket(string[] bans) {
Timestamp = DateTimeOffset.Now.ToUnixTimeSeconds();
Bans = bans;
}
public override string Pack() {
StringBuilder sb = new();
sb.AppendFormat("2\t{0}\t-1\t0\fbanlist\f", DateTimeOffset.Now.ToUnixTimeSeconds());
sb.AppendFormat("2\t{0}\t-1\t0\fbanlist\f", Timestamp);
foreach(string ban in Bans)
sb.AppendFormat(@"<a href=""javascript:void(0);"" onclick=""Chat.SendMessageWrapper('/unban '+ this.innerHTML);"">{0}</a>, ", ban);
if(Bans.Any())
if(Bans.Length > 0)
sb.Length -= 2;
sb.AppendFormat("\t{0}\t10010", SequenceId);

View file

@ -0,0 +1,17 @@
using System;
namespace SharpChat.Packet {
public class ChannelCreateResponsePacket : ServerPacket {
private readonly long Timestamp;
private readonly string ChannelName;
public ChannelCreateResponsePacket(string channelName) {
Timestamp = DateTimeOffset.Now.ToUnixTimeSeconds();
ChannelName = channelName;
}
public override string Pack() {
return string.Format("2\t{0}\t-1\t0\fcrchan\f{1}\t{2}\t10010", Timestamp, ChannelName, SequenceId);
}
}
}

View file

@ -0,0 +1,17 @@
using System;
namespace SharpChat.Packet {
public class ChannelDeleteNotAllowedErrorPacket : ServerPacket {
private readonly long Timestamp;
private readonly string ChannelName;
public ChannelDeleteNotAllowedErrorPacket(string channelName) {
Timestamp = DateTimeOffset.Now.ToUnixTimeSeconds();
ChannelName = channelName;
}
public override string Pack() {
return string.Format("2\t{0}\t-1\t1\fndchan\f{1}\t{2}\t10010", Timestamp, ChannelName, SequenceId);
}
}
}

View file

@ -5,7 +5,7 @@ namespace SharpChat.Packet {
private readonly string ChannelName;
public ChannelDeletePacket(string channelName) {
ChannelName = channelName ?? throw new ArgumentNullException(nameof(channelName));
ChannelName = channelName;
}
public override string Pack() {

View file

@ -0,0 +1,17 @@
using System;
namespace SharpChat.Packet {
public class ChannelDeleteResponsePacket : ServerPacket {
private readonly long Timestamp;
private readonly string ChannelName;
public ChannelDeleteResponsePacket(string channelName) {
Timestamp = DateTimeOffset.Now.ToUnixTimeSeconds();
ChannelName = channelName;
}
public override string Pack() {
return string.Format("2\t{0}\t-1\t0\fdelchan\f{1}\t{2}\t10010", Timestamp, ChannelName, SequenceId);
}
}
}

View file

@ -0,0 +1,15 @@
using System;
namespace SharpChat.Packet {
public class ChannelNameFormatErrorPacket : ServerPacket {
private readonly long Timestamp;
public ChannelNameFormatErrorPacket() {
Timestamp = DateTimeOffset.Now.ToUnixTimeSeconds();
}
public override string Pack() {
return string.Format("2\t{0}\t-1\t1\finchan\t{1}\t10010", Timestamp, SequenceId);
}
}
}

View file

@ -0,0 +1,17 @@
using System;
namespace SharpChat.Packet {
public class ChannelNameInUseErrorPacket : ServerPacket {
private readonly long Timestamp;
private readonly string ChannelName;
public ChannelNameInUseErrorPacket(string channelName) {
Timestamp = DateTimeOffset.Now.ToUnixTimeSeconds();
ChannelName = channelName;
}
public override string Pack() {
return string.Format("2\t{0}\t-1\t1\fnischan\f{1}\t{2}\t10010", Timestamp, ChannelName, SequenceId);
}
}
}

View file

@ -0,0 +1,17 @@
using System;
namespace SharpChat.Packet {
public class ChannelNotFoundErrorPacket : ServerPacket {
private readonly long Timestamp;
private readonly string ChannelName;
public ChannelNotFoundErrorPacket(string channelName) {
Timestamp = DateTimeOffset.Now.ToUnixTimeSeconds();
ChannelName = channelName;
}
public override string Pack() {
return string.Format("2\t{0}\t-1\t1\fnochan\f{1}\t{2}\t10010", Timestamp, ChannelName, SequenceId);
}
}
}

View file

@ -0,0 +1,15 @@
using System;
namespace SharpChat.Packet {
public class ChannelPasswordChangedResponsePacket : ServerPacket {
private readonly long Timestamp;
public ChannelPasswordChangedResponsePacket() {
Timestamp = DateTimeOffset.Now.ToUnixTimeSeconds();
}
public override string Pack() {
return string.Format("2\t{0}\t-1\t0\fcpwdchan\t{1}\t10010", Timestamp, SequenceId);
}
}
}

View file

@ -0,0 +1,17 @@
using System;
namespace SharpChat.Packet {
public class ChannelPasswordWrongErrorPacket : ServerPacket {
private readonly long Timestamp;
private readonly string ChannelName;
public ChannelPasswordWrongErrorPacket(string channelName) {
Timestamp = DateTimeOffset.Now.ToUnixTimeSeconds();
ChannelName = channelName;
}
public override string Pack() {
return string.Format("2\t{0}\t-1\t1\fipwchan\f{1}\t{2}\t10010", Timestamp, ChannelName, SequenceId);
}
}
}

View file

@ -0,0 +1,15 @@
using System;
namespace SharpChat.Packet {
public class ChannelRankChangedResponsePacket : ServerPacket {
private readonly long Timestamp;
public ChannelRankChangedResponsePacket() {
Timestamp = DateTimeOffset.Now.ToUnixTimeSeconds();
}
public override string Pack() {
return string.Format("2\t{0}\t-1\t0\fcprivchan\t{1}\t10010", Timestamp, SequenceId);
}
}
}

View file

@ -0,0 +1,15 @@
using System;
namespace SharpChat.Packet {
public class ChannelRankTooHighErrorPacket : ServerPacket {
private readonly long Timestamp;
public ChannelRankTooHighErrorPacket() {
Timestamp = DateTimeOffset.Now.ToUnixTimeSeconds();
}
public override string Pack() {
return string.Format("2\t{0}\t-1\t1\frankerr\t{1}\t10010", Timestamp, SequenceId);
}
}
}

View file

@ -0,0 +1,17 @@
using System;
namespace SharpChat.Packet {
public class ChannelRankTooLowErrorPacket : ServerPacket {
private readonly long Timestamp;
private readonly string ChannelName;
public ChannelRankTooLowErrorPacket(string channelName) {
Timestamp = DateTimeOffset.Now.ToUnixTimeSeconds();
ChannelName = channelName;
}
public override string Pack() {
return string.Format("2\t{0}\t-1\t1\fipchan\f{1}\t{2}\t10010", Timestamp, ChannelName, SequenceId);
}
}
}

View file

@ -2,12 +2,12 @@
using System.Text;
namespace SharpChat.Packet {
public class ContextChannelsPacket : ServerPacket {
public class ChannelsPopulatePacket : ServerPacket {
public record ListEntry(string Name, bool HasPassword, bool IsTemporary);
private readonly ListEntry[] Entries;
public ContextChannelsPacket(ListEntry[] entries) {
public ChannelsPopulatePacket(ListEntry[] entries) {
Entries = entries ?? throw new ArgumentNullException(nameof(entries));
}

View file

@ -2,22 +2,17 @@
namespace SharpChat.Packet {
public class ForceDisconnectPacket : ServerPacket {
private readonly DateTimeOffset Expires;
private readonly long Expires;
public ForceDisconnectPacket() {
Expires = DateTimeOffset.MinValue;
}
public ForceDisconnectPacket() {}
public ForceDisconnectPacket(DateTimeOffset expires) {
Expires = expires;
Expires = expires.Year >= 2100 ? -1 : expires.ToUnixTimeSeconds();
}
public override string Pack() {
if(Expires == DateTimeOffset.MinValue)
return string.Format(
"9\t1\t{0}",
Expires.Year >= 2100 ? -1 : Expires.ToUnixTimeSeconds()
);
if(Expires != 0)
return string.Format("9\t1\t{0}", Expires);
return "9\t0";
}

View file

@ -0,0 +1,17 @@
using System;
namespace SharpChat.Packet {
public class KickBanNoRecordErrorPacket : ServerPacket {
private readonly long Timestamp;
private readonly string TargetName;
public KickBanNoRecordErrorPacket(string targetName) {
Timestamp = DateTimeOffset.Now.ToUnixTimeSeconds();
TargetName = targetName;
}
public override string Pack() {
return string.Format("2\t{0}\t-1\t1\fnotban\f{1}\t{2}\t10010", Timestamp, TargetName, SequenceId);
}
}
}

View file

@ -0,0 +1,17 @@
using System;
namespace SharpChat.Packet {
public class KickBanNotAllowedErrorPacket : ServerPacket {
private readonly long Timestamp;
private readonly string UserName;
public KickBanNotAllowedErrorPacket(string userName) {
Timestamp = DateTimeOffset.Now.ToUnixTimeSeconds();
UserName = userName;
}
public override string Pack() {
return string.Format("2\t{0}\t-1\t1\fkickna\f{1}\t{2}\t10010", Timestamp, UserName, SequenceId);
}
}
}

View file

@ -1,63 +0,0 @@
using System;
using System.Text;
namespace SharpChat.Packet {
public class LegacyCommandResponse : ServerPacket {
private readonly bool IsError;
private readonly string StringId;
private readonly object[] Arguments;
public LegacyCommandResponse(
string stringId,
bool isError = true,
params object[] args
) {
IsError = isError;
StringId = stringId;
Arguments = args;
}
public override string Pack() {
StringBuilder sb = new();
sb.AppendFormat(
"2\t{0}\t-1\t{1}\f{2}",
DateTimeOffset.Now.ToUnixTimeSeconds(),
IsError ? 1 : 0,
StringId
);
foreach(object arg in Arguments)
sb.AppendFormat("\f{0}", arg);
sb.AppendFormat("\t{0}\t10010", SequenceId);
return sb.ToString();
}
}
// Abbreviated class name because otherwise shit gets wide
public static class LCR {
public const string CHANNEL_CREATED = "crchan";
public const string CHANNEL_DELETED = "delchan";
public const string CHANNEL_PASSWORD_CHANGED = "cpwdchan";
public const string CHANNEL_RANK_CHANGED = "cprivchan";
public const string USERS_LISTING_CHANNEL = "whochan";
public const string USERS_LISTING_SERVER = "who";
public const string USER_UNBANNED = "unban";
public const string USER_NOT_FOUND = "usernf";
public const string NAME_IN_USE = "nameinuse";
public const string CHANNEL_INSUFFICIENT_RANK = "ipchan";
public const string CHANNEL_INVALID_PASSWORD = "ipwchan";
public const string CHANNEL_NOT_FOUND = "nochan";
public const string CHANNEL_ALREADY_EXISTS = "nischan";
public const string CHANNEL_NAME_INVALID = "inchan";
public const string CHANNEL_DELETE_FAILED = "ndchan";
public const string USERS_LISTING_ERROR = "whoerr";
public const string INSUFFICIENT_RANK = "rankerr";
public const string MESSAGE_DELETE_ERROR = "delerr";
public const string KICK_NOT_ALLOWED = "kickna";
public const string USER_NOT_BANNED = "notban";
}
}

View file

@ -1,14 +1,14 @@
using System;
namespace SharpChat.Packet {
public class ChatMessageAddPacket : ServerPacket {
private readonly DateTimeOffset Created;
public class MessageAddPacket : ServerPacket {
private readonly long Created;
private readonly long UserId;
private readonly string Body;
private readonly bool IsAction;
private readonly bool IsPrivate;
public ChatMessageAddPacket(
public MessageAddPacket(
long msgId,
DateTimeOffset created,
long userId,
@ -16,7 +16,7 @@ namespace SharpChat.Packet {
bool isAction,
bool isPrivate
) : base(msgId) {
Created = created;
Created = created.ToUnixTimeSeconds();
UserId = userId < 0 ? -1 : userId;
Body = body ?? throw new ArgumentNullException(nameof(body));
IsAction = isAction;
@ -30,7 +30,7 @@ namespace SharpChat.Packet {
return string.Format(
"2\t{0}\t{1}\t{2}\t{3}\t{4}{5}{6}{7}{8}",
Created.ToUnixTimeSeconds(),
Created,
UserId,
body,
SequenceId,

View file

@ -1,11 +1,11 @@
using System;
namespace SharpChat.Packet {
public class BroadcastPacket : ServerPacket {
public class MessageBroadcastPacket : ServerPacket {
private readonly long Timestamp;
private readonly string Body;
public BroadcastPacket(string body) {
public MessageBroadcastPacket(string body) {
Timestamp = DateTimeOffset.Now.ToUnixTimeSeconds();
Body = body;
}

View file

@ -0,0 +1,15 @@
using System;
namespace SharpChat.Packet {
public class MessageDeleteNotAllowedErrorPacket : ServerPacket {
private readonly long Timestamp;
public MessageDeleteNotAllowedErrorPacket() {
Timestamp = DateTimeOffset.Now.ToUnixTimeSeconds();
}
public override string Pack() {
return string.Format("2\t{0}\t-1\t1\fdelerr\t{1}\t10010", Timestamp, SequenceId);
}
}
}

View file

@ -1,8 +1,8 @@
namespace SharpChat.Packet {
public class ChatMessageDeletePacket : ServerPacket {
public class MessageDeletePacket : ServerPacket {
private readonly long MessageId;
public ChatMessageDeletePacket(long msgId) {
public MessageDeletePacket(long msgId) {
MessageId = msgId;
}

View file

@ -4,11 +4,11 @@ using System.Text;
namespace SharpChat.Packet {
// this entire class is disgusting
public class ContextMessagePacket : ServerPacket {
public class MessagePopulatePacket : ServerPacket {
private readonly StoredEventInfo Event;
private readonly bool Notify;
public ContextMessagePacket(StoredEventInfo evt, bool notify = false) {
public MessagePopulatePacket(StoredEventInfo evt, bool notify = false) {
Event = evt ?? throw new ArgumentNullException(nameof(evt));
Notify = notify;
}

View file

@ -0,0 +1,17 @@
using System;
namespace SharpChat.Packet {
public class PardonResponsePacket : ServerPacket {
private readonly long Timestamp;
private readonly string Subject;
public PardonResponsePacket(string subject) {
Timestamp = DateTimeOffset.Now.ToUnixTimeSeconds();
Subject = subject;
}
public override string Pack() {
return string.Format("2\t{0}\t-1\t0\funban\f{1}\t{2}\t10010", Timestamp, Subject, SequenceId);
}
}
}

View file

@ -9,18 +9,18 @@ namespace SharpChat.Packet {
}
public class UserDisconnectPacket : ServerPacket {
private readonly DateTimeOffset Disconnected;
private readonly long Timestamp;
private readonly long UserId;
private readonly string UserName;
private readonly UserDisconnectReason Reason;
public UserDisconnectPacket(
DateTimeOffset disconnected,
DateTimeOffset timestamp,
long userId,
string userName,
UserDisconnectReason reason
) {
Disconnected = disconnected;
Timestamp = timestamp.ToUnixTimeSeconds();
UserId = userId;
UserName = userName ?? throw new ArgumentNullException(nameof(userName));
Reason = reason;
@ -38,7 +38,7 @@ namespace SharpChat.Packet {
UserDisconnectReason.Flood => "flood",
_ => "leave",
},
Disconnected.ToUnixTimeSeconds(),
Timestamp,
SequenceId
);
}

View file

@ -0,0 +1,17 @@
using System;
namespace SharpChat.Packet {
public class UserNameInUseErrorPacket : ServerPacket {
private readonly long Timestamp;
private readonly string UserName;
public UserNameInUseErrorPacket(string userName) {
Timestamp = DateTimeOffset.Now.ToUnixTimeSeconds();
UserName = userName;
}
public override string Pack() {
return string.Format("2\t{0}\t-1\t1\fnameinuse\f{1}\t{2}\t10010", Timestamp, UserName, SequenceId);
}
}
}

View file

@ -0,0 +1,17 @@
using System;
namespace SharpChat.Packet {
public class UserNotFoundErrorPacket : ServerPacket {
private readonly long Timestamp;
private readonly string UserName;
public UserNotFoundErrorPacket(string userName) {
Timestamp = DateTimeOffset.Now.ToUnixTimeSeconds();
UserName = userName;
}
public override string Pack() {
return string.Format("2\t{0}\t-1\t1\fusernf\f{1}\t{2}\t10010", Timestamp, UserName, SequenceId);
}
}
}

View file

@ -4,18 +4,18 @@ namespace SharpChat.Packet {
public class UserUpdateNotificationPacket : ServerPacket {
private readonly string PreviousName;
private readonly string NewName;
private readonly DateTimeOffset Timestamp;
private readonly long Timestamp;
public UserUpdateNotificationPacket(string previousName, string newName) {
PreviousName = previousName ?? throw new ArgumentNullException(nameof(previousName));
NewName = newName ?? throw new ArgumentNullException(nameof(newName));
Timestamp = DateTimeOffset.Now;
Timestamp = DateTimeOffset.Now.ToUnixTimeSeconds();
}
public override string Pack() {
return string.Format(
"2\t{0}\t-1\t0\fnick\f{1}\f{2}\t{3}\t10010",
Timestamp.ToUnixTimeSeconds(),
Timestamp,
PreviousName,
NewName,
SequenceId

View file

@ -2,12 +2,12 @@
using System.Text;
namespace SharpChat.Packet {
public class ContextUsersPacket : ServerPacket {
public class UsersPopulatePacket : ServerPacket {
public record ListEntry(long Id, string Name, ChatColour Colour, int Rank, ChatUserPermissions Perms, bool Visible);
private readonly ListEntry[] Entries;
public ContextUsersPacket(ListEntry[] entries) {
public UsersPopulatePacket(ListEntry[] entries) {
Entries = entries ?? throw new ArgumentNullException(nameof(entries));
}

View file

@ -0,0 +1,17 @@
using System;
namespace SharpChat.Packet {
public class WhoChannelNotFoundErrorPacket : ServerPacket {
private readonly long Timestamp;
private readonly string ChannelName;
public WhoChannelNotFoundErrorPacket(string channelName) {
Timestamp = DateTimeOffset.Now.ToUnixTimeSeconds();
ChannelName = channelName;
}
public override string Pack() {
return string.Format("2\t{0}\t-1\t1\fwhoerr\f{1}\t{2}\t10010", Timestamp, ChannelName, SequenceId);
}
}
}

View file

@ -0,0 +1,40 @@
using System;
using System.Text;
namespace SharpChat.Packet {
public class WhoChannelResponsePacket : ServerPacket {
private readonly long Timestamp;
private readonly string ChannelName;
private readonly string[] Users;
private readonly string SelfName;
public WhoChannelResponsePacket(string channelName, string[] users, string selfName) {
Timestamp = DateTimeOffset.Now.ToUnixTimeSeconds();
ChannelName = channelName;
Users = users;
SelfName = selfName;
}
public override string Pack() {
StringBuilder sb = new();
sb.AppendFormat("2\t{0}\t-1\t0\fwhochan\f{1}\f", Timestamp, ChannelName);
foreach(string userName in Users) {
sb.Append(@"<a href=""javascript:void(0);"" onclick=""UI.InsertChatText(this.innerHTML);""");
if(userName.Equals(SelfName, StringComparison.InvariantCultureIgnoreCase))
sb.Append(@" style=""font-weight: bold;""");
sb.AppendFormat(@">{0}</a>, ", userName);
}
if(Users.Length > 0)
sb.Length -= 2;
sb.AppendFormat("\t{0}\t10010", SequenceId);
return sb.ToString();
}
}
}

View file

@ -0,0 +1,38 @@
using System;
using System.Text;
namespace SharpChat.Packet {
public class WhoServerResponsePacket : ServerPacket {
private readonly long Timestamp;
private readonly string[] Users;
private readonly string SelfName;
public WhoServerResponsePacket(string[] users, string selfName) {
Timestamp = DateTimeOffset.Now.ToUnixTimeSeconds();
Users = users;
SelfName = selfName;
}
public override string Pack() {
StringBuilder sb = new();
sb.AppendFormat("2\t{0}\t-1\t0\fwho\f", Timestamp);
foreach(string userName in Users) {
sb.Append(@"<a href=""javascript:void(0);"" onclick=""UI.InsertChatText(this.innerHTML);""");
if(userName.Equals(SelfName, StringComparison.InvariantCultureIgnoreCase))
sb.Append(@" style=""font-weight: bold;""");
sb.AppendFormat(@">{0}</a>, ", userName);
}
if(Users.Length > 0)
sb.Length -= 2;
sb.AppendFormat("\t{0}\t10010", SequenceId);
return sb.ToString();
}
}
}

View file

@ -83,18 +83,18 @@ namespace SharpChat {
});
SendMessageHandler.AddCommands(new IChatCommand[] {
new AFKCommand(),
new NickCommand(),
new WhisperCommand(),
new ActionCommand(),
new UserAFKCommand(),
new UserNickCommand(),
new MessageWhisperCommand(),
new MessageActionCommand(),
new WhoCommand(),
new JoinChannelCommand(),
new CreateChannelCommand(),
new DeleteChannelCommand(),
new PasswordChannelCommand(),
new RankChannelCommand(),
new BroadcastCommand(),
new DeleteMessageCommand(),
new ChannelJoinCommand(),
new ChannelCreateCommand(),
new ChannelDeleteCommand(),
new ChannelPasswordCommand(),
new ChannelRankCommand(),
new MessageBroadcastCommand(),
new MessageDeleteCommand(),
new KickBanCommand(msz),
new PardonUserCommand(msz),
new PardonAddressCommand(msz),