From 4cd965884ae9a9e9738818eca11af9ba9aa792d4 Mon Sep 17 00:00:00 2001
From: Luke Bratch <luke@bratch.co.uk>
Date: Fri, 17 May 2019 22:35:15 +0100
Subject: Track and relay our user MODE correctly, including for new clients.

---
 blabouncer.c | 31 +++++++++++++++++++++++++++++--
 1 file changed, 29 insertions(+), 2 deletions(-)

diff --git a/blabouncer.c b/blabouncer.c
index c4396f4..775ccce 100644
--- a/blabouncer.c
+++ b/blabouncer.c
@@ -6,7 +6,7 @@
 // - Do we actually need to store the modes in the channel struct?
 // - Get CAP from server and relay to client
 // - "01:53:47 -!- ServerMode/#test [b] by irc.tghost.co.uk" on existing clients when new client connects
-// - Keep track of changing user modes
+// - Keep track of changing user modes in channels
 // - Should replay log do more than PRIVMSGs?
 // - Check authentication before even getting to the send functions to save unnecessary processing
 // - Configurable auto channels
@@ -15,7 +15,6 @@
 // - Alert when clients connect/authenticate/disconnect
 // - Perhaps rename clients.ssl and server_ssl since they may not even be OpenSSL sockets
 // - Is it possible to replay JOINs/PARTs accurately?
-// - New clients don't get their own server mode (e.g. blabounce(+i))
 //
 // Example WHOIS reply:
 // BOUNCER-SERVER RECEIVED: :irc.tghost.co.uk 307 blabounce l_bratch :is identified for this nick
@@ -88,6 +87,7 @@ struct ircdstrings {
   char ircnick[MAXNICKLENGTH];
   char ircusername[MAXUSERNAMELEN];
   char currentmsg[MAXDATASIZE]; // Holding area for the current server-received IRC message being processed in case it needs building across multiple reads (i.e. a truncated/split message)
+  char mode[MAXDATASIZE];
 };
 
 // Structure of settings either to be read from the configuration file or set/changed at runtime
@@ -802,6 +802,19 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli
 
           return 1;
         }
+
+        // Server MODE received?  Store in ircdstrings for when clients connect and relay to current clients.
+        if (strncmp(tokens[1], "MODE", strlen(tokens[1])) == 0) {
+          printf("Server MODE found and it is: %s with length %zd!  Mode is '%s'.  Storing for later.\n", tokens[1], strlen(tokens[1]), tokens[3]);
+
+          // Store for new clients
+          strcpy(ircdstrings->mode, tokens[3]);
+
+          // Relay to all current clients
+          sendtoallclients(clients, str, sourcefd, settings);
+
+          return 1;
+        }
       }
 
       // Don't return if we got here because this means we didn't process something above
@@ -931,6 +944,13 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli
           sendtoclient(sourcefd, outgoingmsg, clients, settings);
         }
 
+        // Send our mode to the client
+        if (!snprintf(outgoingmsg, MAXDATASIZE, ":%s MODE %s %s", ircdstrings->ircnick, ircdstrings->ircnick, ircdstrings->mode)) {
+          fprintf(stderr, "Error while preparing USER just connected, MODE response!\n");
+          exit(1);
+        }
+        sendtoclient(sourcefd, outgoingmsg, clients, settings);
+
         // Set the client as registered
         clients[arrindex(clients, sourcefd)].registered = 1;
 
@@ -1034,6 +1054,13 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli
         return 1;
       }
 
+      // Just send MODE to server and let it talk back to clients as required
+      if (strncmp(tokens[0], "MODE", strlen(tokens[0])) == 0) {
+        printf("Client MODE found and it is: %s with length %zd!  Sending to server...\n", tokens[0], strlen(tokens[0]));
+        sendtoserver(server_ssl, str, strlen(str), sourcefd, clients, settings);
+        return 1;
+      }
+
       // Custom BLABOUNCER command received
       // Case insensitive comparisons here since clients won't be recognising and uppercasing these commands
       if (strncasecmp(tokens[0], "BLABOUNCER", strlen(tokens[0])) == 0) {
-- 
cgit v1.2.3