From 512eff727ba77929dfa9166ec59829b057d27e82 Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Wed, 15 Mar 2023 16:57:52 +0200 Subject: [PATCH 01/34] Client - Use freenode to test with for a little --- source/birchwood/client/client.d | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/source/birchwood/client/client.d b/source/birchwood/client/client.d index 445d225..3050b7c 100644 --- a/source/birchwood/client/client.d +++ b/source/birchwood/client/client.d @@ -874,11 +874,11 @@ public class Client : Thread unittest { /* FIXME: Get domaina name resolution support */ - // ConnectionInfo connInfo = ConnectionInfo.newConnection("irc.freenode.net", 6667, "testBirchwood"); + ConnectionInfo connInfo = ConnectionInfo.newConnection("irc.freenode.net", 6667, "testBirchwood"); //freenode: 149.28.246.185 //snootnet: 178.62.125.123 //bonobonet: fd08:8441:e254::5 - ConnectionInfo connInfo = ConnectionInfo.newConnection("worcester.community.networks.deavmi.assigned.network", 6667, "testBirchwood"); + // ConnectionInfo connInfo = ConnectionInfo.newConnection("worcester.community.networks.deavmi.assigned.network", 6667, "testBirchwood"); // // Set the fakelag to 1 second // connInfo.setFakeLag(1); @@ -977,5 +977,7 @@ public class Client : Thread } + + } \ No newline at end of file From a42d913236b808d34f06606d409338ff7b6b2fc9 Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Wed, 15 Mar 2023 17:13:30 +0200 Subject: [PATCH 02/34] Receiver - Parse all messages into a `Message` array (`SList`) - If a PING is found then we put it aside and check if we have one and then reply - The PING is removed and all normal messages remain and then get EVenty events triggered for them for `IRCEvent` --- source/birchwood/client/receiver.d | 117 ++++++++++++++--------------- 1 file changed, 57 insertions(+), 60 deletions(-) diff --git a/source/birchwood/client/receiver.d b/source/birchwood/client/receiver.d index 93be2e8..4cbfbdc 100644 --- a/source/birchwood/client/receiver.d +++ b/source/birchwood/client/receiver.d @@ -117,29 +117,62 @@ public final class ReceiverThread : Thread /* Lock the receieve queue */ recvQueueLock.lock(); - /* Message being analysed */ - Message curMsg; + /* Parsed messages */ + SList!(Message) currentMessageQueue; - /* Search for a PING */ - ubyte[] pingMessage; - - ulong pos = 0; + /** + * Parse all messages and save them + * into the above array + */ foreach(ubyte[] message; recvQueue[]) { - // FIXME: Holy shit this is funny (see https://github.com/deavmi/birchwood/issues/13) - if(indexOf(cast(string)message, "PING") > -1) - { - pingMessage = message; - recvQueue.linearRemoveElement(message); + /* Decode the message */ + string decodedMessage = decodeMessage(message); - import std.stdio; - writeln("\n\nHOLY SHIT\n: "~cast(string)(message)~"\n\n"); + /* Parse the message */ + Message parsedMessage = Message.parseReceivedMessage(decodedMessage); + + /* Save it */ + currentMessageQueue.insertAfter(currentMessageQueue[], parsedMessage); + } + + + /** + * Search for any PING messages, then store it if so + * and remove it so it isn't processed again later + */ + Message pingMessage; + foreach(Message curMsg; currentMessageQueue[]) + { + import std.string : cmp; + if(cmp(curMsg.getCommand(), "PING") == 0) + { + currentMessageQueue.linearRemoveElement(curMsg); + pingMessage = curMsg; break; } - - pos++; } + /** + * If we have a PING then respond with a PONG + */ + if(pingMessage !is null) + { + logger.log("Found a ping: "~pingMessage.toString()); + + /* Extract the PING ID */ + string pingID = pingMessage.getParams(); + + /* Spawn a PONG event */ + EventyEvent pongEvent = new PongEvent(pingID); + client.engine.push(pongEvent); + } + + + + + + /** * TODO: Plan of action @@ -156,61 +189,25 @@ public final class ReceiverThread : Thread * - we can cache or remember stuff when we get 353 */ - - - - /* If we found a PING */ - if(pingMessage.length > 0) - { - /* Decode the message and parse it */ - curMsg = Message.parseReceivedMessage(decodeMessage(pingMessage)); - logger.log("Found a ping: "~curMsg.toString()); - - // string ogMessage = cast(string)pingMessage; - // long idxSigStart = indexOf(ogMessage, ":")+1; - // long idxSigEnd = lastIndexOf(ogMessage, '\r'); - - // string pingID = ogMessage[idxSigStart..idxSigEnd]; - string pingID = curMsg.getParams(); - - - // this.socket.send(encodeMessage("PONG "~pingID)); - // string messageToSend = "PONG "~pingID; - - // sendMessage(messageToSend); - - // logger.log("Ponged"); - - /* TODO: Implement */ - // TODO: Remove the Eventy push and replace with a handler call (on second thought no) - EventyEvent pongEvent = new PongEvent(pingID); - client.engine.push(pongEvent); - } - /** * Process each message remaining in the queue now * till it is empty */ - while(!recvQueue.empty()) + while(!currentMessageQueue.empty()) { - ubyte[] message = recvQueue.front(); - - /* Decode message */ - string messageNormal = decodeMessage(message); - - recvQueue.linearRemoveElement(recvQueue.front()); - - // writeln("Normal message: "~messageNormal); - - - - /* TODO: Parse message and call correct handler */ - curMsg = Message.parseReceivedMessage(messageNormal); + /* Get the frontmost Message */ + Message curMsg = currentMessageQueue.front(); // TODO: Remove the Eventy push and replace with a handler call (on second thought no) EventyEvent ircEvent = new IRCEvent(curMsg); client.engine.push(ircEvent); + + /* Remove the message from the queue */ + currentMessageQueue.linearRemoveElement(curMsg); } + + /* Clear the receive queue */ + recvQueue.clear(); /* Unlock the receive queue */ recvQueueLock.unlock(); From 2a50c8efbb2238a827807422c4f4b4268b87b26f Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Wed, 15 Mar 2023 17:15:25 +0200 Subject: [PATCH 03/34] Unit tests - Switch back to my IPv6-only server for testing --- source/birchwood/client/client.d | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/source/birchwood/client/client.d b/source/birchwood/client/client.d index 3050b7c..eb3baff 100644 --- a/source/birchwood/client/client.d +++ b/source/birchwood/client/client.d @@ -873,12 +873,11 @@ public class Client : Thread unittest { - /* FIXME: Get domaina name resolution support */ - ConnectionInfo connInfo = ConnectionInfo.newConnection("irc.freenode.net", 6667, "testBirchwood"); + // ConnectionInfo connInfo = ConnectionInfo.newConnection("irc.freenode.net", 6667, "testBirchwood"); //freenode: 149.28.246.185 //snootnet: 178.62.125.123 //bonobonet: fd08:8441:e254::5 - // ConnectionInfo connInfo = ConnectionInfo.newConnection("worcester.community.networks.deavmi.assigned.network", 6667, "testBirchwood"); + ConnectionInfo connInfo = ConnectionInfo.newConnection("worcester.community.networks.deavmi.assigned.network", 6667, "testBirchwood"); // // Set the fakelag to 1 second // connInfo.setFakeLag(1); From 681dfc042cb2794bb8c0e088f019555c38f4dcdd Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Wed, 15 Mar 2023 20:07:10 +0200 Subject: [PATCH 04/34] Client - Added TODO where response code handling needs to go --- source/birchwood/client/client.d | 3 +++ 1 file changed, 3 insertions(+) diff --git a/source/birchwood/client/client.d b/source/birchwood/client/client.d index 3050b7c..248145f 100644 --- a/source/birchwood/client/client.d +++ b/source/birchwood/client/client.d @@ -524,6 +524,9 @@ public class Client : Thread // If the command is numeric then it is a reply of some sorts else if(ircMessage.isResponseMessage()) { + // TODO: Add numeric response check here for CERTAIN ones which add to client + // ... state + /* Call the command reply handler */ onCommandReply(ircMessage); } From 672b8fee645c835d1a930432dcd6321996abc745 Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Wed, 15 Mar 2023 20:23:30 +0200 Subject: [PATCH 05/34] Client - Added some TODOs for comments --- source/birchwood/client/client.d | 34 +++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/source/birchwood/client/client.d b/source/birchwood/client/client.d index 248145f..ffdecf1 100644 --- a/source/birchwood/client/client.d +++ b/source/birchwood/client/client.d @@ -80,23 +80,55 @@ public class Client : Thread /** * User overridable handler functions below */ + + // TODO: comment + /** + * + * Params: + * fullMessage = + * channel = + * msgBody = + */ public void onChannelMessage(Message fullMessage, string channel, string msgBody) { /* Default implementation */ logger.log("Channel("~channel~"): "~msgBody); } + + // TODO: comment + /** + * + * Params: + * fullMessage = + * nickname = + * msgBody = + */ public void onDirectMessage(Message fullMessage, string nickname, string msgBody) { /* Default implementation */ logger.log("DirectMessage("~nickname~"): "~msgBody); } + + // TODO: comment + /** + * + * Params: + * message = + */ public void onGenericCommand(Message message) { /* Default implementation */ logger.log("Generic("~message.getCommand()~", "~message.getFrom()~"): "~message.getParams()); } + + + // TODO: Hook certain ones default style with an implemenation + // ... for things that the client can learn from public void onCommandReply(Message commandReply) { + // TODO: Add numeric response check here for CERTAIN ones which add to client + // ... state + /* Default implementation */ logger.log("Response("~to!(string)(commandReply.getReplyType())~", "~commandReply.getFrom()~"): "~commandReply.toString()); } @@ -526,7 +558,7 @@ public class Client : Thread { // TODO: Add numeric response check here for CERTAIN ones which add to client // ... state - + /* Call the command reply handler */ onCommandReply(ircMessage); } From 7c8208182fce332b637b95a2b7cdafffe8c2c10c Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Wed, 15 Mar 2023 20:24:05 +0200 Subject: [PATCH 06/34] Client - Added TODOs for comments --- source/birchwood/client/client.d | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/source/birchwood/client/client.d b/source/birchwood/client/client.d index 3050b7c..5e9fb27 100644 --- a/source/birchwood/client/client.d +++ b/source/birchwood/client/client.d @@ -80,21 +80,51 @@ public class Client : Thread /** * User overridable handler functions below */ + + // TODO: comment + /** + * + * Params: + * fullMessage = + * channel = + * msgBody = + */ public void onChannelMessage(Message fullMessage, string channel, string msgBody) { /* Default implementation */ logger.log("Channel("~channel~"): "~msgBody); } + + // TODO: comment + /** + * + * Params: + * message = + */ public void onDirectMessage(Message fullMessage, string nickname, string msgBody) { /* Default implementation */ logger.log("DirectMessage("~nickname~"): "~msgBody); } + + // TODO: comment + /** + * + * Params: + * commandReply = + */ public void onGenericCommand(Message message) { /* Default implementation */ logger.log("Generic("~message.getCommand()~", "~message.getFrom()~"): "~message.getParams()); } + + // TODO: comment + /** + * + * Params: + * commandReply = + */ public void onCommandReply(Message commandReply) { /* Default implementation */ From 1f7e3a96afb138b3c69f215fe136be844d676d67 Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Wed, 15 Mar 2023 20:34:36 +0200 Subject: [PATCH 07/34] Constants - Segmented into sections based on rfc - Added a few new constants from RFC2812 - `RPL_BOUNCE` (`005`) is a numeric response to note as it has key-value pairs associated with it --- source/birchwood/protocol/constants.d | 302 ++++++++++++++------------ 1 file changed, 161 insertions(+), 141 deletions(-) diff --git a/source/birchwood/protocol/constants.d b/source/birchwood/protocol/constants.d index e3ab7d6..5ac148d 100644 --- a/source/birchwood/protocol/constants.d +++ b/source/birchwood/protocol/constants.d @@ -1,148 +1,168 @@ module birchwood.protocol.constants; -/* Reply object */ - public enum ReplyType : ulong - { - /* Error replies */ - ERR_NOSUCHNICK = 401, - ERR_NOSUCHSERVER = 402, - ERR_NOSUCHCHANNEL = 403, - ERR_CANNOTSENDTOCHAN = 404, - ERR_TOOMANYCHANNELS = 405, - ERR_WASNOSUCHNICK = 406, - ERR_TOOMANYTARGETS = 407, - ERR_NOORIGIN = 409, - ERR_NORECIPIENT = 411, - ERR_NOTEXTTOSEND = 412, - ERR_NOTOPLEVEL = 413, - ERR_WILDTOPLEVEL = 414, - ERR_UNKNOWNCOMMAND = 421, - ERR_NOMOTD = 422, - ERR_NOADMININFO = 423, - ERR_FILEERROR = 424, - ERR_NONICKNAMEGIVEN = 431, - ERR_ERRONEUSNICKNAME = 432, - ERR_NICKNAMEINUSE = 433, - ERR_NICKCOLLISION = 436, - ERR_USERNOTINCHANNEL = 441, - ERR_NOTONCHANNEL = 442, - ERR_USERONCHANNEL = 443, - ERR_NOLOGIN = 444, - ERR_SUMMONDISABLED = 445, - ERR_USERSDISABLED = 446, - ERR_NOTREGISTERED = 451, - ERR_NEEDMOREPARAMS = 461, - ERR_ALREADYREGISTRED = 462, - ERR_NOPERMFORHOST = 463, - ERR_PASSWDMISMATCH = 464, - ERR_YOUREBANNEDCREEP = 465, - ERR_KEYSET = 467, - ERR_CHANNELISFULL = 471, - ERR_UNKNOWNMODE = 472, - ERR_INVITEONLYCHAN = 473, - ERR_BANNEDFROMCHAN = 474, - ERR_BADCHANNELKEY = 475, - ERR_NOPRIVILEGES = 481, - ERR_CHANOPRIVSNEEDED = 482, - ERR_CANTKILLSERVER = 483, - ERR_NOOPERHOST = 491, - ERR_UMODEUNKNOWNFLAG = 501, - ERR_USERSDONTMATCH = 502, +/** + * The type of numeric response + */ +public enum ReplyType : ulong +{ + /** + * rfc 1459 + */ - /* Command responses */ - RPL_NONE = 300, - RPL_USERHOST = 302, - RPL_ISON = 303, - RPL_AWAY = 301, - RPL_UNAWAY = 305, - RPL_NOWAWAY = 306, - RPL_WHOISUSER = 311, - RPL_WHOISSERVER = 312, - RPL_WHOISOPERATOR = 313, - RPL_WHOISIDLE = 317, - RPL_ENDOFWHOIS = 318, - RPL_WHOISCHANNELS = 319, - RPL_WHOWASUSER = 314, - RPL_ENDOFWHOWAS = 369, - RPL_LISTSTART = 321, - RPL_LIST = 322, - RPL_LISTEND = 323, - RPL_CHANNELMODEIS = 324, - RPL_NOTOPIC = 331, - RPL_TOPIC = 332, - RPL_INVITING = 341, - RPL_SUMMONING = 342, - RPL_VERSION = 351, - RPL_WHOREPLY = 352, - RPL_ENDOFWHO = 315, - RPL_NAMREPLY = 353, - RPL_ENDOFNAMES = 366, - RPL_LINKS = 364, - RPL_ENDOFLINKS = 365, - RPL_BANLIST = 367, - RPL_ENDOFBANLIST = 368, - RPL_INFO = 371, - RPL_ENDOFINFO = 374, - RPL_MOTDSTART = 375, - RPL_MOTD = 372, - RPL_ENDOFMOTD = 376, - RPL_YOUREOPER = 381, - RPL_REHASHING = 382, - RPL_TIME = 391, - RPL_USERSSTART = 392, - RPL_USERS = 393, - RPL_ENDOFUSERS = 394, - RPL_NOUSERS = 395, - RPL_TRACELINK = 200, - RPL_TRACECONNECTING = 201, - RPL_TRACEHANDSHAKE = 202, - RPL_TRACEUNKNOWN = 203, - RPL_TRACEOPERATOR = 204, - RPL_TRACEUSER = 205, - RPL_TRACESERVER = 206, - RPL_TRACENEWTYPE = 208, - RPL_TRACELOG = 261, - RPL_STATSLINKINFO = 211, - RPL_STATSCOMMANDS = 212, - RPL_STATSCLINE = 213, - RPL_STATSNLINE = 214, - RPL_STATSILINE = 215, - RPL_STATSKLINE = 216, - RPL_STATSYLINE = 218, - RPL_ENDOFSTATS = 219, - RPL_STATSLLINE = 241, - RPL_STATSUPTIME = 242, - RPL_STATSOLINE = 243, - RPL_STATSHLINE = 244, - RPL_UMODEIS = 221, - RPL_LUSERCLIENT = 251, - RPL_LUSEROP = 252, - RPL_LUSERUNKNOWN = 253, - RPL_LUSERCHANNELS = 254, - RPL_LUSERME = 255, - RPL_ADMINME = 256, - RPL_ADMINLOC1 = 257, - RPL_ADMINLOC2 = 258, - RPL_ADMINEMAIL = 259, + /* Error replies */ + ERR_NOSUCHNICK = 401, + ERR_NOSUCHSERVER = 402, + ERR_NOSUCHCHANNEL = 403, + ERR_CANNOTSENDTOCHAN = 404, + ERR_TOOMANYCHANNELS = 405, + ERR_WASNOSUCHNICK = 406, + ERR_TOOMANYTARGETS = 407, + ERR_NOORIGIN = 409, + ERR_NORECIPIENT = 411, + ERR_NOTEXTTOSEND = 412, + ERR_NOTOPLEVEL = 413, + ERR_WILDTOPLEVEL = 414, + ERR_UNKNOWNCOMMAND = 421, + ERR_NOMOTD = 422, + ERR_NOADMININFO = 423, + ERR_FILEERROR = 424, + ERR_NONICKNAMEGIVEN = 431, + ERR_ERRONEUSNICKNAME = 432, + ERR_NICKNAMEINUSE = 433, + ERR_NICKCOLLISION = 436, + ERR_USERNOTINCHANNEL = 441, + ERR_NOTONCHANNEL = 442, + ERR_USERONCHANNEL = 443, + ERR_NOLOGIN = 444, + ERR_SUMMONDISABLED = 445, + ERR_USERSDISABLED = 446, + ERR_NOTREGISTERED = 451, + ERR_NEEDMOREPARAMS = 461, + ERR_ALREADYREGISTRED = 462, + ERR_NOPERMFORHOST = 463, + ERR_PASSWDMISMATCH = 464, + ERR_YOUREBANNEDCREEP = 465, + ERR_KEYSET = 467, + ERR_CHANNELISFULL = 471, + ERR_UNKNOWNMODE = 472, + ERR_INVITEONLYCHAN = 473, + ERR_BANNEDFROMCHAN = 474, + ERR_BADCHANNELKEY = 475, + ERR_NOPRIVILEGES = 481, + ERR_CHANOPRIVSNEEDED = 482, + ERR_CANTKILLSERVER = 483, + ERR_NOOPERHOST = 491, + ERR_UMODEUNKNOWNFLAG = 501, + ERR_USERSDONTMATCH = 502, - /* Reserved Numerics (See section 6.3 in RFC 1459) */ - RPL_TRACECLASS = 209, - RPL_SERVICEINFO = 231, - RPL_SERVICE = 233, - RPL_SERVLISTEND = 235, - RPL_WHOISCHANOP = 316, - RPL_CLOSING = 362, - RPL_INFOSTART = 372, - ERR_YOUWILLBEBANNED = 466, - ERR_NOSERVICEHOST = 492, - RPL_STATSQLINE = 217, - RPL_ENDOFSERVICES = 232, - RPL_SERVLIST = 234, - RPL_KILLDONE = 361, - RPL_CLOSEEND = 363, - RPL_MYPORTIS = 384, - ERR_BADCHANMASK = 476, + /* Command responses */ + RPL_NONE = 300, + RPL_USERHOST = 302, + RPL_ISON = 303, + RPL_AWAY = 301, + RPL_UNAWAY = 305, + RPL_NOWAWAY = 306, + RPL_WHOISUSER = 311, + RPL_WHOISSERVER = 312, + RPL_WHOISOPERATOR = 313, + RPL_WHOISIDLE = 317, + RPL_ENDOFWHOIS = 318, + RPL_WHOISCHANNELS = 319, + RPL_WHOWASUSER = 314, + RPL_ENDOFWHOWAS = 369, + RPL_LISTSTART = 321, + RPL_LIST = 322, + RPL_LISTEND = 323, + RPL_CHANNELMODEIS = 324, + RPL_NOTOPIC = 331, + RPL_TOPIC = 332, + RPL_INVITING = 341, + RPL_SUMMONING = 342, + RPL_VERSION = 351, + RPL_WHOREPLY = 352, + RPL_ENDOFWHO = 315, + RPL_NAMREPLY = 353, + RPL_ENDOFNAMES = 366, + RPL_LINKS = 364, + RPL_ENDOFLINKS = 365, + RPL_BANLIST = 367, + RPL_ENDOFBANLIST = 368, + RPL_INFO = 371, + RPL_ENDOFINFO = 374, + RPL_MOTDSTART = 375, + RPL_MOTD = 372, + RPL_ENDOFMOTD = 376, + RPL_YOUREOPER = 381, + RPL_REHASHING = 382, + RPL_TIME = 391, + RPL_USERSSTART = 392, + RPL_USERS = 393, + RPL_ENDOFUSERS = 394, + RPL_NOUSERS = 395, + RPL_TRACELINK = 200, + RPL_TRACECONNECTING = 201, + RPL_TRACEHANDSHAKE = 202, + RPL_TRACEUNKNOWN = 203, + RPL_TRACEOPERATOR = 204, + RPL_TRACEUSER = 205, + RPL_TRACESERVER = 206, + RPL_TRACENEWTYPE = 208, + RPL_TRACELOG = 261, + RPL_STATSLINKINFO = 211, + RPL_STATSCOMMANDS = 212, + RPL_STATSCLINE = 213, + RPL_STATSNLINE = 214, + RPL_STATSILINE = 215, + RPL_STATSKLINE = 216, + RPL_STATSYLINE = 218, + RPL_ENDOFSTATS = 219, + RPL_STATSLLINE = 241, + RPL_STATSUPTIME = 242, + RPL_STATSOLINE = 243, + RPL_STATSHLINE = 244, + RPL_UMODEIS = 221, + RPL_LUSERCLIENT = 251, + RPL_LUSEROP = 252, + RPL_LUSERUNKNOWN = 253, + RPL_LUSERCHANNELS = 254, + RPL_LUSERME = 255, + RPL_ADMINME = 256, + RPL_ADMINLOC1 = 257, + RPL_ADMINLOC2 = 258, + RPL_ADMINEMAIL = 259, + + /* Reserved Numerics (See section 6.3 in RFC 1459) */ + RPL_TRACECLASS = 209, + RPL_SERVICEINFO = 231, + RPL_SERVICE = 233, + RPL_SERVLISTEND = 235, + RPL_WHOISCHANOP = 316, + RPL_CLOSING = 362, + RPL_INFOSTART = 372, + ERR_YOUWILLBEBANNED = 466, + ERR_NOSERVICEHOST = 492, + RPL_STATSQLINE = 217, + RPL_ENDOFSERVICES = 232, + RPL_SERVLIST = 234, + RPL_KILLDONE = 361, + RPL_CLOSEEND = 363, + RPL_MYPORTIS = 384, + ERR_BADCHANMASK = 476, - BIRCHWOOD_UNKNOWN_RESP_CODE = 0 + /** + * rfc 2812 + */ + RPL_WELCOME = 001, + RPL_YOURHOST = 002, + RPL_CREATED = 003, + RPL_MYINFO = 004, + RPL_BOUNCE = 005, // TODO: We care about the key-value pairs here in RPL_BOUNCE + + + + /** + * If no code is matched then this is the default + */ + BIRCHWOOD_UNKNOWN_RESP_CODE = 0 } \ No newline at end of file From 57ce756120864cc22601b4abcf190e3679bd0ea0 Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Wed, 15 Mar 2023 20:50:03 +0200 Subject: [PATCH 08/34] Constants - Added `ERR_NOCHANMODES` --- source/birchwood/protocol/constants.d | 1 + 1 file changed, 1 insertion(+) diff --git a/source/birchwood/protocol/constants.d b/source/birchwood/protocol/constants.d index 5ac148d..b01a5e4 100644 --- a/source/birchwood/protocol/constants.d +++ b/source/birchwood/protocol/constants.d @@ -158,6 +158,7 @@ public enum ReplyType : ulong RPL_CREATED = 003, RPL_MYINFO = 004, RPL_BOUNCE = 005, // TODO: We care about the key-value pairs here in RPL_BOUNCE + ERR_NOCHANMODES = 477, From d66bec5fa6ab09f2e2e0e739b8dc9e5b213e3bf0 Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Wed, 15 Mar 2023 21:26:07 +0200 Subject: [PATCH 09/34] Client - Switch back to BNET test server --- source/birchwood/client/client.d | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/birchwood/client/client.d b/source/birchwood/client/client.d index c690246..1a46a23 100644 --- a/source/birchwood/client/client.d +++ b/source/birchwood/client/client.d @@ -917,11 +917,11 @@ public class Client : Thread unittest { /* FIXME: Get domaina name resolution support */ - ConnectionInfo connInfo = ConnectionInfo.newConnection("irc.freenode.net", 6667, "testBirchwood"); + // ConnectionInfo connInfo = ConnectionInfo.newConnection("irc.freenode.net", 6667, "testBirchwood"); //freenode: 149.28.246.185 //snootnet: 178.62.125.123 //bonobonet: fd08:8441:e254::5 - // ConnectionInfo connInfo = ConnectionInfo.newConnection("worcester.community.networks.deavmi.assigned.network", 6667, "testBirchwood"); + ConnectionInfo connInfo = ConnectionInfo.newConnection("worcester.community.networks.deavmi.assigned.network", 6667, "testBirchwood"); // // Set the fakelag to 1 second // connInfo.setFakeLag(1); From 66cd409234297b465e1ec31d8b82d7bc6f10d69b Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Wed, 15 Mar 2023 21:29:07 +0200 Subject: [PATCH 10/34] Package (protocol) - Make `ReplyType` available --- source/birchwood/protocol/package.d | 1 + 1 file changed, 1 insertion(+) diff --git a/source/birchwood/protocol/package.d b/source/birchwood/protocol/package.d index 0853c26..733ce7a 100644 --- a/source/birchwood/protocol/package.d +++ b/source/birchwood/protocol/package.d @@ -1,6 +1,7 @@ module birchwood.protocol; public import birchwood.protocol.messages : Message; +public import birchwood.protocol.constants : ReplyType; // TODO: Look how to neaten up (if any) public import birchwood.protocol.formatting; \ No newline at end of file From 087eb954d13a54ea0adad3d4e8d7bdb36d47fc15 Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Thu, 16 Mar 2023 08:05:34 +0200 Subject: [PATCH 11/34] Client - Print out `RPL_BOUNCE` when it appears --- source/birchwood/client/client.d | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/source/birchwood/client/client.d b/source/birchwood/client/client.d index 1a46a23..b2b4210 100644 --- a/source/birchwood/client/client.d +++ b/source/birchwood/client/client.d @@ -139,6 +139,13 @@ public class Client : Thread /* Default implementation */ logger.log("Response("~to!(string)(commandReply.getReplyType())~", "~commandReply.getFrom()~"): "~commandReply.toString()); + + import birchwood.protocol.constants : ReplyType; + + if(commandReply.getReplyType() == ReplyType.RPL_BOUNCE) + { + logger.log("Take a look:\n\n"~commandReply.getParams()); + } } /** From 66c3a02d6e0ef810ec2f20ad147d8b5588786f01 Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Thu, 16 Mar 2023 08:17:56 +0200 Subject: [PATCH 12/34] Client - Added missing documentation for `onDirectMessage`, `onChannelMessage`, `onGenericCommand` and `onCommandReply` --- source/birchwood/client/client.d | 36 +++++++++++++++----------------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/source/birchwood/client/client.d b/source/birchwood/client/client.d index 5e9fb27..30d2de5 100644 --- a/source/birchwood/client/client.d +++ b/source/birchwood/client/client.d @@ -71,23 +71,19 @@ public class Client : Thread //TODO: Do something here, tare downs } + // TODO: Investigate public ConnectionInfo getConnInfo() { return connInfo; } - - /** - * User overridable handler functions below - */ - - // TODO: comment /** - * + * Called on reception of a channel message + * * Params: - * fullMessage = - * channel = - * msgBody = + * fullMessage = the channel message in its entirety + * channel = the channel + * msgBody = the body of the message */ public void onChannelMessage(Message fullMessage, string channel, string msgBody) { @@ -95,11 +91,13 @@ public class Client : Thread logger.log("Channel("~channel~"): "~msgBody); } - // TODO: comment /** - * + * Called on reception of a direct message + * * Params: - * message = + * fullMessage = the direct message in its entirety + * nickname = the sender + * msgBody = the body of the message */ public void onDirectMessage(Message fullMessage, string nickname, string msgBody) { @@ -107,11 +105,11 @@ public class Client : Thread logger.log("DirectMessage("~nickname~"): "~msgBody); } - // TODO: comment /** - * + * Called on generic commands + * * Params: - * commandReply = + * commandReply = the generic message */ public void onGenericCommand(Message message) { @@ -119,11 +117,11 @@ public class Client : Thread logger.log("Generic("~message.getCommand()~", "~message.getFrom()~"): "~message.getParams()); } - // TODO: comment /** - * + * Called on command replies + * * Params: - * commandReply = + * commandReply = the command's reply */ public void onCommandReply(Message commandReply) { From 93fecfaad57a98fc2f6adfd77797d8b059f3d798 Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Thu, 16 Mar 2023 08:26:03 +0200 Subject: [PATCH 13/34] Client - Removed now-completed TODO - Implemented `joinChannel(string[])` Unit tests - Use BNET test server - Added test calls to `joinChannel(string[])` --- source/birchwood/client/client.d | 83 +++++++++++++++++++++++++++++--- 1 file changed, 76 insertions(+), 7 deletions(-) diff --git a/source/birchwood/client/client.d b/source/birchwood/client/client.d index 30d2de5..31b78fb 100644 --- a/source/birchwood/client/client.d +++ b/source/birchwood/client/client.d @@ -133,8 +133,6 @@ public class Client : Thread * User operations (request-response type) */ - // TODO: Add joinChannels(strung[]) - /** * Joins the requested channel * @@ -166,6 +164,75 @@ public class Client : Thread } } + /** + * Joins the requested channels + * + * Params: + * channels = the channels to join + * Throws: + * BirchwoodException on invalid channel name + */ + public void joinChannel(string[] channels) + { + /* If single channel */ + if(channels.length == 1) + { + /* Join the channel */ + joinChannel(channels[0]); + } + /* If multiple channels */ + else if(channels.length > 1) + { + string channelLine = channels[0]; + + /* Ensure valid characters in first channel */ + if(isValidText(channelLine)) + { + //TODO: Add check for # + + /* Append on a trailing `,` */ + channelLine ~= ","; + + for(ulong i = 1; i < channels.length; i++) + { + string currentChannel = channels[i]; + + /* Ensure the character channel is valid */ + if(isValidText(currentChannel)) + { + //TODO: Add check for # + + if(i == channels.length-1) + { + channelLine~=currentChannel; + } + else + { + channelLine~=currentChannel~","; + } + } + else + { + throw new BirchwoodException(BirchwoodException.ErrorType.ILLEGAL_CHARACTERS); + } + } + + /* Join multiple channels */ + Message joinMessage = new Message("", "JOIN", channelLine); + sendMessage(joinMessage); + } + else + { + throw new BirchwoodException(BirchwoodException.ErrorType.ILLEGAL_CHARACTERS); + } + } + /* If no channels provided at all (error) */ + else + { + throw new BirchwoodException(BirchwoodException.ErrorType.EMPTY_PARAMS); + } + } + /** * Parts from a list of channel(s) in one go * @@ -902,11 +969,11 @@ public class Client : Thread unittest { /* FIXME: Get domaina name resolution support */ - ConnectionInfo connInfo = ConnectionInfo.newConnection("irc.freenode.net", 6667, "testBirchwood"); + // ConnectionInfo connInfo = ConnectionInfo.newConnection("irc.freenode.net", 6667, "testBirchwood"); //freenode: 149.28.246.185 //snootnet: 178.62.125.123 //bonobonet: fd08:8441:e254::5 - // ConnectionInfo connInfo = ConnectionInfo.newConnection("worcester.community.networks.deavmi.assigned.network", 6667, "testBirchwood"); + ConnectionInfo connInfo = ConnectionInfo.newConnection("worcester.community.networks.deavmi.assigned.network", 6667, "testBirchwood"); // // Set the fakelag to 1 second // connInfo.setFakeLag(1); @@ -928,9 +995,11 @@ public class Client : Thread client.joinChannel("#birchwood"); // TODO: Add a joinChannels(string[]) client.joinChannel("#birchwood2"); - client.joinChannel("#birchwoodLeave1"); - client.joinChannel("#birchwoodLeave2"); - client.joinChannel("#birchwoodLeave3"); + + client.joinChannel(["#birchwoodLeave1", "#birchwoodLeave2", "#birchwoodLeave3"]); + // client.joinChannel("#birchwoodLeave1"); + // client.joinChannel("#birchwoodLeave2"); + // client.joinChannel("#birchwoodLeave3"); Thread.sleep(dur!("seconds")(2)); client.command(new Message("", "NAMES", "")); // TODO: add names commdn From d2acd08a9871fc6e8ffd03e0ed05ddb52864c554 Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Thu, 16 Mar 2023 08:37:04 +0200 Subject: [PATCH 14/34] Client - Removed commented-out code --- source/birchwood/client/client.d | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/source/birchwood/client/client.d b/source/birchwood/client/client.d index 31b78fb..2b0bbc1 100644 --- a/source/birchwood/client/client.d +++ b/source/birchwood/client/client.d @@ -727,25 +727,6 @@ public class Client : Thread receiver.rq(message); } - // /** - // * Sends a message to the server by enqueuing it on - // * the client-side send queue - // * - // * Params: - // * messageOut = the message to send - // */ - // private void sendMessage(string messageOut) - // { - // // TODO: Do message splits here - - - // /* Encode the mesage */ - // ubyte[] encodedMessage = encodeMessage(messageOut); - - // /* Enqueue the message to the send queue */ - // sender.sq(encodedMessage); - // } - /** * Sends a message to the server by enqueuing it on * the client-side send queue. From 9cc40938ee2cfabd7f02aba102a50ebd82d4e163 Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Thu, 16 Mar 2023 08:38:47 +0200 Subject: [PATCH 15/34] Receiver - Added documentation for `rq` Sender - Added documentation for `sq` --- source/birchwood/client/receiver.d | 7 +++++++ source/birchwood/client/sender.d | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/source/birchwood/client/receiver.d b/source/birchwood/client/receiver.d index 93be2e8..5957b29 100644 --- a/source/birchwood/client/receiver.d +++ b/source/birchwood/client/receiver.d @@ -53,6 +53,13 @@ public final class ReceiverThread : Thread } // TODO: Rename to `receiveQ` + /** + * Enqueues the raw message into the receieve queue + * for eventual processing + * + * Params: + * encodedMessage = the message to enqueue + */ public void rq(ubyte[] encodedMessage) { /* Lock queue */ diff --git a/source/birchwood/client/sender.d b/source/birchwood/client/sender.d index 8f22468..3e70f90 100644 --- a/source/birchwood/client/sender.d +++ b/source/birchwood/client/sender.d @@ -48,6 +48,13 @@ public final class SenderThread : Thread } // TODO: Rename to `sendQ` + /** + * Enqueues the raw message into the send queue + * for eventual sending + * + * Params: + * encodedMessage = the message to enqueue + */ public void sq(ubyte[] encodedMessage) { /* Lock queue */ From c1bf76df1922acf78694293a4a15f31d575c923c Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Thu, 16 Mar 2023 13:03:16 +0200 Subject: [PATCH 16/34] Updated IRC compatibility information --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ed07c15..83dedb5 100644 --- a/README.md +++ b/README.md @@ -40,8 +40,10 @@ You can take a look at the `Client` API documentation on [DUB](https://birchwood ## Compatibiloty -- [ ] rfc1459 - * Should be more or less stable in supporting this standard +- [x] [rfc1459](https://www.rfc-editor.org/rfc/rfc1459) + * Supports all the numeric codes +- [x] [rfc2812](https://www.rfc-editor.org/rfc/rfc2812) + * Supports all the numeric codes More standards will be added within the next month or so, mostly relating to new response codes that just need to be added. From b34eaf0e4ee1e348888ce8a37d76fdd0b36b403e Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Thu, 16 Mar 2023 13:45:56 +0200 Subject: [PATCH 17/34] Messages - Added work-in-progress `parameterParse()` which attempts to parse parameters and trailing text (if any of both) - Added `ppTrailing` for any possible trailing text - Added `ppKVPairs` for any potential key-value pairs - Call `parameterParse()` on initialization of a new `Message` object --- source/birchwood/protocol/messages.d | 59 ++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/source/birchwood/protocol/messages.d b/source/birchwood/protocol/messages.d index 590335c..ce70c21 100644 --- a/source/birchwood/protocol/messages.d +++ b/source/birchwood/protocol/messages.d @@ -138,6 +138,9 @@ public final class Message logger.log(e); } } + + /* Parse the parameters into key-value pairs (if any) and trailing text (if any) */ + parameterParse(); } /* TODO: Implement encoder function */ @@ -276,6 +279,62 @@ public final class Message return params; } + + private string ppTrailing; + private string[string] ppKVPairs; + + private void parameterParse() + { + /* Only parse if there are params */ + if(params.length) + { + logger.debug_("Message: ", this); + logger.debug_("ParamsSTring in: ", params); + + /* Key-value pairs */ + string kvPairs; + + /* Trailing text */ + string trailing; + + /* Find the first (and should be only) : (if any) */ + long trailingIdx = indexOf(params, ":"); + + /* If there is trailing */ + if(trailingIdx > -1) + { + /* Then read till (and not including the `:` indicator) */ + kvPairs = params[0..trailingIdx]; + + /* Save the trailing text */ + trailing = params[trailingIdx+1..params.length]; + } + /* If there is no trailing */ + else + { + /* Read the entire parameter string */ + kvPairs = params; + } + + /* Generate the key-value pairs */ + string[] pairs = split(kvPairs, " "); + logger.debug_("Pairs: ", pairs); + foreach(string pair; pairs) + { + /* Only do this if we have an `=` in the current pair */ + if(indexOf(pair, "=") > -1) + { + string key = split(pair, "=")[0]; + string value = split(pair, "=")[1]; + ppKVPairs[key] = value; + } + } + + /* Save the trailing */ + ppTrailing = trailing; + } + } + /** * Returns whether or not this message was * a numeric response From 0224f4554b48cc1949a1f383b557c3712d054153 Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Thu, 16 Mar 2023 13:52:29 +0200 Subject: [PATCH 18/34] Messages - Added `getTrailing()` which returns the trailing text - Added `getKVPairs()` which returns the key-value pairs --- source/birchwood/protocol/messages.d | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/source/birchwood/protocol/messages.d b/source/birchwood/protocol/messages.d index ce70c21..a85275b 100644 --- a/source/birchwood/protocol/messages.d +++ b/source/birchwood/protocol/messages.d @@ -280,6 +280,16 @@ public final class Message } + public string getTrailing() + { + return ppTrailing; + } + + public string[string] getKVPairs() + { + return ppKVPairs; + } + private string ppTrailing; private string[string] ppKVPairs; From 8a808cf9f2f32c3393f0ca968bd1770152f70ba1 Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Thu, 16 Mar 2023 13:53:14 +0200 Subject: [PATCH 19/34] Client - Test out new `getKVPairs()` and `getTrailing()` --- source/birchwood/client/client.d | 3 +++ 1 file changed, 3 insertions(+) diff --git a/source/birchwood/client/client.d b/source/birchwood/client/client.d index 1c8291e..0f5187c 100644 --- a/source/birchwood/client/client.d +++ b/source/birchwood/client/client.d @@ -609,6 +609,9 @@ public class Client : Thread if(cmp(command, "PRIVMSG") == 0) { + logger.debug_("PrivMessage parser (kv-pairs): ", ircMessage.getKVPairs()); + logger.debug_("PrivMessage parser (trailing): ", ircMessage.getTrailing()); + /* Split up into (channel/nick) and (message)*/ long firstSpaceIdx = indexOf(params, " "); //TODO: validity check; string chanNick = params[0..firstSpaceIdx]; From f120a566a7fd0ae911e74997c71d7e1c1f8312ba Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Thu, 16 Mar 2023 13:58:20 +0200 Subject: [PATCH 20/34] Client - Added TODO regarding what needs to be done to update the `"PRIVMSG"` sub-handler --- source/birchwood/client/client.d | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/source/birchwood/client/client.d b/source/birchwood/client/client.d index 0f5187c..ffc17b8 100644 --- a/source/birchwood/client/client.d +++ b/source/birchwood/client/client.d @@ -609,6 +609,11 @@ public class Client : Thread if(cmp(command, "PRIVMSG") == 0) { + // TODO: We will need a non kv pair thing as well to see (in the + // ... case of channel messages) the singular pair + // ... name. + // + // Then our message will be in `getTrailing()` logger.debug_("PrivMessage parser (kv-pairs): ", ircMessage.getKVPairs()); logger.debug_("PrivMessage parser (trailing): ", ircMessage.getTrailing()); From c0a249a31c14af3762d317ddde2a0242c3e42d90 Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Thu, 16 Mar 2023 18:19:01 +0200 Subject: [PATCH 21/34] Constants - Don't use octals --- source/birchwood/protocol/constants.d | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/source/birchwood/protocol/constants.d b/source/birchwood/protocol/constants.d index b01a5e4..b1d6d3e 100644 --- a/source/birchwood/protocol/constants.d +++ b/source/birchwood/protocol/constants.d @@ -153,11 +153,11 @@ public enum ReplyType : ulong /** * rfc 2812 */ - RPL_WELCOME = 001, - RPL_YOURHOST = 002, - RPL_CREATED = 003, - RPL_MYINFO = 004, - RPL_BOUNCE = 005, // TODO: We care about the key-value pairs here in RPL_BOUNCE + RPL_WELCOME = 1, + RPL_YOURHOST = 2, + RPL_CREATED = 3, + RPL_MYINFO = 4, + RPL_BOUNCE = 5, // TODO: We care about the key-value pairs here in RPL_BOUNCE ERR_NOCHANMODES = 477, From dafc39274d8da131353a60f0813a1e9b77612f3e Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Thu, 16 Mar 2023 18:20:14 +0200 Subject: [PATCH 22/34] Constants - Don't use octal --- source/birchwood/protocol/constants.d | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/source/birchwood/protocol/constants.d b/source/birchwood/protocol/constants.d index b01a5e4..b1d6d3e 100644 --- a/source/birchwood/protocol/constants.d +++ b/source/birchwood/protocol/constants.d @@ -153,11 +153,11 @@ public enum ReplyType : ulong /** * rfc 2812 */ - RPL_WELCOME = 001, - RPL_YOURHOST = 002, - RPL_CREATED = 003, - RPL_MYINFO = 004, - RPL_BOUNCE = 005, // TODO: We care about the key-value pairs here in RPL_BOUNCE + RPL_WELCOME = 1, + RPL_YOURHOST = 2, + RPL_CREATED = 3, + RPL_MYINFO = 4, + RPL_BOUNCE = 5, // TODO: We care about the key-value pairs here in RPL_BOUNCE ERR_NOCHANMODES = 477, From 75f3f7b867f17ffa0f86f43c1fccbe49cb330d6a Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Thu, 16 Mar 2023 18:38:06 +0200 Subject: [PATCH 23/34] Messages - Slightly improved trailer detection - Added some TODOs and notes Client - Log the key-value parameters and trailer --- source/birchwood/client/client.d | 3 +++ source/birchwood/protocol/messages.d | 15 ++++++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/source/birchwood/client/client.d b/source/birchwood/client/client.d index ffc17b8..09a9463 100644 --- a/source/birchwood/client/client.d +++ b/source/birchwood/client/client.d @@ -140,6 +140,9 @@ public class Client : Thread if(commandReply.getReplyType() == ReplyType.RPL_BOUNCE) { logger.log("Take a look:\n\n"~commandReply.getParams()); + + logger.log("And here is key-value pairs: ", commandReply.getKVPairs()); + logger.log("And here is everything: ", commandReply.getTrailing()); } } diff --git a/source/birchwood/protocol/messages.d b/source/birchwood/protocol/messages.d index a85275b..b71b39d 100644 --- a/source/birchwood/protocol/messages.d +++ b/source/birchwood/protocol/messages.d @@ -293,6 +293,12 @@ public final class Message private string ppTrailing; private string[string] ppKVPairs; + /** + * NOTE: This needs more work with trailing support + * we must make sure we only look for lastInex of `:` + * where it is first cyaracter after space but NOT within + * an active parameter + */ private void parameterParse() { /* Only parse if there are params */ @@ -308,7 +314,10 @@ public final class Message string trailing; /* Find the first (and should be only) : (if any) */ - long trailingIdx = indexOf(params, ":"); + // TODO: Maybe i misunderstoof it as it appears in + // some key-value pairs as the value + // ... therefore let's just look for the last one + long trailingIdx = lastIndexOf(params, ":"); /* If there is trailing */ if(trailingIdx > -1) @@ -318,6 +327,8 @@ public final class Message /* Save the trailing text */ trailing = params[trailingIdx+1..params.length]; + + logger.debug_("Look at this trailing '"~trailing~"'"); } /* If there is no trailing */ else @@ -326,6 +337,8 @@ public final class Message kvPairs = params; } + // TODO: strip whitespace on either side of `kvPairs` + /* Generate the key-value pairs */ string[] pairs = split(kvPairs, " "); logger.debug_("Pairs: ", pairs); From fc9301f632601099ecf70438343ffe160db5f7e2 Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Fri, 17 Mar 2023 08:35:23 +0200 Subject: [PATCH 24/34] Message - Implemented `splitting(string)` which returns a `string[]` of split parameters according to the rfc1459's ENBF --- source/birchwood/protocol/messages.d | 69 ++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/source/birchwood/protocol/messages.d b/source/birchwood/protocol/messages.d index b71b39d..4099fb6 100644 --- a/source/birchwood/protocol/messages.d +++ b/source/birchwood/protocol/messages.d @@ -293,6 +293,73 @@ public final class Message private string ppTrailing; private string[string] ppKVPairs; + + unittest + { + import std.stdio; + + string testInput = "A:=1 A=2 :Hello this is text"; + writeln("Input: ", testInput); + + string[] splitted = splitting(testInput); + writeln("Input (split): ", splitted); + } + + /** + * Imagine: `A:=1 A=2 :Hello` + * + * Params: + * input = + * Returns: + */ + private static string[] splitting(string input) + { + string[] splits; + + bool trailingMode; + string buildUp; + for(ulong idx = 0; idx < input.length; idx++) + { + /* Get current character */ + char curCHar = input[idx]; + + + if(trailingMode) + { + buildUp ~= curCHar; + continue; + } + + if(buildUp.length == 0) + { + if(curCHar == ':') + { + trailingMode = true; + continue; + } + } + + + if(curCHar == ' ') + { + /* Flush */ + splits ~= buildUp; + buildUp = ""; + } + else + { + buildUp ~= curCHar; + } + } + + if(buildUp.length) + { + splits ~= buildUp; + } + + return splits; + } + /** * NOTE: This needs more work with trailing support * we must make sure we only look for lastInex of `:` @@ -307,6 +374,8 @@ public final class Message logger.debug_("Message: ", this); logger.debug_("ParamsSTring in: ", params); + logger.debug_("Custom splitter: ", splitting(params)); + /* Key-value pairs */ string kvPairs; From 1af73cb9d39b3cdb2fe9e3fb8a09e5acb79eff42 Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Fri, 17 Mar 2023 08:36:09 +0200 Subject: [PATCH 25/34] Messages - Added unit test for `splitting(string)` --- source/birchwood/protocol/messages.d | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/source/birchwood/protocol/messages.d b/source/birchwood/protocol/messages.d index 4099fb6..ab92469 100644 --- a/source/birchwood/protocol/messages.d +++ b/source/birchwood/protocol/messages.d @@ -303,6 +303,11 @@ public final class Message string[] splitted = splitting(testInput); writeln("Input (split): ", splitted); + + + assert(cmp(splitted[0], "A:=1") == 0); + assert(cmp(splitted[1], "A=12") == 0); + assert(cmp(splitted[2], "Hello this is text") == 0); } /** From 988b1686d7c5cbdfd69e5171bf64e2930376229f Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Fri, 17 Mar 2023 08:37:13 +0200 Subject: [PATCH 26/34] Messages - FIxed assertion in unit test --- source/birchwood/protocol/messages.d | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/birchwood/protocol/messages.d b/source/birchwood/protocol/messages.d index ab92469..1a73735 100644 --- a/source/birchwood/protocol/messages.d +++ b/source/birchwood/protocol/messages.d @@ -306,7 +306,7 @@ public final class Message assert(cmp(splitted[0], "A:=1") == 0); - assert(cmp(splitted[1], "A=12") == 0); + assert(cmp(splitted[1], "A=2") == 0); assert(cmp(splitted[2], "Hello this is text") == 0); } From d705ad1e66fed48cb72fc0f26bcf45c0da1195a8 Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Fri, 17 Mar 2023 09:09:40 +0200 Subject: [PATCH 27/34] Messages - Added `ppPairs` and `getPairs()` which returns a `string[]` of all parameters (excluding trailing) - Implemented usage of new `splitter(string, ref bool)` - The `splitter()` function now sets a flag if there is a trailer Unit tests - Updated unit test to use new `splitter(string ref bool)` --- source/birchwood/protocol/messages.d | 65 ++++++++++++++-------------- 1 file changed, 33 insertions(+), 32 deletions(-) diff --git a/source/birchwood/protocol/messages.d b/source/birchwood/protocol/messages.d index 1a73735..cbc411d 100644 --- a/source/birchwood/protocol/messages.d +++ b/source/birchwood/protocol/messages.d @@ -290,8 +290,14 @@ public final class Message return ppKVPairs; } + public string[] getPairs() + { + return ppPairs; + } + private string ppTrailing; private string[string] ppKVPairs; + private string[] ppPairs; unittest @@ -301,12 +307,17 @@ public final class Message string testInput = "A:=1 A=2 :Hello this is text"; writeln("Input: ", testInput); - string[] splitted = splitting(testInput); + bool hasTrailer; + string[] splitted = splitting(testInput, hasTrailer); writeln("Input (split): ", splitted); + assert(cmp(splitted[0], "A:=1") == 0); assert(cmp(splitted[1], "A=2") == 0); + + /* Trailer test */ + assert(hasTrailer); assert(cmp(splitted[2], "Hello this is text") == 0); } @@ -317,7 +328,7 @@ public final class Message * input = * Returns: */ - private static string[] splitting(string input) + private static string[] splitting(string input, ref bool hasTrailer) { string[] splits; @@ -362,6 +373,8 @@ public final class Message splits ~= buildUp; } + hasTrailer = trailingMode; + return splits; } @@ -376,47 +389,33 @@ public final class Message /* Only parse if there are params */ if(params.length) { - logger.debug_("Message: ", this); - logger.debug_("ParamsSTring in: ", params); - - logger.debug_("Custom splitter: ", splitting(params)); - - /* Key-value pairs */ - string kvPairs; - /* Trailing text */ string trailing; - /* Find the first (and should be only) : (if any) */ - // TODO: Maybe i misunderstoof it as it appears in - // some key-value pairs as the value - // ... therefore let's just look for the last one - long trailingIdx = lastIndexOf(params, ":"); + /* Split the `` */ + bool hasTrailer; + string[] paramsSplit = splitting(params, hasTrailer); - /* If there is trailing */ - if(trailingIdx > -1) + logger.debug_("ParamsSPlit direct:", paramsSplit); + + + + /* Extract the trailer as the last item in the array (if it exists) */ + if(hasTrailer) { - /* Then read till (and not including the `:` indicator) */ - kvPairs = params[0..trailingIdx]; + trailing = paramsSplit[paramsSplit.length-1]; - /* Save the trailing text */ - trailing = params[trailingIdx+1..params.length]; + /* Remove it from the parameters */ + paramsSplit = paramsSplit[0..$-1]; - logger.debug_("Look at this trailing '"~trailing~"'"); - } - /* If there is no trailing */ - else - { - /* Read the entire parameter string */ - kvPairs = params; + logger.debug_("GOt railer ", trailing); } - // TODO: strip whitespace on either side of `kvPairs` + ppPairs = paramsSplit; + /* Generate the key-value pairs */ - string[] pairs = split(kvPairs, " "); - logger.debug_("Pairs: ", pairs); - foreach(string pair; pairs) + foreach(string pair; paramsSplit) { /* Only do this if we have an `=` in the current pair */ if(indexOf(pair, "=") > -1) @@ -429,6 +428,8 @@ public final class Message /* Save the trailing */ ppTrailing = trailing; + + logger.debug_("ppTrailing: ", ppTrailing); } } From 0c4382d7cef94a6c5ff618698d0c83b2bca9d502 Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Fri, 17 Mar 2023 09:10:04 +0200 Subject: [PATCH 28/34] Client - Test new parameter parsing - Noted DLog logging bug where output cannot be seen --- source/birchwood/client/client.d | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/source/birchwood/client/client.d b/source/birchwood/client/client.d index 09a9463..1e2c7da 100644 --- a/source/birchwood/client/client.d +++ b/source/birchwood/client/client.d @@ -139,10 +139,25 @@ public class Client : Thread if(commandReply.getReplyType() == ReplyType.RPL_BOUNCE) { + logger.log(); + logger.log("<<<>>>"); + logger.log("Take a look:\n\n"~commandReply.getParams()); logger.log("And here is key-value pairs: ", commandReply.getKVPairs()); - logger.log("And here is everything: ", commandReply.getTrailing()); + logger.log("And here is array: ", commandReply.getPairs()); + + // TODO: DLog bug, this prints nothing + logger.log("And here is trailing: ", commandReply.getTrailing().length); + + import std.stdio; + writeln("Trailer: "~commandReply.getTrailing()); + + logger.log("<<<>>>"); + logger.log(); + + + } } From 3c6ee2bbbb5294fca858d3e4a74460342cb24021 Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Fri, 17 Mar 2023 09:11:22 +0200 Subject: [PATCH 29/34] Unit tests - Added another unit test --- source/birchwood/protocol/messages.d | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/source/birchwood/protocol/messages.d b/source/birchwood/protocol/messages.d index cbc411d..c088e70 100644 --- a/source/birchwood/protocol/messages.d +++ b/source/birchwood/protocol/messages.d @@ -321,6 +321,19 @@ public final class Message assert(cmp(splitted[2], "Hello this is text") == 0); } + unittest + { + import std.stdio; + + string testInput = ":Hello this is text"; + bool hasTrailer; + string[] splitted = splitting(testInput, hasTrailer); + + /* Trailer test */ + assert(hasTrailer); + assert(cmp(splitted[0], "Hello this is text") == 0); + } + /** * Imagine: `A:=1 A=2 :Hello` * From 0e9c042d213b9d6d5e346b6d47f66f2e02d6dac2 Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Fri, 17 Mar 2023 09:18:17 +0200 Subject: [PATCH 30/34] Unit tests - Cleaned up --- source/birchwood/protocol/messages.d | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/source/birchwood/protocol/messages.d b/source/birchwood/protocol/messages.d index c088e70..0f405de 100644 --- a/source/birchwood/protocol/messages.d +++ b/source/birchwood/protocol/messages.d @@ -300,10 +300,13 @@ public final class Message private string[] ppPairs; - unittest + version(unittest) { import std.stdio; + } + unittest + { string testInput = "A:=1 A=2 :Hello this is text"; writeln("Input: ", testInput); @@ -323,8 +326,6 @@ public final class Message unittest { - import std.stdio; - string testInput = ":Hello this is text"; bool hasTrailer; string[] splitted = splitting(testInput, hasTrailer); From d982205b1b4c4c2d791ca29936249cbcd5c1d919 Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Fri, 17 Mar 2023 09:20:54 +0200 Subject: [PATCH 31/34] Messages - Documented `getKVPairs()`, `getTrailing()` and `getPairs()` --- source/birchwood/protocol/messages.d | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/source/birchwood/protocol/messages.d b/source/birchwood/protocol/messages.d index 0f405de..1e29dc1 100644 --- a/source/birchwood/protocol/messages.d +++ b/source/birchwood/protocol/messages.d @@ -279,17 +279,35 @@ public final class Message return params; } - + /** + * Retrieves the trailing text in the paramaters + * (if any) + * + * Returns: the trailing text + */ public string getTrailing() { return ppTrailing; } + /** + * Returns the parameters excluding the trailing text + * which are seperated by spaces but only those + * which are key-value pairs + * + * Returns: the key-value pair parameters + */ public string[string] getKVPairs() { return ppKVPairs; } + /** + * Returns the parameters excluding the trailing text + * which are seperated by spaces + * + * Returns: the parameters + */ public string[] getPairs() { return ppPairs; From ac6d9dbc14245e62005cda1711104c62ae009fe3 Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Fri, 17 Mar 2023 09:24:24 +0200 Subject: [PATCH 32/34] ConnInfo - Added method documentation --- source/birchwood/config/conninfo.d | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/source/birchwood/config/conninfo.d b/source/birchwood/config/conninfo.d index ce2b9be..df69d94 100644 --- a/source/birchwood/config/conninfo.d +++ b/source/birchwood/config/conninfo.d @@ -36,16 +36,32 @@ public struct ConnectionInfo return this.bulkReadSize; } + /** + * Get the address of the endpoint server + * + * Returns: the server's address + */ public Address getAddr() { return addrInfo; } + /** + * Get the chosen fake lag + * + * Returns: the fake lag in seconds + */ public ulong getFakeLag() { return fakeLag; } + /** + * Sets the fake lag in seconds + * + * Params: + * fakeLag = the fake lag to use + */ public void setFakeLag(ulong fakeLag) { this.fakeLag = fakeLag; From 91235f7484baf338587fdd1489da728eaa5684e3 Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Fri, 17 Mar 2023 09:25:26 +0200 Subject: [PATCH 33/34] ConnInfo - Documented module ConnectionInfo - Documented struct --- source/birchwood/config/conninfo.d | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/source/birchwood/config/conninfo.d b/source/birchwood/config/conninfo.d index df69d94..2eebd76 100644 --- a/source/birchwood/config/conninfo.d +++ b/source/birchwood/config/conninfo.d @@ -1,8 +1,15 @@ +/** + * COnfiguration-related types + */ module birchwood.config.conninfo; import std.socket : SocketException, Address, getAddress; import birchwood.client.exceptions : BirchwoodException; +/** + * Represents the connection details for a server + * to connect to + */ public struct ConnectionInfo { /* Server address information */ From c6953057e8dd076708b842161e3c372020b655c2 Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Fri, 17 Mar 2023 09:29:04 +0200 Subject: [PATCH 34/34] Client - Disable testing code for now --- source/birchwood/client/client.d | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/source/birchwood/client/client.d b/source/birchwood/client/client.d index 1e2c7da..5c79113 100644 --- a/source/birchwood/client/client.d +++ b/source/birchwood/client/client.d @@ -139,22 +139,25 @@ public class Client : Thread if(commandReply.getReplyType() == ReplyType.RPL_BOUNCE) { - logger.log(); - logger.log("<<<>>>"); + // TODO: Testing code was here + // logger.log(); + // logger.log("<<<>>>"); - logger.log("Take a look:\n\n"~commandReply.getParams()); + // logger.log("Take a look:\n\n"~commandReply.getParams()); - logger.log("And here is key-value pairs: ", commandReply.getKVPairs()); - logger.log("And here is array: ", commandReply.getPairs()); + // logger.log("And here is key-value pairs: ", commandReply.getKVPairs()); + // logger.log("And here is array: ", commandReply.getPairs()); - // TODO: DLog bug, this prints nothing - logger.log("And here is trailing: ", commandReply.getTrailing().length); + // // TODO: DLog bug, this prints nothing + // logger.log("And here is trailing: ", commandReply.getTrailing()); - import std.stdio; - writeln("Trailer: "~commandReply.getTrailing()); + // import std.stdio; + // writeln("Trailer: "~commandReply.getTrailing()); - logger.log("<<<>>>"); - logger.log(); + // writeln(cast(ubyte[])commandReply.getTrailing()); + + // logger.log("<<<>>>"); + // logger.log();