diff options
author | Test_User <hax@andrewyu.org> | 2024-06-15 18:35:19 -0400 |
---|---|---|
committer | Test_User <hax@andrewyu.org> | 2024-06-15 18:35:19 -0400 |
commit | 98040ca35a29172701adf32c95e6d15392ec5fd1 (patch) | |
tree | db51f5aba9e3cdacd8a636faf19758538a9bf60e | |
parent | 4876b376c4eed926e4500b9f2cd1a3b8bfde554f (diff) | |
download | haxircd-98040ca35a29172701adf32c95e6d15392ec5fd1.tar.gz haxircd-98040ca35a29172701adf32c95e6d15392ec5fd1.zip |
Start of InspIRCd v3 support
-rw-r--r-- | Makefile | 19 | ||||
-rw-r--r-- | general_network.c | 81 | ||||
-rw-r--r-- | general_network.h | 19 | ||||
-rw-r--r-- | protocol_numbers.h | 39 | ||||
-rw-r--r-- | protocols.c | 171 | ||||
-rw-r--r-- | protocols.h | 27 | ||||
-rw-r--r-- | protocols/inspircd2.c | 25 | ||||
-rw-r--r-- | protocols/inspircd2.h | 13 | ||||
-rw-r--r-- | protocols/inspircd3.c | 1548 | ||||
-rw-r--r-- | protocols/inspircd3.h | 100 | ||||
-rw-r--r-- | real_main.c | 4 | ||||
-rw-r--r-- | server_network.c | 41 |
12 files changed, 1974 insertions, 113 deletions
@@ -42,6 +42,7 @@ LDFLAGS = -lpthread printf '%s\n' 'LAST_OPENSSL_CLIENT = $(OPENSSL_CLIENT)' >> .makeopts printf '%s\n' 'LAST_OPENSSL_SERVER = $(OPENSSL_SERVER)' >> .makeopts printf '%s\n' 'LAST_INSPIRCD2_PROTOCOL = $(INSPIRCD2_PROTOCOL)' >> .makeopts + printf '%s\n' 'LAST_INSPIRCD3_PROTOCOL = $(INSPIRCD3_PROTOCOL)' >> .makeopts printf '%s\n' 'LAST_HAXSERV_PSUEDOCLIENT = $(HAXSERV_PSUEDOCLIENT)' >> .makeopts printf '%s\n' 'LAST_SAFE_STACK = $(SAFE_STACK)' >> .makeopts printf '%s\n' 'LAST_CFLAGS = $(ORIGINAL_CFLAGS)' >> .makeopts @@ -108,6 +109,14 @@ else INSPIRCD2_PROTOCOL = $(LAST_INSPIRCD2_PROTOCOL) endif +ifneq ($(INSPIRCD3_PROTOCOL),) +ifneq ($(INSPIRCD3_PROTOCOL),$(LAST_INSPIRCD3_PROTOCOL)) +rebuild = 1 +endif +else +INSPIRCD3_PROTOCOL = $(LAST_INSPIRCD3_PROTOCOL) +endif + ifneq ($(HAXSERV_PSUEDOCLIENT),) ifneq ($(HAXSERV_PSUEDOCLIENT),$(LAST_HAXSERV_PSUEDOCLIENT)) rebuild = 1 @@ -197,6 +206,12 @@ CFLAGS += -DUSE_INSPIRCD2_PROTOCOL USE_PROTOCOLS = 1 endif +ifeq ($(INSPIRCD3_PROTOCOL),1) +OFILES += protocols/inspircd3.o +CFLAGS += -DUSE_INSPIRCD3_PROTOCOL +USE_PROTOCOLS = 1 +endif + ifeq ($(HAXSERV_PSUEDOCLIENT),1) @@ -321,6 +336,10 @@ ifeq ($(INSPIRCD2_PROTOCOL),1) $(call DEPS,protocols/inspircd2,o) endif +ifeq ($(INSPIRCD3_PROTOCOL),1) +$(call DEPS,protocols/inspircd3,o) +endif + ifeq ($(USE_PSUEDOCLIENTS),1) $(call DEPS,psuedoclients,o) endif diff --git a/general_network.c b/general_network.c index 13626cf..b300c87 100644 --- a/general_network.c +++ b/general_network.c @@ -50,6 +50,10 @@ #include "openssl_network.h" #endif +#ifdef USE_PROTOCOLS +#include "protocols.h" +#endif + #ifdef USE_PSUEDOCLIENTS #include "psuedoclients.h" #endif @@ -292,12 +296,7 @@ int add_user(struct string from, struct string attached_to, struct string uid, s 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 + protocols_propagate_new_user(from, new_info); #endif return 0; @@ -342,12 +341,7 @@ int rename_user(struct string from, struct user_info *user, struct string nick, } #ifdef USE_SERVER -#ifdef USE_HAXIRCD_PROTOCOL - protocols[HAXIRCD_PROTOCOL].propagate_rename_user(from, user, nick, timestamp, timestamp_str); -#endif -#ifdef USE_INSPIRCD2_PROTOCOL - protocols[INSPIRCD2_PROTOCOL].propagate_rename_user(from, user, nick, timestamp, timestamp_str); -#endif + protocols_propagate_rename_user(from, user, nick, timestamp, timestamp_str); #endif free(user->nick.data); @@ -361,12 +355,7 @@ int rename_user(struct string from, struct user_info *user, struct string nick, 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 + protocols_propagate_remove_user(from, user, reason); } #endif @@ -411,12 +400,7 @@ int kill_user(struct string from, struct string source, struct user_info *user, #endif #ifdef USE_SERVER -#ifdef USE_HAXIRCD_PROTOCOL - protocols[HAXIRCD_PROTOCOL].propagate_kill_user(from, source, user, reason); -#endif -#ifdef USE_INSPIRCD2_PROTOCOL - protocols[INSPIRCD2_PROTOCOL].propagate_kill_user(from, source, user, reason); -#endif + protocols_propagate_kill_user(from, source, user, reason); #endif remove_user(from, user, reason, 0); @@ -430,12 +414,7 @@ int oper_user(struct string from, struct user_info *user, struct string type) { return 1; #ifdef USE_SERVER -#ifdef USE_HAXIRCD_PROTOCOL - protocols[HAXIRCD_PROTOCOL].propagate_oper_user(from, user, type); -#endif -#ifdef USE_INSPIRCD2_PROTOCOL - protocols[INSPIRCD2_PROTOCOL].propagate_oper_user(from, user, type); -#endif + protocols_propagate_oper_user(from, user, type); #endif free(user->oper_type.data); @@ -489,12 +468,7 @@ int set_channel(struct string from, struct string name, size_t timestamp, size_t } #ifdef USE_SERVER -#ifdef USE_HAXIRCD_PROTOCOL - protocols[HAXIRCD_PROTOCOL].propagate_set_channel(from, channel, is_new_channel, user_count, users); -#endif -#ifdef USE_INSPIRCD2_PROTOCOL - protocols[INSPIRCD2_PROTOCOL].propagate_set_channel(from, channel, is_new_channel, user_count, users); -#endif + protocols_propagate_set_channel(from, channel, is_new_channel, user_count, users); #endif return 0; @@ -548,12 +522,7 @@ int join_channel(struct string from, struct channel_info *channel, size_t user_c #endif #ifdef USE_SERVER -#ifdef USE_HAXIRCD_PROTOCOL - protocols[HAXIRCD_PROTOCOL].propagate_join_channel(from, channel, user_count, users); -#endif -#ifdef USE_INSPIRCD2_PROTOCOL - protocols[INSPIRCD2_PROTOCOL].propagate_join_channel(from, channel, user_count, users); -#endif + protocols_propagate_join_channel(from, channel, user_count, users); #endif } @@ -576,12 +545,7 @@ void part_channel(struct string from, struct channel_info *channel, struct user_ if (propagate) { #ifdef USE_SERVER -#ifdef USE_HAXIRCD_PROTOCOL - protocols[HAXIRCD_PROTOCOL].propagate_part_channel(from, channel, user, reason); -#endif -#ifdef USE_INSPIRCD2_PROTOCOL - protocols[INSPIRCD2_PROTOCOL].propagate_part_channel(from, channel, user, reason); -#endif + protocols_propagate_part_channel(from, channel, user, reason); #endif } @@ -611,12 +575,7 @@ int kick_channel(struct string from, struct string source, struct channel_info * #endif #ifdef USE_SERVER -#ifdef USE_HAXIRCD_PROTOCOL - protocols[HAXIRCD_PROTOCOL].propagate_kick_channel(from, source, channel, user, reason); -#endif -#ifdef USE_INSPIRCD2_PROTOCOL - protocols[INSPIRCD2_PROTOCOL].propagate_kick_channel(from, source, channel, user, reason); -#endif + protocols_propagate_kick_channel(from, source, channel, user, reason); #endif return 1; @@ -654,12 +613,7 @@ int privmsg(struct string from, struct string sender, struct string target, stru } while (0); #ifdef USE_SERVER -#ifdef USE_HAXIRCD_PROTOCOL - protocols[HAXIRCD_PROTOCOL].propagate_privmsg(from, sender, target, msg); -#endif -#ifdef USE_INSPIRCD2_PROTOCOL - protocols[INSPIRCD2_PROTOCOL].propagate_privmsg(from, sender, target, msg); -#endif + protocols_propagate_privmsg(from, sender, target, msg); #endif #ifdef USE_PSUEDOCLIENTS @@ -714,12 +668,7 @@ int notice(struct string from, struct string sender, struct string target, struc } while (0); #ifdef USE_SERVER -#ifdef USE_HAXIRCD_PROTOCOL - protocols[HAXIRCD_PROTOCOL].propagate_notice(from, sender, target, msg); -#endif -#ifdef USE_INSPIRCD2_PROTOCOL - protocols[INSPIRCD2_PROTOCOL].propagate_notice(from, sender, target, msg); -#endif + protocols_propagate_notice(from, sender, target, msg); #endif return 0; diff --git a/general_network.h b/general_network.h index def220c..b8e235c 100644 --- a/general_network.h +++ b/general_network.h @@ -33,6 +33,7 @@ #include <sys/socket.h> #include "haxstring.h" +#include "protocol_numbers.h" #include "table.h" struct network { @@ -57,6 +58,8 @@ struct server_info { struct table user_list; + void *protocol_specific[NUM_PROTOCOLS]; + void *handle; size_t protocol; @@ -92,6 +95,8 @@ struct user_info { struct table channel_list; + void *protocol_specific[NUM_PROTOCOLS]; + void *handle; size_t protocol; @@ -113,6 +118,8 @@ struct channel_info { size_t channel_ts; struct table user_list; + + void *protocol_specific[NUM_PROTOCOLS]; }; int resolve(struct string address, struct string port, struct sockaddr *sockaddr); @@ -149,6 +156,18 @@ extern char casemap[UCHAR_MAX+1]; #endif #define NUM_NET_TYPES 3 + +#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 struct network networks[NUM_NET_TYPES]; extern struct table server_list; diff --git a/protocol_numbers.h b/protocol_numbers.h new file mode 100644 index 0000000..23f9dcc --- /dev/null +++ b/protocol_numbers.h @@ -0,0 +1,39 @@ +// Written by: Test_User <hax@andrewyu.org> +// +// This is free and unencumbered software released into the public +// domain. +// +// Anyone is free to copy, modify, publish, use, compile, sell, or +// distribute this software, either in source code form or as a compiled +// binary, for any purpose, commercial or non-commercial, and by any +// means. +// +// In jurisdictions that recognize copyright laws, the author or authors +// of this software dedicate any and all copyright interest in the +// software to the public domain. We make this dedication for the benefit +// of the public at large and to the detriment of our heirs and +// successors. We intend this dedication to be an overt act of +// relinquishment in perpetuity of all present and future rights to this +// software under copyright law. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. + +#pragma once + +#ifdef USE_HAXIRCD_PROTOCOL +#define HAXIRCD_PROTOCOL 0 +#endif +#ifdef USE_INSPIRCD2_PROTOCOL +#define INSPIRCD2_PROTOCOL 1 +#endif +#ifdef USE_INSPIRCD3_PROTOCOL +#define INSPIRCD3_PROTOCOL 2 +#endif + +#define NUM_PROTOCOLS 3 diff --git a/protocols.c b/protocols.c index 6ccf69c..8d82907 100644 --- a/protocols.c +++ b/protocols.c @@ -31,6 +31,9 @@ #ifdef USE_INSPIRCD2_PROTOCOL #include "protocols/inspircd2.h" #endif +#ifdef USE_INSPIRCD3_PROTOCOL +#include "protocols/inspircd3.h" +#endif struct protocol protocols[NUM_PROTOCOLS] = { #ifdef USE_INSPIRCD2_PROTOCOL @@ -63,4 +66,172 @@ struct protocol protocols[NUM_PROTOCOLS] = { .do_unlink = inspircd2_protocol_do_unlink, }, #endif +#ifdef USE_INSPIRCD3_PROTOCOL + [INSPIRCD3_PROTOCOL] = { + .init = init_inspircd3_protocol, + + .handle_connection = inspircd3_protocol_connection, + .autoconnect = inspircd3_protocol_autoconnect, + .update_propagations = inspircd3_protocol_update_propagations, + + .propagate = inspircd3_protocol_propagate, + + .propagate_new_server = inspircd3_protocol_propagate_new_server, + .propagate_unlink_server = inspircd3_protocol_propagate_unlink_server, + + .propagate_new_user = inspircd3_protocol_propagate_new_user, + .propagate_rename_user = inspircd3_protocol_propagate_rename_user, + .propagate_remove_user = inspircd3_protocol_propagate_remove_user, + .propagate_kill_user = inspircd3_protocol_propagate_kill_user, + .propagate_oper_user = inspircd3_protocol_propagate_oper_user, + + .propagate_set_channel = inspircd3_protocol_propagate_set_channel, + .propagate_join_channel = inspircd3_protocol_propagate_join_channel, + .propagate_part_channel = inspircd3_protocol_propagate_part_channel, + .propagate_kick_channel = inspircd3_protocol_propagate_kick_channel, + + .propagate_privmsg = inspircd3_protocol_propagate_privmsg, + .propagate_notice = inspircd3_protocol_propagate_notice, + + .do_unlink = inspircd3_protocol_do_unlink, + }, +#endif }; + +int protocols_init(void) { +#ifdef USE_INSPIRCD2_PROTOCOL + if (protocols[INSPIRCD2_PROTOCOL].init() != 0) + return 1; +#endif +#ifdef USE_INSPIRCD3_PROTOCOL + if (protocols[INSPIRCD3_PROTOCOL].init() != 0) + return 1; +#endif + + return 0; +} + +void protocols_update_propagations(void) { +#ifdef USE_INSPIRCD2_PROTOCOL + protocols[INSPIRCD2_PROTOCOL].update_propagations(); +#endif +#ifdef USE_INSPIRCD3_PROTOCOL + protocols[INSPIRCD3_PROTOCOL].update_propagations(); +#endif +} + +void protocols_propagate_new_server(struct string from, struct string attached_to, struct server_info *info) { +#ifdef USE_INSPIRCD2_PROTOCOL + protocols[INSPIRCD2_PROTOCOL].propagate_new_server(from, attached_to, info); +#endif +#ifdef USE_INSPIRCD3_PROTOCOL + protocols[INSPIRCD3_PROTOCOL].propagate_new_server(from, attached_to, info); +#endif +} +void protocols_propagate_unlink_server(struct string from, struct server_info *a, struct server_info *b, size_t protocol) { +#ifdef USE_INSPIRCD2_PROTOCOL + protocols[INSPIRCD2_PROTOCOL].propagate_unlink_server(from, a, b, protocol); +#endif +#ifdef USE_INSPIRCD3_PROTOCOL + protocols[INSPIRCD3_PROTOCOL].propagate_unlink_server(from, a, b, protocol); +#endif +} + +void protocols_propagate_new_user(struct string from, struct user_info *info) { +#ifdef USE_INSPIRCD2_PROTOCOL + protocols[INSPIRCD2_PROTOCOL].propagate_new_user(from, info); +#endif +#ifdef USE_INSPIRCD3_PROTOCOL + protocols[INSPIRCD3_PROTOCOL].propagate_new_user(from, info); +#endif +} + +void protocols_propagate_rename_user(struct string from, struct user_info *info, struct string nick, size_t timestamp, struct string timestamp_str) { +#ifdef USE_INSPIRCD2_PROTOCOL + protocols[INSPIRCD2_PROTOCOL].propagate_rename_user(from, info, nick, timestamp, timestamp_str); +#endif +#ifdef USE_INSPIRCD3_PROTOCOL + protocols[INSPIRCD3_PROTOCOL].propagate_rename_user(from, info, nick, timestamp, timestamp_str); +#endif +} + +void protocols_propagate_remove_user(struct string from, struct user_info *info, struct string reason) { +#ifdef USE_INSPIRCD2_PROTOCOL + protocols[INSPIRCD2_PROTOCOL].propagate_remove_user(from, info, reason); +#endif +#ifdef USE_INSPIRCD3_PROTOCOL + protocols[INSPIRCD3_PROTOCOL].propagate_remove_user(from, info, reason); +#endif +} + +void protocols_propagate_kill_user(struct string from, struct string source, struct user_info *info, struct string reason) { +#ifdef USE_INSPIRCD2_PROTOCOL + protocols[INSPIRCD2_PROTOCOL].propagate_kill_user(from, source, info, reason); +#endif +#ifdef USE_INSPIRCD3_PROTOCOL + protocols[INSPIRCD3_PROTOCOL].propagate_kill_user(from, source, info, reason); +#endif +} + +void protocols_propagate_oper_user(struct string from, struct user_info *info, struct string type) { +#ifdef USE_INSPIRCD2_PROTOCOL + protocols[INSPIRCD2_PROTOCOL].propagate_oper_user(from, info, type); +#endif +#ifdef USE_INSPIRCD3_PROTOCOL + protocols[INSPIRCD3_PROTOCOL].propagate_oper_user(from, info, type); +#endif +} + +void protocols_propagate_set_channel(struct string from, struct channel_info *channel, char is_new_channel, size_t user_count, struct user_info **users) { +#ifdef USE_INSPIRCD2_PROTOCOL + protocols[INSPIRCD2_PROTOCOL].propagate_set_channel(from, channel, is_new_channel, user_count, users); +#endif +#ifdef USE_INSPIRCD3_PROTOCOL + protocols[INSPIRCD3_PROTOCOL].propagate_set_channel(from, channel, is_new_channel, user_count, users); +#endif +} + +void protocols_propagate_join_channel(struct string from, struct channel_info *channel, size_t user_count, struct user_info **users) { +#ifdef USE_INSPIRCD2_PROTOCOL + protocols[INSPIRCD2_PROTOCOL].propagate_join_channel(from, channel, user_count, users); +#endif +#ifdef USE_INSPIRCD3_PROTOCOL + protocols[INSPIRCD3_PROTOCOL].propagate_join_channel(from, channel, user_count, users); +#endif +} + +void protocols_propagate_part_channel(struct string from, struct channel_info *channel, struct user_info *user, struct string reason) { +#ifdef USE_INSPIRCD2_PROTOCOL + protocols[INSPIRCD2_PROTOCOL].propagate_part_channel(from, channel, user, reason); +#endif +#ifdef USE_INSPIRCD3_PROTOCOL + protocols[INSPIRCD3_PROTOCOL].propagate_part_channel(from, channel, user, reason); +#endif +} + +void protocols_propagate_kick_channel(struct string from, struct string source, struct channel_info *channel, struct user_info *user, struct string reason) { +#ifdef USE_INSPIRCD2_PROTOCOL + protocols[INSPIRCD2_PROTOCOL].propagate_kick_channel(from, source, channel, user, reason); +#endif +#ifdef USE_INSPIRCD3_PROTOCOL + protocols[INSPIRCD3_PROTOCOL].propagate_kick_channel(from, source, channel, user, reason); +#endif +} + +void protocols_propagate_privmsg(struct string from, struct string source, struct string target, struct string msg) { +#ifdef USE_INSPIRCD2_PROTOCOL + protocols[INSPIRCD2_PROTOCOL].propagate_privmsg(from, source, target, msg); +#endif +#ifdef USE_INSPIRCD3_PROTOCOL + protocols[INSPIRCD3_PROTOCOL].propagate_privmsg(from, source, target, msg); +#endif +} + +void protocols_propagate_notice(struct string from, struct string source, struct string target, struct string msg) { +#ifdef USE_INSPIRCD2_PROTOCOL + protocols[INSPIRCD2_PROTOCOL].propagate_notice(from, source, target, msg); +#endif +#ifdef USE_INSPIRCD3_PROTOCOL + protocols[INSPIRCD3_PROTOCOL].propagate_notice(from, source, target, msg); +#endif +} diff --git a/protocols.h b/protocols.h index 915bb96..61836bd 100644 --- a/protocols.h +++ b/protocols.h @@ -30,6 +30,7 @@ #include "haxstring.h" #include "general_network.h" +#include "protocol_numbers.h" #include "server_network.h" struct protocol { @@ -60,13 +61,25 @@ struct protocol { void (*do_unlink)(struct string from, struct server_info *a, struct server_info *b); }; -#ifdef USE_HAXIRCD_PROTOCOL -#define HAXIRCD_PROTOCOL 0 -#endif -#ifdef USE_INSPIRCD2_PROTOCOL -#define INSPIRCD2_PROTOCOL 1 -#endif +int protocols_init(void); -#define NUM_PROTOCOLS 2 +void protocols_update_propagations(void); + +void protocols_propagate_new_server(struct string from, struct string attached_to, struct server_info *info); +void protocols_propagate_unlink_server(struct string from, struct server_info *a, struct server_info *b, size_t protocol); + +void protocols_propagate_new_user(struct string from, struct user_info *info); +void protocols_propagate_rename_user(struct string from, struct user_info *info, struct string nick, size_t timestamp, struct string timestamp_str); +void protocols_propagate_remove_user(struct string from, struct user_info *info, struct string reason); +void protocols_propagate_kill_user(struct string from, struct string source, struct user_info *info, struct string reason); +void protocols_propagate_oper_user(struct string from, struct user_info *info, struct string type); + +void protocols_propagate_set_channel(struct string from, struct channel_info *channel, char is_new_channel, size_t user_count, struct user_info **users); +void protocols_propagate_join_channel(struct string from, struct channel_info *channel, size_t user_count, struct user_info **users); +void protocols_propagate_part_channel(struct string from, struct channel_info *channel, struct user_info *user, struct string reason); +void protocols_propagate_kick_channel(struct string from, struct string source, struct channel_info *channel, struct user_info *user, struct string reason); + +void protocols_propagate_privmsg(struct string from, struct string source, struct string target, struct string msg); +void protocols_propagate_notice(struct string from, struct string source, struct string target, struct string msg); extern struct protocol protocols[NUM_PROTOCOLS]; diff --git a/protocols/inspircd2.c b/protocols/inspircd2.c index 9bd40b9..cfc9cf9 100644 --- a/protocols/inspircd2.c +++ b/protocols/inspircd2.c @@ -253,7 +253,13 @@ void * inspircd2_protocol_connection(void *type) { struct string line = {.data = full_msg.data, .len = msg_len}; - WRITES(2, STRING("[InspIRCd v2] [server -> us] Got `")); + if (ready) { + WRITES(2, STRING("[InspIRCd v2] [")); + WRITES(2, config->name); + WRITES(2, STRING(" -> us] Got `")); + } else { + WRITES(2, STRING("[InspIRCd v2] [unidentified server -> us] Got `")); + } WRITES(2, line); WRITES(2, STRING("'\r\n")); @@ -362,6 +368,23 @@ void * inspircd2_protocol_connection(void *type) { pthread_mutex_lock(&state_lock); + if (source.len != 0) { + struct server_info *server; + struct user_info *user = get_table_index(user_list, source); + if (user) + server = get_table_index(server_list, user->server); + else + server = get_table_index(server_list, source); + + if (!server) + goto inspircd2_protocol_handle_connection_unlock_next; + + if (STRING_EQ(server->sid, SID) || !STRING_EQ(server->next, config->sid)) { + WRITES(2, STRING("[InspIRCd v2] Protocol violation: sourge isn't on this link.\r\n\n")); + goto inspircd2_protocol_handle_connection_unlock_close; + } + } + if (!ready) { int (*func)(struct string source, size_t argc, struct string *argv, size_t net, void *handle, struct server_config **config, char is_incoming); func = get_table_index(inspircd2_protocol_init_commands, command); diff --git a/protocols/inspircd2.h b/protocols/inspircd2.h index 47df9a6..315e012 100644 --- a/protocols/inspircd2.h +++ b/protocols/inspircd2.h @@ -30,7 +30,8 @@ #include "../config.h" #include "../haxstring.h" -#include "../server_network.h" +#include "../general_network.h" +#include "../table.h" extern struct table inspircd2_protocol_init_commands; extern struct table inspircd2_protocol_commands; @@ -91,15 +92,5 @@ int inspircd2_protocol_handle_notice(struct string source, size_t argc, struct s int inspircd2_protocol_handle_dump(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/protocols/inspircd3.c b/protocols/inspircd3.c new file mode 100644 index 0000000..1124dd7 --- /dev/null +++ b/protocols/inspircd3.c @@ -0,0 +1,1548 @@ +// One of the code files for HaxServ +// +// Written by: Test_User <hax@andrewyu.org> +// +// This is free and unencumbered software released into the public +// domain. +// +// Anyone is free to copy, modify, publish, use, compile, sell, or +// distribute this software, either in source code form or as a compiled +// binary, for any purpose, commercial or non-commercial, and by any +// means. +// +// In jurisdictions that recognize copyright laws, the author or authors +// of this software dedicate any and all copyright interest in the +// software to the public domain. We make this dedication for the benefit +// of the public at large and to the detriment of our heirs and +// successors. We intend this dedication to be an overt act of +// relinquishment in perpetuity of all present and future rights to this +// software under copyright law. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. + +#include <pthread.h> +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <sys/time.h> +#include <unistd.h> + +#include "../config.h" +#include "../general_network.h" +#include "../haxstring.h" +#include "../haxstring_utils.h" +#include "../main.h" +#include "../server_network.h" +#include "inspircd3.h" + +struct table inspircd3_protocol_init_commands = {0}; +struct table inspircd3_protocol_commands = {0}; + +char inspircd3_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 inspircd3_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_inspircd3_protocol(void) { + inspircd3_protocol_commands.array = malloc(0); + + set_table_index(&inspircd3_protocol_init_commands, STRING("CAPAB"), &inspircd3_protocol_init_handle_capab); + set_table_index(&inspircd3_protocol_init_commands, STRING("SERVER"), &inspircd3_protocol_init_handle_server); + + + + set_table_index(&inspircd3_protocol_commands, STRING("PING"), &inspircd3_protocol_handle_ping); + set_table_index(&inspircd3_protocol_commands, STRING("PONG"), &inspircd3_protocol_handle_pong); + + set_table_index(&inspircd3_protocol_commands, STRING("SERVER"), &inspircd3_protocol_handle_server); + set_table_index(&inspircd3_protocol_commands, STRING("SQUIT"), &inspircd3_protocol_handle_squit); + set_table_index(&inspircd3_protocol_commands, STRING("RSQUIT"), &inspircd3_protocol_handle_rsquit); + + set_table_index(&inspircd3_protocol_commands, STRING("UID"), &inspircd3_protocol_handle_uid); + set_table_index(&inspircd3_protocol_commands, STRING("NICK"), &inspircd3_protocol_handle_nick); + set_table_index(&inspircd3_protocol_commands, STRING("QUIT"), &inspircd3_protocol_handle_quit); + set_table_index(&inspircd3_protocol_commands, STRING("KILL"), &inspircd3_protocol_handle_kill); + set_table_index(&inspircd3_protocol_commands, STRING("OPERTYPE"), &inspircd3_protocol_handle_opertype); + +// set_table_index(&inspircd3_protocol_commands, STRING("FJOIN"), &inspircd3_protocol_handle_fjoin); +// set_table_index(&inspircd3_protocol_commands, STRING("PART"), &inspircd3_protocol_handle_part); +// set_table_index(&inspircd3_protocol_commands, STRING("KICK"), &inspircd3_protocol_handle_kick); +// +// set_table_index(&inspircd3_protocol_commands, STRING("PRIVMSG"), &inspircd3_protocol_handle_privmsg); +// set_table_index(&inspircd3_protocol_commands, STRING("NOTICE"), &inspircd3_protocol_handle_notice); + + return 0; +} + +void * inspircd3_protocol_connection(void *type) { + struct string address; + size_t net; + char is_incoming; + int fd; + void *handle; + struct server_config *config; + + char ready = 0; + + { + struct server_connection_info *t = type; + address = t->address; + fd = t->fd; + handle = t->handle; + config = t->config; + net = t->type->net_type; + is_incoming = t->type->is_incoming; + if (is_incoming) + free(type); + } + + if (!is_incoming) { + networks[net].send(handle, STRING("CAPAB START 1205\nCAPAB END\n")); + + networks[net].send(handle, STRING("SERVER ")); + networks[net].send(handle, SERVER_NAME); + networks[net].send(handle, STRING(" ")); + networks[net].send(handle, config->out_pass); + networks[net].send(handle, STRING(" 0 ")); + networks[net].send(handle, SID); + networks[net].send(handle, STRING(" :")); + networks[net].send(handle, SERVER_FULLNAME); + networks[net].send(handle, STRING("\n")); + } + + struct string full_msg = {.data = malloc(0), .len = 0}; + + while (1) { + size_t msg_len; + size_t old_len; + { + char data[512]; + unsigned char timeout = 0; + size_t new_len; + while (1) { + char err; + new_len = networks[net].recv(handle, data, sizeof(data), &err); + if (err >= 2) { // Connection closed, or some uncorrected error + goto inspircd3_protocol_handle_connection_close; + } else if (err == 1) { // Timed out + if (ready) { + if (timeout > 0) + goto inspircd3_protocol_handle_connection_close; + timeout++; + + pthread_mutex_lock(&(state_lock)); + networks[net].send(handle, STRING(":")); + networks[net].send(handle, SID); + networks[net].send(handle, STRING(" PING :")); + networks[net].send(handle, config->sid); + networks[net].send(handle, STRING("\n")); + + struct server_info *server = get_table_index(server_list, config->sid); + server->awaiting_pong = 1; + gettimeofday(&(server->last_ping), 0); + + pthread_mutex_unlock(&(state_lock)); + } else { + goto inspircd3_protocol_handle_connection_close; + } + } else { + break; + } + } + old_len = full_msg.len; + full_msg.len += new_len; + void *tmp = realloc(full_msg.data, full_msg.len); + if (!tmp && full_msg.len + new_len != 0) + goto inspircd3_protocol_handle_connection_close; + full_msg.data = tmp; + memcpy(full_msg.data + old_len, data, new_len); + } + + while (1) { + char found = 0; + for (size_t i = old_len; i < full_msg.len; i++) { + if (full_msg.data[i] == '\n') { + found = 1; + msg_len = i; + break; + } + } + if (!found) + break; + old_len = 0; + + struct string line = {.data = full_msg.data, .len = msg_len}; + + if (ready) { + WRITES(2, STRING("[InspIRCd v3] [")); + WRITES(2, config->name); + WRITES(2, STRING(" -> us] Got `")); + } else { + WRITES(2, STRING("[InspIRCd v3] [unidentified server -> us] Got `")); + } + WRITES(2, line); + WRITES(2, STRING("'\r\n")); + + size_t offset = 0; + while (offset < msg_len && full_msg.data[offset] == ' ') + offset++; + + if (msg_len == offset) { + WRITES(2, STRING("[InspIRCd v3] Protocol violation: empty message.\r\n\n")); + goto inspircd3_protocol_handle_connection_close; + } + + // Trim tags + while (offset < full_msg.len && full_msg.data[offset] == '@') { + while (offset < full_msg.len && full_msg.data[offset] != ' ') + offset++; + + while (offset < full_msg.len && full_msg.data[offset] == ' ') + offset++; + } + + if (msg_len == offset) { + WRITES(2, STRING("[InspIRCd v3] Protocol violation: empty message.\r\n\n")); + goto inspircd3_protocol_handle_connection_close; + } + + struct string source; + if (full_msg.data[offset] == ':') { + source.data = full_msg.data + offset + 1; + found = 0; + source.len = 0; + for (size_t i = offset + 1; i < msg_len; i++) { + if (full_msg.data[i] == ' ') { + found = 1; + source.len = i - offset - 1; + offset = i + 1; + while (offset < msg_len && full_msg.data[offset] == ' ') + offset++; + break; + } + source.len++; + } + if (source.len == 0) { + WRITES(2, STRING("[InspIRCd v3] Protocol violation: source prefix but no source.\r\n\n")); + goto inspircd3_protocol_handle_connection_close; + } + if (!found || offset >= msg_len) { + WRITES(2, STRING("[InspIRCd v3] Protocol violation: source but no command.\r\n\n")); + goto inspircd3_protocol_handle_connection_close; + } + + if (STRING_EQ(source, SID)) { + WRITES(2, STRING("[InspIRCd v3] Protocol violation: other server sent us as source!\r\n\n")); + goto inspircd3_protocol_handle_connection_close; + } + } else { + if (ready) + source = config->sid; + else + source = (struct string){0}; + } + + struct string command; + command.data = full_msg.data + offset; + found = 0; + for (size_t i = offset; i < msg_len; i++) { + if (full_msg.data[i] == ' ') { + found = 1; + command.len = i - offset; + offset = i + 1; + while (offset < msg_len && full_msg.data[offset] == ' ') + offset++; + break; + } + } + if (!found) { + command.len = msg_len - offset; + offset = msg_len; + } + + size_t argc = 0; + size_t old_offset = offset; + while (offset < msg_len) { + if (full_msg.data[offset] == ':') { + argc++; + break; + } + + while (offset < msg_len && full_msg.data[offset] != ' ') + offset++; + + argc++; + + while (offset < msg_len && full_msg.data[offset] == ' ') + offset++; + } + offset = old_offset; + + struct string argv[argc]; // TODO: Maybe dynamically allocate this if it exceeds some number that probably shouldn't be put on the stack + for (size_t i = 0; offset < msg_len;) { + if (full_msg.data[offset] == ':') { + argv[i].data = full_msg.data + offset + 1; + argv[i].len = msg_len - offset - 1; + break; + } + + argv[i].data = full_msg.data + offset; + size_t start = offset; + + while (offset < msg_len && full_msg.data[offset] != ' ') + offset++; + + argv[i].len = offset - start; + + while (offset < msg_len && full_msg.data[offset] == ' ') + offset++; + + i++; + } + + pthread_mutex_lock(&state_lock); + + if (source.len != 0) { + struct server_info *server; + struct user_info *user = get_table_index(user_list, source); + if (user) + server = get_table_index(server_list, user->server); + else + server = get_table_index(server_list, source); + + if (!server) + goto inspircd3_protocol_handle_connection_unlock_next; + + if (!STRING_EQ(server->next, config->sid)) { + WRITES(2, STRING("[InspIRCd v3] Protocol violation: sourge isn't on this link.\r\n\n")); + goto inspircd3_protocol_handle_connection_unlock_close; + } + } + + if (!ready) { + int (*func)(struct string source, size_t argc, struct string *argv, size_t net, void *handle, struct server_config **config, char is_incoming); + func = get_table_index(inspircd3_protocol_init_commands, command); + if (!func) { + WRITES(2, STRING("WARNING: Command is unknown, ignoring.\r\n")); + goto inspircd3_protocol_handle_connection_unlock_next; + } + + int res = func(source, argc, argv, net, handle, &config, is_incoming); + if (res < 0) // Disconnect + goto inspircd3_protocol_handle_connection_unlock_close; + else if (res > 0) // Connection is now "ready" + ready = 1; + } else { + int (*func)(struct string source, size_t argc, struct string *argv, size_t net, void *handle, struct server_config *config, char is_incoming); + func = get_table_index(inspircd3_protocol_commands, command); + if (!func) { + WRITES(2, STRING("WARNING: Command is unknown, ignoring.\r\n")); + goto inspircd3_protocol_handle_connection_unlock_next; + } + + int res = func(source, argc, argv, net, handle, config, is_incoming); + if (res < 0) // Disconnect + goto inspircd3_protocol_handle_connection_unlock_close; + } + + inspircd3_protocol_handle_connection_unlock_next: + WRITES(2, STRING("\n")); + + do_trivial_reloads(); + pthread_mutex_unlock(&state_lock); + memmove(full_msg.data, full_msg.data + msg_len + 1, full_msg.len - msg_len - 1); + full_msg.len -= msg_len + 1; + void *tmp = realloc(full_msg.data, full_msg.len); + if (tmp || full_msg.len == 0) + full_msg.data = tmp; + } + } + + inspircd3_protocol_handle_connection_unlock_close: + pthread_mutex_unlock(&state_lock); + inspircd3_protocol_handle_connection_close: + free(full_msg.data); + + if (ready) { + pthread_mutex_lock(&(state_lock)); + unlink_server(config->sid, get_table_index(server_list, config->sid), self, INSPIRCD3_PROTOCOL); + pthread_mutex_unlock(&(state_lock)); + } + + networks[net].close(fd, handle); + free(address.data); + + return 0; +} + +void * inspircd3_protocol_autoconnect(void *tmp) { + struct server_config *config = tmp; + + struct server_connection_info *info; + info = malloc(sizeof(*info)); + if (!info) + return 0; + + struct server_network_info *type; + type = malloc(sizeof(*type)); + if (!type) { + free(info); + return 0; + } + + type->net_type = config->autoconnect_type; + type->protocol = INSPIRCD3_PROTOCOL; + type->is_incoming = 0; + info->type = type; + info->config = config; + + time_t last_time = 0; + while (1) { + for (time_t current = time(NULL); current < last_time + 10; current = time(NULL)) + sleep(10 - (current - last_time)); + last_time = time(NULL); + + info->fd = networks[type->net_type].connect(&(info->handle), config->address, config->port, &(info->address)); + if (info->fd == -1) + continue; + + inspircd3_protocol_connection(info); + } +} + +void inspircd3_protocol_update_propagations_inner(struct server_info *source) { + for (size_t i = 0; i < source->connected_to.len; i++) { + struct server_info *adjacent = source->connected_to.array[i].ptr; + if (adjacent->distance == 0 && !STRING_EQ(adjacent->sid, SID)) { + adjacent->distance = source->distance + 1; + if (adjacent->distance == 1) { + adjacent->next = adjacent->sid; + } else { + adjacent->next = source->next; + adjacent->handle = source->handle; + } + inspircd3_protocol_update_propagations_inner(adjacent); + } + } +} + +void inspircd3_protocol_update_propagations(void) { + for (size_t i = 0; i < server_list.len; i++) { + struct server_info *other = server_list.array[i].ptr; + if (other->protocol == INSPIRCD3_PROTOCOL) { + other->distance = 0; + } + } + + inspircd3_protocol_update_propagations_inner(self); +} + +void inspircd3_protocol_propagate(struct string from, struct string msg) { + for (size_t i = 0; i < self->connected_to.len; i++) { + struct server_info *adjacent = self->connected_to.array[i].ptr; + if (adjacent->protocol != INSPIRCD3_PROTOCOL || STRING_EQ(from, adjacent->sid)) + continue; // Not ours or it's the source of this message + + networks[adjacent->net].send(adjacent->handle, msg); + } +} + +// [:source] SERVER <name> <sid> <fullname> +void inspircd3_protocol_propagate_new_server(struct string from, struct string attached_to, struct server_info *info) { + inspircd3_protocol_propagate(from, STRING(":")); + + if (info->protocol == INSPIRCD3_PROTOCOL) + inspircd3_protocol_propagate(from, attached_to); + else // Just pretend servers connected via a different protocol are connected directly to us + inspircd3_protocol_propagate(from, SID); + + inspircd3_protocol_propagate(from, STRING(" SERVER ")); + inspircd3_protocol_propagate(from, info->name); + inspircd3_protocol_propagate(from, STRING(" ")); + inspircd3_protocol_propagate(from, info->sid); + inspircd3_protocol_propagate(from, STRING(" :")); + inspircd3_protocol_propagate(from, info->fullname); + inspircd3_protocol_propagate(from, STRING("\n")); + + inspircd3_protocol_propagate(from, STRING(":")); + inspircd3_protocol_propagate(from, info->sid); + inspircd3_protocol_propagate(from, STRING(" BURST ")); + + time_t current = time(0); + struct string current_time; + char err = unsigned_to_str((size_t)current, ¤t_time); + + if (current < 0 || err) { + inspircd3_protocol_propagate(from, STRING("1")); + } else { + inspircd3_protocol_propagate(from, current_time); + free(current_time.data); + } + + inspircd3_protocol_propagate(from, STRING("\n:")); + inspircd3_protocol_propagate(from, info->sid); + inspircd3_protocol_propagate(from, STRING(" ENDBURST\n")); +} + +// [:source] SQUIT <sid> [<reason>?] +void inspircd3_protocol_propagate_unlink_server(struct string from, struct server_info *a, struct server_info *b, size_t protocol) { + struct server_info *source; + struct server_info *target; + if (a->distance == 0 && !STRING_EQ(a->sid, SID)) { + source = b; + target = a; + } else if (b->distance == 0 && !STRING_EQ(b->sid, SID)) { + source = a; + target = b; + } else { + return; + } + + inspircd3_protocol_propagate(from, STRING(":")); + if (protocol == INSPIRCD3_PROTOCOL) + inspircd3_protocol_propagate(from, source->sid); + else + inspircd3_protocol_propagate(from, SID); + inspircd3_protocol_propagate(from, STRING(" SQUIT ")); + inspircd3_protocol_propagate(from, target->sid); + inspircd3_protocol_propagate(from, STRING(" :\n")); +} + +// [:source] UID <UID> <nick_ts> <nick> <host> <vhost> <ident> <address> <user_ts> <modes> [<mode args>] <fullname> +void inspircd3_protocol_propagate_new_user(struct string from, struct user_info *info) { + inspircd3_protocol_propagate(from, STRING(":")); + inspircd3_protocol_propagate(from, info->server); + inspircd3_protocol_propagate(from, STRING(" UID ")); + inspircd3_protocol_propagate(from, info->uid); + inspircd3_protocol_propagate(from, STRING(" ")); + inspircd3_protocol_propagate(from, info->nick_ts_str); + inspircd3_protocol_propagate(from, STRING(" ")); + inspircd3_protocol_propagate(from, info->nick); + inspircd3_protocol_propagate(from, STRING(" ")); + inspircd3_protocol_propagate(from, info->host); + inspircd3_protocol_propagate(from, STRING(" ")); + inspircd3_protocol_propagate(from, info->vhost); + inspircd3_protocol_propagate(from, STRING(" ")); + inspircd3_protocol_propagate(from, info->ident); + inspircd3_protocol_propagate(from, STRING(" ")); + inspircd3_protocol_propagate(from, info->address); + inspircd3_protocol_propagate(from, STRING(" ")); + inspircd3_protocol_propagate(from, info->user_ts_str); + inspircd3_protocol_propagate(from, STRING(" + :")); + inspircd3_protocol_propagate(from, info->fullname); + inspircd3_protocol_propagate(from, STRING("\n")); +} + +// :source NICK <nick> <timestamp> +void inspircd3_protocol_propagate_rename_user(struct string from, struct user_info *user, struct string nick, size_t timestamp, struct string timestamp_str) { + inspircd3_protocol_propagate(from, STRING(":")); + inspircd3_protocol_propagate(from, user->uid); + inspircd3_protocol_propagate(from, STRING(" NICK ")); + inspircd3_protocol_propagate(from, nick); + inspircd3_protocol_propagate(from, STRING(" ")); + inspircd3_protocol_propagate(from, timestamp_str); + inspircd3_protocol_propagate(from, STRING("\n")); +} + +// :source QUIT [<reason>?] +void inspircd3_protocol_propagate_remove_user(struct string from, struct user_info *info, struct string reason) { + inspircd3_protocol_propagate(from, STRING(":")); + inspircd3_protocol_propagate(from, info->uid); + inspircd3_protocol_propagate(from, STRING(" QUIT :")); + inspircd3_protocol_propagate(from, reason); + inspircd3_protocol_propagate(from, STRING("\n")); +} + +// [:source] KILL <target> [<reason>?] +void inspircd3_protocol_propagate_kill_user(struct string from, struct string source, struct user_info *info, struct string reason) { + inspircd3_protocol_propagate(from, STRING(":")); + inspircd3_protocol_propagate(from, source); + inspircd3_protocol_propagate(from, STRING(" KILL ")); + inspircd3_protocol_propagate(from, info->uid); + inspircd3_protocol_propagate(from, STRING(" :")); + inspircd3_protocol_propagate(from, reason); + inspircd3_protocol_propagate(from, STRING("\n")); +} + +// :source OPERTYPE <type> +void inspircd3_protocol_propagate_oper_user(struct string from, struct user_info *user, struct string type) { + inspircd3_protocol_propagate(from, STRING(":")); + inspircd3_protocol_propagate(from, user->uid); + inspircd3_protocol_propagate(from, STRING(" OPERTYPE :")); + inspircd3_protocol_propagate(from, type); + inspircd3_protocol_propagate(from, STRING("\n")); +} + +// [:source] FJOIN <channel> <timestamp> <modes> [<mode args>] <userlist: modes,uid [...]> +void inspircd3_protocol_propagate_set_channel(struct string from, struct channel_info *channel, char is_new_server, size_t user_count, struct user_info **users) { + inspircd3_protocol_propagate(from, STRING(":")); + inspircd3_protocol_propagate(from, SID); + inspircd3_protocol_propagate(from, STRING(" FJOIN ")); + inspircd3_protocol_propagate(from, channel->name); + inspircd3_protocol_propagate(from, STRING(" ")); + inspircd3_protocol_propagate(from, channel->channel_ts_str); + inspircd3_protocol_propagate(from, STRING(" + :")); + for (size_t x = 0; x < user_count; x++) { + inspircd3_protocol_propagate(from, STRING(",")); + inspircd3_protocol_propagate(from, users[x]->uid); + if (x != channel->user_list.len - 1) + inspircd3_protocol_propagate(from, STRING(" ")); + } + inspircd3_protocol_propagate(from, STRING("\n")); +} + +// [:source] FJOIN <channel> <timestamp> <modes> [<mode args>] <userlist: modes,uid [...]> +void inspircd3_protocol_propagate_join_channel(struct string from, struct channel_info *channel, size_t user_count, struct user_info **users) { + inspircd3_protocol_propagate(from, STRING(":")); + inspircd3_protocol_propagate(from, SID); + inspircd3_protocol_propagate(from, STRING(" FJOIN ")); + inspircd3_protocol_propagate(from, channel->name); + inspircd3_protocol_propagate(from, STRING(" ")); + inspircd3_protocol_propagate(from, channel->channel_ts_str); + inspircd3_protocol_propagate(from, STRING(" + :")); + for (size_t x = 0; x < user_count; x++) { + inspircd3_protocol_propagate(from, STRING(",")); + inspircd3_protocol_propagate(from, users[x]->uid); + if (x != channel->user_list.len - 1) + inspircd3_protocol_propagate(from, STRING(" ")); + } + inspircd3_protocol_propagate(from, STRING("\n")); +} + +// :source PART <channel> [<reason>] +void inspircd3_protocol_propagate_part_channel(struct string from, struct channel_info *channel, struct user_info *user, struct string reason) { + inspircd3_protocol_propagate(from, STRING(":")); + inspircd3_protocol_propagate(from, user->uid); + inspircd3_protocol_propagate(from, STRING(" PART ")); + inspircd3_protocol_propagate(from, channel->name); + inspircd3_protocol_propagate(from, STRING(" :")); + inspircd3_protocol_propagate(from, reason); + inspircd3_protocol_propagate(from, STRING("\n")); +} + +// [:source] KICK <channel> <user> [<reason>] +void inspircd3_protocol_propagate_kick_channel(struct string from, struct string source, struct channel_info *channel, struct user_info *user, struct string reason) { + inspircd3_protocol_propagate(from, STRING(":")); + inspircd3_protocol_propagate(from, source); + inspircd3_protocol_propagate(from, STRING(" KICK ")); + inspircd3_protocol_propagate(from, channel->name); + inspircd3_protocol_propagate(from, STRING(" ")); + inspircd3_protocol_propagate(from, user->uid); + inspircd3_protocol_propagate(from, STRING(" :")); + inspircd3_protocol_propagate(from, reason); + inspircd3_protocol_propagate(from, STRING("\n")); +} + +// [:source] PRIVMSG <target> <message> +void inspircd3_protocol_propagate_privmsg(struct string from, struct string source, struct string target, struct string msg) { + struct user_info *user = get_table_index(user_list, target); + struct server_info *server; + if (!user) + server = get_table_index(server_list, target); + + if (user || server) { + struct server_info *target_server; + if (user) { + target_server = get_table_index(server_list, user->server); + } else { + target_server = server; + } + + if (target_server->protocol != INSPIRCD3_PROTOCOL || STRING_EQ(target_server->sid, SID)) + return; + + struct server_info *adjacent = get_table_index(server_list, target_server->next); + networks[adjacent->net].send(adjacent->handle, STRING(":")); + networks[adjacent->net].send(adjacent->handle, source); + networks[adjacent->net].send(adjacent->handle, STRING(" PRIVMSG ")); + networks[adjacent->net].send(adjacent->handle, target); + networks[adjacent->net].send(adjacent->handle, STRING(" :")); + networks[adjacent->net].send(adjacent->handle, msg); + networks[adjacent->net].send(adjacent->handle, STRING("\n")); + } else { + // TODO: Trim target list for channels as well + inspircd3_protocol_propagate(from, STRING(":")); + inspircd3_protocol_propagate(from, source); + inspircd3_protocol_propagate(from, STRING(" PRIVMSG ")); + inspircd3_protocol_propagate(from, target); + inspircd3_protocol_propagate(from, STRING(" :")); + inspircd3_protocol_propagate(from, msg); + inspircd3_protocol_propagate(from, STRING("\n")); + } +} + +// [:source] NOTICE <target> <message> +void inspircd3_protocol_propagate_notice(struct string from, struct string source, struct string target, struct string msg) { + struct user_info *user = get_table_index(user_list, target); + struct server_info *server; + if (!user) + server = get_table_index(server_list, target); + + if (user || server) { + struct server_info *target_server; + if (user) { + target_server = get_table_index(server_list, user->server); + } else { + target_server = server; + } + + if (target_server->protocol != INSPIRCD3_PROTOCOL || STRING_EQ(target_server->sid, SID)) + return; + + struct server_info *adjacent = get_table_index(server_list, target_server->next); + networks[adjacent->net].send(adjacent->handle, STRING(":")); + networks[adjacent->net].send(adjacent->handle, source); + networks[adjacent->net].send(adjacent->handle, STRING(" NOTICE ")); + networks[adjacent->net].send(adjacent->handle, target); + networks[adjacent->net].send(adjacent->handle, STRING(" :")); + networks[adjacent->net].send(adjacent->handle, msg); + networks[adjacent->net].send(adjacent->handle, STRING("\n")); + } else { + // TODO: Trim target list for channels as well + inspircd3_protocol_propagate(from, STRING(":")); + inspircd3_protocol_propagate(from, source); + inspircd3_protocol_propagate(from, STRING(" NOTICE ")); + inspircd3_protocol_propagate(from, target); + inspircd3_protocol_propagate(from, STRING(" :")); + inspircd3_protocol_propagate(from, msg); + inspircd3_protocol_propagate(from, STRING("\n")); + } +} + +void inspircd3_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; + while (target->connected_to.len > i) { + struct server_info *adjacent = target->connected_to.array[i].ptr; + if (adjacent->distance != 0) { + i = 1; + continue; + } + inspircd3_protocol_do_unlink_inner(from, adjacent, reason); + remove_server(from, adjacent, reason); + } +} + +void inspircd3_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)) { + inspircd3_protocol_do_unlink_inner(from, a, reason); + remove_server(from, a, reason); + } else { + inspircd3_protocol_do_unlink_inner(from, b, reason); + remove_server(from, b, reason); + } + + if (valid) + free(reason.data); +} + +void inspircd3_protocol_introduce_servers_to_inner(size_t net, void *handle, struct string source, struct server_info *target) { + networks[net].send(handle, STRING(":")); + networks[net].send(handle, source); + networks[net].send(handle, STRING(" SERVER ")); + networks[net].send(handle, target->name); + networks[net].send(handle, STRING(" * 0 ")); + networks[net].send(handle, target->sid); + networks[net].send(handle, STRING(" :")); + networks[net].send(handle, target->fullname); + networks[net].send(handle, STRING("\n")); + + for (size_t i = 0; i < target->connected_to.len; i++) { + struct server_info *adjacent = target->connected_to.array[i].ptr; + if (adjacent->distance > target->distance) { + inspircd3_protocol_introduce_servers_to_inner(net, handle, target->sid, adjacent); + } + } +} + +void inspircd3_protocol_introduce_servers_to(size_t net, void *handle) { + for (size_t i = 0; i < self->connected_to.len; i++) { + struct server_info *info = self->connected_to.array[i].ptr; + if (info->protocol == INSPIRCD3_PROTOCOL) { // This server hasn't been added to the list yet, so no need to check for that + inspircd3_protocol_introduce_servers_to_inner(net, handle, SID, info); + } + } +} + +void inspircd3_protocol_introduce_user_to(size_t net, void *handle, struct user_info *user, char join_channels) { + 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(" ")); + networks[net].send(handle, user->user_ts_str); + 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(" ")); + networks[net].send(handle, user->nick_ts_str); + networks[net].send(handle, STRING(" + :")); + networks[net].send(handle, user->fullname); + networks[net].send(handle, STRING("\n")); + + if (user->oper_type.len != 0) { + networks[net].send(handle, STRING(":")); + networks[net].send(handle, user->uid); + networks[net].send(handle, STRING(" OPERTYPE :")); + networks[net].send(handle, user->oper_type); + networks[net].send(handle, STRING("\n")); + } + + if (join_channels) { + for (size_t i = 0; i < user->channel_list.len; i++) { + struct channel_info *channel = user->channel_list.array[i].ptr; + + networks[net].send(handle, STRING(":")); + networks[net].send(handle, SID); + networks[net].send(handle, STRING(" FJOIN ")); + networks[net].send(handle, channel->name); + networks[net].send(handle, STRING(" ")); + networks[net].send(handle, channel->channel_ts_str); + networks[net].send(handle, STRING(" + :,")); + networks[net].send(handle, user->uid); + networks[net].send(handle, STRING("\n")); + } + } +} + +void inspircd3_protocol_introduce_channel_to(size_t net, void *handle, struct channel_info *channel) { + networks[net].send(handle, STRING(":")); + networks[net].send(handle, SID); + networks[net].send(handle, STRING(" FJOIN ")); + networks[net].send(handle, channel->name); + networks[net].send(handle, STRING(" ")); + networks[net].send(handle, channel->channel_ts_str); + networks[net].send(handle, STRING(" + :")); + for (size_t i = 0; i < channel->user_list.len; i++) { + networks[net].send(handle, STRING(",")); + networks[net].send(handle, channel->user_list.array[i].name); + if (i != channel->user_list.len - 1) + networks[net].send(handle, STRING(" ")); + } + networks[net].send(handle, STRING("\n")); +} + +// CAPAB <type> [<args> [, ...]] +int inspircd3_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) { + if (argc < 1) { + WRITES(2, STRING("[InspIRCd v3] Invalid CAPAB recieved! (Missing parameters)\r\n")); + return -1; + } + + if (is_incoming && STRING_EQ(argv[0], STRING("START"))) { // This seems to be a proper server connection by now, can start sending stuff + networks[net].send(handle, STRING("CAPAB START 1205\nCAPAB END\n")); + } + + return 0; +} + +// SERVER <address> <password> <always 0> <SID> [key=value, ...] <name> +int inspircd3_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) { + if (argc < 5) { + WRITES(2, STRING("[InspIRCd v3] Invalid SERVER recieved! (Missing parameters)\r\n")); + return -1; + } + + if (source.len != 0) { + WRITES(2, STRING("[InspIRCd v3] Server attempting to use a source without having introduced itself!\r\n")); + return -1; + } + + if (is_incoming) { + *config = get_table_index(server_config, argv[3]); + if (!(*config)) { + WRITES(2, STRING("[InspIRCd v3] Unknown SID attempted to connect.\r\n")); + return -1; + } + } else { + if (!STRING_EQ(argv[3], (*config)->sid)) { + WRITES(2, STRING("[InspIRCd v3] Wrong SID given in SERVER!\r\n")); + return -1; + } + } + + if (!STRING_EQ(argv[1], (*config)->in_pass)) { + WRITES(2, STRING("[InspIRCd v3] WARNING: Server supplied the wrong password!\r\n")); + return -1; + } + + if (is_incoming) { + networks[net].send(handle, STRING("SERVER ")); + networks[net].send(handle, SERVER_NAME); + networks[net].send(handle, STRING(" ")); + networks[net].send(handle, (*config)->out_pass); + networks[net].send(handle, STRING(" 0 ")); + networks[net].send(handle, SID); + networks[net].send(handle, STRING(" :")); + networks[net].send(handle, SERVER_FULLNAME); + networks[net].send(handle, STRING("\n")); + } + + time_t now = time(0); + if (now < 0) { + WRITES(2, STRING("ERROR: Negative clock!\r\n")); + return -1; + } + struct string time; + int res = unsigned_to_str((size_t)now, &time); + if (res != 0) { + WRITES(2, STRING("[InspIRCd v3] ERROR: OOM, severing link.\r\n")); + return -1; + } + + networks[net].send(handle, STRING(":")); + networks[net].send(handle, SID); + networks[net].send(handle, STRING(" BURST ")); + networks[net].send(handle, time); + networks[net].send(handle, STRING("\n")); + + inspircd3_protocol_introduce_servers_to(net, handle); + + for (size_t i = 0; i < user_list.len; i++) + inspircd3_protocol_introduce_user_to(net, handle, user_list.array[i].ptr, 0); + + for (size_t i = 0; i < channel_list.len; i++) + inspircd3_protocol_introduce_channel_to(net, handle, channel_list.array[i].ptr); + + networks[net].send(handle, STRING(":")); + networks[net].send(handle, SID); + networks[net].send(handle, STRING(" ENDBURST\n")); + + free(time.data); + + if (add_server((*config)->sid, SID, argv[3], argv[0], argv[argc - 1], INSPIRCD3_PROTOCOL, net, handle) != 0) { + WRITES(2, STRING("ERROR: Unable to add server!\r\n")); + return -1; + } + + struct server_info *server = get_table_index(server_list, (*config)->sid); + server->awaiting_pong = 0; + + return 1; +} + +// [:source] PING <target> +int inspircd3_protocol_handle_ping(struct string source, size_t argc, struct string *argv, size_t net, void *handle, struct server_config *config, char is_incoming) { + if (argc < 1) { + WRITES(2, STRING("[InspIRCd v3] Invalid PING recieved! (Missing parameters)\r\n")); + return -1; + } + + if (STRING_EQ(config->sid, source) && STRING_EQ(SID, argv[1])) { + struct server_info *server = get_table_index(server_list, config->sid); + if (!server->awaiting_pong) { + networks[net].send(handle, STRING(":")); + networks[net].send(handle, SID); + networks[net].send(handle, STRING(" PING :")); + networks[net].send(handle, config->sid); + networks[net].send(handle, STRING("\n")); + + server->awaiting_pong = 1; + gettimeofday(&(server->last_ping), 0); + } + } + + struct server_info *reply = get_table_index(server_list, argv[0]); + if (!reply || !STRING_EQ(reply->next, config->sid)) + return 0; + + networks[net].send(handle, STRING(":")); + networks[net].send(handle, argv[1]); + networks[net].send(handle, STRING(" PONG :")); + networks[net].send(handle, argv[0]); + networks[net].send(handle, STRING("\n")); + + return 0; +} + +// [:source] PONG <target> <reply_to> +int inspircd3_protocol_handle_pong(struct string source, size_t argc, struct string *argv, size_t net, void *handle, struct server_config *config, char is_incoming) { + struct timeval now; + gettimeofday(&now, 0); + struct server_info *server = get_table_index(server_list, config->sid); + + if (!server->awaiting_pong) // We don't relay PINGs, so PONGs also shouldn't need relayed + return 1; + + if (now.tv_usec < server->last_ping.tv_usec) { + server->latency.tv_sec = now.tv_sec - server->last_ping.tv_sec - 1; + server->latency.tv_usec = (suseconds_t)((size_t)1000000 - (size_t)server->last_ping.tv_usec + (size_t)now.tv_usec); // >_> + } else { + server->latency.tv_sec = now.tv_sec - server->last_ping.tv_sec; + server->latency.tv_usec = now.tv_usec - server->last_ping.tv_usec; + } + server->latency_valid = 1; + server->awaiting_pong = 0; + + return 0; +} + +// [:source] SERVER <address> <SID> [key=value, ...] <name> +int inspircd3_protocol_handle_server(struct string source, size_t argc, struct string *argv, size_t net, void *handle, struct server_config *config, char is_incoming) { + if (argc < 3) { + WRITES(2, STRING("[InspIRCd v3] Invalid SERVER recieved! (Missing parameters)\r\n")); + return -1; + } + + if (has_table_index(server_list, argv[1])) { + WRITES(2, STRING("[InspIRCd v3] Duplicate SERVER attempted to be created!\r\n")); + return -1; + } + + if (add_server(config->sid, source, argv[1], argv[0], argv[argc - 1], INSPIRCD3_PROTOCOL, net, handle) != 0) { + WRITES(2, STRING("ERROR: Unable to add server!\r\n")); + return -1; + } + + return 0; +} + +// [:source] SQUIT <SID> [<reason>?] +int inspircd3_protocol_handle_squit(struct string source, size_t argc, struct string *argv, size_t net, void *handle, struct server_config *config, char is_incoming) { + if (argc < 1) { + WRITES(2, STRING("[InspIRCd v3] Invalid SQUIT recieved! (Missing parameters)\r\n")); + return -1; + } + + if (STRING_EQ(argv[0], SID)) { // Not an error, this server is trying to split from us + return -1; + } + + struct server_info *a = get_table_index(server_list, source); + struct server_info *b = get_table_index(server_list, argv[0]); + if (!a || !b) { // Maybe we already RSQUIT it or smth + WRITES(2, STRING("[InspIRCd v3] Invalid SQUIT recieved! (Unknown source or target)\r\n")); + return -1; + } + if (a->protocol != INSPIRCD3_PROTOCOL || b->protocol != INSPIRCD3_PROTOCOL) { // They're trying to use SQUIT for some unrelated server... + WRITES(2, STRING("[InspIRCd v3] Invalid SQUIT recieved! (Bad SID or source)\r\n")); + return -1; + } + + unlink_server(config->sid, a, b, INSPIRCD3_PROTOCOL); + + return 0; +} + +// [:source] RSQUIT <server name> [<reason>?] +int inspircd3_protocol_handle_rsquit(struct string source, size_t argc, struct string *argv, size_t net, void *handle, struct server_config *config, char is_incoming) { + if (argc < 1) { + WRITES(2, STRING("[InspIRCd v3] Invalid RSQUIT recieved! (Missing parameters)\r\n")); + return -1; + } + + if (config->ignore_remote_unlinks) + return 0; + + for (size_t i = 0; i < server_list.len; i++) { + struct server_info *target = server_list.array[i].ptr; + if (target->protocol != INSPIRCD3_PROTOCOL) + continue; // TODO: Maybe actually unlink this somehow + if (!STRING_EQ(target->name, argv[0])) + continue; + + if (has_table_index(target->connected_to, SID)) { + networks[target->net].shutdown(target->handle); + } else { + struct server_info *next = get_table_index(server_list, target->next); + networks[next->net].send(next->handle, STRING(":")); + networks[next->net].send(next->handle, source); + networks[next->net].send(next->handle, STRING(" RSQUIT ")); + networks[next->net].send(next->handle, argv[0]); + if (argc > 1) { + networks[next->net].send(next->handle, STRING(" :")); + networks[next->net].send(next->handle, argv[1]); + networks[next->net].send(next->handle, STRING("\n")); + } else { + networks[next->net].send(next->handle, STRING(":\n")); + } + } + } + + return 0; +} + +// [:source] UID <UID> <nick_ts> <nick> <host> <vhost> <ident> <address> <user_ts> <modes> [<mode args>] <fullname> +int inspircd3_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 v3] Invalid UID recieved! (Missing parameters)\r\n")); + return -1; + } + + if (has_table_index(user_list, argv[0])) { + WRITES(2, STRING("[InspIRCd v3] 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 v3] Invalid UID recieved! (Mode direction not set)\r\n")); + return -1; + } + + switch(inspircd3_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 v3] Invalid UID recieved! (Unknown mode given)\r\n")); + return -1; + } + } + + mode_i++; + } + + if (arg_i >= argc) { + WRITES(2, STRING("[InspIRCd v3] 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 v3] 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 v3] 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, 0) != 0) { + WRITES(2, STRING("ERROR: Unable to add user!\r\n")); + return -1; + } + + return 0; +} + +// :source NICK <nick> <timestamp> +int inspircd3_protocol_handle_nick(struct string source, size_t argc, struct string *argv, size_t net, void *handle, struct server_config *config, char is_incoming) { + if (argc < 2) { + WRITES(2, STRING("[InspIRCd v3] Invalid NICK recieved! (Missing parameters)\r\n")); + return -1; + } + + char err; + size_t nick_ts = str_to_unsigned(argv[1], &err); + if (err) { + WRITES(2, STRING("[InspIRCd v3] Invalid NICK recieved! (Invalid timestamp)\r\n")); + return -1; + } + + struct user_info *user = get_table_index(user_list, source); + if (!user) + return 0; // KILL timings, etc + + if (rename_user(config->sid, user, argv[0], nick_ts) != 0) + return -1; + + return 0; +} + +// :source QUIT [<reason>?] +int inspircd3_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 v3] Invalid QUIT recieved! (Attempting to quit a local user)\r\n")); + return -1; + } + + remove_user(config->sid, user, reason, 1); + + return 0; +} + +// [:source] KILL <target> [<reason>?] +int inspircd3_protocol_handle_kill(struct string source, size_t argc, struct string *argv, size_t net, void *handle, struct server_config *config, char is_incoming) { + if (argc < 1) { + WRITES(2, STRING("[InspIRCd v3] Invalid KILL recieved! (Missing parameters)\r\n")); + return -1; + } + + struct user_info *user = get_table_index(user_list, argv[0]); + if (!user) { + for (size_t i = 0; i < user_list.len; i++) { + struct user_info *tmp = user_list.array[i].ptr; + if (STRING_EQ(tmp->nick, argv[0])) { + user = tmp; + break; + } + } + + if (!user) + return 0; + } + + int ignore; + if (STRING_EQ(user->server, SID)) { + if (config->ignore_local_kills) { + ignore = 1; + } else { + if (argc > 1) + ignore = kill_user(config->sid, source, user, argv[1]); + else + ignore = kill_user(config->sid, source, user, STRING("")); + } + } else if (!config->ignore_remote_kills) { + if (argc > 1) + ignore = kill_user(config->sid, source, user, argv[1]); + else + ignore = kill_user(config->sid, source, user, STRING("")); + } else { + ignore = 1; + } + + if (ignore) + inspircd3_protocol_introduce_user_to(net, handle, user, 1); + + return 0; +} + +// :source OPERTYPE <type> +int inspircd3_protocol_handle_opertype(struct string source, size_t argc, struct string *argv, size_t net, void *handle, struct server_config *config, char is_incoming) { + if (argc < 1) { + WRITES(2, STRING("[InspIRCd v3] Invalid OPERTYPE recieved! (Missing parameters)\r\n")); + return -1; + } + + struct user_info *user = get_table_index(user_list, source); + if (!user) + return 0; + + if (oper_user(config->sid, user, argv[0]) != 0) { + WRITES(2, STRING("[InspIRCd v3] ERROR: Unable to set oper type!\r\n")); + return -1; + } + + return 0; +} + +//// [:source] FJOIN <channel> <timestamp> <modes> [<mode args>] <userlist: modes,uid [...]> +//int inspircd3_protocol_handle_fjoin(struct string source, size_t argc, struct string *argv, size_t net, void *handle, struct server_config *config, char is_incoming) { +// if (argc < 4) { +// WRITES(2, STRING("[InspIRCd v3] Invalid FJOIN recieved! (Missing parameters)\r\n")); +// return -1; +// } +// +// char err; +// size_t timestamp = str_to_unsigned(argv[1], &err); +// if (err) { +// WRITES(2, STRING("[InspIRCd v3] Invalid FJOIN recieved! (Invalid timestamp)\r\n")); +// return -1; +// } +// +// size_t arg_i = 3; +// char dir = '?'; +// for (size_t i = 0; i < argv[2].len; i++) { +// switch(argv[2].data[i]) { +// case '+': +// case '-': +// dir = argv[2].data[i]; +// break; +// default: +// if (dir == '?') { +// WRITES(2, STRING("[InspIRCd v3] Invalid FJOIN recieved (Mode direction not set)\r\n")); +// return -1; +// } +// switch(inspircd3_protocol_channel_mode_types[(unsigned char)argv[2].data[i]]) { +// case MODE_TYPE_NOARGS: +// break; +// case MODE_TYPE_REPLACE: +// case MODE_TYPE_MODE: +// if (dir == '-') +// break; +// case MODE_TYPE_MULTIPLE: +// arg_i++; +// break; +// case MODE_TYPE_USERS: +// WRITES(2, STRING("[InspIRCd v3] Invalid FJOIN recieved! (User mode put in the modes instead of the user list)\r\n")); +// return -1; +// default: +// WRITES(2, STRING("[InspIRCd v3] Invalid FJOIN recieved! (Unknown mode given)\r\n")); +// return -1; +// } +// } +// } +// +// size_t user_count = 0; +// for (size_t i = 0; i < argv[arg_i].len;) { +// while (i < argv[arg_i].len && argv[arg_i].data[i] != ',') +// i++; +// +// i++; +// +// user_count++; +// +// while (i < argv[arg_i].len && argv[arg_i].data[i] != ' ') +// i++; +// } +// +// struct user_info **users; +// users = malloc(sizeof(**users) * user_count); +// if (!users && user_count != 0) { +// WRITES(2, STRING("[InspIRCd v3] [FJOIN] OOM! Disconnecting server.\r\n")); +// return -1; +// } +// +// for (size_t i = 0, n = 0; i < argv[arg_i].len; n++) { +// struct string uid; +// while (i < argv[arg_i].len && argv[arg_i].data[i] != ',') +// i++; +// +// i++; +// +// uid.data = &(argv[arg_i].data[i]); +// +// while (i < argv[arg_i].len && argv[arg_i].data[i] != ' ') +// i++; +// +// uid.len = (size_t)(&(argv[arg_i].data[i]) - uid.data); +// +// users[n] = get_table_index(user_list, uid); +// if (!users[n]) { // Maybe KILLed or smth +// n--; +// user_count--; +// } +// } +// +// struct channel_info *channel = get_table_index(channel_list, argv[0]); +// if (!channel || timestamp < channel->channel_ts) { +// if (set_channel(config->sid, argv[0], timestamp, user_count, users) != 0) +// goto inspircd3_protocol_handle_fjoin_free_users; +// } else { +// if (join_channel(config->sid, channel, user_count, users, 1) != 0) +// goto inspircd3_protocol_handle_fjoin_free_users; +// } +// +// free(users); +// +// return 0; +// +// inspircd3_protocol_handle_fjoin_free_users: +// free(users); +// return -1; +//} +// +//// :source PART <channel> [<reason>] +//int inspircd3_protocol_handle_part(struct string source, size_t argc, struct string *argv, size_t net, void *handle, struct server_config *config, char is_incoming) { +// if (argc < 1) { +// WRITES(2, STRING("[InspIRCd v3] Invalid PART recieved! (Missing parameters)\r\n")); +// return -1; +// } +// struct string reason; +// if (argc < 2) +// reason = STRING(""); +// else +// reason = argv[1]; +// +// struct user_info *user = get_table_index(user_list, source); +// if (!user) +// return 0; +// +// struct channel_info *channel = get_table_index(channel_list, argv[0]); +// if (!channel) +// return 0; +// +// part_channel(config->sid, channel, user, reason, 1); +// +// return 0; +//} +// +//// [:source] KICK <channel> <user> [<reason>] +//int inspircd3_protocol_handle_kick(struct string source, size_t argc, struct string *argv, size_t net, void *handle, struct server_config *config, char is_incoming) { +// if (argc < 2) { +// WRITES(2, STRING("[InspIRCd v3] Invalid KICK recieved! (Missing parameters)\r\n")); +// return -1; +// } +// +// struct channel_info *channel = get_table_index(channel_list, argv[0]); +// if (!channel) +// return 0; +// +// struct user_info *user = get_table_index(user_list, argv[1]); +// if (!user) { +// char found = 0; +// for (size_t i = 0; i < user_list.len; i++) { +// user = user_list.array[i].ptr; +// if (STRING_EQ(user->nick, argv[1])) { +// found = 1; +// break; +// } +// } +// if (!found) +// return 0; +// } +// +// int rejoin; +// if (argc > 2) +// rejoin = kick_channel(config->sid, source, channel, user, argv[2]); +// else +// rejoin = kick_channel(config->sid, source, channel, user, STRING("")); +// +// if (rejoin) { +// networks[net].send(handle, STRING(":")); +// networks[net].send(handle, SID); +// networks[net].send(handle, STRING(" FJOIN ")); +// networks[net].send(handle, channel->name); +// networks[net].send(handle, STRING(" ")); +// networks[net].send(handle, channel->channel_ts_str); +// networks[net].send(handle, STRING(" + :,")); +// networks[net].send(handle, user->uid); +// networks[net].send(handle, STRING("\n")); +// } +// +// return 0; +//} +// +//// [:source] PRIVMSG <target> <message> +//int inspircd3_protocol_handle_privmsg(struct string source, size_t argc, struct string *argv, size_t net, void *handle, struct server_config *config, char is_incoming) { +// if (argc < 2) { +// WRITES(2, STRING("[InspIRCd v3] Invalid PRIVMSG recieved! (Missing parameters)\r\n")); +// return -1; +// } +// +// privmsg(config->sid, source, argv[0], argv[1]); +// +// return 0; +//} +// +//// [:source] NOTICE <target> <message> +//int inspircd3_protocol_handle_notice(struct string source, size_t argc, struct string *argv, size_t net, void *handle, struct server_config *config, char is_incoming) { +// if (argc < 2) { +// WRITES(2, STRING("[InspIRCd v3] Invalid NOTICE recieved! (Missing parameters)\r\n")); +// return -1; +// } +// +// notice(config->sid, source, argv[0], argv[1]); +// +// return 0; +//} diff --git a/protocols/inspircd3.h b/protocols/inspircd3.h new file mode 100644 index 0000000..060e85d --- /dev/null +++ b/protocols/inspircd3.h @@ -0,0 +1,100 @@ +// Written by: Test_User <hax@andrewyu.org> +// +// This is free and unencumbered software released into the public +// domain. +// +// Anyone is free to copy, modify, publish, use, compile, sell, or +// distribute this software, either in source code form or as a compiled +// binary, for any purpose, commercial or non-commercial, and by any +// means. +// +// In jurisdictions that recognize copyright laws, the author or authors +// of this software dedicate any and all copyright interest in the +// software to the public domain. We make this dedication for the benefit +// of the public at large and to the detriment of our heirs and +// successors. We intend this dedication to be an overt act of +// relinquishment in perpetuity of all present and future rights to this +// software under copyright law. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. + +#pragma once + +#include <stddef.h> + +#include "../config.h" +#include "../haxstring.h" +#include "../general_network.h" +#include "../table.h" + +struct inspircd3_protocol_specific_user { + struct table memberships; +}; + +extern struct table inspircd3_protocol_init_commands; +extern struct table inspircd3_protocol_commands; + +int init_inspircd3_protocol(void); + +void * inspircd3_protocol_connection(void *type); +void * inspircd3_protocol_autoconnect(void *type); +void inspircd3_protocol_update_propagations(void); + +void inspircd3_protocol_propagate(struct string from, struct string msg); + +void inspircd3_protocol_propagate_new_server(struct string from, struct string attached_to, struct server_info *info); +void inspircd3_protocol_propagate_unlink_server(struct string from, struct server_info *a, struct server_info *b, size_t protocol); + +void inspircd3_protocol_propagate_new_user(struct string from, struct user_info *info); +void inspircd3_protocol_propagate_rename_user(struct string from, struct user_info *info, struct string nick, size_t timestamp, struct string timestamp_str); +void inspircd3_protocol_propagate_remove_user(struct string from, struct user_info *info, struct string reason); +void inspircd3_protocol_propagate_kill_user(struct string from, struct string source, struct user_info *info, struct string reason); +void inspircd3_protocol_propagate_oper_user(struct string from, struct user_info *info, struct string type); + +void inspircd3_protocol_propagate_set_channel(struct string from, struct channel_info *channel, char is_new_channel, size_t user_count, struct user_info **users); +void inspircd3_protocol_propagate_join_channel(struct string from, struct channel_info *channel, size_t user_count, struct user_info **users); +void inspircd3_protocol_propagate_part_channel(struct string from, struct channel_info *channel, struct user_info *user, struct string reason); +void inspircd3_protocol_propagate_kick_channel(struct string from, struct string source, struct channel_info *channel, struct user_info *user, struct string reason); + +void inspircd3_protocol_propagate_privmsg(struct string from, struct string source, struct string target, struct string msg); +void inspircd3_protocol_propagate_notice(struct string from, struct string source, struct string target, struct string msg); + +void inspircd3_protocol_do_unlink(struct string from, struct server_info *a, struct server_info *b); + +void inspircd3_protocol_update_propagations_inner(struct server_info *source); + +void inspircd3_protocol_do_unlink_inner(struct string from, struct server_info *source, struct string reason); + +int inspircd3_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 inspircd3_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); + +int inspircd3_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 inspircd3_protocol_handle_pong(struct string source, size_t argc, struct string *argv, size_t net, void *handle, struct server_config *config, char is_incoming); + +int inspircd3_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 inspircd3_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 inspircd3_protocol_handle_rsquit(struct string source, size_t argc, struct string *argv, size_t net, void *handle, struct server_config *config, char is_incoming); + +int inspircd3_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 inspircd3_protocol_handle_nick(struct string source, size_t argc, struct string *argv, size_t net, void *handle, struct server_config *config, char is_incoming); +int inspircd3_protocol_handle_quit(struct string source, size_t argc, struct string *argv, size_t net, void *handle, struct server_config *config, char is_incoming); +int inspircd3_protocol_handle_kill(struct string source, size_t argc, struct string *argv, size_t net, void *handle, struct server_config *config, char is_incoming); +int inspircd3_protocol_handle_opertype(struct string source, size_t argc, struct string *argv, size_t net, void *handle, struct server_config *config, char is_incoming); + +int inspircd3_protocol_handle_fjoin(struct string source, size_t argc, struct string *argv, size_t net, void *handle, struct server_config *config, char is_incoming); +int inspircd3_protocol_handle_part(struct string source, size_t argc, struct string *argv, size_t net, void *handle, struct server_config *config, char is_incoming); +int inspircd3_protocol_handle_kick(struct string source, size_t argc, struct string *argv, size_t net, void *handle, struct server_config *config, char is_incoming); + +int inspircd3_protocol_handle_privmsg(struct string source, size_t argc, struct string *argv, size_t net, void *handle, struct server_config *config, char is_incoming); +int inspircd3_protocol_handle_notice(struct string source, size_t argc, struct string *argv, size_t net, void *handle, struct server_config *config, char is_incoming); + +int inspircd3_protocol_handle_dump(struct string source, size_t argc, struct string *argv, size_t net, void *handle, struct server_config *config, char is_incoming); + +extern char inspircd3_protocol_user_mode_types[UCHAR_MAX+1]; +extern char inspircd3_protocol_channel_mode_types[UCHAR_MAX+1]; diff --git a/real_main.c b/real_main.c index 6548449..ec88938 100644 --- a/real_main.c +++ b/real_main.c @@ -50,10 +50,6 @@ #include "client_network.h" #endif -#ifdef USE_INSPIRCD2_PROTOCOL -#include "protocols/inspircd2.h" -#endif - #ifdef USE_PSUEDOCLIENTS #include "psuedoclients.h" #endif diff --git a/server_network.c b/server_network.c index bf9e442..a3f420a 100644 --- a/server_network.c +++ b/server_network.c @@ -55,10 +55,8 @@ int init_server_network(void) { } } -#ifdef USE_INSPIRCD2_PROTOCOL - if (protocols[INSPIRCD2_PROTOCOL].init() != 0) + if (protocols_init() != 0) return 1; -#endif return 0; } @@ -108,6 +106,20 @@ int start_server_network_threads(size_t net) { } } #endif +#ifdef USE_INSPIRCD3_PROTOCOL + if (SERVER_INCOMING[net][INSPIRCD3_PROTOCOL]) { + type = malloc(sizeof(*type)); + if (!type) + return 1; + type->net_type = net; + type->protocol = INSPIRCD3_PROTOCOL; + type->is_incoming = 1; + if (pthread_create(&trash, &pthread_attr, server_accept_thread, type) != 0) { + free(type); + return 1; + } + } +#endif return 0; } @@ -214,12 +226,7 @@ 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, new_info); -#endif -#ifdef USE_INSPIRCD2_PROTOCOL - protocols[INSPIRCD2_PROTOCOL].propagate_new_server(from, attached_to, new_info); -#endif + protocols_propagate_new_server(from, attached_to, new_info); return 0; @@ -266,15 +273,6 @@ void remove_server(struct string from, struct server_info *server, struct string free_server(server); } -void update_all_propagations(void) { -#ifdef USE_HAXIRCD_PROTOCOL - protocols[HAXIRCD_PROTOCOL].update_propagations(); -#endif -#ifdef USE_INSPIRCD2_PROTOCOL - protocols[INSPIRCD2_PROTOCOL].update_propagations(); -#endif -} - void unlink_server(struct string from, struct server_info *a, struct server_info *b, size_t protocol) { if (!has_table_index(a->connected_to, b->sid)) return; @@ -284,12 +282,7 @@ void unlink_server(struct string from, struct server_info *a, struct server_info protocols[protocol].update_propagations(); -#ifdef USE_HAXIRCD_PROTOCOL - protocols[HAXIRCD_PROTOCOL].propagate_unlink_server(from, a, b, protocol); -#endif -#ifdef USE_INSPIRCD2_PROTOCOL - protocols[INSPIRCD2_PROTOCOL].propagate_unlink_server(from, a, b, protocol); -#endif + protocols_propagate_unlink_server(from, a, b, protocol); protocols[protocol].do_unlink(from, a, b); } |