summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--blabouncer.c57
-rw-r--r--functions.c94
-rw-r--r--functions.h4
3 files changed, 139 insertions, 16 deletions
diff --git a/blabouncer.c b/blabouncer.c
index 559e2b1..c4396f4 100644
--- a/blabouncer.c
+++ b/blabouncer.c
@@ -114,6 +114,7 @@ struct client {
int fd; // Client socket fd - 0 means not connected, greater than 0 means connected and the value is the fd number (so we know which ones to try to read and send to)
int authed; // Client authentication status - 0 means not authenticated, 1 means authenticated.
SSL *ssl; // OpenSSL structures when using TLS, or faked by casting fd ints to SSL* if not. - TODO - Can we drop one of either "int fd" or "SSL *ssl" now?
+ int registered; // Whether the client has finished registering with the bouncer
};
// Return index of requested client FD within the clients array.
@@ -159,8 +160,8 @@ int sendtoclient(int fd, char *str, struct client *clients, struct settings *set
}
// Disconnect the client fd "fd" by close()ing it and remove
-// it from the arr_clients array of clients.
-// Also set its authentication status to 0.
+// it from the array of clients.
+// Also set its authentication and registration statuses to 0.
int disconnectclient(int fd, struct client *clients) {
printf("disconnectclient(): disconnecting client fd '%d'\n", fd);
close(fd); // bye!
@@ -170,6 +171,7 @@ int disconnectclient(int fd, struct client *clients) {
printf("found and clearing fd %d from clients[%d]\n", fd, i);
clients[i].fd = 0;
clients[i].authed = 0;
+ clients[i].registered = 0;
return 1;
}
}
@@ -476,7 +478,12 @@ int removechannel(struct channel *channels, char *name) {
if (strncmp(channels[i].name, name, strlen(name)) == 0) {
// ..and NULL its name (0th character = '\0')
channels[i].name[0] = '\0';
- printf("removechannel(): channel removed and topicwhen set to '%s'.\n", channels[i].topicwhen);
+ printf("removechannel(): channel '%s' removed and topicwhen set to '%s'.\n", name, channels[i].topicwhen);
+ // Finally clear all its users
+ for (int j = 0; j < MAXCHANUSERS; j++) {
+ channels[i].nicks[j][0] = '\0';
+ }
+ printf("removechannel(): channel '%s' users cleared.\n", name);
return 1;
}
}
@@ -491,7 +498,7 @@ int removechannel(struct channel *channels, char *name) {
// 'sourcefd' is the client to send to, and replayseconds is the number of
// seconds of replay to replay.
// Returns 1 for success or 0 for failure.
-int doreplay(int sourcefd, int replayseconds, struct client *clients, struct settings *settings) {
+int doreplay(int sourcefd, int replayseconds, struct client *clients, struct settings *settings, struct ircdstrings *ircdstrings) {
char outgoingmsg[MAXDATASIZE];
// Figure out how many lines to replay
@@ -502,7 +509,7 @@ int doreplay(int sourcefd, int replayseconds, struct client *clients, struct set
printf("Error getting number of replay lines.\n");
exit(1);
} else if (numlines == 0) {
- snprintf(outgoingmsg, MAXDATASIZE, "NOTICE %s :0 replay log lines found in the time requested, nothing to send.", settings->ircnick);
+ snprintf(outgoingmsg, MAXDATASIZE, "NOTICE %s :0 replay log lines found in the time requested, nothing to send.", ircdstrings->ircnick);
sendtoclient(sourcefd, outgoingmsg, clients, settings);
return 1;
}
@@ -768,12 +775,19 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli
// Was it us?
if (strncmp(ircdstrings->nickuserhost, tokens[0], strlen(ircdstrings->nickuserhost)) == 0) {
+ // Make a copy of the old nickuserhost for updategreetings() below
+ char *nickuserhostcpy = strdup(ircdstrings->nickuserhost);
// Update nickuserhost with the new :nick!user@host
updatenickuserhost(ircdstrings->nickuserhost, tokens[2]);
printf("Updated nickuserhost to '%s'.\n", ircdstrings->nickuserhost);
- // Update ircnick
+ // Prepare to update ircnick and greetings strings
+ // Temporary copy of new nickuserhost
char *prefixcopy = strdup(ircdstrings->nickuserhost);
+ // Get nick from it
extractnickfromprefix(prefixcopy);
+ // Update greeting strings for relaying to new clients
+ updategreetings(ircdstrings->greeting001, ircdstrings->greeting002, ircdstrings->greeting003, ircdstrings->greeting004, ircdstrings->nickuserhost, nickuserhostcpy, tokens[2], ircdstrings->ircnick);
+ // Update our nick
strcpy(ircdstrings->ircnick, prefixcopy);
printf("Updated ircnick to '%s'.\n", ircdstrings->ircnick);
}
@@ -830,13 +844,13 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli
sendtoclient(sourcefd, outgoingmsg, clients, settings);
// Send our own greeting message
- snprintf(outgoingmsg, MAXDATASIZE, "NOTICE %s :Welcome to blabouncer!", settings->ircnick);
+ snprintf(outgoingmsg, MAXDATASIZE, "NOTICE %s :Welcome to blabouncer!", ircdstrings->ircnick);
sendtoclient(sourcefd, outgoingmsg, clients, settings);
- snprintf(outgoingmsg, MAXDATASIZE, "NOTICE %s :Blabouncer commands are all prefixed with BLABOUNCER which you can usually send using \"/QUOTE BLABOUNCER\"", settings->ircnick);
+ snprintf(outgoingmsg, MAXDATASIZE, "NOTICE %s :Blabouncer commands are all prefixed with BLABOUNCER which you can usually send using \"/QUOTE BLABOUNCER\"", ircdstrings->ircnick);
sendtoclient(sourcefd, outgoingmsg, clients, settings);
- snprintf(outgoingmsg, MAXDATASIZE, "NOTICE %s :Valid blabouncer commands are:", settings->ircnick);
+ snprintf(outgoingmsg, MAXDATASIZE, "NOTICE %s :Valid blabouncer commands are:", ircdstrings->ircnick);
sendtoclient(sourcefd, outgoingmsg, clients, settings);
- snprintf(outgoingmsg, MAXDATASIZE, "NOTICE %s :\"BLABOUNCER REPLAY [seconds]\" (Where [seconds] is the number of seconds of replay log to replay.)", settings->ircnick);
+ snprintf(outgoingmsg, MAXDATASIZE, "NOTICE %s :\"BLABOUNCER REPLAY [seconds]\" (Where [seconds] is the number of seconds of replay log to replay.)", ircdstrings->ircnick);
sendtoclient(sourcefd, outgoingmsg, clients, settings);
// Get the channel count so we can enumerate over all channels.
@@ -917,9 +931,19 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli
sendtoclient(sourcefd, outgoingmsg, clients, settings);
}
+ // Set the client as registered
+ clients[arrindex(clients, sourcefd)].registered = 1;
+
// Catch the client up with the default number of seconds of replay
- doreplay(sourcefd, settings->replayseconds, clients, settings);
+ doreplay(sourcefd, settings->replayseconds, clients, settings, ircdstrings);
+
+ return 1;
+ }
+ // Pretty much ignore anything else the client says if it's not registered yet,
+ // as the first thing we want to hear is either PASS or USER
+ if (!clients[arrindex(clients, sourcefd)].registered) {
+ printf("Ignoring client command '%s' from sourcefd '%d' as not registered yet.\n", tokens[0], sourcefd);
return 1;
}
@@ -1021,19 +1045,19 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli
int replayseconds;
if ((replayseconds = strtol(tokens[2], NULL, 10)) == 0) {
printf("Invalid number of replay seconds provided by REPLAY. Telling client.\n");
- snprintf(outgoingmsg, MAXDATASIZE, "NOTICE %s :Invalid number of seconds of replay requested by REPLAY command.", settings->ircnick);
+ snprintf(outgoingmsg, MAXDATASIZE, "NOTICE %s :Invalid number of seconds of replay requested by REPLAY command.", ircdstrings->ircnick);
sendtoclient(sourcefd, outgoingmsg, clients, settings);
return 1;
}
- doreplay(sourcefd, replayseconds, clients, settings);
+ doreplay(sourcefd, replayseconds, clients, settings, ircdstrings);
return 1;
// Unrecognised BLABOUNCER command received, send some help instructions
} else {
printf("Client BLABOUNCER unrecognised command found and it is: %s with length %zd! Sending a help message.\n", tokens[1], strlen(tokens[1]));
- snprintf(outgoingmsg, MAXDATASIZE, "NOTICE %s :Unrecognised BLABOUNCER command received. Valid commands are:", settings->ircnick);
+ snprintf(outgoingmsg, MAXDATASIZE, "NOTICE %s :Unrecognised BLABOUNCER command received. Valid commands are:", ircdstrings->ircnick);
sendtoclient(sourcefd, outgoingmsg, clients, settings);
- snprintf(outgoingmsg, MAXDATASIZE, "NOTICE %s :\"BLABOUNCER REPLAY [seconds]\" (Where [seconds] is the number of seconds of replay log to replay.)", settings->ircnick);
+ snprintf(outgoingmsg, MAXDATASIZE, "NOTICE %s :\"BLABOUNCER REPLAY [seconds]\" (Where [seconds] is the number of seconds of replay log to replay.)", ircdstrings->ircnick);
sendtoclient(sourcefd, outgoingmsg, clients, settings);
return 1;
}
@@ -1186,10 +1210,11 @@ void dochat(int *serversockfd, int *clientsockfd, struct settings *settings) {
// Set up clients structure
struct client clients[MAXCLIENTS];
- // Set all the clients to be "not connected" and "not authenticated"
+ // Set all the clients to be "not connected", "not authenticated", and "not registered"
for (int i = 0; i < MAXCLIENTS; i++) {
clients[i].fd = 0;
clients[i].authed = 0;
+ clients[i].registered = 0;
}
// Initialise OpenSSL (used for both client and server)
diff --git a/functions.c b/functions.c
index 6034250..ffd94f1 100644
--- a/functions.c
+++ b/functions.c
@@ -1,5 +1,50 @@
#include "functions.h"
+// Internal function just to replace nick in server greeting strings
+// (as in ":servername 00x oldnick :Blablabla" -> ":servername 00x newnick :Blablabla")
+void updategreetingnick(char *greeting, char *greetingnum, char *newnick, char *oldnick) {
+ printf("updategreetingnick(): '%s' '%s' '%s' '%s'.\n", greeting, greetingnum, newnick, oldnick);
+
+ // Find the position of the old nick in the current greeting
+ char searchstr[MAXDATASIZE];
+ snprintf(searchstr, MAXDATASIZE, " %s %s :", greetingnum, oldnick);
+ char *ret;
+ ret = strstr(greeting, searchstr);
+
+ // If ret not found, try again without the colon (e.g. for greeting 004)
+ if (ret == NULL) {
+ snprintf(searchstr, MAXDATASIZE, " %s %s ", greetingnum, oldnick);
+ ret = strstr(greeting, searchstr);
+ }
+
+ // If ret *still* not found, abandon ship
+ if (ret == NULL) {
+ printf("Error updating greeting string, substring not found. Exiting!\n");
+ exit(1);
+ }
+
+ int pos = ret - greeting + 5; // +5 for " 001 "
+
+ // Copy the start of the old greeting into a new string
+ char greetingtmp[MAXDATASIZE];
+ strncpy(greetingtmp, greeting, pos);
+ // Terminate it
+ greetingtmp[pos] = '\0';
+
+ // Now smash everything (start of old greeting + new nick + remainder of old greeting)
+ // together into the new greeting, put in a new temporary string
+ char greetingtmp2[MAXDATASIZE];
+ if (!snprintf(greetingtmp2, MAXDATASIZE, "%s%s %s", greetingtmp, newnick, greeting + pos + strlen(oldnick) + 1)) {
+ fprintf(stderr, "Error while preparing new greeting string!\n");
+ exit(1);
+ }
+
+ // And finally copy back to source string
+ strcpy(greeting, greetingtmp2);
+
+ printf("updategreetingnick(): Built new greeting '%s' '%s', length '%ld'.\n", greetingnum, greeting, strlen(greeting));
+}
+
// Get stdin line with buffer overrun protection
int getstdin(char *prompt, char *buff, size_t sz) {
int ch, extra;
@@ -182,3 +227,52 @@ void updatenickuserhost(char *nickuserhost, char *nick) {
printf("updatenickuserhost(): new nickuserhost '%s', length '%ld'.\n", nickuserhost, strlen(nickuserhost));
}
+
+// Update existing greeting strings with a new nickuserhost and new nick
+void updategreetings(char *greeting001, char *greeting002, char *greeting003, char *greeting004, char *newnickuserhost, char *oldnickuserhost, char *newnick, char *oldnick) {
+ printf("updategreetings(): updating greetings with new nickuserhost '%s' and nick '%s'.\n", newnickuserhost, newnick);
+
+ // nickuserhost and greeting001's final component first
+ // (final component as in ":servername 001 nick :Blablabla final!com@ponent"
+
+ // Make copies of the nickuserhosts to work with
+ char newnickuserhostcpy[MAXDATASIZE];
+ strcpy(newnickuserhostcpy, newnickuserhost);
+ stripprefix(newnickuserhostcpy);
+ char oldnickuserhostcpy[MAXDATASIZE];
+ strcpy(oldnickuserhostcpy, oldnickuserhost);
+ stripprefix(oldnickuserhostcpy);
+
+ // Find the position of the old nickuserhost in the current greeting 001
+ char *ret;
+ ret = strstr(greeting001, oldnickuserhostcpy);
+ int pos = ret - greeting001;
+
+ // Terminate greeting001 where the nickuserhost begins
+ greeting001[pos] = '\0';
+
+ // Stick the new nickuserhost in place in a temporary greeting 001 string
+ char greetingtmp[MAXDATASIZE];
+ snprintf(greetingtmp, MAXDATASIZE, "%s%s", greeting001, newnickuserhostcpy);
+
+ // Terminate it
+ greetingtmp[pos + strlen(newnickuserhostcpy)] = '\0';
+
+ // Copy back to source greeting 001
+ strcpy(greeting001, greetingtmp);
+
+ printf("updategreetings(): new greeting 001 '%s', length '%ld'.\n", greeting001, strlen(greeting001));
+
+ // Get the new nick
+
+ char newnickcpy[MAXDATASIZE];
+ strcpy(newnickcpy, newnick);
+ extractnickfromprefix(newnickcpy);
+
+ // greeting nicks next
+ // (as in ":servername 00x oldnick :Blablabla" -> ":servername 00x newnick :Blablabla")
+ updategreetingnick(greeting001, "001", newnickcpy, oldnick);
+ updategreetingnick(greeting002, "002", newnickcpy, oldnick);
+ updategreetingnick(greeting003, "003", newnickcpy, oldnick);
+ updategreetingnick(greeting004, "004", newnickcpy, oldnick);
+}
diff --git a/functions.h b/functions.h
index de631e9..2877bc5 100644
--- a/functions.h
+++ b/functions.h
@@ -14,6 +14,7 @@
#include <sys/select.h>
#define MAXDATASIZE 513 // max number of bytes we can get at once (RFC2812 says 512, plus one for null terminator)
+#define MAXTOKENS 100 // maximum number of (CRLF or space) separated tokens per server response we expect (TODO - check this is reasonable)
// getstdin() return codes
#define OK 0
@@ -38,4 +39,7 @@ void extractnickfromprefix(char *string);
// Update an existing nickuserhost string with a new nick
void updatenickuserhost(char *nickuserhost, char *nick);
+// Update an existing 001 greeting with a new nickuserhost
+void updategreetings(char *greeting001, char *greeting002, char *greeting003, char *greeting004, char *newnickuserhost, char *oldnickuserhost, char *newnick, char *oldnick);
+
#endif