summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Bratch <luke@bratch.co.uk>2019-05-11 15:01:22 +0100
committerLuke Bratch <luke@bratch.co.uk>2019-05-11 15:01:22 +0100
commitc46d01b5afd2da4779efb2700469037eca6122be (patch)
tree9db52afe3643c0643414dcf638fa579176b62487
parentd950304536f870ad989e0049e4e8b4a5a72a9315 (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--Makefile6
-rw-r--r--blabouncer.c53
-rw-r--r--blabouncer.conf9
-rw-r--r--config.c103
-rw-r--r--config.h12
5 files changed, 158 insertions, 25 deletions
diff --git a/Makefile b/Makefile
index 88487ec..3f8d034 100644
--- a/Makefile
+++ b/Makefile
@@ -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