summaryrefslogtreecommitdiff
path: root/blabouncer.c
diff options
context:
space:
mode:
authorLuke Bratch <luke@bratch.co.uk>2019-05-16 23:40:43 +0100
committerLuke Bratch <luke@bratch.co.uk>2019-05-16 23:40:43 +0100
commit93e530320e024e9119fb8717459ef618086c5839 (patch)
tree779e015cba061c55362f650638e5b92d8f53dc63 /blabouncer.c
parent57faf310db4c7d7d07a5695fb305c481e040e4fb (diff)
Correctly handle nicks changing and actually track users PARTing channels.
Also change nickuserhost to store the leading colon (:) since it's always needed (so far).
Diffstat (limited to 'blabouncer.c')
-rw-r--r--blabouncer.c102
1 files changed, 91 insertions, 11 deletions
diff --git a/blabouncer.c b/blabouncer.c
index 7d2ea31..2a3bf7e 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 nicks/modes
+// - Keep track of changing user modes
// - Should replay log do more than PRIVMSGs?
// - Consider moving the three fd-related arrays into one struct
// - Check authentication before even getting to the send functions to save unnecessary processing
@@ -84,8 +84,8 @@ struct ircdstrings {
char greeting003[MAXDATASIZE];
char greeting004[MAXDATASIZE];
char ircdname[MAXDATASIZE];
- char nickuserhost[MAXDATASIZE]; // TODO - Make sure this changes when nick changes, if that's meant to happen.
- char ircnick[MAXNICKLENGTH]; // TODO - Make sure this changes when nick changes
+ char nickuserhost[MAXDATASIZE];
+ 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)
};
@@ -328,6 +328,51 @@ int addusertochannel(struct channel *channels, char *channelname, char *nick) {
return 0;
}
+int removeuserfromchannel(struct channel *channels, char *channelname, char *nick) {
+ printf("removeuserfromchannel(): given \"%s\" and \"%s\".\n", channelname, nick);
+
+ // Go through all the channels
+ for (int i = 0; i < MAXCHANNELS; i++) {
+ // Until we find the channel
+ if (strncmp(channels[i].name, channelname, strlen(channelname)) == 0) {
+ // Go through all the users in the channel
+ for (int j = 0; j < MAXCHANUSERS; j++) {
+ // And remove the user if found
+ if (strncmp(channels[i].nicks[j], nick, strlen(nick)) == 0) {
+ channels[i].nicks[j][0] = '\0';
+ return 1;
+ }
+ }
+ // We failed
+ return 0;
+ }
+ }
+
+ // TODO - Make a failed return do something to callers
+ return 0;
+}
+
+// Update any instance of oldnick with newnick in all channels,
+// for instance of a new changed their nick.
+int updatechannelnicks(struct channel *channels, char *oldnick, char *newnick) {
+ printf("updatechannelnicks(): given '%s' and '%s'.\n", oldnick, newnick);
+
+ // Go through all the channels
+ for (int i = 0; i < MAXCHANNELS; i++) {
+ // Go through all the users in the channel
+ for (int j = 0; j < MAXCHANUSERS; j++) {
+ // And update the nick if found
+ if (strncmp(channels[i].nicks[j], oldnick, strlen(oldnick)) == 0) {
+ printf("Updating '%s' to '%s' in '%s'.\n", channels[i].nicks[j], newnick, channels[i].name);
+ strcpy(channels[i].nicks[j], newnick);
+ }
+ }
+ }
+
+ // TODO - Detect failing to update anything and tell the caller
+ return 1;
+}
+
int setchanneltopicwhotime(struct channel *channels, char *channelname, char *who, char *when) {
printf("setchanneltopicwhotime(): given \"%s\", \"%s\", and \"%s\".\n", channelname, who, when);
@@ -536,10 +581,15 @@ int processircmessage(SSL *server_ssl, int *clientsockfd, char *str, int source,
strncpy(ircdstrings->greeting001, str, strlen(str));
// Null the end of the string
ircdstrings->greeting001[strlen(str)] = '\0';
- printf("Storing our nick!user@host (%s) from greeting 001 in ircdstrings struct.\n", tokens[counter - 1]);
- strncpy(ircdstrings->nickuserhost, tokens[counter - 1], strlen(tokens[counter - 1]));
- // Null the end of the string
- ircdstrings->nickuserhost[strlen(tokens[counter - 1])] = '\0';
+ printf("Storing our nick!user@host (:%s) from greeting 001 in ircdstrings struct.\n", tokens[counter - 1]);
+ // Prepend a colon (:) first since everything (so far) needs one
+ if (!snprintf(ircdstrings->nickuserhost, MAXDATASIZE, ":%s", tokens[counter - 1])) {
+ fprintf(stderr, "Error while preparing nickuserhost for storage!\n");
+ exit(1);
+ }
+ // Null the end of the new string
+ ircdstrings->nickuserhost[strlen(tokens[counter - 1]) + 1] = '\0'; // +1 for the inserted colon
+ printf("nickuserhost '%s' stored.\n", ircdstrings->nickuserhost);
return 1;
} else if (strncmp(tokens[1], "002", strlen(tokens[1])) == 0) {
printf("Found greeting 002 (%s), storing in ircdstrings struct.\n", str);
@@ -576,7 +626,6 @@ int processircmessage(SSL *server_ssl, int *clientsockfd, char *str, int source,
// If the user JOINing is us, then we must have joined a channel, so add to our local channel array.
// Copy to a temporary string so we still have the original in case we need it
char *prefixcopy = strdup(tokens[0]);
- stripprefix(prefixcopy);
if (strncmp(prefixcopy, ircdstrings->nickuserhost, strlen(tokens[0])) == 0) {
printf("Server JOIN: nickuserhost is ours ('%s' vs '%s').\n", prefixcopy, ircdstrings->nickuserhost);
// TODO - Saner way to initialise this since we don't have the variables yet?
@@ -603,12 +652,13 @@ int processircmessage(SSL *server_ssl, int *clientsockfd, char *str, int source,
// (If it's not us, then it's another user PARTing a channel, so just pass straight through to letting all our clients know.)
// Copy to a temporary string so we still have the original in case we need it
char *prefixcopy = strdup(tokens[0]);
- stripprefix(prefixcopy);
if (strncmp(prefixcopy, ircdstrings->nickuserhost, strlen(tokens[0])) == 0) {
printf("Server PART: nickuserhost is ours ('%s' vs '%s').\n", prefixcopy, ircdstrings->nickuserhost);
removechannel(channels, tokens[2]);
} else {
printf("Server PART: nickuserhost is NOT ours ('%s' vs '%s').\n", prefixcopy, ircdstrings->nickuserhost);
+ extractnickfromprefix(tokens[0]);
+ removeuserfromchannel(channels, tokens[2], tokens[0]);
}
// And then send to all clients
@@ -701,6 +751,36 @@ int processircmessage(SSL *server_ssl, int *clientsockfd, char *str, int source,
return 1;
}
+
+ // Server NICK received?
+ // 1. Find out if it was us and change ircnick and nickuserhost if so
+ // 2. Either way, update our records of nicks in channels
+ // 3. Either way, relay to all clients
+ if (strncmp(tokens[1], "NICK", strlen(tokens[1])) == 0) {
+ printf("Server NICK found and it is: %s with length %zd! Next token is '%s'. Updating records and relaying to all clients.\n", tokens[0], strlen(tokens[0]), tokens[2]);
+
+ // Was it us?
+ if (strncmp(ircdstrings->nickuserhost, tokens[0], strlen(ircdstrings->nickuserhost)) == 0) {
+ // Update nickuserhost with the new :nick!user@host
+ updatenickuserhost(ircdstrings->nickuserhost, tokens[2]);
+ printf("Updated nickuserhost to '%s'.\n", ircdstrings->nickuserhost);
+ // Update ircnick
+ char *prefixcopy = strdup(ircdstrings->nickuserhost);
+ extractnickfromprefix(prefixcopy);
+ strcpy(ircdstrings->ircnick, prefixcopy);
+ printf("Updated ircnick to '%s'.\n", ircdstrings->ircnick);
+ }
+
+ // Update all nicks in channels
+ extractnickfromprefix(tokens[0]);
+ stripprefix(tokens[2]);
+ updatechannelnicks(channels, tokens[0], tokens[2]);
+
+ // Relay to all clients
+ sendtoallclients(clientsockfd, fdmax, arr_clients, str, sourcefd, arr_authed, arr_ssl, settings);
+
+ return 1;
+ }
}
// Don't return if we got here because this means we didn't process something above
@@ -767,7 +847,7 @@ int processircmessage(SSL *server_ssl, int *clientsockfd, char *str, int source,
}
// Get client to join channels
- if (!snprintf(outgoingmsg, MAXDATASIZE, ":%s JOIN :%s", ircdstrings->nickuserhost, channels[i].name)) {
+ if (!snprintf(outgoingmsg, MAXDATASIZE, "%s JOIN :%s", ircdstrings->nickuserhost, channels[i].name)) {
fprintf(stderr, "Error while preparing USER just connected, channel JOIN responses!\n");
exit(1);
}
@@ -873,7 +953,7 @@ int processircmessage(SSL *server_ssl, int *clientsockfd, char *str, int source,
// Rebuild to full PRIVMSG string and relay to all other clients
char outgoingmsg[MAXDATASIZE]; // String to send to client
- if (!snprintf(outgoingmsg, MAXDATASIZE, ":%s %s", ircdstrings->nickuserhost, str)) {
+ if (!snprintf(outgoingmsg, MAXDATASIZE, "%s %s", ircdstrings->nickuserhost, str)) {
fprintf(stderr, "Error while preparing PRIVMSG relay from another bouncer client.\n");
exit(1);
}