summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Bratch <luke@bratch.co.uk>2019-09-14 20:44:32 +0100
committerLuke Bratch <luke@bratch.co.uk>2019-09-14 20:44:32 +0100
commit4dea4c16313ba3d1575cfa6722d75492c907f551 (patch)
treecade95813a471e3aa4597a5a35e907e2cd675181
parente1f41810ac85a0d210062ed33f43938dc4b03be4 (diff)
Specify multiple nicks using a configuration array instead of multiple individual settings.
-rw-r--r--README4
-rw-r--r--TODO2
-rw-r--r--blabouncer.c39
-rw-r--r--blabouncer.conf.example31
-rw-r--r--config.c11
-rw-r--r--functions.c66
-rw-r--r--message.c61
-rw-r--r--structures.h6
8 files changed, 129 insertions, 91 deletions
diff --git a/README b/README
index e2a026f..c688dae 100644
--- a/README
+++ b/README
@@ -30,9 +30,7 @@ Certain configuration options can be changed at runtime by changing them in the
issuing a BLABOUNCER REHASH command, or by sending SIGHUP to the blabouncer process.
These options can be changed by issuing a BLABOUNCER REHASH command or by sending SIGHUP to blabouncer:
- - nick
- - nick2
- - nick3
+ - nicks
- replaymode
- replayseconds
- replaydates
diff --git a/TODO b/TODO
index 7b94d3d..68e0122 100644
--- a/TODO
+++ b/TODO
@@ -1,5 +1,3 @@
-Specify multiple nicks using configuration arrays.
-
All the TODOs sprinkled throughout the code!
Is there a way to log nick changes to the normal log despite not tracking nicks in each channel? (We do track channel names themselves.)
diff --git a/blabouncer.c b/blabouncer.c
index e6a56c1..772b969 100644
--- a/blabouncer.c
+++ b/blabouncer.c
@@ -137,8 +137,8 @@ int connecttoircserver(SSL_CTX **serverctx, SSL **server_ssl, int *serversockfd,
// ircdstate.clientchangetime and ircdstate.clientsnonetime not set here as they are set at startup and only changed when clients connect/disconnect
// ircdstate.clientcodes not set here, set on startup and whenever a client sets one
- // 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);
+ // Populate nicks[0] and username from our configuration file for now, real IRCd may change them later (TODO - Is this true of username?)
+ strcpy(ircdstate->ircnick, settings->ircnicks[0]);
strcpy(ircdstate->ircusername, settings->ircusername);
// Send the server password if one was configured
@@ -967,22 +967,27 @@ int main(int argc, char *argv[]) {
exit(1);
}
- // What is the configured nick?
- if (!getconfstr("nick", settings.conffile, settings.ircnick)) {
- printf("main(): error getting 'nick' from configuration file.\n");
+ // What are the configured nick(s)?
+ int ret = getconfarr("nicks", settings.conffile, settings.ircnicks);
+ if (!ret) {
+ printf("main(): error getting any 'nicks' from configuration file.\n");
+ } else if (ret == -1) {
+ // Error reading an array line from the configuration file
+ // Remove any newlines from the middle of the string so error printing works nicely
+ for (size_t i = 0; i < strlen(settings.ircnicks[0]) - 1; i++) {
+ if (settings.ircnicks[0][i] == '\n') {
+ settings.ircnicks[0][i] = ' ';
+ }
+ }
+ printf("main(): error getting 'nicks' from configuration file: %s", settings.ircnicks[0]);
exit(1);
}
-
- // What is the configured nick2?
- if (!getconfstr("nick2", settings.conffile, settings.ircnick2)) {
- // Not configured, set to blank string
- settings.ircnick2[0] = '\0';
- }
-
- // What is the configured nick3?
- if (!getconfstr("nick3", settings.conffile, settings.ircnick3)) {
- // Not configured, set to blank string
- settings.ircnick3[0] = '\0';
+ // Make sure nicks aren't too long (since getconfarr() has to use MAXDATASIZE for all string lengths)
+ for (int i = 0; i < MAXCONFARR; i++) {
+ if (settings.ircnicks[i][0] && strlen(settings.ircnicks[i]) > MAXNICKLENGTH) {
+ printf("main(): error: specified nick '%s' is too long, maximum length is %d.\n", settings.ircnicks[i], MAXNICKLENGTH);
+ exit(1);
+ }
}
// What is the configured username?
@@ -1026,7 +1031,7 @@ int main(int argc, char *argv[]) {
}
// What are the connect commands, if any?
- int ret = getconfarr("connectcommands", settings.conffile, settings.connectcommands);
+ ret = getconfarr("connectcommands", settings.conffile, settings.connectcommands);
if (!ret) {
for (int i = 0; i < MAXCONFARR; i++) {
settings.connectcommands[i][0] = '\0';
diff --git a/blabouncer.conf.example b/blabouncer.conf.example
index 12727c9..0513fdc 100644
--- a/blabouncer.conf.example
+++ b/blabouncer.conf.example
@@ -1,18 +1,34 @@
# blabouncer configuration file
#
-# Entries must be in the form:
+# Normal entries must be in the form:
# option name, space, equals sign, space, double quote, option value, double quote
# e.g.
# realname = "Mr Bla Bouncer"
#
+# Array entries must be in the form:
+# option name, space, equals sign, space, open brace
+# (optional indentation,) double quote, element value, double quoute
+# (optional multiple values to be repeated after the first one(s))
+# close brace
+# e.g.
+# connectcommands = {
+# "PRIVMSG NickServ IDENTIFY bananas"
+# "PRIVMSG myfriend I'm online!"
+# }
+#
# Shell expansion is not supported, so do not try and specify e.g.
# "~/.blabouncer/" or "$HOME/.blabouncer/", instead use "/home/foo/.blabouncer"
#
# Some settings can be reloaded at runtime, please refer to README for details.
-nick = "blabounce"
-nick2 = "bbounce2"
-nick3 = "bbounce3"
+# Nick(s) to use when connecting - will be cycled through in order in the event of
+# a nick being in use or invalid
+nicks = {
+ "blabounce"
+ "bbounce2"
+ "bbounce3"
+}
+
username = "bounceusr"
realname = "Mr Bla Bouncer"
@@ -57,8 +73,11 @@ ircserverport = "6697"
# Real IRC server password
#ircserverpassword = "apples"
-# Command to send to the server upon completing registration (e.g. a NickServ password)
-#connectcommand "PRIVMSG NickServ IDENTIFY bananas"
+# Command(s) to send to the server upon completing registration (e.g. a NickServ password)
+#connectcommands = {
+# "PRIVMSG NickServ IDENTIFY bananas"
+# "PRIVMSG myfriend I'm online!"
+#}
# Base directory (defaults to $HOME/.blabouncer/)
# Things such as the logs directory will be placed below this
diff --git a/config.c b/config.c
index 842f389..5b706b0 100644
--- a/config.c
+++ b/config.c
@@ -333,9 +333,14 @@ int createconfigfile(char *filename) {
"#\n"
"# Some settings can be reloaded at runtime, please refer to README for details.\n"
"\n"
- "nick = \"blabounce\"\n"
- "nick2 = \"bbounce2\"\n"
- "nick3 = \"bbounce3\"\n"
+ "# Nick(s) to use when connecting - will be cycled through in order in the event of\n"
+ "# a nick being in use or invalid\n"
+ "nicks = {\n"
+ " \"blabounce\"\n"
+ " \"bbounce2\"\n"
+ " \"bbounce3\"\n"
+ "}\n"
+ "\n"
"username = \"bounceusr\"\n"
"realname = \"Mr Bla Bouncer\"\n"
"\n"
diff --git a/functions.c b/functions.c
index af8d5dd..fe96e0a 100644
--- a/functions.c
+++ b/functions.c
@@ -1086,31 +1086,51 @@ void cleanexit(SSL *server_ssl, struct client *clients, int sourcefd, struct irc
int rehash(struct settings *settings, char *failuremsg) {
// TODO - Try to share some/all of this code with the initial main() settings loading
- // What is the nick?
- char oldircnick[MAXNICKLENGTH];
- strcpy(oldircnick, settings->ircnick);
- if (!getconfstr("nick", settings->conffile, settings->ircnick)) {
- strcpy(settings->ircnick, oldircnick);
- strcpy(failuremsg, "error getting 'nick' from configuration file");
+ // What are the configured nick(s)?
+ char oldircnicks[MAXCONFARR][MAXDATASIZE];
+ // Backup the existing configured nicks in case this rehash fails
+ for (int i = 0; i < MAXCONFARR; i++) {
+ strcpy(oldircnicks[i], settings->ircnicks[i]);
+ }
+ int ret = getconfarr("nicks", settings->conffile, settings->ircnicks);
+ if (!ret) {
+ // No nicks read, copy the old ones back
+ for (int i = 0; i < MAXCONFARR; i++) {
+ strcpy(settings->ircnicks[i], oldircnicks[i]);
+ }
+ strcpy(failuremsg, "error getting any 'nicks' from configuration file");
+ return 0;
+ } else if (ret == -1) {
+ // Error reading an array line from the configuration file
+ // Remove any newlines from the string so error printing works nicely
+ for (size_t i = 0; i < strlen(settings->ircnicks[0]); i++) {
+ if (settings->ircnicks[0][i] == '\n') {
+ settings->ircnicks[0][i] = ' ';
+ }
+ }
+ if (!snprintf(failuremsg, MAXDATASIZE, "error getting 'nicks' from configuration file: %s", settings->ircnicks[0])) {
+ debugprint(DEBUG_CRIT, "Error while preparing nick error response!\n");
+ strcpy(failuremsg, "Error while preparing nick error response!");
+ }
+ // Copy the old ones back (after setting failuremsg so we can read the error string from element 0)
+ for (int i = 0; i < MAXCONFARR; i++) {
+ strcpy(settings->ircnicks[i], oldircnicks[i]);
+ }
return 0;
}
-
- // What is nick2?
- char oldircnick2[MAXNICKLENGTH];
- strcpy(oldircnick2, settings->ircnick2);
- if (!getconfstr("nick2", settings->conffile, settings->ircnick2)) {
- strcpy(settings->ircnick2, oldircnick2);
- // Not configured, set to blank string
- settings->ircnick2[0] = '\0';
- }
-
- // What is nick3?
- char oldircnick3[MAXNICKLENGTH];
- strcpy(oldircnick3, settings->ircnick3);
- if (!getconfstr("nick3", settings->conffile, settings->ircnick3)) {
- strcpy(settings->ircnick3, oldircnick3);
- // Not configured, set to blank string
- settings->ircnick3[0] = '\0';
+ // Make sure nicks aren't too long (since getconfarr() has to use MAXDATASIZE for all string lengths)
+ for (int i = 0; i < MAXCONFARR; i++) {
+ if (settings->ircnicks[i][0] && strlen(settings->ircnicks[i]) > MAXNICKLENGTH) {
+ // A nick is too long, copy the old ones back
+ for (int i = 0; i < MAXCONFARR; i++) {
+ strcpy(settings->ircnicks[i], oldircnicks[i]);
+ }
+ if (!snprintf(failuremsg, MAXDATASIZE, "error: specified nick '%s' is too long, maximum length is %d.\n", settings->ircnicks[i], MAXNICKLENGTH)) {
+ debugprint(DEBUG_CRIT, "Error while preparing nick too long response!\n");
+ strcpy(failuremsg, "Error while preparing nick too long response!");
+ }
+ return 0;
+ }
}
// What is the auto replay mode?
diff --git a/message.c b/message.c
index 3887ec9..ed27173 100644
--- a/message.c
+++ b/message.c
@@ -64,6 +64,16 @@ int processservermessage(SSL *server_ssl, char *str, struct client *clients, int
// Null the end of the new string
ircdstate->nickuserhost[strlen(tokens[counter - 1]) + 1] = '\0'; // +1 for the inserted colon
debugprint(DEBUG_FULL, "nickuserhost '%s' stored.\n", ircdstate->nickuserhost);
+ // Set our current ircnick based on whatever was in greeting 001
+ if (counter >= 3) {
+ // Assuming there at least three tokens (:ircdname 001 nick etc.) then store the nick
+ strcpy(ircdstate->ircnick, tokens[2]);
+ debugprint(DEBUG_FULL, "Updated ircnick to '%s' from greeting 001.\n", ircdstate->ircnick);
+ } else {
+ // Something has gone fairly wrong with greeting 001
+ debugprint(DEBUG_CRIT, "Greeting 001 ('%s') is not long enough, don't know how to proceed, exiting...\n", str);
+ exit(1);
+ }
return 1;
} else if (strncmp(tokens[1], "002", strlen(tokens[1])) == 0) {
debugprint(DEBUG_FULL, "Found greeting 002 (%s), storing in ircdstate struct.\n", str);
@@ -642,42 +652,27 @@ int processservermessage(SSL *server_ssl, char *str, struct client *clients, int
debugprint(DEBUG_SOME, "Server 432 (ERR_ERRONEUSNICKNAME) or 433 (ERR_NICKNAMEINUSE) found and it is: %s with length %zd! Trying another nick...\n",
tokens[1], strlen(tokens[1]));
- // Do we have both a nick2 and a nick3? (And not tried autonick yet.)
- if (settings->ircnick2[0] && settings->ircnick3[0] && !ircdstate->autonicknum) {
- // Has nick3 already been tried?
- if (strncmp(ircdstate->ircnick, settings->ircnick3, strlen(settings->ircnick)) == 0) {
- // Then try autonick
- tryautonick(ircdstate);
- // Has nick2 already been tried?
- } else if (strncmp(ircdstate->ircnick, settings->ircnick2, strlen(settings->ircnick)) == 0) {
- // Then try nick3
- debugprint(DEBUG_SOME, "Trying nick3, nick2 was already tried.\n");
- strcpy(ircdstate->ircnick, settings->ircnick3);
- // Have neither been tried?
- } else {
- // Then try nick2
- debugprint(DEBUG_SOME, "Trying nick2, nick3 is also configured.\n");
- strcpy(ircdstate->ircnick, settings->ircnick2);
- }
- // Do we only have a nick2? (And not tried autonick yet.)
- } else if (settings->ircnick2[0] && !ircdstate->autonicknum) {
- // Has it already been tried?
- if (strncmp(ircdstate->ircnick, settings->ircnick2, strlen(settings->ircnick)) == 0) {
- // Then try autonick
- tryautonick(ircdstate);
- } else {
- // Then try it
- debugprint(DEBUG_SOME, "Trying nick2, nick3 is not configured.\n");
- strcpy(ircdstate->ircnick, settings->ircnick2);
+ // Find the nick (its index in the nicks array) currently selected
+ int nickindex = -1; // -1 used later if current nick isn't in the configuration array
+ int nickcount = 0; // How many nicks are configured in the configuration array
+ for (int i = 0; i < MAXCONFARR; i++) {
+ if (settings->ircnicks[i][0]) {
+ nickcount++;
+ if (strncmp(ircdstate->ircnick, settings->ircnicks[i], strlen(settings->ircnicks[i])) == 0 && strlen(ircdstate->ircnick) == strlen(settings->ircnicks[i])) {
+ nickindex = i;
+ }
}
- // Do we have neither? (Or have already started autonick.)
- } else {
- // Then try autonick
- tryautonick(ircdstate);
}
- // Set whichever one we settled on in the settings in case we reference settings later
- strcpy(settings->ircnick, ircdstate->ircnick);
+ // If there are more nicks left to try, then try the next one
+ if (nickindex < nickcount - 1) {
+ strcpy(ircdstate->ircnick, settings->ircnicks[nickindex + 1]);
+ debugprint(DEBUG_SOME, "Switched nick to '%s' and retrying...\n", ircdstate->ircnick);
+ // Otherwise, give up on configured nicks and switch to autonick
+ } else {
+ debugprint(DEBUG_SOME, "Giving up on preconfigured nicks trying autonick...\n", ircdstate->ircnick);
+ tryautonick(ircdstate);
+ }
// Try it with the server
char outgoingmsg[MAXDATASIZE];
diff --git a/structures.h b/structures.h
index 8a99163..8d68083 100644
--- a/structures.h
+++ b/structures.h
@@ -39,7 +39,7 @@ struct ircdstate {
char greeting005a[MAXDATASIZE];
char greeting005b[MAXDATASIZE];
char greeting005c[MAXDATASIZE];
- char ircdname[MAXDATASIZE];
+ char ircdname[MAXDATASIZE]; // In both settings and ircdstate as settings is from our file whereas server may change ircdstate copy
char nickuserhost[MAXDATASIZE];
char ircnick[MAXNICKLENGTH];
char ircusername[MAXUSERNAMELEN];
@@ -61,9 +61,7 @@ struct settings {
char replaymode[MAXDATASIZE];
int replayseconds;
char clientport[MAXPORTLEN];
- char ircnick[MAXNICKLENGTH]; // In both settings and ircdstate as settings is from our file whereas server may change ircdstate copy
- char ircnick2[MAXNICKLENGTH];
- char ircnick3[MAXNICKLENGTH];
+ char ircnicks[MAXCONFARR][MAXDATASIZE]; // MAXDATASIZE instead of MAXNICKLENGTH so getconfarr() only has one string size to deal with
char ircusername[MAXUSERNAMELEN]; // (Is this also true for the username? Can the server change that?)
char ircrealname[MAXREALNAMELEN];
char password[MAXDATASIZE];