aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--general_network.c200
-rw-r--r--general_network.h50
-rw-r--r--protocols.c2
-rw-r--r--protocols.h6
-rw-r--r--protocols/inspircd2.c349
-rw-r--r--protocols/inspircd2.h23
-rw-r--r--server_network.c42
-rw-r--r--server_network.h23
9 files changed, 625 insertions, 72 deletions
diff --git a/Makefile b/Makefile
index 4bc5184..8d541a0 100644
--- a/Makefile
+++ b/Makefile
@@ -28,7 +28,7 @@
INCLUDEFLAGS =
-CFLAGS += $(INCLUDEFLAGS) -D_REENTRANT -ggdb3 -Wall -Wextra -Wsign-conversion -Wno-unused-parameter -std=gnu99
+CFLAGS += $(INCLUDEFLAGS) -D_REENTRANT -ggdb3 -Wall -Wextra -Wsign-conversion -Wno-unused-parameter -Wno-implicit-fallthrough -std=gnu99
LDFLAGS = -lpthread
diff --git a/general_network.c b/general_network.c
index 5987e98..6df6ba8 100644
--- a/general_network.c
+++ b/general_network.c
@@ -27,6 +27,8 @@
// OTHER DEALINGS IN THE SOFTWARE.
#include <arpa/inet.h>
+#include <stdlib.h>
+#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
@@ -108,6 +110,7 @@ struct network networks[NUM_NET_TYPES] = {
};
struct table server_list = {0};
+struct table user_list = {0};
// TODO: Proper string handling
int resolve(struct string address, struct string port, struct sockaddr *sockaddr) {
@@ -130,7 +133,6 @@ int resolve(struct string address, struct string port, struct sockaddr *sockaddr
return success;
}
-// TODO: May leak memory on failure, not currently an issue since this failing currently just results in program exit anyways
int init_general_network(void) {
for (size_t i = 1; i < UCHAR_MAX + 1; i++) {
if (casemap[i] == 0) {
@@ -138,5 +140,201 @@ int init_general_network(void) {
}
}
+ server_list.array = malloc(0);
+
+ struct server_info *own_info;
+ own_info = malloc(sizeof(*own_info));
+ if (!own_info) {
+ free(server_list.array);
+ return 1;
+ }
+
+ own_info->sid.data = malloc(SID.len);
+ if (!own_info->sid.data) {
+ free(server_list.array);
+ free(own_info);
+ return 1;
+ }
+ memcpy(own_info->sid.data, SID.data, SID.len);
+ own_info->sid.len = SID.len;
+
+ own_info->name.data = malloc(SERVER_NAME.len);
+ if (!own_info->name.data) {
+ free(server_list.array);
+ free(own_info->sid.data);
+ free(own_info);
+ return 1;
+ }
+ memcpy(own_info->name.data, SERVER_NAME.data, SERVER_NAME.len);
+ own_info->name.len = SERVER_NAME.len;
+
+ own_info->fullname.data = malloc(SERVER_FULLNAME.len);
+ if (!own_info->fullname.data) {
+ free(server_list.array);
+ free(own_info->name.data);
+ free(own_info->sid.data);
+ free(own_info);
+ return 1;
+ }
+ memcpy(own_info->fullname.data, SERVER_FULLNAME.data, SERVER_FULLNAME.len);
+ own_info->fullname.len = SERVER_FULLNAME.len;
+
+ if (set_table_index(&server_list, SID, own_info) != 0) {
+ free(server_list.array);
+ free(own_info->fullname.data);
+ free(own_info->name.data);
+ free(own_info->sid.data);
+ free(own_info);
+ return 1;
+ }
+
+ own_info->next = SID;
+ own_info->connected_to = (struct table){.array = malloc(0), .len = 0};
+ own_info->user_list = (struct table){.array = malloc(0), .len = 0};
+ own_info->distance = 0;
+ own_info->net = 0;
+ own_info->protocol = 0;
+
+ user_list.array = malloc(0);
+
return 0;
}
+
+int add_user(struct string from, struct string attached_to, struct string uid, struct string nick, struct string fullname, struct string ident, struct string vhost, struct string host, struct string address, size_t user_ts, size_t nick_ts, void *handle, size_t protocol, size_t net) {
+ struct server_info *attached = get_table_index(server_list, attached_to);
+ if (!attached)
+ return 1;
+
+ if (has_table_index(user_list, uid))
+ return 1;
+
+ struct user_info *new_info;
+ new_info = malloc(sizeof(*new_info));
+ if (!new_info)
+ return 1;
+
+ new_info->user_ts = user_ts;
+ new_info->nick_ts = nick_ts;
+
+ new_info->protocol = protocol;
+ new_info->net = net;
+ new_info->handle = handle;
+
+ new_info->server = attached->sid;
+
+ new_info->uid.data = malloc(uid.len);
+ if (!new_info->uid.data)
+ goto add_user_free_info;
+ memcpy(new_info->uid.data, uid.data, uid.len);
+ new_info->uid.len = uid.len;
+
+ new_info->nick.data = malloc(nick.len);
+ if (!new_info->nick.data)
+ goto add_user_free_uid;
+ memcpy(new_info->nick.data, nick.data, nick.len);
+ new_info->nick.len = nick.len;
+
+ new_info->fullname.data = malloc(fullname.len);
+ if (!new_info->fullname.data && fullname.len != 0)
+ goto add_user_free_nick;
+ memcpy(new_info->fullname.data, fullname.data, fullname.len);
+ new_info->fullname.len = fullname.len;
+
+ new_info->ident.data = malloc(ident.len);
+ if (!new_info->ident.data)
+ goto add_user_free_fullname;
+ memcpy(new_info->ident.data, ident.data, ident.len);
+ new_info->ident.len = ident.len;
+
+ new_info->vhost.data = malloc(vhost.len);
+ if (!new_info->vhost.data)
+ goto add_user_free_ident;
+ memcpy(new_info->vhost.data, vhost.data, vhost.len);
+ new_info->vhost.len = vhost.len;
+
+ new_info->host.data = malloc(host.len);
+ if (!new_info->host.data)
+ goto add_user_free_vhost;
+ memcpy(new_info->host.data, host.data, host.len);
+ new_info->host.len = host.len;
+
+ new_info->address.data = malloc(address.len);
+ if (!new_info->address.data)
+ goto add_user_free_host;
+ memcpy(new_info->address.data, address.data, address.len);
+ new_info->address.len = address.len;
+
+ if (set_table_index(&user_list, uid, new_info) != 0)
+ goto add_user_free_address;
+
+ if (set_table_index(&(attached->user_list), uid, new_info) != 0)
+ goto add_user_remove_user_list;
+
+ new_info->channel_list.array = malloc(0);
+ new_info->channel_list.len = 0;
+
+#ifdef USE_SERVER
+#ifdef USE_HAXIRCD_PROTOCOL
+ protocols[HAXIRCD_PROTOCOL].propagate_new_user(from, new_info);
+#endif
+#ifdef USE_INSPIRCD2_PROTOCOL
+ protocols[INSPIRCD2_PROTOCOL].propagate_new_user(from, new_info);
+#endif
+#endif
+
+ return 0;
+
+ add_user_remove_user_list:
+ remove_table_index(&user_list, uid);
+ add_user_free_address:
+ free(new_info->address.data);
+ add_user_free_host:
+ free(new_info->host.data);
+ add_user_free_vhost:
+ free(new_info->vhost.data);
+ add_user_free_ident:
+ free(new_info->ident.data);
+ add_user_free_fullname:
+ free(new_info->fullname.data);
+ add_user_free_nick:
+ free(new_info->nick.data);
+ add_user_free_uid:
+ free(new_info->uid.data);
+ add_user_free_info:
+ free(new_info);
+
+ return 1;
+}
+
+void remove_user(struct string from, struct user_info *user, struct string reason, char propagate) {
+#ifdef USE_SERVER
+ if (propagate) {
+#ifdef USE_HAXIRCD_PROTOCOL
+ protocols[HAXIRCD_PROTOCOL].propagate_remove_user(from, user, reason);
+#endif
+#ifdef USE_INSPIRCD2_PROTOCOL
+ protocols[INSPIRCD2_PROTOCOL].propagate_remove_user(from, user, reason);
+#endif
+ }
+#endif
+
+ remove_table_index(&user_list, user->uid);
+
+ struct server_info *server = get_table_index(server_list, user->server);
+ if (server) {
+ remove_table_index(&(server->user_list), user->uid);
+ }
+
+ // TODO: Channel cleanup code hereish
+ clear_table(&(user->channel_list));
+ free(user->channel_list.array);
+
+ free(user->uid.data);
+ free(user->nick.data);
+ free(user->fullname.data);
+ free(user->ident.data);
+ free(user->vhost.data);
+ free(user->host.data);
+ free(user->address.data);
+ free(user);
+}
diff --git a/general_network.h b/general_network.h
index 202f877..6b76256 100644
--- a/general_network.h
+++ b/general_network.h
@@ -45,10 +45,57 @@ struct network {
void (*close)(int fd, void *handle);
};
+struct server_info {
+ struct string sid;
+ struct string name;
+ struct string fullname;
+
+ struct string next; // Self for self, else which server we should send a message to to get to this server
+
+ struct table connected_to; // List of servers that this server is connected to
+
+ struct table user_list;
+
+ void *handle;
+
+ size_t protocol;
+ size_t net;
+
+ size_t distance;
+};
+
+struct user_info {
+ struct string uid;
+ struct string nick;
+ struct string fullname;
+
+ struct string ident;
+
+ struct string vhost;
+ struct string host;
+ struct string address;
+
+ size_t user_ts;
+ size_t nick_ts;
+
+ struct string server;
+
+ struct table channel_list;
+
+ void *handle;
+
+ size_t protocol;
+ size_t net;
+};
+
int resolve(struct string address, struct string port, struct sockaddr *sockaddr);
int init_general_network(void);
+int add_user(struct string from, struct string attached_to, struct string uid, struct string nick, struct string fullname, struct string ident, struct string vhost, struct string host, struct string address, size_t user_ts, size_t nick_ts, void *handle, size_t protocol, size_t net);
+// Does not propagate, but will inform local clients about it
+void remove_user(struct string from, struct user_info *user, struct string reason, char propagate);
+
extern char casemap[UCHAR_MAX+1];
#define CASEMAP(x) (casemap[(unsigned char)x])
@@ -64,3 +111,6 @@ extern char casemap[UCHAR_MAX+1];
#define NUM_NET_TYPES 3
extern struct network networks[NUM_NET_TYPES];
+
+extern struct table server_list;
+extern struct table user_list;
diff --git a/protocols.c b/protocols.c
index 1adb383..04dd2f9 100644
--- a/protocols.c
+++ b/protocols.c
@@ -41,6 +41,8 @@ struct protocol protocols[NUM_PROTOCOLS] = {
.propagate_new_server = inspircd2_protocol_propagate_new_server,
.propagate_unlink = inspircd2_protocol_propagate_unlink,
+ .propagate_new_user = inspircd2_protocol_propagate_new_user,
+ .propagate_remove_user = inspircd2_protocol_propagate_remove_user,
.do_unlink = inspircd2_protocol_do_unlink,
},
diff --git a/protocols.h b/protocols.h
index 3b4aca3..723d971 100644
--- a/protocols.h
+++ b/protocols.h
@@ -33,10 +33,12 @@ struct protocol {
void * (*autoconnect)(void *config);
void (*update_propagations)(void);
- void (*propagate_new_server)(struct string from, struct string attached_to, struct string sid, struct server_info *info);
+ void (*propagate_new_server)(struct string from, struct string attached_to, struct server_info *info);
void (*propagate_unlink)(struct string from, struct server_info *a, struct server_info *b, size_t protocol);
+ void (*propagate_new_user)(struct string from, struct user_info *info);
+ void (*propagate_remove_user)(struct string from, struct user_info *info, struct string reason);
- void (*do_unlink)(struct server_info *a, struct server_info *b);
+ void (*do_unlink)(struct string from, struct server_info *a, struct server_info *b);
};
#ifdef USE_HAXIRCD_PROTOCOL
diff --git a/protocols/inspircd2.c b/protocols/inspircd2.c
index 496c0d0..883dbc5 100644
--- a/protocols/inspircd2.c
+++ b/protocols/inspircd2.c
@@ -43,6 +43,81 @@
struct table inspircd2_protocol_init_commands = {0};
struct table inspircd2_protocol_commands = {0};
+char inspircd2_protocol_user_mode_types[UCHAR_MAX+1] = {
+ ['c'] = MODE_TYPE_NOARGS,
+ ['d'] = MODE_TYPE_NOARGS,
+ ['g'] = MODE_TYPE_NOARGS,
+ ['h'] = MODE_TYPE_NOARGS,
+ ['i'] = MODE_TYPE_NOARGS,
+ ['k'] = MODE_TYPE_NOARGS,
+ ['o'] = MODE_TYPE_NOARGS,
+ ['r'] = MODE_TYPE_NOARGS,
+ ['s'] = MODE_TYPE_MODE,
+ ['w'] = MODE_TYPE_NOARGS,
+ ['x'] = MODE_TYPE_NOARGS,
+ ['z'] = MODE_TYPE_NOARGS,
+ ['B'] = MODE_TYPE_NOARGS,
+ ['D'] = MODE_TYPE_NOARGS,
+ ['G'] = MODE_TYPE_NOARGS,
+ ['H'] = MODE_TYPE_NOARGS,
+ ['I'] = MODE_TYPE_NOARGS,
+ ['L'] = MODE_TYPE_NOARGS,
+ ['N'] = MODE_TYPE_NOARGS,
+ ['O'] = MODE_TYPE_NOARGS,
+ ['R'] = MODE_TYPE_NOARGS,
+ ['S'] = MODE_TYPE_NOARGS,
+ ['T'] = MODE_TYPE_NOARGS,
+ ['W'] = MODE_TYPE_NOARGS,
+};
+
+char inspircd2_protocol_channel_mode_types[UCHAR_MAX+1] = {
+ ['a'] = MODE_TYPE_USERS,
+ ['b'] = MODE_TYPE_MULTIPLE,
+ ['c'] = MODE_TYPE_NOARGS,
+ ['d'] = MODE_TYPE_REPLACE,
+ ['e'] = MODE_TYPE_MULTIPLE,
+ ['f'] = MODE_TYPE_REPLACE,
+ ['g'] = MODE_TYPE_REPLACE,
+ ['h'] = MODE_TYPE_USERS,
+ ['i'] = MODE_TYPE_NOARGS,
+ ['j'] = MODE_TYPE_REPLACE,
+ ['k'] = MODE_TYPE_REPLACE,
+ ['l'] = MODE_TYPE_REPLACE,
+ ['m'] = MODE_TYPE_NOARGS,
+ ['n'] = MODE_TYPE_NOARGS,
+ ['o'] = MODE_TYPE_USERS,
+ ['p'] = MODE_TYPE_NOARGS,
+ ['q'] = MODE_TYPE_USERS,
+ ['r'] = MODE_TYPE_NOARGS,
+ ['s'] = MODE_TYPE_NOARGS,
+ ['t'] = MODE_TYPE_NOARGS,
+ ['u'] = MODE_TYPE_NOARGS,
+ ['v'] = MODE_TYPE_USERS,
+ ['w'] = MODE_TYPE_MULTIPLE,
+ ['z'] = MODE_TYPE_NOARGS,
+ ['A'] = MODE_TYPE_NOARGS,
+ ['B'] = MODE_TYPE_NOARGS,
+ ['C'] = MODE_TYPE_NOARGS,
+ ['D'] = MODE_TYPE_NOARGS,
+ ['E'] = MODE_TYPE_REPLACE,
+ ['F'] = MODE_TYPE_REPLACE,
+ ['G'] = MODE_TYPE_NOARGS,
+ ['H'] = MODE_TYPE_REPLACE,
+ ['I'] = MODE_TYPE_MULTIPLE,
+ ['J'] = MODE_TYPE_REPLACE,
+ ['K'] = MODE_TYPE_NOARGS,
+ ['L'] = MODE_TYPE_REPLACE,
+ ['M'] = MODE_TYPE_NOARGS,
+ ['N'] = MODE_TYPE_NOARGS,
+ ['O'] = MODE_TYPE_NOARGS,
+ ['P'] = MODE_TYPE_NOARGS,
+ ['Q'] = MODE_TYPE_NOARGS,
+ ['R'] = MODE_TYPE_NOARGS,
+ ['S'] = MODE_TYPE_NOARGS,
+ ['T'] = MODE_TYPE_NOARGS,
+ ['X'] = MODE_TYPE_MULTIPLE,
+};
+
int init_inspircd2_protocol(void) {
inspircd2_protocol_commands.array = malloc(0);
@@ -52,6 +127,8 @@ int init_inspircd2_protocol(void) {
set_table_index(&inspircd2_protocol_commands, STRING("PING"), &inspircd2_protocol_handle_ping);
set_table_index(&inspircd2_protocol_commands, STRING("SERVER"), &inspircd2_protocol_handle_server);
set_table_index(&inspircd2_protocol_commands, STRING("SQUIT"), &inspircd2_protocol_handle_squit);
+ set_table_index(&inspircd2_protocol_commands, STRING("UID"), &inspircd2_protocol_handle_uid);
+ set_table_index(&inspircd2_protocol_commands, STRING("QUIT"), &inspircd2_protocol_handle_quit);
return 0;
}
@@ -159,7 +236,7 @@ void * inspircd2_protocol_connection(void *type) {
offset++;
if (msg_len == offset) {
- WRITES(2, STRING("Protocol violation: empty message.\r\n\n"));
+ WRITES(2, STRING("[InspIRCd v2] Protocol violation: empty message.\r\n\n"));
goto inspircd2_protocol_handle_connection_close;
}
@@ -180,11 +257,16 @@ void * inspircd2_protocol_connection(void *type) {
source.len++;
}
if (source.len == 0) {
- WRITES(2, STRING("Protocol violation: source prefix but no source.\r\n\n"));
+ WRITES(2, STRING("[InspIRCd v2] Protocol violation: source prefix but no source.\r\n\n"));
goto inspircd2_protocol_handle_connection_close;
}
if (!found || offset >= msg_len) {
- WRITES(2, STRING("Protocol violation: source but no command.\r\n\n"));
+ WRITES(2, STRING("[InspIRCd v2] Protocol violation: source but no command.\r\n\n"));
+ goto inspircd2_protocol_handle_connection_close;
+ }
+
+ if (STRING_EQ(source, SID)) {
+ WRITES(2, STRING("[InspIRCd v2] Protocol violation: other server sent us as source!\r\n\n"));
goto inspircd2_protocol_handle_connection_close;
}
} else {
@@ -372,7 +454,7 @@ void inspircd2_protocol_update_propagations(void) {
inspircd2_protocol_update_propagations_inner(self);
}
-void inspircd2_protocol_propagate_new_server(struct string from, struct string attached_to, struct string sid, struct server_info *info) {
+void inspircd2_protocol_propagate_new_server(struct string from, struct string attached_to, struct server_info *info) {
struct server_info *self = get_table_index(server_list, SID);
for (size_t i = 0; i < self->connected_to.len; i++) {
@@ -390,13 +472,13 @@ void inspircd2_protocol_propagate_new_server(struct string from, struct string a
networks[adjacent->net].send(adjacent->handle, STRING(" SERVER "));
networks[adjacent->net].send(adjacent->handle, info->name);
networks[adjacent->net].send(adjacent->handle, STRING(" * 0 "));
- networks[adjacent->net].send(adjacent->handle, sid);
+ networks[adjacent->net].send(adjacent->handle, info->sid);
networks[adjacent->net].send(adjacent->handle, STRING(" :"));
networks[adjacent->net].send(adjacent->handle, info->fullname);
networks[adjacent->net].send(adjacent->handle, STRING("\n"));
networks[adjacent->net].send(adjacent->handle, STRING(":"));
- networks[adjacent->net].send(adjacent->handle, sid);
+ networks[adjacent->net].send(adjacent->handle, info->sid);
networks[adjacent->net].send(adjacent->handle, STRING(" BURST "));
time_t current = time(0);
@@ -404,14 +486,14 @@ void inspircd2_protocol_propagate_new_server(struct string from, struct string a
char err = unsigned_to_str((size_t)current, &current_time);
if (current < 0 || err) {
- networks[adjacent->net].send(adjacent->handle, STRING("0"));
+ networks[adjacent->net].send(adjacent->handle, STRING("1"));
} else {
networks[adjacent->net].send(adjacent->handle, current_time);
free(current_time.data);
}
networks[adjacent->net].send(adjacent->handle, STRING("\n:"));
- networks[adjacent->net].send(adjacent->handle, sid);
+ networks[adjacent->net].send(adjacent->handle, info->sid);
networks[adjacent->net].send(adjacent->handle, STRING(" ENDBURST\n"));
}
}
@@ -446,7 +528,74 @@ void inspircd2_protocol_propagate_unlink(struct string from, struct server_info
}
}
-void inspircd2_protocol_do_unlink_inner(struct server_info *target) {
+void inspircd2_protocol_propagate_new_user(struct string from, struct user_info *info) {
+ struct server_info *self = get_table_index(server_list, SID);
+
+ for (size_t i = 0; i < self->connected_to.len; i++) {
+ struct server_info *adjacent = self->connected_to.array[i].ptr;
+ if (adjacent->protocol != INSPIRCD2_PROTOCOL || STRING_EQ(from, adjacent->sid))
+ continue;
+
+ networks[adjacent->net].send(adjacent->handle, STRING(":"));
+ networks[adjacent->net].send(adjacent->handle, info->server);
+ networks[adjacent->net].send(adjacent->handle, STRING(" UID "));
+ networks[adjacent->net].send(adjacent->handle, info->uid);
+ networks[adjacent->net].send(adjacent->handle, STRING(" "));
+
+ struct string timestamp;
+ char err = unsigned_to_str(info->nick_ts, &timestamp);
+
+ if (err) {
+ networks[adjacent->net].send(adjacent->handle, STRING("1")); // TODO: Better fallback
+ } else {
+ networks[adjacent->net].send(adjacent->handle, timestamp);
+ free(timestamp.data);
+ }
+
+ networks[adjacent->net].send(adjacent->handle, STRING(" "));
+ networks[adjacent->net].send(adjacent->handle, info->nick);
+ networks[adjacent->net].send(adjacent->handle, STRING(" "));
+ networks[adjacent->net].send(adjacent->handle, info->host);
+ networks[adjacent->net].send(adjacent->handle, STRING(" "));
+ networks[adjacent->net].send(adjacent->handle, info->vhost);
+ networks[adjacent->net].send(adjacent->handle, STRING(" "));
+ networks[adjacent->net].send(adjacent->handle, info->ident);
+ networks[adjacent->net].send(adjacent->handle, STRING(" "));
+ networks[adjacent->net].send(adjacent->handle, info->address);
+ networks[adjacent->net].send(adjacent->handle, STRING(" "));
+
+ err = unsigned_to_str(info->user_ts, &timestamp);
+
+ if (err) {
+ networks[adjacent->net].send(adjacent->handle, STRING("1"));
+ } else {
+ networks[adjacent->net].send(adjacent->handle, timestamp);
+ free(timestamp.data);
+ }
+
+ networks[adjacent->net].send(adjacent->handle, STRING(" + :"));
+ networks[adjacent->net].send(adjacent->handle, info->fullname);
+ networks[adjacent->net].send(adjacent->handle, STRING("\n"));
+ }
+}
+
+void inspircd2_protocol_propagate_remove_user(struct string from, struct user_info *info, struct string reason) {
+ struct server_info *self = get_table_index(server_list, SID);
+
+ for (size_t i = 0; i < self->connected_to.len; i++) {
+ struct server_info *adjacent = self->connected_to.array[i].ptr;
+ if (adjacent->protocol != INSPIRCD2_PROTOCOL || STRING_EQ(from, adjacent->sid))
+ continue;
+
+ networks[adjacent->net].send(adjacent->handle, STRING(":"));
+ networks[adjacent->net].send(adjacent->handle, info->uid);
+ networks[adjacent->net].send(adjacent->handle, STRING(" QUIT :"));
+ networks[adjacent->net].send(adjacent->handle, reason);
+ networks[adjacent->net].send(adjacent->handle, STRING("\n"));
+ }
+}
+
+void inspircd2_protocol_do_unlink_inner(struct string from, struct server_info *target, struct string reason) {
target->distance = 1; // Reusing distance for `have passed`, since its set to 0 bc severed anyways
unsigned char i = 0;
@@ -456,25 +605,36 @@ void inspircd2_protocol_do_unlink_inner(struct server_info *target) {
i = 1;
continue;
}
- inspircd2_protocol_do_unlink_inner(adjacent);
- remove_table_index(&(target->connected_to), adjacent->sid);
- remove_table_index(&(server_list), adjacent->sid);
- free_server(adjacent);
+ inspircd2_protocol_do_unlink_inner(from, adjacent, reason);
+ remove_server(from, adjacent, reason);
}
}
-void inspircd2_protocol_do_unlink(struct server_info *a, struct server_info *b) {
+void inspircd2_protocol_do_unlink(struct string from, struct server_info *a, struct server_info *b) {
+ char valid;
+ struct string reason;
+ reason.data = malloc(a->name.len + 1 + b->name.len);
+ if (!reason.data) {
+ valid = 0;
+ reason = STRING("*.net *.split");
+ } else {
+ valid = 1;
+ memcpy(reason.data, a->name.data, a->name.len);
+ reason.data[a->name.len] = ' ';
+ memcpy(&(reason.data[a->name.len + 1]), b->name.data, b->name.len);
+ reason.len = a->name.len + 1 + b->name.len;
+ }
+
if (a->distance == 0 && !STRING_EQ(a->sid, SID)) {
- inspircd2_protocol_do_unlink_inner(a);
- remove_table_index(&(b->connected_to), a->sid);
- remove_table_index(&(server_list), a->sid);
- free_server(a);
+ inspircd2_protocol_do_unlink_inner(from, a, reason);
+ remove_server(from, a, reason);
} else {
- inspircd2_protocol_do_unlink_inner(b);
- remove_table_index(&(a->connected_to), b->sid);
- remove_table_index(&(server_list), b->sid);
- free_server(b);
+ inspircd2_protocol_do_unlink_inner(from, b, reason);
+ remove_server(from, b, reason);
}
+
+ if (valid)
+ free(reason.data);
}
void inspircd2_protocol_introduce_servers_to_inner(size_t net, void *handle, struct string source, struct server_info *target) {
@@ -582,6 +742,49 @@ int inspircd2_protocol_init_handle_server(struct string source, size_t argc, str
inspircd2_protocol_introduce_servers_to(net, handle);
+ for (size_t i = 0; i < user_list.len; i++) {
+ struct user_info *user = user_list.array[i].ptr;
+
+ networks[net].send(handle, STRING(":"));
+ networks[net].send(handle, user->server);
+ networks[net].send(handle, STRING(" UID "));
+ networks[net].send(handle, user->uid);
+ networks[net].send(handle, STRING(" "));
+
+ struct string timestamp;
+ char err = unsigned_to_str(user->nick_ts, &timestamp);
+
+ if (err) {
+ return -1;
+ }
+ networks[net].send(handle, timestamp);
+ free(timestamp.data);
+
+ networks[net].send(handle, STRING(" "));
+ networks[net].send(handle, user->nick);
+ networks[net].send(handle, STRING(" "));
+ networks[net].send(handle, user->host);
+ networks[net].send(handle, STRING(" "));
+ networks[net].send(handle, user->vhost);
+ networks[net].send(handle, STRING(" "));
+ networks[net].send(handle, user->ident);
+ networks[net].send(handle, STRING(" "));
+ networks[net].send(handle, user->address);
+ networks[net].send(handle, STRING(" "));
+
+ err = unsigned_to_str(user->nick_ts, &timestamp);
+
+ if (err) {
+ return -1;
+ }
+ networks[net].send(handle, timestamp);
+ free(timestamp.data);
+
+ networks[net].send(handle, STRING(" + :"));
+ networks[net].send(handle, user->fullname);
+ networks[net].send(handle, STRING("\n"));
+ }
+
networks[net].send(handle, STRING(":"));
networks[net].send(handle, SID);
networks[net].send(handle, STRING(" ENDBURST\n"));
@@ -621,6 +824,11 @@ int inspircd2_protocol_handle_server(struct string source, size_t argc, struct s
return -1;
}
+ if (has_table_index(server_list, argv[3])) {
+ WRITES(2, STRING("[InspIRCd v2] Duplicate SERVER attempted to be created!\r\n"));
+ return -1;
+ }
+
if (add_server(config->sid, source, argv[3], argv[0], argv[4], INSPIRCD2_PROTOCOL, net, handle) != 0) {
WRITES(2, STRING("ERROR: Unable to add server!\r\n"));
return -1;
@@ -655,3 +863,100 @@ int inspircd2_protocol_handle_squit(struct string source, size_t argc, struct st
return 0;
}
+
+// [:source] UID <UID> <nick_ts> <nick> <host> <vhost> <ident> <address> <user_ts> <modes> [<mode args>] <fullname>
+int inspircd2_protocol_handle_uid(struct string source, size_t argc, struct string *argv, size_t net, void *handle, struct server_config *config, char is_incoming) {
+ if (argc < 10) {
+ WRITES(2, STRING("[InspIRCd v2] Invalid UID recieved! (Missing parameters)\r\n"));
+ return -1;
+ }
+
+ if (has_table_index(user_list, argv[0])) {
+ WRITES(2, STRING("[InspIRCd v2] Duplicate UID attempted to be created!\r\n"));
+ return -1;
+ }
+
+ char dir = '?';
+ size_t arg_i = 9;
+ size_t mode_i = 0;
+
+ while (1) {
+ if (argv[8].len <= mode_i)
+ break;
+ switch(argv[8].data[mode_i]) {
+ case '+':
+ case '-':
+ dir = argv[8].data[mode_i];
+ break;
+ default:
+ if (dir == '?') {
+ WRITES(2, STRING("[InspIRCd v2] Invalid UID recieved! (Mode direction not set)\r\n"));
+ return -1;
+ }
+
+ switch(inspircd2_protocol_user_mode_types[(unsigned char)argv[8].data[mode_i]]) {
+ case MODE_TYPE_NOARGS:
+ break;
+ case MODE_TYPE_REPLACE:
+ case MODE_TYPE_MODE:
+ if (dir == '-') // Shouldn't actually happen here, but whatever
+ break;
+ case MODE_TYPE_MULTIPLE:
+ arg_i++;
+ break;
+ default:
+ WRITES(2, STRING("[InspIRCd v2] Invalid UID recieved! (Unknown mode given)\r\n"));
+ return -1;
+ }
+ }
+
+ mode_i++;
+ }
+
+ if (arg_i >= argc) {
+ WRITES(2, STRING("[InspIRCd v2] Invalid UID recieved! (Missing mode arguments)\r\n"));
+ return -1;
+ }
+
+ char err;
+ size_t nick_ts = str_to_unsigned(argv[1], &err);
+ if (err) {
+ WRITES(2, STRING("[InspIRCd v2] Invalid UID recieved! (Invalid nick timestamp)\r\n"));
+ return -1;
+ }
+
+ size_t user_ts = str_to_unsigned(argv[7], &err);
+ if (err) {
+ WRITES(2, STRING("[InspIRCd v2] Invalid UID recieved! (Invalid user timestamp)\r\n"));
+ return -1;
+ }
+
+ if (add_user(config->sid, source, argv[0], argv[2], argv[arg_i], argv[5], argv[4], argv[3], argv[6], user_ts, nick_ts, 0, 0, 0) != 0) {
+ WRITES(2, STRING("ERROR: Unable to add user!\r\n"));
+ return -1;
+ }
+
+ return 0;
+}
+
+// :source QUIT <reason>
+int inspircd2_protocol_handle_quit(struct string source, size_t argc, struct string *argv, size_t net, void *handle, struct server_config *config, char is_incoming) {
+ struct string reason;
+ if (argc < 1)
+ reason = STRING("");
+ else
+ reason = argv[0];
+
+ struct user_info *user = get_table_index(user_list, source);
+ if (!user)
+ return 0; // Maybe KILLed or something
+
+ if (STRING_EQ(user->server, SID)) {
+ WRITES(2, STRING("[InspIRCd v2] Invalid QUIT recieved! (Attempting to quit a local user)\r\n"));
+ return -1;
+ }
+
+ remove_user(config->sid, user, reason, 1);
+
+ return 0;
+}
diff --git a/protocols/inspircd2.h b/protocols/inspircd2.h
index 48a6f59..e31bf19 100644
--- a/protocols/inspircd2.h
+++ b/protocols/inspircd2.h
@@ -41,14 +41,16 @@ void * inspircd2_protocol_connection(void *type);
void * inspircd2_protocol_autoconnect(void *type);
void inspircd2_protocol_update_propagations(void);
-void inspircd2_protocol_propagate_new_server(struct string from, struct string attached_to, struct string sid, struct server_info *info);
+void inspircd2_protocol_propagate_new_server(struct string from, struct string attached_to, struct server_info *info);
void inspircd2_protocol_propagate_unlink(struct string from, struct server_info *a, struct server_info *b, size_t protocol);
+void inspircd2_protocol_propagate_new_user(struct string from, struct user_info *info);
+void inspircd2_protocol_propagate_remove_user(struct string from, struct user_info *info, struct string reason);
-void inspircd2_protocol_do_unlink(struct server_info *a, struct server_info *b);
+void inspircd2_protocol_do_unlink(struct string from, struct server_info *a, struct server_info *b);
void inspircd2_protocol_update_propagations_inner(struct server_info *source);
-void inspircd2_protocol_do_unlink_inner(struct server_info *source);
+void inspircd2_protocol_do_unlink_inner(struct string from, struct server_info *source, struct string reason);
int inspircd2_protocol_init_handle_server(struct string source, size_t argc, struct string *argv, size_t net, void *handle, struct server_config **config, char is_incoming);
int inspircd2_protocol_init_handle_capab(struct string source, size_t argc, struct string *argv, size_t net, void *handle, struct server_config **config, char is_incoming);
@@ -56,3 +58,18 @@ int inspircd2_protocol_init_handle_capab(struct string source, size_t argc, stru
int inspircd2_protocol_handle_ping(struct string source, size_t argc, struct string *argv, size_t net, void *handle, struct server_config *config, char is_incoming);
int inspircd2_protocol_handle_server(struct string source, size_t argc, struct string *argv, size_t net, void *handle, struct server_config *config, char is_incoming);
int inspircd2_protocol_handle_squit(struct string source, size_t argc, struct string *argv, size_t net, void *handle, struct server_config *config, char is_incoming);
+int inspircd2_protocol_handle_uid(struct string source, size_t argc, struct string *argv, size_t net, void *handle, struct server_config *config, char is_incoming);
+int inspircd2_protocol_handle_quit(struct string source, size_t argc, struct string *argv, size_t net, void *handle, struct server_config *config, char is_incoming);
+
+#define MODE_TYPE_UNKNOWN 0
+#define MODE_TYPE_NOARGS 1
+#define MODE_TYPE_REPLACE 2
+#define MODE_TYPE_MULTIPLE 3
+
+// Channel modes only, goes away when the related user leaves
+#define MODE_TYPE_USERS 4
+
+// Used for e.g. snomasks
+#define MODE_TYPE_MODE 5
+extern char inspircd2_protocol_user_mode_types[UCHAR_MAX+1];
+extern char inspircd2_protocol_channel_mode_types[UCHAR_MAX+1];
diff --git a/server_network.c b/server_network.c
index 7f481ec..ea92d3c 100644
--- a/server_network.c
+++ b/server_network.c
@@ -53,25 +53,6 @@ int init_server_network(void) {
}
}
- server_list.array = malloc(0);
-
- struct server_info *own_info;
- own_info = malloc(sizeof(*own_info));
- own_info->sid.data = malloc(SID.len);
- if (!own_info->sid.data)
- return 1;
- memcpy(own_info->sid.data, SID.data, SID.len);
- own_info->sid.len = SID.len;
-
- own_info->next = SID;
- own_info->connected_to = (struct table){.array = malloc(0), .len = 0};
- own_info->user_list = (struct table){.array = malloc(0), .len = 0};
- own_info->distance = 0;
- own_info->net = 0;
- own_info->protocol = 0;
- if (set_table_index(&server_list, SID, own_info) != 0)
- return 1;
-
return 0;
}
@@ -241,10 +222,10 @@ int add_server(struct string from, struct string attached_to, struct string sid,
protocols[protocol].update_propagations();
#ifdef USE_HAXIRCD_PROTOCOL
- protocols[HAXIRCD_PROTOCOL].propagate_new_server(from, attached_to, sid, new_info);
+ protocols[HAXIRCD_PROTOCOL].propagate_new_server(from, attached_to, new_info);
#endif
#ifdef USE_INSPIRCD2_PROTOCOL
- protocols[INSPIRCD2_PROTOCOL].propagate_new_server(from, attached_to, sid, new_info);
+ protocols[INSPIRCD2_PROTOCOL].propagate_new_server(from, attached_to, new_info);
#endif
return 0;
@@ -267,6 +248,8 @@ int add_server(struct string from, struct string attached_to, struct string sid,
void free_server(struct server_info *server) {
free(server->sid.data);
+ free(server->name.data);
+ free(server->fullname.data);
clear_table(&(server->connected_to));
free(server->connected_to.array);
clear_table(&(server->user_list));
@@ -275,6 +258,21 @@ void free_server(struct server_info *server) {
free(server);
}
+void remove_server(struct string from, struct server_info *server, struct string reason) {
+ while (server->user_list.len != 0) {
+ remove_user(from, server->user_list.array[0].ptr, reason, 0);
+ }
+
+ for (size_t i = 0; i < server->connected_to.len; i++) {
+ struct server_info *adjacent = server->connected_to.array[i].ptr;
+ remove_table_index(&(adjacent->connected_to), server->sid);
+ }
+
+ remove_table_index(&(server_list), server->sid);
+
+ free_server(server);
+}
+
void update_all_propagations(void) {
#ifdef USE_HAXIRCD_PROTOCOL
protocols[HAXIRCD_PROTOCOL].update_propagations();
@@ -300,5 +298,5 @@ void unlink_server(struct string from, struct server_info *a, struct server_info
protocols[INSPIRCD2_PROTOCOL].propagate_unlink(from, a, b, protocol);
#endif
- protocols[protocol].do_unlink(a, b);
+ protocols[protocol].do_unlink(from, a, b);
}
diff --git a/server_network.h b/server_network.h
index ac4a23e..8b6457e 100644
--- a/server_network.h
+++ b/server_network.h
@@ -28,6 +28,7 @@
#include <stddef.h>
+#include "general_network.h"
#include "haxstring.h"
#include "table.h"
@@ -45,25 +46,6 @@ struct server_connection_info {
void *handle;
};
-struct server_info {
- struct string sid;
- struct string name;
- struct string fullname;
-
- struct string next; // Self for self, else which server we should send a message to to get to this server
-
- struct table connected_to; // List of servers that this server is connected to
-
- struct table user_list;
-
- void *handle;
-
- size_t protocol;
- size_t net;
-
- size_t distance;
-};
-
int init_server_network(void);
int start_server_network(void);
int start_server_network_threads(size_t net);
@@ -74,10 +56,9 @@ void * handle_server_thread(void *type);
int add_server(struct string from, struct string attached_to, struct string sid, struct string name, struct string fullname, size_t protocol, size_t net, void *handle);
void free_server(struct server_info *server);
+void remove_server(struct string from, struct server_info *server, struct string reason);
void update_all_propagations(void);
void unlink_server(struct string from, struct server_info *a, struct server_info *b, size_t protocol);
extern struct table server_config;
-
-extern struct table server_list;