From 2e665e03b6175b3f31f0ef1e058183417df1456e Mon Sep 17 00:00:00 2001 From: Luke Bratch Date: Thu, 24 Nov 2022 00:08:34 +0000 Subject: Fix replaymode = "lastspoke" by using line numbers rather than time to calculate replay start point. Introduce new function doreplaylastspoke() to achieve this, move doreplay() into replay.c as doreplaytime() and refactor common things into sanitisereplay(). --- functions.c | 132 +++++++----------------------------------------------------- 1 file changed, 14 insertions(+), 118 deletions(-) (limited to 'functions.c') diff --git a/functions.c b/functions.c index 917f688..6d85d8e 100644 --- a/functions.c +++ b/functions.c @@ -873,110 +873,6 @@ int channelindex(struct channel *channels, int maxchannelcount, char *name) { return -1; } -// Send the requested number of seconds worth of replay log lines to the requested client. -// 'sourcefd' is the client to send to, and 'replayseconds' is the number of -// seconds of replay log to replay. -// Returns 1 for success or 0 for failure. -int doreplay(int sourcefd, int replayseconds, struct client *clients, struct settings *settings, struct ircdstate *ircdstate, struct channel *channels) { - char outgoingmsg[MAXDATASIZE]; - - // Figure out how many lines to replay - int numlines = replaylines(replayseconds, settings->basedir); - debugprint(DEBUG_FULL, "Replay log lines: '%d'.\n", numlines); - - if (numlines < 0) { - debugprint(DEBUG_CRIT, "Error getting number of replay lines.\n"); - return 0; - } else if (numlines == 0) { - snprintf(outgoingmsg, MAXDATASIZE, "NOTICE %s :0 replay log lines found in the time requested, nothing to send.", ircdstate->ircnick); - sendtoclient(sourcefd, outgoingmsg, clients, settings, 0); - return 1; - } - - // Announce the start - snprintf(outgoingmsg, MAXDATASIZE, "NOTICE %s :Starting log replay....", ircdstate->ircnick); - sendtoclient(sourcefd, outgoingmsg, clients, settings, 0); - - // Replay those lines! - for (int i = 0; i < numlines; i++) { - int ret = readreplayline(replayseconds, i, outgoingmsg, settings, ircdstate); - if (ret == 0) { - debugprint(DEBUG_CRIT, "Error requesting replay line.\n"); - return 0; - } else if (ret == -1) { - debugprint(DEBUG_FULL, "doreplay(): readreplayline() said to ignore replay line.\n"); - continue; - } - - // Check if the replay line is a TOPIC, a JOIN, or a PART so we don't - // replay those if we are not currently in the channel they are from - // otherwise clients and state go a bit mad. - // Never replay them if they are from us. - - // Copy to a temporary string - char *strcopy = strdup(outgoingmsg); - // Keep track of initial pointer for free()ing later - char *strcopyPtr = strcopy; - - // Build array of each space-separated token - char tokens[3][MAXDATASIZE]; - char *token; - - for (int j = 0; j < 3; j++) { - // Try to split - if ((token = strsep(&strcopy, " ")) == NULL) { - debugprint(DEBUG_CRIT, "doreplay(): error splitting string on iteration '%d', returning!\n", j); - return 0; - } - // Copy into the token array (strlen + 1 to get the NULL terminator) - strncpy(tokens[j], token, strlen(token) + 1); - } - - if (strncmp(tokens[1], "TOPIC", strlen("TOPIC")) == 0 || - strncmp(tokens[1], "JOIN", strlen("JOIN")) == 0 || - strncmp(tokens[1], "PART", strlen("PART")) == 0) { - // Skip over colon if present in channel name - int offset = 0; - if (tokens[2][0] == ':') { - offset = 1; - } - - // To make sure it's not us - extractnickfromprefix(tokens[0], 1); - - // Check if we're currently in this channel or if the log line is from us - if (!inchannel(channels, ircdstate->maxchannelcount, tokens[2] + offset) || - ((strlen(tokens[0]) == strlen(ircdstate->ircnick)) && (strncmp(tokens[0], ircdstate->ircnick, strlen(tokens[0])) == 0))) { - debugprint(DEBUG_FULL, "Not sending '%s' replay line '%s'.\n", tokens[1], outgoingmsg); - free(strcopyPtr); - continue; - } - } - - // Separate special check for if a NICK change is from us but it isn't our current nick - if (strncmp(tokens[1], "NICK", strlen("NICK")) == 0) { - extractnickfromprefix(tokens[0], 1); - - if ((strlen(tokens[0]) == strlen(ircdstate->ircnick)) && (strncmp(tokens[0], ircdstate->ircnick, strlen(tokens[0])) == 0)) { - debugprint(DEBUG_FULL, "Not sending '%s' replay line '%s'.\n", tokens[1], outgoingmsg); - free(strcopyPtr); - continue; - } - } - - free(strcopyPtr); - - debugprint(DEBUG_FULL, "Sending replay line: '%s'.\n", outgoingmsg); - sendtoclient(sourcefd, outgoingmsg, clients, settings, 0); - } - - // Announce the end - snprintf(outgoingmsg, MAXDATASIZE, "NOTICE %s :Log replay complete.", ircdstate->ircnick); - sendtoclient(sourcefd, outgoingmsg, clients, settings, 0); - - return 1; -} - // Send the auto replay to the requested client, where 'sourcefd' is the client // to send to. The type of replay will depend on the user's settings. // Returns 1 for success or 0 for failure. @@ -989,9 +885,9 @@ int doautoreplay(int sourcefd, struct client *clients, struct settings *settings // If replaymode = "time" then send whatever replayseconds is set to if (!strncmp(settings->replaymode, "time", strlen("time"))) { - debugprint(DEBUG_FULL, "doautoreplay(): replaymode = \"time\", calling doreplay() with '%d' seconds.\n", settings->replayseconds); - if (!doreplay(sourcefd, settings->replayseconds, clients, settings, ircdstate, channels)) { - debugprint(DEBUG_SOME, "doautoreplay(): doreplay() returned 0, returning 0 to caller...\n"); + debugprint(DEBUG_FULL, "doautoreplay(): replaymode = \"time\", calling doreplaytime() with '%d' seconds.\n", settings->replayseconds); + if (!doreplaytime(sourcefd, settings->replayseconds, clients, settings, ircdstate, channels)) { + debugprint(DEBUG_SOME, "doautoreplay(): doreplaytime() returned 0, returning 0 to caller...\n"); return 0; } return 1; @@ -999,15 +895,15 @@ int doautoreplay(int sourcefd, struct client *clients, struct settings *settings // If replaymode = "lastspoke" then send whatever happened since the user's current nick last spoke if (!strncmp(settings->replaymode, "lastspoke", strlen("lastspoke"))) { - debugprint(DEBUG_FULL, "doautoreplay(): replaymode = \"lastspoke\".\n", settings->replayseconds); - int secondsago = lastspokesecondsago(ircdstate->ircnick, settings->basedir); - if (secondsago < 1) { - debugprint(DEBUG_SOME, "doautoreplay(): lastspokesecondsago() returned < 1, returning 0 to caller...\n"); + debugprint(DEBUG_FULL, "doautoreplay(): replaymode = \"lastspoke\", calling doreplaylastspoke().\n"); + long linenumber = lastspokelinenumber(ircdstate->ircnick, settings->basedir); + if (linenumber < 1) { + debugprint(DEBUG_SOME, "doautoreplay(): lastspokelinenumber() returned < 1, returning 0 to caller...\n"); return 0; } - debugprint(DEBUG_FULL, "doautoreplay(): replaymode = \"lastspoke\", sending lines from '%d' seconds ago to sourcefd '%d'.\n", secondsago, sourcefd); - if (!doreplay(sourcefd, secondsago, clients, settings, ircdstate, channels)) { - debugprint(DEBUG_SOME, "doautoreplay(): doreplay() returned 0, returning 0 to caller...\n"); + debugprint(DEBUG_FULL, "doautoreplay(): replaymode = \"lastspoke\", replaying from line '%ld' to sourcefd '%d'.\n", linenumber, sourcefd); + if (!doreplaylastspoke(sourcefd, linenumber, clients, settings, ircdstate, channels)) { + debugprint(DEBUG_SOME, "doautoreplay(): doreplaylastspoke() returned 0, returning 0 to caller...\n"); // CORRECT? return 0; } return 1; @@ -1016,8 +912,8 @@ int doautoreplay(int sourcefd, struct client *clients, struct settings *settings // If replaymode = "noclients" and there is currently only one client connected, then send whatever happened since there were last no clients connected if (!strncmp(settings->replaymode, "noclients", strlen("noclients")) && numclients(clients) == 1) { debugprint(DEBUG_FULL, "doautoreplay(): replaymode = \"noclients\", sending '%d' seconds of replay.\n", time(NULL) - ircdstate->clientsnonetime); - if (!doreplay(sourcefd, time(NULL) - ircdstate->clientsnonetime, clients, settings, ircdstate, channels)) { - debugprint(DEBUG_SOME, "doautoreplay(): doreplay() returned 0, returning 0 to caller...\n"); + if (!doreplaytime(sourcefd, time(NULL) - ircdstate->clientsnonetime, clients, settings, ircdstate, channels)) { + debugprint(DEBUG_SOME, "doautoreplay(): doreplaytime() returned 0, returning 0 to caller...\n"); return 0; } return 1; @@ -1026,8 +922,8 @@ int doautoreplay(int sourcefd, struct client *clients, struct settings *settings // If replaymode = "lastchange" then send whatever happened since the last client registration or disconnection if (!strncmp(settings->replaymode, "lastchange", strlen("lastchange"))) { debugprint(DEBUG_FULL, "doautoreplay(): replaymode = \"lastchange\", sending '%d' seconds of replay.\n", time(NULL) - ircdstate->clientchangetime); - if (!doreplay(sourcefd, time(NULL) - ircdstate->clientchangetime, clients, settings, ircdstate, channels)) { - debugprint(DEBUG_SOME, "doautoreplay(): doreplay() returned 0, returning 0 to caller...\n"); + if (!doreplaytime(sourcefd, time(NULL) - ircdstate->clientchangetime, clients, settings, ircdstate, channels)) { + debugprint(DEBUG_SOME, "doautoreplay(): doreplaytime() returned 0, returning 0 to caller...\n"); return 0; } return 1; -- cgit v1.2.3