summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--blabouncer.c445
-rw-r--r--functions.c77
-rw-r--r--functions.h6
3 files changed, 508 insertions, 20 deletions
diff --git a/blabouncer.c b/blabouncer.c
index 39e8166..6728fcc 100644
--- a/blabouncer.c
+++ b/blabouncer.c
@@ -1,6 +1,14 @@
// TODO FOR TOMORROW:
// - FIGURE OUT WHEN WE'RE REGISTERED (NICK and USER from user are replied to with commands 001, 002, 003, and 004 from the ircd when registration successful)
// - int registered = 0; already created to track when this has happened (assuming still want to do it this way)
+// - handle nick in use
+// - Might need to change channel struct nicks to be channel struct user struct with its own nick/modes/etc.
+// - Do we actually need to store the modes in the channel struct?
+// - Get CAP from server and relay to client
+// - Add blabouncer MOTD (375, 372, 376)
+// - Need to delete channels from struct when PARTing them
+// - Joining while connected doesn't properly join other clients
+//
// Example WHOIS reply:
// BOUNCER-SERVER RECEIVED: :irc.tghost.co.uk 307 blabounce l_bratch :is identified for this nick
@@ -13,6 +21,7 @@
#include <errno.h>
#include <string.h>
#include <netdb.h>
+#include <time.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
@@ -31,19 +40,59 @@
#define MAXCLIENTS 32 // maximum number of clients that can connect to the bouncer at a time
#define MAXTOKENS 100 // maximum number of (CRLF or space) separated tokens per server response we expect (TODO - check this is reasonable) (CRLF and spaces just grouped here due to laziness)
#define MAXPONGSIZE 32 // let's assume PING/PONG responses can't be larger than this (TODO - check this [it's totally made up]!)
+#define MAXCHANNELS 1024 // let's assume 1024 is reasonable for now (it's configured per IRCd)
+#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 IRCUSERHOST "tghost.co.uk" // TODO: change this to a config option!
+
+struct channel {
+ char name[MAXCHANLENGTH];
+ char topic[MAXDATASIZE]; // TODO - Is there a particular maximum topic length? // TODO - DO WE NEED THIS!? What a twist!
+ char topicwho[MAXNICKLENGTH];
+ char topicwhen[11]; // 32-bit unixtime is up to 10 characters (+1 for null char) // TODO - Make this Year 2038 proof
+ char modes[MAXDATASIZE]; // TODO - Is there a particular maximum modes length? // TODO - DO WE NEED THIS!? What a twist!
+ char nicks[MAXCHANUSERS][MAXNICKLENGTH]; // TODO - Need to modify this as people leave/join, not just when we first join
+ char namestype[2]; // Single character (@/*/=) (+1 for null char) // TODO - Is this a sensible name?
+};
+
+struct ircdstrings {
+ char greeting001[MAXDATASIZE];
+ char greeting002[MAXDATASIZE];
+ char greeting003[MAXDATASIZE];
+ char greeting004[MAXDATASIZE];
+ char ircdname[MAXDATASIZE];
+ char nickuserhost[MAXDATASIZE]; // TODO - Make sure this changes when nick changes, if that's meant to happen.
+};
int debugmode = 0;
+// Send whatever string to a specific client by providing the FD
+int sendtoclient(int fd, char *str) {
+ appendcrlf(str); // Do this just before sending so callers don't need to worry about it
+
+ printf("sendtoclient(): sending \"%s\" (length %zd) to client with fd %d.\n", str, strlen(str), fd);
+ if (send(fd, str, strlen(str), 0) == -1) {
+ perror("error: sendtoclient() send()\n");
+ return 0;
+ }
+
+ return 1;
+}
+
// Relay/send message to all clients (optionally except one)
// "except" is used to send to all clients _except_ the fd provided (except = 0 (EXCEPT_NONE) avoids this, i.e. sends to all)
-int sendtoallclients(int *clientsockfd, int fdmax, int arr_clients[], char *str, int str_len, int except) {
+// TODO - is passing str_len useful if we're appendcrlfing and then using strlen(str) in the send? I guess not... (As long as we're always null terminated in the correct place.)
+int sendtoallclients(int *clientsockfd, int fdmax, int arr_clients[], char *str, int except) {
char *sendertype;
+ appendcrlf(str); // Do this just before sending so callers don't need to worry about it
+
// Decide what sort of text to prefix the debug output with
// At the moment if non-zero "except" is specified then it must be a message from a bouncer client
// and if "except" is zero then it must be a message from the real IRC server
@@ -63,9 +112,9 @@ int sendtoallclients(int *clientsockfd, int fdmax, int arr_clients[], char *str,
// ...but only if they are connected
for (int j = 0; j < MAXCLIENTS; j++) {
if (arr_clients[j] == i) {
- printf("%s: sending %s to client with fd %d.\n", sendertype, str, i);
- if (send(i, str, str_len, 0) == -1) {
- perror("send");
+ printf("sendtoallclients(): %s: sending %s to client with fd %d.\n", sendertype, str, i);
+ if (send(i, str, strlen(str), 0) == -1) {
+ perror("error: sendtoallclients() send()\n");
}
}
}
@@ -80,16 +129,140 @@ int sendtoserver(int *serversockfd, char *str, int str_len) {
str_len = strlen(str); // Recalculate str_len in case it changed (TODO: so do we even need to pass it to this function?)
printf("sendtoserver(): sending %s to IRC server (length %d).\n", str, str_len);
if (send(*serversockfd, str, str_len, 0) == -1) { // 0 is bitwise OR for no send() flags
- printf("send error, exiting...\n");
- perror("send");
+ printf("error: sendtoserver() send()\n");
+ }
+
+ return 0;
+}
+
+int createchannel(struct channel *channels, char *name, char *topic, char *topicwho, char *topicwhen, char *modes, char *namestype) {
+ printf("createchannel(): given \"%s\", \"%s\", \"%s\", \"%s\", \"%s\", and \"%s\".\n", name, topic, topicwho, topicwhen, modes, namestype);
+
+
+ // Find a free slot in the array (with the channel name is not set (0th character is '\0')...
+ for (int i = 0; i < MAXCHANNELS; i++) {
+ if (!channels[i].name[0]) {
+ // ...and set the name and topic
+ strncpy(channels[i].name, name, strlen(name));
+ strncpy(channels[i].topic, topic, strlen(topic));
+ strncpy(channels[i].topicwho, topicwho, strlen(topicwho));
+ strncpy(channels[i].topicwhen, topicwhen, strlen(topicwhen));
+ strncpy(channels[i].modes, modes, strlen(modes));
+ strncpy(channels[i].namestype, topic, strlen(namestype));
+ return 1;
+ break;
+ }
+ }
+
+ // TODO - Make a failed return do something to callers
+ return 0;
+}
+
+int addusertochannel(struct channel *channels, char *channelname, char *nick) {
+ printf("addusertochannel(): given \"%s\" and \"%s\".\n", channelname, nick);
+
+ for (int i = 0; i < MAXCHANNELS; i++) {
+ if (strncmp(channels[i].name, channelname, strlen(channelname)) == 0) {
+ // Looking for free user slot...
+ for (int j = 0; j < MAXCHANUSERS; j++) {
+ if (!channels[i].nicks[j][0]) {
+ // ...and adding user
+ strncpy(channels[i].nicks[j], nick, strlen(nick));
+ return 1;
+ }
+ }
+ break;
+ }
+ }
+
+ // TODO - Make a failed return do something to callers
+ return 0;
+}
+
+int setchanneltopicwhotime(struct channel *channels, char *channelname, char *who, char *when) {
+ printf("setchanneltopicwhotime(): given \"%s\", \"%s\", and \"%s\".\n", channelname, who, when);
+
+ for (int i = 0; i < MAXCHANNELS; i++) {
+ if (strncmp(channels[i].name, channelname, strlen(channelname)) == 0) {
+ strncpy(channels[i].topicwho, who, strlen(who));
+ strncpy(channels[i].topicwhen, when, strlen(when));
+ return 1;
+ }
+ }
+
+ // TODO - Make a failed return do something to callers
+ return 0;
+}
+
+int setchanneltopic(struct channel *channels, char *channelname, char *topic) {
+ printf("setchanneltopic(): given \"%s\" and \"%s\".\n", channelname, topic);
+
+ for (int i = 0; i < MAXCHANNELS; i++) {
+ if (strncmp(channels[i].name, channelname, strlen(channelname)) == 0) {
+ strncpy(channels[i].topic, topic, strlen(topic));
+ return 1;
+ }
+ }
+
+ // TODO - Make a failed return do something to callers
+ return 0;
+}
+
+int setchannelnamestype(struct channel *channels, char *channelname, char *type) {
+ printf("setchannelnamestype(): given \"%s\" and \"%s\".\n", channelname, type);
+
+ for (int i = 0; i < MAXCHANNELS; i++) {
+ if (strncmp(channels[i].name, channelname, strlen(channelname)) == 0) {
+ strncpy(channels[i].namestype, type, strlen(type));
+ return 1;
+ }
}
+ // TODO - Make a failed return do something to callers
return 0;
}
+int getchannelcount(struct channel *channels) {
+ int count = 0;
+
+ for (int i = 0; i < MAXCHANNELS; i++) {
+ if (channels[i].name[0]) {
+ count++;
+ }
+ }
+
+ printf("getchannelcount(): counted %d channels.\n", count);
+
+ return count;
+}
+
+int getchannelnamescount(struct channel *channels, char *channelname) {
+ int count = 0;
+
+ // Find channel
+ for (int i = 0; i < MAXCHANNELS; i++) {
+ if (strncmp(channels[i].name, channelname, strlen(channelname)) == 0) {
+ // Count nicks
+ for (int j = 0; j < MAXCHANUSERS; j++) {
+ // If not null character then it's a nick
+ if (channels[i].nicks[j][0]) {
+ count++;
+ }
+ }
+ break;
+ }
+ }
+
+ return count;
+ printf("getchannelnamescount(): counted %d channels for channel '%s'.\n", count, channelname);
+}
+
// Figure out what to do with each CRLF-split IRC message (if anything)
// by splitting out the different components by space character (ASCII 0x20).
-// Get serversockfd and clientsockfd in case we need to send a response.
+//
+// serversockfd, clientsockfd, fdmax, arr_clients, except all passed to here so we can
+// send/relay a response to server or (other) client(s) directly from this function if
+// we want to.
//
// str is the raw string
//
@@ -97,7 +270,8 @@ int sendtoserver(int *serversockfd, char *str, int str_len) {
//
// Return 1 if we processed something and expect the caller to not need to do anything more
// Return 0 if we didn't process it and the caller might want to do something
-int processircmessage(int *serversockfd, int *clientsockfd, char *str, int source) {
+//int processircmessage(int *serversockfd, int *clientsockfd, char *str, int source) {
+int processircmessage(int *serversockfd, int *clientsockfd, char *str, int source, int fdmax, int arr_clients[], int sourcefd, struct ircdstrings *ircdstrings, struct channel *channels) {
// Track which space-separated token within this response we're on
int counter = 0;
@@ -106,9 +280,12 @@ int processircmessage(int *serversockfd, int *clientsockfd, char *str, int sourc
printf(" >> processircmessage(): Processing source %d message \"%s\"...\n", source, str);
+ // Copy to a temporary string so we still have the original in case it's not processed
+ char *strcopy = strdup(str);
+
char *token;
- while ((token = strsep(&str, " ")) != NULL) {
+ while ((token = strsep(&strcopy, " ")) != NULL) {
if (*token == '\0') continue; // Skip consecutive matches
printf(" >> Message Token: \"%s\", length %zd.\n", token, strlen(token));
// Copy into the token array (strlen + 1 to get the NULL terminator)
@@ -121,9 +298,9 @@ int processircmessage(int *serversockfd, int *clientsockfd, char *str, int sourc
switch(source) {
case SOURCE_SERVER: // If message(s) were from the real IRC server
- // PING received? If so, send a PONG back with the next element as the argument.
+ // Server PING received? If so, send a PONG back with the next element as the argument.
if (strncmp(tokens[0], "PING", strlen(tokens[0])) == 0) {
- printf("PING found and it is: %s with length %zd! Sending response...\n", tokens[0], strlen(tokens[0]));
+ printf("Server PING found and it is: %s with length %zd! Sending response...\n", tokens[0], strlen(tokens[0]));
char outgoingmsg[MAXDATASIZE]; // String to send to server
if (!snprintf(outgoingmsg, MAXDATASIZE, "PONG %s", tokens[1])) { // TODO - Make sure tokens[1] actually has a token
@@ -135,8 +312,215 @@ int processircmessage(int *serversockfd, int *clientsockfd, char *str, int sourc
// We processed something so return true
return 1;
}
+
+ // Prefix received? TODO - Care about what the prefix is - what if it's a different server/network/whatever?
+ if (tokens[0][0] == ':') {
+ printf("Prefix found: '%s'! Next token is '%s', length %zd.\n", tokens[0], tokens[1], strlen(tokens[1]));
+ // Greetings 001 through to 004, store in ircdstrings array for resending when clients connect
+ // Also store our nick!user@host from greeting 001
+ // Also store the real IRCd's name from greeting 004
+ if (strncmp(tokens[1], "001", strlen(tokens[1])) == 0) {
+ printf("Found greeting 001 (%s) (length %zd), storing in ircdstrings struct.\n", str, strlen(str));
+ strncpy(ircdstrings->greeting001, str, strlen(str));
+ // Null the end of the string
+ ircdstrings->greeting001[strlen(str)] = '\0';
+ printf("Storing our nick!user@host (%s) from greeting 001 in ircdstrings struct.\n", tokens[counter - 1]);
+ strncpy(ircdstrings->nickuserhost, tokens[counter - 1], strlen(tokens[counter - 1]));
+ // Null the end of the string
+ ircdstrings->nickuserhost[strlen(tokens[counter - 1])] = '\0';
+ return 1;
+ } else if (strncmp(tokens[1], "002", strlen(tokens[1])) == 0) {
+ printf("Found greeting 002 (%s), storing in ircdstrings struct.\n", str);
+ strncpy(ircdstrings->greeting002, str, strlen(str));
+ // Null the end of the string
+ ircdstrings->greeting002[strlen(str)] = '\0';
+ return 1;
+ } else if (strncmp(tokens[1], "003", strlen(tokens[1])) == 0) {
+ printf("Found greeting 003 (%s), storing in ircdstrings struct.\n", str);
+ strncpy(ircdstrings->greeting003, str, strlen(str));
+ // Null the end of the string
+ ircdstrings->greeting003[strlen(str)] = '\0';
+ return 1;
+ } else if (strncmp(tokens[1], "004", strlen(tokens[1])) == 0) {
+ printf("Found greeting 004 (%s), storing in ircdstrings struct.\n", str);
+ strncpy(ircdstrings->greeting004, str, strlen(str));
+ // Null the end of the string
+ ircdstrings->greeting004[strlen(str)] = '\0';
+ printf("Storing the real IRCd's name (%s) from greeting 004 in ircdstrings struct.\n", tokens[3]);
+ strncpy(ircdstrings->ircdname, tokens[3], strlen(tokens[3]));
+ // Null the end of the string
+ ircdstrings->ircdname[strlen(tokens[3])] = '\0';
+ return 1;
+ }
+
+ // Server JOIN received? Add to our local channel list.
+ if (strncmp(tokens[1], "JOIN", strlen(tokens[1])) == 0) {
+ printf("Server JOIN found and it is: %s with length %zd! Next token is '%s'. Adding to local channel list.\n", tokens[0], strlen(tokens[0]), tokens[2]);
+ // Next token should be the channel name but it probably needs the leading ':' stripping
+ printf("processircmessage(): Channel name was '%s'\n", tokens[2]);
+ stripprefix(tokens[2]);
+ printf("processircmessage(): Channel name now '%s'\n", tokens[2]);
+
+ createchannel(channels, tokens[2], "TOPIC", "TOPICWHO", "0", "CHANNELMODES", "="); // TODO - Saner way to initialise this since we don't have the variables yet?
+ // - Defaulting to type '=' which is "public" since I don't know what else to guess.
+
+ // We processed something so return true
+ return 1;
+ }
+
+ // Channel topics/names/nicks/etc.
+ // Server 332 (RPL_TOPIC) set the channel topic
+ if (strncmp(tokens[1], "332", strlen(tokens[1])) == 0) {
+ printf("Server 332 (RPL_TOPIC) found, extracting topic and storing in channel struct.\n");
+ // Need to extract the final parameter as topics can have spaces
+ // Copy to a temporary string so we still have the original in case we need it
+ char *topiccopy = strdup(str);
+ extractfinalparameter(topiccopy);
+ setchanneltopic(channels, tokens[3], topiccopy);
+ // Server 333 (RPL_TOPICWHOTIME) set the channel topic setter and the time it was set
+ } else if (strncmp(tokens[1], "333", strlen(tokens[1])) == 0) {
+ printf("Server 333 (RPL_TOPICWHOTIME) found, extracting who and when, and storing in channel struct.\n");
+ setchanneltopicwhotime(channels, tokens[3], tokens[4], tokens[5]);
+ // Server 353 (RPL_NAMREPLY) add channel names type (secret/private/public) and the names of those already in the channel
+ } else if (strncmp(tokens[1], "353", strlen(tokens[1])) == 0) {
+ // TODO - Do we also need to watch out for 366 (RPL_ENDOFNAMES)?
+ printf("Server 353 (RPL_NAMREPLY) found, extracting nicks and storing in channel struct.\n");
+ // Set channel type
+ setchannelnamestype(channels, tokens[4], tokens[3]);
+ // Add nicks
+ // Strip prefix from first nick first
+ stripprefix(tokens[5]);
+ // Now go through all nicks and add them to the channel
+ for (int i = 5; i < counter; i++) {
+ addusertochannel(channels, tokens[4], tokens[i]);
+ }
+ }
+ // Don't return if we got here because this means we didn't process something above
+ }
+
break;
case SOURCE_CLIENT: // If message(s) were from a real IRC client
+ // USER received? If so, assume this is a new client connecting and catch them on up on the state
+ if (strncmp(tokens[0], "USER", strlen(tokens[0])) == 0) {
+ // Need to sort out channel structure first!!
+ printf("TODO: USER received!\n");
+
+ // Somewhere to store the several strings we will need to build and send
+ char outgoingmsg[MAXDATASIZE]; // String to send to client
+
+ // Send IRC greeting strings (001/RPL_WELCOME, 002/RPL_YOURHOST, 003/RPL_CREATED, 004/RPL_MYINFO) to client
+ snprintf(outgoingmsg, MAXDATASIZE, "%s", ircdstrings->greeting001);
+ sendtoclient(sourcefd, outgoingmsg);
+ snprintf(outgoingmsg, MAXDATASIZE, "%s", ircdstrings->greeting002);
+ sendtoclient(sourcefd, outgoingmsg);
+ snprintf(outgoingmsg, MAXDATASIZE, "%s", ircdstrings->greeting003);
+ sendtoclient(sourcefd, outgoingmsg);
+ snprintf(outgoingmsg, MAXDATASIZE, "%s", ircdstrings->greeting004);
+ sendtoclient(sourcefd, outgoingmsg);
+
+ // Get client to join channels, and tell client about those channels
+ for (int i = 0; i < getchannelcount(channels); i++) {
+ // Get client to join channels
+ if (!snprintf(outgoingmsg, MAXDATASIZE, ":%s JOIN :%s", ircdstrings->nickuserhost, channels[i].name)) {
+ fprintf(stderr, "Error while preparing USER just connected, channel JOIN responses!\n");
+ exit(1);
+ }
+ sendtoclient(sourcefd, outgoingmsg);
+
+ // Send topic to client - TODO: Handle not having a topic set (331)
+ if (!snprintf(outgoingmsg, MAXDATASIZE, ":%s 332 %s %s :%s", ircdstrings->ircdname, IRCNICK, channels[i].name, channels[i].topic)) {
+ fprintf(stderr, "Error while preparing USER just connected, channel JOIN responses!\n");
+ exit(1);
+ }
+ sendtoclient(sourcefd, outgoingmsg);
+
+ // Send list of names
+ // Store count of names so we can increment it in the loop if we encounter gaps in the names array
+ int namescount = getchannelnamescount(channels, channels[i].name);
+ // Go through each name...
+ for (int j = 0; j < namescount; j++) {
+ // TODO - Batch these up and send multiple names per line
+ // ...making sure it they are not null (probably a gap in the names array)
+ if (!channels[i].nicks[j][0]) {
+ // Skip this one and increment namescount so we find it later on instead
+ namescount++;
+ 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])) {
+ fprintf(stderr, "Error while preparing USER just connected, channel NAMES responses!\n");
+ exit(1);
+ }
+ sendtoclient(sourcefd, outgoingmsg);
+ }
+
+ // 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)) {
+ fprintf(stderr, "Error while preparing USER just connected, end of NAMES response!\n");
+ exit(1);
+ }
+ sendtoclient(sourcefd, outgoingmsg);
+ }
+
+ return 1;
+ }
+
+ // Client PING received? If so, send a PONG back with the next element as the argument.
+ if (strncmp(tokens[0], "PING", strlen(tokens[0])) == 0) {
+ printf("Client PING found and it is: %s with length %zd! Sending response...\n", tokens[0], strlen(tokens[0]));
+
+ char outgoingmsg[MAXDATASIZE]; // String to send to client
+ if (!snprintf(outgoingmsg, MAXDATASIZE, "PONG %s", tokens[1])) { // TODO - Make sure tokens[1] actually has a token
+ fprintf(stderr, "Error while preparing PONG response!\n");
+ exit(1);
+ }
+ sendtoclient(sourcefd, outgoingmsg);
+
+ // We processed something so return true
+ return 1;
+ }
+
+ // TODO - Ignoring CAP for now so as not to confuse other clients, but we should probably query the server then relay the response to the client
+ if (strncmp(tokens[0], "CAP", strlen(tokens[0])) == 0) {
+ printf("Client CAP found and it is: %s with length %zd! Ignoring completely for now - TODO - do something useful!\n", tokens[0], strlen(tokens[0]));
+ return 1;
+ }
+
+ // Just send NICK to server and let it change all clients' nicks if needed
+ if (strncmp(tokens[0], "NICK", strlen(tokens[0])) == 0) {
+ printf("Client NICK found and it is: %s with length %zd! Sending to server...\n", tokens[0], strlen(tokens[0]));
+ sendtoserver(serversockfd, str, strlen(str));
+ return 1;
+ }
+
+ // If PRIVMSG received, send to server, but also reformat and send to all other clients
+ if (strncmp(tokens[0], "PRIVMSG", strlen(tokens[0])) == 0) {
+ printf("Client PRIVMSG found and it is: %s with length %zd! Sending to server then back to other clients...\n", tokens[0], strlen(tokens[0]));
+ // Send original request straight to server
+ sendtoserver(serversockfd, str, strlen(str));
+
+ // Rebuild to full PRIVMSG string and relay to all other clients
+ char outgoingmsg[MAXDATASIZE]; // String to send to client
+
+ snprintf(outgoingmsg, MAXDATASIZE, ":%s!%s@%s %s", IRCNICK, IRCUSER, IRCUSERHOST, str);
+ // Send to all except source client
+ sendtoallclients(clientsockfd, fdmax, arr_clients, outgoingmsg, sourcefd);
+
+ return 1;
+ }
+
+ // Just send JOIN to server and let it talk back to clients as required
+ if (strncmp(tokens[0], "JOIN", strlen(tokens[0])) == 0) {
+ printf("Client JOIN found and it is: %s with length %zd! Sending to server...\n", tokens[0], strlen(tokens[0]));
+ sendtoserver(serversockfd, str, strlen(str));
+ return 1;
+ }
+
+ // Don't do anything with QUIT, just let the client go - TODO: Let another clients know with a NOTICE or something
+ if (strncmp(tokens[0], "QUIT", strlen(tokens[0])) == 0) {
+ printf("Client QUITfound and it is: %s with length %zd! Doing nothing at all.\n", tokens[0], strlen(tokens[0]));
+ return 1;
+ }
break;
default:
fprintf(stderr, "Unexpected raw IRC string source!\n");
@@ -166,7 +550,7 @@ int processircmessage(int *serversockfd, int *clientsockfd, char *str, int sourc
//
// Return 0 if something went wrong
// Return 1 if everything OK
-int processrawstring(int *serversockfd, int *clientsockfd, char *str, int source, int fdmax, int arr_clients[], int except) {
+int processrawstring(int *serversockfd, int *clientsockfd, char *str, int source, int fdmax, int arr_clients[], int sourcefd, struct ircdstrings *ircdstrings, struct channel *channels) {
// Copy to a temporary string so we still have the original in case it's not processed
char *strcopy = strdup(str);
@@ -195,7 +579,7 @@ int processrawstring(int *serversockfd, int *clientsockfd, char *str, int source
for (int i = 0; i < messagecount; i++) {
// Copy to a temporary string so we still have the original in case it's not processed
char *messagecopy = strdup(messages[i]);
- if (processircmessage(serversockfd, clientsockfd, messagecopy, source)) {
+ if (processircmessage(serversockfd, clientsockfd, messagecopy, source, fdmax, arr_clients, sourcefd, ircdstrings, channels)) {
printf("Message processed: \"%s\", NULLing...\n", messages[i]);
messages[i][0] = '\0';
}
@@ -211,15 +595,15 @@ int processrawstring(int *serversockfd, int *clientsockfd, char *str, int source
// Relay/send to all clients ("except" = 0 because this should send to all clients)
// TODO - Is this really going to send the original string if we have messed it with it in processrawstring() and friends!?
printf("bouncer-server: sending \"%s\" to all clients, length %zd.\n", messages[i], strlen(messages[i]));
- sendtoallclients(clientsockfd, fdmax, arr_clients, messages[i], strlen(messages[i]), EXCEPT_NONE);
+ sendtoallclients(clientsockfd, fdmax, arr_clients, messages[i], EXCEPT_NONE);
break;
case SOURCE_CLIENT: // If message(s) were from a real IRC client
// Send to server
printf("bouncer-client: sending \"%s\" to the server, length %zd.\n", messages[i], strlen(messages[i]));
sendtoserver(serversockfd, messages[i], strlen(messages[i]));
- // send the same thing to all *other* clients (all except for fd "i")
- sendtoallclients(clientsockfd, fdmax, arr_clients, messages[i], strlen(messages[i]), except);
+ // send the same thing to all *other* clients (all except for source fd)
+ sendtoallclients(clientsockfd, fdmax, arr_clients, messages[i], sourcefd);
break;
default:
fprintf(stderr, "Unexpected raw IRC string source!\n");
@@ -271,10 +655,31 @@ void dochat(int *serversockfd, int *clientsockfd) {
sendtoserver(serversockfd, outgoingmsg, strlen(outgoingmsg));
// Send our USER
-
snprintf(outgoingmsg, MAXDATASIZE, "USER %s 8 * : %s", IRCUSER, 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';
+
+/*
+ createchannel(channels, "testchannel", "Test topic!", "+");
+ addusertochannel(channels, "testchannel", "l_bratch");
+ createchannel(channels, "secondchan", "Yo yo yo", "+nrst");
+ addusertochannel(channels, "secondchan", "l_bratch");
+ addusertochannel(channels, "secondchan", "coold00d");
+*/
// =============================================>
while (1) {
@@ -320,11 +725,11 @@ void dochat(int *serversockfd, int *clientsockfd) {
}
serverbuf[servernumbytes] = '\0';
- printf("BOUNCER-SERVER RECEIVED: %s\n", serverbuf);
+ printf("BOUNCER-SERVER RECEIVED: '%s'\n", serverbuf);
// Try to process received string (which should contain one or more server responses/commands)
// TODO - What if there were two server respones/commands and only one didn't need relaying?
- if (!processrawstring(serversockfd, clientsockfd, serverbuf, SOURCE_SERVER, fdmax, arr_clients, EXCEPT_NONE)) {
+ if (!processrawstring(serversockfd, clientsockfd, serverbuf, SOURCE_SERVER, fdmax, arr_clients, EXCEPT_NONE, &ircdstrings, channels)) {
fprintf(stderr, "Error: bouncer-server failed to process raw string.\n");
exit(1);
}
@@ -422,7 +827,7 @@ void dochat(int *serversockfd, int *clientsockfd) {
// Try to process received string (which should contain one or more client responses/commands)
// TODO - What if there were two server respones/commands and only one didn't need relaying?
- if (!processrawstring(serversockfd, clientsockfd, clientbuf, SOURCE_CLIENT, fdmax, arr_clients, i)) {
+ if (!processrawstring(serversockfd, clientsockfd, clientbuf, SOURCE_CLIENT, fdmax, arr_clients, i, &ircdstrings, channels)) {
fprintf(stderr, "Error: bouncer-client failed to process raw string.\n");
exit(1);
}
diff --git a/functions.c b/functions.c
index 97f8629..86a1f03 100644
--- a/functions.c
+++ b/functions.c
@@ -50,3 +50,80 @@ void appendcrlf(char *string) {
string[startlen + 1] = '\n'; // Add LF
string[startlen + 2] = '\0'; // Finish with null terminator
}
+
+// Remove leading colon ':' which is the starting character of a prefix in an IRC message
+void stripprefix(char *string) {
+ // Make a copy to work with
+ char string2[strlen(string)];
+
+ printf("stripprefix(): starting with '%s', strlen: %zd.\n", string, strlen(string));
+
+ // Don't bother if this isn't a prefix with a leading ':'
+ if (string[0] != ':') {
+ printf("stripprefix(): no leading ':', returning.\n");
+ return;
+ }
+
+ // Copy the old string into a new one, but...
+ for (size_t i = 1; i < strlen(string); i++) {
+ printf("i: %zd. strlen: %zd.\n", i, strlen(string));
+ string2[i - 1] = string[i];
+ }
+
+ // Copy result back to original string
+ strncpy(string, string2, strlen(string) - 1);
+
+ // Finish with null terminator
+ string[strlen(string) - 1] = '\0';
+
+ printf("stripprefix(): finishing with '%s', strlen: %zd.\n", string, strlen(string));
+}
+
+// Extract final parameter from IRC message, removing the leading colon ':'
+// e.g. given this string:
+// ":irc.tghost.co.uk 332 blabounce #test :This is a test topic!"
+// We want to end up with:
+// "This is a test topic!"
+void extractfinalparameter(char *string) {
+ // Make a copy to work with
+ char string2[strlen(string)];
+
+ // Position of colon
+ int colonpos = -1;
+
+ printf("extractfinalparameter(): starting with '%s', strlen: %zd.\n", string, strlen(string));
+
+ // Strip the colon at position 0 if there is one
+ stripprefix(string);
+
+ // Find the colon
+ for (size_t i = 0; i < strlen(string); i++) {
+ printf("i: %zd. strlen: %zd.\n", i, strlen(string));
+ if (string[i] == ':') {
+ printf("Found colon at position %zd!\n", i);
+ colonpos = i;
+ break;
+ }
+ }
+
+ if (colonpos == -1) {
+ printf("no colon found, returning\n");
+ return;
+ }
+
+ // Build a new string starting from the next position after the colon
+ int counter = 0;
+ for (size_t i = colonpos + 1; i < strlen(string); i++) {
+ printf("i: %zd. strlen: %zd.\n", i, strlen(string));
+ string2[counter] = string[i];
+ counter++;
+ }
+
+ // Copy result back to original string
+ strncpy(string, string2, counter);
+
+ // Finish with null terminator
+ string[counter] = '\0';
+
+ printf("extractfinalparameter(): finishing with '%s', strlen: %zd.\n", string, strlen(string));
+}
diff --git a/functions.h b/functions.h
index 4605da6..d51d61c 100644
--- a/functions.h
+++ b/functions.h
@@ -27,4 +27,10 @@ int getstdin(char *prompt, char *buff, size_t sz);
// Append CR-LF to the end of a string (after cleaning up any existing trailing CR or LF)
void appendcrlf(char *string);
+// Remove leading colon ':' which is the starting character of a prefix in an IRC message
+void stripprefix(char *string);
+
+// Extract final parameter from IRC message, removing the leading colon ':'
+void extractfinalparameter(char *string);
+
#endif