Commit e1f41810 authored by Luke Bratch's avatar Luke Bratch
Browse files

Implement arrays in the configuration file and start using them to allow for...

Implement arrays in the configuration file and start using them to allow for multiple connect commands.
parent e546de81
......@@ -20,6 +20,9 @@ All arguments are optional, but they must be specified in the order shown above
An example configuration file is provided named "blabouncer.conf.example".
Configuration options are either simple single string options, or multiple line arrays. The usage is
explained in the example configuration file.
If you don't specify one using "-c /path/to/configuration/file" then the example one will be created
for you at $HOME/.blabouncer/blabouncer.conf when starting for the first time.
......
Support multiple connect commands.
Support arrays or similar in the configuration file (for nick(s), connectcommand(s), etc.)
Specify multiple nicks using configuration arrays.
All the TODOs sprinkled throughout the code!
......
......@@ -1025,9 +1025,21 @@ int main(int argc, char *argv[]) {
settings.ircserverpassword[0] = '\0';
}
// What is the connect command, if any?
if (!getconfstr("connectcommand", settings.conffile, settings.connectcommand)) {
settings.connectcommand[0] = '\0';
// What are the connect commands, if any?
int ret = getconfarr("connectcommands", settings.conffile, settings.connectcommands);
if (!ret) {
for (int i = 0; i < MAXCONFARR; i++) {
settings.connectcommands[i][0] = '\0';
}
} else if (ret == -1) {
// Remove any newlines from the middle of the string so error printing works nicely
for (size_t i = 0; i < strlen(settings.connectcommands[0]) - 1; i++) {
if (settings.connectcommands[0][i] == '\n') {
settings.connectcommands[0][i] = ' ';
}
}
printf("main(): error getting 'commandcommands' from configuration file: %s", settings.connectcommands[0]);
exit(1);
}
// Is the base directory set? If not, use the default.
......
......@@ -25,7 +25,7 @@ int getconfstr(char *confname, char *filename, char* dest) {
char str[MAXCHAR];
int found = 0; // Have we found the configuration option?
// Set strings to zero-length to begin
// Set string to zero-length to begin
dest[0] = '\0';
// Length of requested configuration option name
......@@ -105,6 +105,165 @@ int getconfstr(char *confname, char *filename, char* dest) {
return 1;
}
// Populates 'dest' with the values of the configuration array option
// with name 'confname' from configuration file 'filename'.
// Returns 1 on success, 0 on reading no values, or -1 on an error.
// On error, dest[0] is set to the error string for later retrieval.
int getconfarr(char *confname, char *filename, char dest[MAXCONFARR][MAXDATASIZE]) {
debugprint(DEBUG_FULL, "getconfarr(): '%s', '%s' and a dest array.\n", confname, filename);
FILE *fp;
char line[MAXCHAR];
int found = 0; // Have we found the configuration option?
int valuecount = 0; // Which element in the configuration array we are on
// Set strings to zero-length to begin
for (int i = 0; i < MAXCONFARR; i++) {
dest[i][0] = '\0';
}
// Length of requested configuration array name
long int namelen = strlen(confname);
fp = fopen(filename, "r");
if (fp == NULL) {
debugprint(DEBUG_CRIT, "error: could not open configuration file '%s'.\n", filename);
exit(1);
}
// Loop through the whole file, looking for the requested configuration array
while (fgets(line, MAXCHAR, fp) != NULL) {
// Don't bother with any of this if this line is a comment
int comment = 0;
for (size_t i = 0; i < strlen(line); i++) {
// Ignore spaces/tabs
if (line[i] == ' ' || line[i] == '\t') {
continue;
} else if (line[i] == '#') {
// If it's a comment, ignore the line
comment = 1;
break;
} else {
// Found something else before a comment, so carry on
break;
}
}
if (comment) {
continue;
}
// If we haven't found our array yet, try to find the opening line
if (!found) {
char substr[MAXCHAR];
// Check if the next character after the length of the requested array
// name is an equals sign, a space, or a tab
if (line[namelen] != '=' && line[namelen] != ' ' && line[namelen] != '\t') {
// If it isn't this can't have been our array
continue;
}
// Copy the number of characters that the requested array name is long
// to a temporary string
strncpy(substr, line, namelen);
substr[namelen] = '\0';
// If the resulting temporary string contains the requested array name,
// we have found our configuration array
if (strstr(substr, confname)) {
// Make sure it is a valid start of array line
for (size_t i = namelen; i < strlen(line); i++) {
if (line[i] == ' ' || line[i] == '\t' || line[i] == '=') {
// Ignore spaces, tabs and equals signs
continue;
} else if (line[i] == '{') {
// Success, found an opening brace
// Ignore anything else on this line
found = 1;
break;
} else {
// Unexpected character found, return failure
snprintf(dest[0], MAXDATASIZE, "Unexpected character '%c' found on configuration array opening line for '%s'.\n", line[i], confname);
fclose(fp);
return -1;
}
}
}
// If we have found our array, extract the value from each line in it
} else {
int valuelen = 0;
int inquotes = 0;
for (size_t i = 0; i < strlen(line); i++) {
// If we've on the closing brace line, then we're done
if (line[i] == '}') {
for (int i = 0; i < valuecount; i++) {
debugprint(DEBUG_FULL, "getconfstr(): returning '%s'.\n", dest[i]);
}
// Close fine and return success (or 0 if no values found in an otherwise valid array)
fclose(fp);
if (valuecount) {
return 1;
} else {
return 0;
}
}
// If not in the quotes yet
if (!inquotes) {
// Skip over initial spaces and tabs
if (line[i] == ' ' || line[i] == '\t') {
continue;
} else if (line[i] == '"') {
// Quotes found, we're now reading the value
inquotes = 1;
continue;
} else {
// Unexpected character found, return failure
snprintf(dest[0], MAXDATASIZE, "Unexpected character '%c' found before opening quotes on array line for '%s'.\n", line[i], confname);
fclose(fp);
return -1;
}
// If inside the quotes (so, we've got to the actual value)
} else if (inquotes) {
// If we're on the last character and it isn't a closing quote, something is wrong
if (i == strlen(line) - 1 && line[i] != '"') {
snprintf(dest[0], MAXDATASIZE, "Reached end of line without finding closing quotes on array line for '%s'.\n", confname);
fclose(fp);
return -1;
}
// If we've found too many values, return an error
if (valuecount > MAXCONFARR) {
snprintf(dest[0], MAXDATASIZE, "Too many elements defined for configuration array '%s', maximum number is '%d'.\n", confname, MAXCONFARR);
fclose(fp);
return -1;
}
// Otherwise, copy everything that isn't the closing quotes to the current element in the dest array
if (line[i] != '"') {
dest[valuecount][valuelen] = line[i];
valuelen++;
continue;
} else {
// When we find the closing quotes, the value is read, so terminate the dest array element string
dest[valuecount][valuelen] = '\0';
// We're done with this value, ignore anything that may be after the closing quotes on this line
valuecount++;
break;
}
}
}
}
}
// If we get this far, then something went wrong
snprintf(dest[0], MAXDATASIZE, "getconfarr(): didn't find any configuration array for '%s'.\n", confname);
fclose(fp);
return 0;
}
// Returns the value of the configuration option with name
// 'confname' from configuration file 'filename'.
// Sets errno to 0 on success, or ECONFINT if it fails, in which case the return value is undefined.
......@@ -153,11 +312,22 @@ int createconfigfile(char *filename) {
char *string =
"# blabouncer configuration file\n"
"#\n"
"# Entries must be in the form:\n"
"# Normal entries must be in the form:\n"
"# option name, space, equals sign, space, double quote, option value, double quote\n"
"# e.g.\n"
"# realname = \"Mr Bla Bouncer\"\n"
"#\n"
"# Array entries must be in the form:\n"
"# option name, space, equals sign, space, open brace\n"
"# (optional indentation,) double quote, element value, double quoute\n"
"# (optional multiple values to be repeated after the first one(s))\n"
"# close brace\n"
"# e.g.\n"
"# connectcommands = {\n"
"# \"PRIVMSG NickServ IDENTIFY bananas\"\n"
"# \"PRIVMSG myfriend I'm online!\"\n"
"# }\n"
"#\n"
"# Shell expansion is not supported, so do not try and specify e.g.\n"
"# \"~/.blabouncer/\" or \"$HOME/.blabouncer/\", instead use \"/home/foo/.blabouncer\"\n"
"#\n"
......@@ -210,8 +380,11 @@ int createconfigfile(char *filename) {
"# Real IRC server password\n"
"#ircserverpassword = \"apples\"\n"
"\n"
"# Command to send to the server upon completing registration (e.g. a NickServ password)\n"
"#connectcommand \"PRIVMSG NickServ IDENTIFY bananas\"\n"
"# Command(s) to send to the server upon completing registration (e.g. a NickServ password)\n"
"#connectcommands = {\n"
"# \"PRIVMSG NickServ IDENTIFY bananas\"\n"
"# \"PRIVMSG myfriend I'm online!\"\n"
"#}\n"
"\n"
"# Base directory (defaults to $HOME/.blabouncer/)\n"
"# Things such as the logs directory will be placed below this\n"
......
......@@ -40,6 +40,12 @@
// getconfstr() returns.
int getconfstr(char *confname, char *filename, char* dest);
// Populates 'dest' with the values of the configuration array option
// with name 'confname' from configuration file 'filename'.
// Returns 1 on success, 0 on reading no values, or -1 on an error.
// On error, dest[0] is set to the error string for later retrieval.
int getconfarr(char *confname, char *filename, char dest[MAXCONFARR][MAXDATASIZE]);
// Returns the value of the configuration option with name
// 'confname' from configuration file 'filename'.
// Sets errno to 0 on success, or ECONFINT if it fails, in which case the return value is undefined.
......
......@@ -89,9 +89,11 @@ int processservermessage(SSL *server_ssl, char *str, struct client *clients, int
// Receiving greeting 004 means we're now registered
// Request IRCv3 multi-prefix extension so we can more accurately inform new clients about current user prefixes
sendtoserver(server_ssl, "CAP REQ multi-prefix", strlen("CAP REQ multi-prefix"), 0, clients, settings);
// Send the connect command, if set
if (settings->connectcommand[0]) {
sendtoserver(server_ssl, settings->connectcommand, strlen(settings->connectcommand), 0, clients, settings);
// Send any configured connect commands
for (int i = 0; i < MAXCONFARR; i++) {
if (settings->connectcommands[i][0]) {
sendtoserver(server_ssl, settings->connectcommands[i], strlen(settings->connectcommands[i]), 0, clients, settings);
}
}
// If this is a reconnection, JOIN existing channels and catch clients up again
if (ircdstate->reconnecting) {
......
......@@ -29,6 +29,7 @@
#define MAXAUTOCHANLEN 1024 // Randomly picked maximum length of the auto channel list
#define CLIENTCODELEN 17 // Max length of a client code + 1 for null
#define MAXCLIENTCODES 64 // Max number of client codes to track
#define MAXCONFARR 10 // Max number of entries that a configuration array can have
struct ircdstate {
char greeting001[MAXDATASIZE];
......@@ -70,7 +71,7 @@ struct settings {
char ircserver[HOST_NAME_MAX];
char ircserverport[MAXPORTLEN];
char ircserverpassword[MAXDATASIZE - 5]; // -5 for "PASS "
char connectcommand[MAXDATASIZE];
char connectcommands[MAXCONFARR][MAXDATASIZE];
char conffile[PATH_MAX];
char certfile[PATH_MAX];
char keyfile[PATH_MAX];
......
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