From c70cd5cccc966a35f175913f2281ce251fd62425 Mon Sep 17 00:00:00 2001 From: Luke Bratch Date: Mon, 17 Jun 2019 01:46:28 +0100 Subject: Implement a per-client identifier so auto replay can replay everything a given client has missed. --- message.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 54 insertions(+), 5 deletions(-) (limited to 'message.c') diff --git a/message.c b/message.c index 3e79605..8eceb4b 100644 --- a/message.c +++ b/message.c @@ -727,7 +727,7 @@ int processservermessage(SSL *server_ssl, char *str, struct client *clients, int // Process an IRC message that came from a client. // Return 1 if we processed it, or 0 if we didn't. int processclientmessage(SSL *server_ssl, char *str, struct client *clients, int sourcefd, struct ircdstate *ircdstate, - struct channel *channels, struct settings *settings, char tokens[MAXTOKENS][MAXDATASIZE], int counter) { + struct channel *channels, struct settings *settings, char tokens[MAXTOKENS][MAXDATASIZE], int counter, struct clientcodes *clientcodes) { // PASS received? User is trying to log in, check their password. if (strncasecmp(tokens[0], "PASS", strlen(tokens[0])) == 0) { if (checkpassword(tokens[1], settings)) { @@ -751,7 +751,7 @@ int processclientmessage(SSL *server_ssl, char *str, struct client *clients, int } } else { debugprint(DEBUG_SOME, "Password rejected, disconnecting fd %d.\n", sourcefd); - disconnectclient(sourcefd, clients, ircdstate, settings); + disconnectclient(sourcefd, clients, ircdstate, settings, clientcodes); // Alert other clients about the failed authentication char alertmsg[MAXDATASIZE]; if (!snprintf(alertmsg, MAXDATASIZE, "NOTICE %s :blabouncer: new client with fd %d has failed to authenticate.", ircdstate->ircnick, sourcefd)) { @@ -828,7 +828,7 @@ int processclientmessage(SSL *server_ssl, char *str, struct client *clients, int // Tell the client to go away if we aren't registered with the real server yet as defined by the last greeting not being set yet if (!strlen(ircdstate->greeting004)) { sendtoclient(sourcefd, "Sorry, we aren't registered with a real IRC server yet.", clients, settings, 0); - disconnectclient(sourcefd, clients, ircdstate, settings); + disconnectclient(sourcefd, clients, ircdstate, settings, clientcodes); return 1; } @@ -865,6 +865,8 @@ int processclientmessage(SSL *server_ssl, char *str, struct client *clients, int sendtoclient(sourcefd, outgoingmsg, clients, settings, 0); snprintf(outgoingmsg, MAXDATASIZE, "NOTICE %s :\"BLABOUNCER REHASH\" (To reload settings from the configuration file, see README for which settings can be reloaded.)", ircdstate->ircnick); sendtoclient(sourcefd, outgoingmsg, clients, settings, 0); + snprintf(outgoingmsg, MAXDATASIZE, "NOTICE %s :\"BLABOUNCER CLIENTCODE [clientcode]\" (To set an identifier for the current client for auto replaying just what this client has missed.)", ircdstate->ircnick); + sendtoclient(sourcefd, outgoingmsg, clients, settings, 0); snprintf(outgoingmsg, MAXDATASIZE, "NOTICE %s :\"BLABOUNCER QUIT [quit message]\" (To quit blabouncer, optionally sending [quit message] to the server.)", ircdstate->ircnick); sendtoclient(sourcefd, outgoingmsg, clients, settings, 0); @@ -1039,7 +1041,7 @@ int processclientmessage(SSL *server_ssl, char *str, struct client *clients, int // A client has QUIT, so disconnect (close) them and don't do anything else for now - TODO: Let another clients know with a NOTICE or something if (strncasecmp(tokens[0], "QUIT", strlen(tokens[0])) == 0) { debugprint(DEBUG_FULL, "Client QUIT found from fd %d and it is: %s with length %zd! Disconnecting that fd.\n", sourcefd, tokens[0], strlen(tokens[0])); - disconnectclient(sourcefd, clients, ircdstate, settings); + disconnectclient(sourcefd, clients, ircdstate, settings, clientcodes); return 1; } @@ -1160,7 +1162,7 @@ int processclientmessage(SSL *server_ssl, char *str, struct client *clients, int char outgoingmsg[MAXDATASIZE]; debugprint(DEBUG_FULL, "Client BLABOUNCER found and it is: %s with length %zd!\n", tokens[1], strlen(tokens[1])); // REPLAY received, send the requested length of replay time to the client - if (strncasecmp(tokens[1], "REPLAY", strlen("REPLAY")) == 0) { + if (strncasecmp(tokens[1], "REPLAY", strlen("REPLAY")) == 0 && counter == 3) { debugprint(DEBUG_FULL, "Client BLABOUNCER REPLAY (custom blabouncer command) found and it is: %s with length %zd!\n", tokens[1], strlen(tokens[1])); // Split the request into days:hours:minutes:seconds @@ -1282,6 +1284,51 @@ int processclientmessage(SSL *server_ssl, char *str, struct client *clients, int sendtoallclients(clients, outgoingmsg, 0, settings); } + return 1; + // CLIENTCODE received, set the provided string as the client code for handling auto replays for when this client code is next seen + } else if (strncasecmp(tokens[1], "CLIENTCODE", strlen("CLIENTCODE")) == 0 && counter == 3) { + debugprint(DEBUG_FULL, "Client BLABOUNCER CLIENTCODE found and it is: %s %s! Setting as this client's client code.\n", tokens[1], tokens[2]); + + // Make sure replaymode = "perclient" is set + if (strcmp(settings->replaymode, "perclient")) { + debugprint(DEBUG_SOME, "CLIENTCODE requested but replaymode not set to \"perclient\".\n"); + snprintf(outgoingmsg, MAXDATASIZE, "NOTICE %s :CLIENTCODE requested but replaymode not set to \"perclient\".", ircdstate->ircnick); + sendtoclient(sourcefd, outgoingmsg, clients, settings, 0); + return 1; + } + + // Make sure the client code length is good + if (strlen(tokens[2]) < 1 || strlen(tokens[2]) > CLIENTCODELEN - 1) { + debugprint(DEBUG_SOME, "Invalid CLIENTODE length.\n"); + snprintf(outgoingmsg, MAXDATASIZE, "NOTICE %s :Invalid CLIENTODE length. Must be 1 to %d characters.", ircdstate->ircnick, CLIENTCODELEN - 1); + sendtoclient(sourcefd, outgoingmsg, clients, settings, 0); + return 1; + } + + // Register the client code (if it doesn't already exist) + int ret = addclientcode(sourcefd, tokens[2], clientcodes, clients); + if (ret == -1) { + // Something went wrong + debugprint(DEBUG_CRIT, "error: addclientcode() returned 0.\n"); + snprintf(outgoingmsg, MAXDATASIZE, "NOTICE %s :Problem registering client code.", ircdstate->ircnick); + sendtoclient(sourcefd, outgoingmsg, clients, settings, 0); + return 1; + } else if (ret == 0) { + // If it did already exist, do a replay of everything since this client code last disconnected + int codetime = getclientcodetime(tokens[2], clientcodes); + if (!codetime) { + debugprint(DEBUG_CRIT, "Error finding last disconnect time of this client code!\n"); + snprintf(outgoingmsg, MAXDATASIZE, "NOTICE %s :Error finding last disconnect time of this client code!", ircdstate->ircnick); + sendtoclient(sourcefd, outgoingmsg, clients, settings, 0); + return 1; + } + if (!doreplay(sourcefd, time(NULL) - codetime, clients, settings, ircdstate, channels)) { + snprintf(outgoingmsg, MAXDATASIZE, "NOTICE %s :Unable to read replay log file!", ircdstate->ircnick); + sendtoclient(sourcefd, outgoingmsg, clients, settings, 0); + return 1; + } + } + return 1; // Unrecognised BLABOUNCER command received, send some help instructions } else { @@ -1292,6 +1339,8 @@ int processclientmessage(SSL *server_ssl, char *str, struct client *clients, int sendtoclient(sourcefd, outgoingmsg, clients, settings, 0); snprintf(outgoingmsg, MAXDATASIZE, "NOTICE %s :\"BLABOUNCER REHASH\" (To reload settings from the configuration file, see README for which settings can be reloaded.)", ircdstate->ircnick); sendtoclient(sourcefd, outgoingmsg, clients, settings, 0); + snprintf(outgoingmsg, MAXDATASIZE, "NOTICE %s :\"BLABOUNCER CLIENTCODE [clientcode]\" (To set an identifier for the current client for auto replaying just what this client has missed.)", ircdstate->ircnick); + sendtoclient(sourcefd, outgoingmsg, clients, settings, 0); snprintf(outgoingmsg, MAXDATASIZE, "NOTICE %s :\"BLABOUNCER QUIT [quit message]\" (To quit blabouncer, optionally sending [quit message] to the server.)", ircdstate->ircnick); sendtoclient(sourcefd, outgoingmsg, clients, settings, 0); return 1; -- cgit v1.2.3