Commit 4dea4c16 authored by Luke Bratch's avatar Luke Bratch

Specify multiple nicks using a configuration array instead of multiple individual settings.

parent e1f41810
......@@ -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
......
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.)
......
......@@ -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';
......
# 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
......
......@@ -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"
......
......@@ -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?
......
......@@ -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];
......
......@@ -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];
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment