diff options
author | Luke Bratch <luke@bratch.co.uk> | 2019-05-11 15:01:22 +0100 |
---|---|---|
committer | Luke Bratch <luke@bratch.co.uk> | 2019-05-11 15:01:22 +0100 |
commit | c46d01b5afd2da4779efb2700469037eca6122be (patch) | |
tree | 9db52afe3643c0643414dcf638fa579176b62487 | |
parent | d950304536f870ad989e0049e4e8b4a5a72a9315 (diff) |
Implement a configuration file reader, an example configuration file, and start reading nick/username/realname from it instead of being statically defined.
-rw-r--r-- | Makefile | 6 | ||||
-rw-r--r-- | blabouncer.c | 53 | ||||
-rw-r--r-- | blabouncer.conf | 9 | ||||
-rw-r--r-- | config.c | 103 | ||||
-rw-r--r-- | config.h | 12 |
5 files changed, 158 insertions, 25 deletions
@@ -1,8 +1,8 @@ CC=gcc -DEPS = functions.h sockets.h +DEPS = functions.h sockets.h config.h %.o: %.c $(DEPS) $(CC) -Wall -Wextra -c -o $@ $< -blabouncer: blabouncer.o functions.o sockets.o - $(CC) -Wall -Wextra -o blabouncer blabouncer.o functions.o sockets.o +blabouncer: blabouncer.o functions.o sockets.o config.o + $(CC) -Wall -Wextra -o blabouncer blabouncer.o functions.o sockets.o config.o diff --git a/blabouncer.c b/blabouncer.c index 80d6940..ba9dca0 100644 --- a/blabouncer.c +++ b/blabouncer.c @@ -8,6 +8,7 @@ // - Add blabouncer MOTD (375, 372, 376) // - "01:53:47 -!- ServerMode/#test [b] by irc.tghost.co.uk" on existing clients when new client connects // - Keep track of changing user nicks/modes +// - Relay log can just be "log/resend everything that ever hit sendto[all]client[s]()" // // Example WHOIS reply: // BOUNCER-SERVER RECEIVED: :irc.tghost.co.uk 307 blabounce l_bratch :is identified for this nick @@ -30,6 +31,7 @@ #include "functions.h" #include "sockets.h" +#include "config.h" #define SOURCE_SERVER 0 #define SOURCE_CLIENT 1 @@ -44,10 +46,8 @@ #define MAXCHANLENGTH 50 // 50 according to RFC 2811 and RFC 2822 #define MAXCHANUSERS 8192 // Randomly picked (TODO - is there an actual maximum number of users per channel?) #define MAXNICKLENGTH 64 // Randomly picked (TODO - is there an actual maximum number (ignoring the RFC preference of 9)?) - -#define IRCNICK "blabounce" // TODO: change this to a config option! -#define IRCUSER "blabounce" // TODO: change this to a config option! -#define IRCREALNAME "Mr Bla Bouncer" // TODO: change this to a config option! +#define MAXUSERNAMELEN 64 // Randomly picked (TODO - is there an actual maximum username length?) +#define MAXREALNAMELEN 128 // Randomly picked (TODO - is there an actual maximum real name length?) struct channel { char name[MAXCHANLENGTH]; @@ -68,6 +68,9 @@ struct ircdstrings { char greeting004[MAXDATASIZE]; char ircdname[MAXDATASIZE]; char nickuserhost[MAXDATASIZE]; // TODO - Make sure this changes when nick changes, if that's meant to happen. + char ircnick[MAXNICKLENGTH]; // TODO - Make sure this changes when nick changes + char ircusername[MAXUSERNAMELEN]; + char ircrealname[MAXREALNAMELEN]; }; int debugmode = 0; @@ -589,7 +592,7 @@ int processircmessage(int *serversockfd, int *clientsockfd, char *str, int sourc // If there isn't one set (we guess this if topic timestamp is 0), send 331 RPL_NOTOPIC if (strncmp(channels[i].topicwhen, "0", 1) == 0) { // Prepare the no topic message... - if (!snprintf(outgoingmsg, MAXDATASIZE, ":%s 331 %s %s :No topic is set.", ircdstrings->ircdname, IRCNICK, channels[i].name)) { + if (!snprintf(outgoingmsg, MAXDATASIZE, ":%s 331 %s %s :No topic is set.", ircdstrings->ircdname, ircdstrings->ircnick, channels[i].name)) { fprintf(stderr, "Error while preparing USER just connected, channel JOIN responses, 331 RPL_NOTOPIC!\n"); exit(1); } @@ -598,7 +601,7 @@ int processircmessage(int *serversockfd, int *clientsockfd, char *str, int sourc // If there is one set, send 332 RPL_TOPIC and 333 RPL_TOPICWHOTIME } else { // Prepare the topic message... - if (!snprintf(outgoingmsg, MAXDATASIZE, ":%s 332 %s %s :%s", ircdstrings->ircdname, IRCNICK, channels[i].name, channels[i].topic)) { + if (!snprintf(outgoingmsg, MAXDATASIZE, ":%s 332 %s %s :%s", ircdstrings->ircdname, ircdstrings->ircnick, channels[i].name, channels[i].topic)) { fprintf(stderr, "Error while preparing USER just connected, channel JOIN responses, 332 RPL_TOPIC!\n"); exit(1); } @@ -606,7 +609,7 @@ int processircmessage(int *serversockfd, int *clientsockfd, char *str, int sourc sendtoclient(sourcefd, outgoingmsg); // Next prepare the topic who/when message... - if (!snprintf(outgoingmsg, MAXDATASIZE, ":%s 333 %s %s %s %s", ircdstrings->ircdname, IRCNICK, channels[i].name, channels[i].topicwho, channels[i].topicwhen)) { + if (!snprintf(outgoingmsg, MAXDATASIZE, ":%s 333 %s %s %s %s", ircdstrings->ircdname, ircdstrings->ircnick, channels[i].name, channels[i].topicwho, channels[i].topicwhen)) { fprintf(stderr, "Error while preparing USER just connected, channel JOIN responses, 333 RPL_TOPICWHOTIME!\n"); exit(1); } @@ -627,7 +630,7 @@ int processircmessage(int *serversockfd, int *clientsockfd, char *str, int sourc continue; } // If there was a nick found, send it to the client (one per line at the moment - TODO - batch them up into fewer lines) - if (!snprintf(outgoingmsg, MAXDATASIZE, ":%s 353 %s %s %s :%s", ircdstrings->ircdname, IRCNICK, channels[i].namestype, channels[i].name, channels[i].nicks[j])) { + if (!snprintf(outgoingmsg, MAXDATASIZE, ":%s 353 %s %s %s :%s", ircdstrings->ircdname, ircdstrings->ircnick, channels[i].namestype, channels[i].name, channels[i].nicks[j])) { fprintf(stderr, "Error while preparing USER just connected, channel NAMES responses!\n"); exit(1); } @@ -635,7 +638,7 @@ int processircmessage(int *serversockfd, int *clientsockfd, char *str, int sourc } // Once all names are sent, send the "end of /NAMES" 366 (RPL_ENDOFNAMES) message - if (!snprintf(outgoingmsg, MAXDATASIZE, ":%s 366 %s %s :End of /NAMES list.", ircdstrings->ircdname, IRCNICK, channels[i].name)) { + if (!snprintf(outgoingmsg, MAXDATASIZE, ":%s 366 %s %s :End of /NAMES list.", ircdstrings->ircdname, ircdstrings->ircnick, channels[i].name)) { fprintf(stderr, "Error while preparing USER just connected, end of NAMES response!\n"); exit(1); } @@ -852,29 +855,35 @@ void dochat(int *serversockfd, int *clientsockfd) { // Registered with the IRCd yet? ////////////// int registered = 0; + // Struct of various strings from and for the real IRCd (such as the greeting strings, the real IRCd's name, + // our nick!user@host string, our nick, username, real name, etc.) + struct ircdstrings ircdstrings; + // Set them to zero-length strings for now + ircdstrings.greeting001[0] = '\0'; + ircdstrings.greeting002[0] = '\0'; + ircdstrings.greeting003[0] = '\0'; + ircdstrings.greeting004[0] = '\0'; + ircdstrings.ircdname[0] = '\0'; + ircdstrings.nickuserhost[0] = '\0'; + ircdstrings.ircnick[0] = '\0'; + ircdstrings.ircusername[0] = '\0'; + ircdstrings.ircrealname[0] = '\0'; + + // Read required things from configuration file + readnames(ircdstrings.ircnick, ircdstrings.ircusername, ircdstrings.ircrealname); + // Send our NICK - snprintf(outgoingmsg, MAXDATASIZE, "NICK %s", IRCNICK); // TODO - Check for success (with return code) + snprintf(outgoingmsg, MAXDATASIZE, "NICK %s", ircdstrings.ircnick); // TODO - Check for success (with return code) sendtoserver(serversockfd, outgoingmsg, strlen(outgoingmsg)); // Send our USER - snprintf(outgoingmsg, MAXDATASIZE, "USER %s 8 * : %s", IRCUSER, IRCREALNAME); // TODO - Check for success (with return code) + snprintf(outgoingmsg, MAXDATASIZE, "USER %s 8 * : %s", ircdstrings.ircusername, ircdstrings.ircrealname); // TODO - Check for success (with return code) // TODO - Send a more intelligent/correct USER string sendtoserver(serversockfd, outgoingmsg, strlen(outgoingmsg)); // Struct of channels we're in struct channel *channels; channels = malloc(sizeof(struct channel) * MAXCHANNELS); - - // Struct of various strings from the real IRCd (such as the greeting strings, the real IRCd's name, our nick!user@host string, etc.) - struct ircdstrings ircdstrings; - // Set them to zero-length strings for now - ircdstrings.greeting001[0] = '\0'; - ircdstrings.greeting002[0] = '\0'; - ircdstrings.greeting003[0] = '\0'; - ircdstrings.greeting004[0] = '\0'; - ircdstrings.ircdname[0] = '\0'; - ircdstrings.nickuserhost[0] = '\0'; - // =============================================> while (1) { diff --git a/blabouncer.conf b/blabouncer.conf new file mode 100644 index 0000000..4f569dd --- /dev/null +++ b/blabouncer.conf @@ -0,0 +1,9 @@ +# blabouncer configuration file +# Entries must be in the form: +# option name, space, equals sign, space, double quote, option value, double quote +# e.g. +# realname = "Mr Bla Bouncer" + +nick = "blabounce" +username = "blabounce" +realname = "Mr Bla Bouncer" diff --git a/config.c b/config.c new file mode 100644 index 0000000..ca6b158 --- /dev/null +++ b/config.c @@ -0,0 +1,103 @@ +#include "config.h" + +// Check to see if a line is the configuration option specified by +// checking to see if str starts with conf followed by a space, a tab, +// or an equals sign. +// Returns the length of the name of the requested option if found, or +// zero if not. +long int isconf(char *str, char *conf) { + char *ret; + char substr[MAXCHAR]; + long int len = strlen(conf); + + // Ensure the next character is an equals sign, a space, or a tab + if (str[len] != '=' && str[len] != ' ' && str[len] != ' ') { + return 0; + } + + strncpy(substr, str, len); + substr[len] = '\0'; + + + if (!(ret = strstr(substr, conf)) == 0) { + return len; + } + + return 0; +} + +// Extracts the value of a configuration option from a string. Expects +// to receive the string and the number of characters long that the +// configuration option name is. +void getconf(char *str, long int start) { + long int len = strlen(str); + long int pos; + char conf[MAXCHAR]; + + for (long int i = start; i < len; i++) { + if (str[i] == '=' || str[i] == ' ' || str[i] == ' ') { + continue; + } else { + pos = i; + break; + } + } + + strncpy(conf, str + pos, len - pos - 1); // Copy remainder to new string and lop off the newline + conf[len - pos - 1] = '\0'; // Null terminate + + // Check for start and end quotes + if (conf[0] != '"' || conf[strlen(conf) - 1] != '"') { + printf("Error reading configuration option, not enclosed in double quotes!\n"); + exit(1); + } + + strncpy(str, conf + 1, strlen(conf) - 2); // Copy result back to original string without quotes + str[strlen(conf) - 2] = '\0'; // Null terminate +} + +int readnames(char *nick, char *username, char *realname) { + FILE *fp; + char str[MAXCHAR]; + char* filename = "blabouncer.conf"; + + // Set all strings to zero-length to begin + nick[0] = '\0'; + username[0] = '\0'; + realname[0] = '\0'; + + fp = fopen(filename, "r"); + + if (fp == NULL) { + printf("error: could not open configuration file '%s.'", filename); + return 1; + } + while (fgets(str, MAXCHAR, fp) != NULL) { + long int len; + if ((len = isconf(str, "nick"))) { + getconf(str, len); + strncpy(nick, str, strlen(str)); + nick[strlen(str)] = '\0'; + printf("Nick is: '%s', length '%ld'.\n", nick, strlen(nick)); + } else if ((len = isconf(str, "username"))) { + getconf(str, len); + strncpy(username, str, strlen(str)); + username[strlen(str)] = '\0'; + printf("Username is: '%s', length '%ld'.\n", username, strlen(username)); + } else if ((len = isconf(str, "realname"))) { + getconf(str, len); + strncpy(realname, str, strlen(str)); + realname[strlen(str)] = '\0'; + printf("Real name is: '%s', length '%ld'.\n", realname, strlen(realname)); + } + } + + // Ensure we have everything required + if (!strlen(nick) || !strlen(username) || !strlen(realname)) { + printf("Failed to read nick and/or username and/or real name from configuration file.\n"); + exit(1); + } + + fclose(fp); + return 1; +} diff --git a/config.h b/config.h new file mode 100644 index 0000000..5307178 --- /dev/null +++ b/config.h @@ -0,0 +1,12 @@ +#ifndef CONFIG_H_INCLUDED +#define CONFIG_H_INCLUDED + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#define MAXCHAR 1000 + +int readnames(char *nick, char *username, char *realname); + +#endif |