summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Bratch <luke@bratch.co.uk>2019-06-16 23:16:18 +0100
committerLuke Bratch <luke@bratch.co.uk>2019-06-16 23:16:18 +0100
commit61906329ccbe96c25c75533f819dea269492f5a7 (patch)
tree647e407cb483fc13a26e616891c7504788bed813
parent87b890b501a9ed7bfbfbe0fabde6ca1ca4c15086 (diff)
Implement two new auto replay modes:
- replaymode = "noclients": All messages since the bouncer last had no clients connected - replaymode = "lastchange": All messages since the last client connect or disconnect
-rw-r--r--TODO6
-rw-r--r--blabouncer.c10
-rw-r--r--blabouncer.conf.example2
-rw-r--r--config.c2
-rw-r--r--functions.c33
-rw-r--r--message.c3
-rw-r--r--structures.h2
7 files changed, 48 insertions, 10 deletions
diff --git a/TODO b/TODO
index c5a5517..e58b82c 100644
--- a/TODO
+++ b/TODO
@@ -1,8 +1,6 @@
Add various auto replay options:
- - All logs since the final client disconnected
- - All logs since the most recent client connect/disconnect
- - All logs since *you* last sent a message (already implemented)
- - All logs since X seconds ago (already implemented)
- All logs since the current client last disconnected (track clients with some special token the client auto sends on connect)
Might need to #include <limits.h> in blabouncer.c to make some operating systems and/or compilers happy.
+
+Don't say "Unable to read replay log file!" just because there was nothing to replay.
diff --git a/blabouncer.c b/blabouncer.c
index 3b0a538..95521f1 100644
--- a/blabouncer.c
+++ b/blabouncer.c
@@ -133,6 +133,7 @@ int connecttoircserver(SSL_CTX **serverctx, SSL **server_ssl, int *serversockfd,
ircdstate->lastmessagetime = time(NULL);
ircdstate->timeoutcheck = 0;
// ircdstate.reconnecting is not set here as we want to track reconnections separately
+ // ircdstate.clientchangetime and ircdstate.clientsnonetime not set here as they are set at startup and only changed when clients connect/disconnect
// Populate nick and username from our configuration file for now, real IRCd may change them later (TODO - Is this true of username?)
strcpy(ircdstate->ircnick, settings->ircnick);
@@ -412,9 +413,11 @@ void dochat(int *serversockfd, int *clientsockfd, struct settings *settings) {
SSL_CTX *serverctx = NULL;
SSL *server_ssl = NULL; // Need to create this either way as referenced later
- // Set reconnection things to null/zero for now (not used unless reconnecting to server)
+ // Set reconnection and other things to null/zero for now (not used unless reconnecting to server)
ircdstate.oldnick[0] = '\0';
ircdstate.reconnecting = 0;
+ ircdstate.clientchangetime = time(NULL);
+ ircdstate.clientsnonetime = time(NULL);
if (!connecttoircserver(&serverctx, &server_ssl, serversockfd, &ircdstate, settings, clients)) {
fprintf(stderr, "Failed to connect to IRC server, exiting.\n");
debugprint(DEBUG_CRIT, "Failed to connect to IRC server, exiting.\n");
@@ -877,8 +880,9 @@ int main(int argc, char *argv[]) {
printf("main(): error getting 'replaymode' from configuration file.\n");
exit(1);
} else {
- if (strcmp(settings.replaymode, "none") && strcmp(settings.replaymode, "time") && strcmp(settings.replaymode, "lastspoke")) {
- printf("main(): replaymode in configuration file must be one of \"none\", \"time\", or \"lastspoke\".\n");
+ if (strcmp(settings.replaymode, "none") && strcmp(settings.replaymode, "time") && strcmp(settings.replaymode, "lastspoke") &&
+ strcmp(settings.replaymode, "noclients") && strcmp(settings.replaymode, "lastchange")) {
+ printf("main(): replaymode in configuration file must be one of \"none\", \"time\", \"lastspoke\", \"noclients\", or \"lastchange\".\n");
exit(1);
}
}
diff --git a/blabouncer.conf.example b/blabouncer.conf.example
index ebb2f23..1537805 100644
--- a/blabouncer.conf.example
+++ b/blabouncer.conf.example
@@ -24,6 +24,8 @@ realname = "Mr Bla Bouncer"
# "none" = Don't auto replay
# "time" = Always send the last "replayseconds" worth of logs
# "lastspoke" = All messages since your current nick last spoke
+# "noclients" = All messages since you last had no clients connected
+# "lastchange" = All messages since your last client connection/disconnection
replaymode = "time"
# How many seconds of replay log should be sent to connecting clients if replaymode = "time"
diff --git a/config.c b/config.c
index 9a144cd..6246789 100644
--- a/config.c
+++ b/config.c
@@ -178,6 +178,8 @@ int createconfigfile(char *filename) {
"# \"none\" = Don't auto replay\n"
"# \"time\" = Always send the last \"replayseconds\" worth of logs\n"
"# \"lastspoke\" = All messages since your current nick last spoke\n"
+ "# \"noclients\" = All messages since you last had no clients connected\n"
+ "# \"lastchange\" = All messages since your last client connection/disconnection\n"
"replaymode = \"time\"\n"
"\n"
"# How many seconds of replay log should be sent to connecting clients if replaymode = \"time\"\n"
diff --git a/functions.c b/functions.c
index 3aa474f..edb77e7 100644
--- a/functions.c
+++ b/functions.c
@@ -550,6 +550,10 @@ int disconnectclient(int fd, struct client *clients, struct ircdstate *ircdstate
for (int i = 0; i < MAXCLIENTS; i++) {
if (clients[i].fd == fd) {
debugprint(DEBUG_FULL, "found and clearing fd %d from clients[%d]\n", fd, i);
+ // If the client was registered, record the time of the last client disconnect
+ if (clients[i].registered) {
+ ircdstate->clientchangetime = time(NULL);
+ }
clients[i].fd = 0;
clients[i].authed = 0;
clients[i].registered = 0;
@@ -569,6 +573,10 @@ int disconnectclient(int fd, struct client *clients, struct ircdstate *ircdstate
close(fd);
// Now clients array is cleared, inform all other clients (source "0" since we trust this message)
sendtoallclients(clients, alertmsg, 0, settings);
+ // If there are now no clients connected, record the time
+ if (numclients(clients) == 0) {
+ ircdstate->clientsnonetime = time(NULL);
+ }
return 1;
}
}
@@ -858,7 +866,7 @@ int doautoreplay(int sourcefd, struct client *clients, struct settings *settings
return 1;
}
- // If replaymode = "lastspoke" then send whatever replayseconds is set to
+ // 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);
@@ -874,6 +882,24 @@ int doautoreplay(int sourcefd, struct client *clients, struct settings *settings
return 1;
}
+ // 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");
+ return 0;
+ }
+ }
+
+ // 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");
+ return 0;
+ }
+ }
+
// We shouldn't get here
return 0;
}
@@ -1046,9 +1072,10 @@ int rehash(struct settings *settings, char *failuremsg) {
strcpy(failuremsg, "error getting 'replaymode' from configuration file");
return 0;
} else {
- if (strcmp(settings->replaymode, "none") && strcmp(settings->replaymode, "time") && strcmp(settings->replaymode, "lastspoke")) {
+ if (strcmp(settings->replaymode, "none") && strcmp(settings->replaymode, "time") && strcmp(settings->replaymode, "lastspoke") &&
+ strcmp(settings->replaymode, "noclients") && strcmp(settings->replaymode, "lastchange")) {
strcpy(settings->replaymode, oldreplaymode);
- strcpy(failuremsg, "replaymode in configuration file must be one of \"none\", \"time\", or \"lastspoke\"");
+ strcpy(failuremsg, "replaymode in configuration file must be one of \"none\", \"time\", \"lastspoke\", \"noclients\", or \"lastchange\"");
return 0;
}
}
diff --git a/message.c b/message.c
index 0137fd4..3e79605 100644
--- a/message.c
+++ b/message.c
@@ -950,6 +950,9 @@ int processclientmessage(SSL *server_ssl, char *str, struct client *clients, int
sendtoclient(sourcefd, outgoingmsg, clients, settings, 0);
}
+ // And record the time of the last client registration
+ ircdstate->clientchangetime = time(NULL);
+
return 1;
}
diff --git a/structures.h b/structures.h
index 3209b21..d1ec4b0 100644
--- a/structures.h
+++ b/structures.h
@@ -48,6 +48,8 @@ struct ircdstate {
int timeoutcheck; // Whether we're checking to see if we've timed out from the server
int reconnecting; // Whether or not we're reconnecting due to an earlier disconnection
char oldnick[MAXNICKLENGTH]; // Set temporarily if we end up reconnecting in case we need to tell existing clients about a nick change
+ int clientchangetime; // The last time a client registered or disconnected
+ int clientsnonetime; // The last time there were no clients registered
};
// Structure of settings either to be read from the configuration file or set/changed at runtime