From e1f41810ac85a0d210062ed33f43938dc4b03be4 Mon Sep 17 00:00:00 2001 From: Luke Bratch Date: Sat, 14 Sep 2019 17:57:07 +0100 Subject: Implement arrays in the configuration file and start using them to allow for multiple connect commands. --- config.c | 181 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 177 insertions(+), 4 deletions(-) (limited to 'config.c') diff --git a/config.c b/config.c index cea404c..842f389 100644 --- a/config.c +++ b/config.c @@ -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" -- cgit v1.2.3