123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982 |
- // Server network command handlers 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 <gnutls/gnutls.h>
- #include <netdb.h>
- #include <arpa/inet.h>
- #include <sys/types.h>
- #include <netinet/in.h>
- #include <sys/socket.h>
- #include <string.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include "network.h"
- #include "types.h"
- #include "table.h"
- #include "tls.h"
- #include "config.h"
- #include "utils.h"
- #include "commands.h"
- pthread_mutex_t send_lock = PTHREAD_MUTEX_INITIALIZER;
- int resolve(char *address, char *port, struct sockaddr *sockaddr) {
- int success;
- struct addrinfo hints = {0}, *info;
- hints.ai_family = AF_INET;
- hints.ai_socktype = SOCK_STREAM;
- hints.ai_protocol = IPPROTO_TCP;
- hints.ai_flags = AI_NUMERICSERV | AI_ADDRCONFIG;
- success = getaddrinfo(address, port, &hints, &info);
- if (success == 0) {
- *sockaddr = *(info->ai_addr);
- freeaddrinfo(info);
- }
- return success;
- }
- struct table server_network_commands = {0};
- struct table server_list = {0};
- struct table user_list = {0};
- struct table channel_list = {0};
- int ping_handler(struct string sender, uint64_t argc, struct string *argv) {
- if (argc < 2) {
- puts("Invalid PING recieved! (Missing parameters)");
- return 1;
- }
- uint64_t len = 1 + argv[1].len + 6 + argv[1].len + 1 + sender.len + 1;
- char msg[len];
- uint64_t offset = 0;
- msg[0] = ':';
- offset++;
- memcpy(msg+offset, argv[1].data, argv[1].len);
- offset += argv[1].len;
- memcpy(msg+offset, " PONG ", 6);
- offset += 6;
- memcpy(msg+offset, argv[1].data, argv[1].len);
- offset += argv[1].len;
- msg[offset] = ' ';
- offset++;
- memcpy(msg+offset, sender.data, sender.len);
- offset += sender.len;
- msg[offset] = '\n';
- SEND(((struct string){msg, len}));
- return 0;
- }
- int server_handler(struct string sender, uint64_t argc, struct string *argv) {
- if (argc < 5) {
- puts("Invalid SERVER recieved! (Missing parameters)");
- return 1;
- }
- if (argv[2].len > 20) {
- puts("Invalid SERVER recieved! (Distance too large)");
- return 1;
- }
- char err;
- uint64_t distance = str_to_unsigned(argv[2], &err);
- if (err) {
- puts("Invalid SERVER recieved! (Invalid distance given)");
- return 1;
- }
- if (sender.len != 0) {
- struct server_info *from = get_table_index(server_list, sender);
- if (!from) {
- puts("Invalid SERVER recieved! (Unknown source)");
- return 1;
- }
- distance += from->distance + 1;
- }
- if (get_table_index(server_list, argv[3]) != 0) {
- WRITES(2, STRING("Invalid SERVER recieved! (Duplicate SID already connected)\n"));
- return 1;
- }
- struct string address;
- address.data = malloc(argv[0].len);
- if (address.data == 0)
- goto server_handler_oom;
- address.len = argv[0].len;
- memcpy(address.data, argv[0].data, argv[0].len);
- struct string name;
- name.data = malloc(argv[4].len);
- if (name.data == 0)
- goto server_handler_free_address;
- name.len = argv[4].len;
- memcpy(name.data, argv[4].data, argv[4].len);
- struct server_info *server = malloc(sizeof(*server));
- if (server == 0)
- goto server_handler_free_name;
- struct string via;
- if (sender.len != 0) { // connected to the sender
- via.data = malloc(sender.len);
- if (!via.data)
- goto server_handler_free_server;
- via.len = sender.len;
- memcpy(via.data, sender.data, sender.len);
- } else { // connected directly to us
- via = (struct string){0};
- }
- *server = (struct server_info){
- .name = name,
- .address = address,
- .distance = distance,
- .via = via,
- };
- if (set_table_index(&server_list, argv[3], server) != 0)
- goto server_handler_free_via;
- return 0;
- server_handler_free_via:
- if (sender.len != 0)
- free(via.data);
- server_handler_free_server:
- free(server);
- server_handler_free_name:
- free(name.data);
- server_handler_free_address:
- free(address.data);
- server_handler_oom:
- puts("OOM! (server_handler)");
- return 1;
- }
- int uid_handler(struct string sender, uint64_t argc, struct string *argv) {
- if (argc < 10) {
- puts("Invalid UID recieved! (Missing parameters)");
- return 1;
- }
- if (argv[1].len > 20 || argv[7].len > 20) {
- puts("Invalid UID recieved! (Timestamp too long)");
- return 1;
- }
- if (sender.len == 0) {
- puts("Invalid UID recieved! (No source)");
- return 1;
- }
- if (get_table_index(user_list, argv[0])) {
- WRITES(2, STRING("Invalid UID revieved! (Attempted to create already-existing user)\n"));
- return 1;
- }
- // TODO: modes
- char err;
- uint64_t nick_ts = str_to_unsigned(argv[1], &err);
- if (err) {
- puts("Invalid UID recieved! (Invalid nick timestamp)");
- return 1;
- }
- uint64_t user_ts = str_to_unsigned(argv[7], &err);
- if (err) {
- puts("Invalid UID recieved! (Invalid user timestamp)");
- return 1;
- }
- struct string server;
- server.data = malloc(sender.len);
- if (!server.data)
- goto uid_handler_oom;
- server.len = sender.len;
- memcpy(server.data, sender.data, sender.len);
- struct string nick;
- nick.data = malloc(argv[2].len);
- if (!nick.data)
- goto uid_handler_free_server;
- nick.len = argv[2].len;
- memcpy(nick.data, argv[2].data, argv[2].len);
- struct string hostname;
- hostname.data = malloc(argv[3].len);
- if (!hostname.data)
- goto uid_handler_free_nick;
- hostname.len = argv[3].len;
- memcpy(hostname.data, argv[3].data, argv[3].len);
- struct string vhost;
- vhost.data = malloc(argv[4].len);
- if (!vhost.data)
- goto uid_handler_free_hostname;
- vhost.len = argv[4].len;
- memcpy(vhost.data, argv[4].data, argv[4].len);
- struct string ident;
- ident.data = malloc(argv[5].len);
- if (!ident.data)
- goto uid_handler_free_vhost;
- ident.len = argv[5].len;
- memcpy(ident.data, argv[5].data, argv[5].len);
- struct string ip;
- ip.data = malloc(argv[6].len);
- if (!ip.data)
- goto uid_handler_free_ident;
- ip.len = argv[6].len;
- memcpy(ip.data, argv[6].data, argv[6].len);
- struct string realname;
- realname.data = malloc(argv[argc - 1].len);
- if (!realname.data)
- goto uid_handler_free_ip;
- realname.len = argv[argc - 1].len;
- memcpy(realname.data, argv[argc - 1].data, argv[argc - 1].len);
- struct user_info *user = malloc(sizeof(*user));
- if (!user)
- goto uid_handler_free_realname;
- *user = (struct user_info){
- .nick_ts = nick_ts,
- .user_ts = user_ts,
- .server = server,
- .nick = nick,
- .hostname = hostname,
- .vhost = vhost,
- .ident = ident,
- .ip = ip,
- .realname = realname,
- .opertype = {.data = malloc(0), .len = 0},
- .metadata = {.array = malloc(0), .len = 0},
- };
- if (set_table_index(&user_list, argv[0], user) != 0)
- goto uid_handler_free_user;
- return 0;
- uid_handler_free_user:
- free(user);
- uid_handler_free_realname:
- free(realname.data);
- uid_handler_free_ip:
- free(ip.data);
- uid_handler_free_ident:
- free(ident.data);
- uid_handler_free_vhost:
- free(vhost.data);
- uid_handler_free_hostname:
- free(hostname.data);
- uid_handler_free_nick:
- free(nick.data);
- uid_handler_free_server:
- free(server.data);
- uid_handler_oom:
- puts("OOM! (uid_handler)");
- return 1;
- }
- int opertype_handler(struct string sender, uint64_t argc, struct string *argv) {
- if (argc < 1) {
- WRITES(2, STRING("Invalid OPERTYPE recieved! (Missing parameters)\n"));
- return 1;
- }
- if (sender.len == 0) {
- WRITES(2, STRING("Invalid OPERTYPE recieved! (No source)\n"));
- return 1;
- }
- struct user_info *user = get_table_index(user_list, sender);
- if (!user) {
- WRITES(2, STRING("Server "));
- WRITES(2, sender);
- WRITES(2, STRING(" attempted to set OPERTYPE on a nonexistent user!\n"));
- return 1;
- }
- struct string opertype = {.data = malloc(argv[0].len), .len = argv[0].len};
- if (!opertype.data) {
- WRITES(2, STRING("OOM! (opertype_handler)\n"));
- return 1;
- }
- memcpy(opertype.data, argv[0].data, argv[0].len);
- free(user->opertype.data);
- user->opertype = opertype;
- return 0;
- }
- int quit_handler(struct string sender, uint64_t argc, struct string *argv) {
- if (argc < 1)
- return remove_user(sender, (struct string){0});
- else
- return remove_user(sender, argv[0]);
- }
- int kill_handler(struct string sender, uint64_t argc, struct string *argv) {
- if (argc < 2) {
- WRITES(2, STRING("Invalid KILL recieved! (Missing parameters)\n"));
- return 1;
- }
- // TODO: Get accurate list of what got killed, what to rejoin, etc
- struct user_info *user = get_table_index(user_list, argv[0]);
- if (!user)
- return 0; // TODO: Currently not all local users are considered; fix that, then make this give an error
- if (STRING_EQ(user->server, STRING("1HC"))) {
- SEND(STRING(":"));
- SEND(argv[0]);
- SEND(STRING(" QUIT :"));
- SEND(argv[1]);
- SEND(STRING("\n"));
- SEND(STRING("GLOADMODULE m_servprotect\n")); // required for the +k we're about to use
- char user_time[21];
- snprintf(user_time, 21, "%ld", user->user_ts);
- char nick_time[21];
- snprintf(nick_time, 21, "%ld", user->nick_ts);
- SEND(STRING("UID "));
- SEND(argv[0]);
- SEND(STRING(" "));
- SEND(NULSTR(user_time));
- SEND(STRING(" "));
- SEND(user->nick);
- SEND(STRING(" "));
- SEND(user->hostname);
- SEND(STRING(" "));
- SEND(user->vhost);
- SEND(STRING(" "));
- SEND(user->ident);
- SEND(STRING(" "));
- SEND(user->ip);
- SEND(STRING(" "));
- SEND(NULSTR(nick_time));
- SEND(STRING(" +k :"));
- SEND(user->realname);
- SEND(STRING("\n"));
- if (STRING_EQ(argv[0], STRING("1HC000001"))) {
- SEND(STRING(":1HC METADATA 1HC000001 ssl_cert :vTrse "));
- SEND(client_cert);
- SEND(STRING("\n:"));
- SEND(argv[0]);
- SEND(STRING(" OPERTYPE "));
- SEND(opertype);
- SEND(STRING("\n"));
- }
- for (uint64_t i = 0; i < channel_list.len; i++) {
- struct channel_info *channel = channel_list.array[i].ptr;
- if (has_table_index(channel->user_list, argv[0])) {
- char timestamp[21];
- SEND(STRING("FJOIN "));
- SEND(channel_list.array[i].name);
- SEND(STRING(" "));
- snprintf(timestamp, 21, "%ld", channel->ts);
- SEND(NULSTR(timestamp));
- SEND(STRING(" + :,"));
- SEND(argv[0]);
- SEND(STRING("\n"));
- }
- }
- } else {
- return remove_user(argv[0], argv[1]);
- }
- return 0;
- }
- int nick_handler(struct string sender, uint64_t argc, struct string *argv) {
- if (argc < 2) {
- WRITES(2, STRING("Invalid NICK recieved! (Missing parameters)\n"));
- return 1;
- }
- struct user_info *info = get_table_index(user_list, sender);
- if (!info) {
- WRITES(2, STRING("NICK: Unknown user!\n"));
- return 1;
- }
- for (uint64_t i = 0; i < channel_list.len; i++) { // TODO: More efficient way of doing this
- struct channel_info *channel = channel_list.array[i].ptr;
- if (has_table_index(channel->user_list, sender) && has_table_index(channel->user_list, STRING("1HC000001"))) {
- SENDCLIENT(STRING(":"));
- SENDCLIENT(info->nick);
- SENDCLIENT(STRING("!"));
- SENDCLIENT(info->ident);
- SENDCLIENT(STRING("@"));
- SENDCLIENT(info->vhost);
- SENDCLIENT(STRING(" NICK :"));
- SENDCLIENT(argv[0]);
- SENDCLIENT(STRING("\r\n"));
- break;
- }
- }
- void *tmp = malloc(argv[0].len);
- if (!tmp) {
- WRITES(2, STRING("OOM! (nick_handler)\n"));
- return 1;
- }
- memcpy(tmp, argv[0].data, argv[0].len);
- free(info->nick.data);
- info->nick.data = tmp;
- info->nick.len = argv[0].len;
- if (argv[1].len > 20) {
- WRITES(2, STRING("Invalid NICK recieved! (Timestamp too long)\n"));
- return 1;
- }
- char err;
- uint64_t ts = str_to_unsigned(argv[1], &err);
- if (err) {
- WRITES(2, STRING("Invalid NICK recieved! (Invalid timestamp)\n"));
- return 1;
- }
- info->nick_ts = ts;
- return 0;
- }
- int fjoin_handler(struct string sender, uint64_t argc, struct string *argv) {
- if (argc < 4) {
- WRITES(2, STRING("Invalid FJOIN recieved! (Missing parameters"));
- return 1;
- }
- char err;
- uint64_t timestamp = str_to_unsigned(argv[1], &err);
- if (err) {
- WRITES(2, STRING("Invalid FJOIN recieved! (Invalid timestamp given)\n"));
- return 1;
- }
- // TODO: Parse modes, then make the rest of this work
- uint64_t userlist_offset = 3;
- {
- char dir = '?';
- for (uint64_t offset = 0; offset < argv[2].len; offset++) {
- if (argv[2].data[offset] == '+') {
- dir = '+';
- } else if (argv[2].data[offset] == '-') {
- dir = '-';
- } else if (dir == '?') {
- WRITES(2, STRING("Invalid FJOIN recieved! (No direction set for modes)\n"));
- return 1;
- } else if (channel_mode_types[(unsigned char)argv[2].data[offset]] == MODE_TYPE_UNKNOWN) {
- WRITES(2, STRING("Invalid FJOIN recieved! (Unknown mode set on the channel)\n"));
- return 1;
- } else if (channel_mode_types[(unsigned char)argv[2].data[offset]] != MODE_TYPE_NOARGS && dir == '+') {
- userlist_offset++;
- }
- }
- }
- if (argc < userlist_offset + 1) {
- WRITES(2, STRING("Invalid FJOIN recieved! (Missing mode parameters or user list)\n"));
- return 1;
- }
- struct channel_info *channel = get_table_index(channel_list, argv[0]);
- if (!channel) {
- channel = malloc(sizeof(*channel));
- if (!channel) {
- WRITES(2, STRING("OOM! (fjoin_handler)\n"));
- return 1;
- }
- *channel = (struct channel_info){
- .ts = timestamp,
- .topic = {.data = malloc(0), .len = 0},
- .topic_ts = 0,
- .modes = {.array = malloc(0), .len = 0},
- .user_list = {.array = malloc(0), .len = 0},
- .metadata = {.array = malloc(0), .len = 0},
- };
- set_table_index(&channel_list, argv[0], channel);
- }
- if (timestamp < channel->ts)
- channel->ts = timestamp;
- struct string userlist = argv[userlist_offset];
- if (userlist.len < 10) // Not enough for any users
- return 0;
- uint8_t sendclient = has_table_index(channel->user_list, STRING("1HC000001"));
- uint64_t offset = 0;
- while (1) {
- while (offset < userlist.len && userlist.data[offset] != ',')
- offset++;
- if (offset > (userlist.len - 1) - 9)
- break;
- offset++;
- struct string user = {.data = &(userlist.data[offset]), .len = 9};
- struct user_info *user_info = get_table_index(user_list, user);
- set_table_index(&(channel->user_list), user, user_info);
- if (user_info && sendclient) {
- SENDCLIENT(STRING(":"));
- SENDCLIENT(user_info->nick);
- SENDCLIENT(STRING("!"));
- SENDCLIENT(user_info->ident);
- SENDCLIENT(STRING("@"));
- SENDCLIENT(user_info->vhost);
- SENDCLIENT(STRING(" JOIN :"));
- SENDCLIENT(argv[0]);
- SENDCLIENT(STRING("\r\n"));
- }
- offset += 10;
- }
- return 0;
- }
- int squit_handler(struct string sender, uint64_t argc, struct string *argv) {
- if (argc < 1) {
- WRITES(2, STRING("Invalid SQUIT recieved! (Missing parameters)\n"));
- return 1;
- }
- struct server_info *server = remove_table_index(&server_list, argv[0]);
- if (!server) {
- WRITES(2, STRING("Invalid SQUIT received! (Unknown server)\n"));
- WRITES(2, STRING("Known servers:\r\n"));
- for (uint64_t i = 0; i < server_list.len; i++) {
- WRITES(2, server_list.array[i].name);
- WRITES(2, STRING("\r\n"));
- }
- return 1;
- }
- for (uint64_t i = 0; i < user_list.len;) {
- struct user_info *info = user_list.array[i].ptr;
- if (STRING_EQ(info->server, argv[0])) {
- remove_user(user_list.array[i].name, STRING("*.net *.split"));
- } else {
- i++; // removal of the user from the table shifts the next user into place for us
- }
- }
- free(server->name.data);
- free(server->address.data);
- if (server->via.data != 0)
- free(server->via.data);
- free(server);
- return 0;
- }
- int privmsg_handler(struct string sender, uint64_t argc, struct string *argv) {
- if (argc < 2) {
- WRITES(2, STRING("Invalid PRIVMSG recieved (Missing parameters)\n"));
- return 1;
- }
- if (sender.len == 0) {
- WRITES(2, STRING("Invalid PRIVMSG recieved (No source)\n"));
- return 1;
- }
- struct user_info *user = get_table_index(user_list, sender);
- struct server_info *server;
- if (user) {
- server = 0;
- if (argv[0].data[0] == '#') {
- struct channel_info *channel = get_table_index(channel_list, argv[0]);
- if (channel && has_table_index(channel->user_list, STRING("1HC000001"))) {
- SENDCLIENT(STRING(":"));
- SENDCLIENT(user->nick);
- SENDCLIENT(STRING("!"));
- SENDCLIENT(user->ident);
- SENDCLIENT(STRING("@"));
- SENDCLIENT(user->vhost);
- SENDCLIENT(STRING(" PRIVMSG "));
- SENDCLIENT(argv[0]);
- SENDCLIENT(STRING(" :"));
- SENDCLIENT(argv[1]);
- SENDCLIENT(STRING("\r\n"));
- }
- } else if (STRING_EQ(argv[0], STRING("1HC000001"))) {
- SENDCLIENT(STRING(":"));
- SENDCLIENT(user->nick);
- SENDCLIENT(STRING("!"));
- SENDCLIENT(user->ident);
- SENDCLIENT(STRING("@"));
- SENDCLIENT(user->vhost);
- SENDCLIENT(STRING(" PRIVMSG "));
- SENDCLIENT(client_nick);
- SENDCLIENT(STRING(" :"));
- SENDCLIENT(argv[1]);
- SENDCLIENT(STRING("\r\n"));
- }
- } else {
- server = get_table_index(server_list, sender);
- if (server) {
- if (argv[0].data[0] == '#') {
- struct channel_info *channel = get_table_index(channel_list, argv[0]);
- if (channel && has_table_index(channel->user_list, STRING("1HC000001"))) {
- SENDCLIENT(STRING(":"));
- SENDCLIENT(server->address);
- SENDCLIENT(STRING(" PRIVMSG "));
- SENDCLIENT(argv[0]);
- SENDCLIENT(STRING(" :"));
- SENDCLIENT(argv[1]);
- SENDCLIENT(STRING("\r\n"));
- }
- } else if (STRING_EQ(argv[0], STRING("1HC000001"))) {
- SENDCLIENT(STRING(":"));
- SENDCLIENT(server->address);
- SENDCLIENT(STRING(" PRIVMSG "));
- SENDCLIENT(client_nick);
- SENDCLIENT(STRING(" :"));
- SENDCLIENT(argv[1]);
- SENDCLIENT(STRING("\r\n"));
- }
- }
- }
- uint64_t offset;
- if (argv[0].data[0] == '#') {
- if (argv[1].len < command_prefix.len || memcmp(argv[1].data, command_prefix.data, command_prefix.len) != 0)
- return 0;
- struct channel_info *channel_info = get_table_index(channel_list, argv[0]);
- if (!channel_info)
- return 0;
- if (!has_table_index(channel_info->user_list, STRING("1HC000000")))
- return 0;
- offset = command_prefix.len;
- } else if (STRING_EQ(argv[0], STRING("1HC000000"))) {
- offset = 0;
- } else {
- return 0;
- }
- if (offset >= argv[1].len || argv[1].data[offset] == ' ')
- return 0;
- uint64_t command_argc = 0;
- uint64_t old_offset = offset;
- while (offset < argv[1].len) {
- while (offset < argv[1].len && argv[1].data[offset] != ' ')
- offset++;
- command_argc++;
- while (offset < argv[1].len && argv[1].data[offset] == ' ')
- offset++;
- }
- offset = old_offset;
- struct string command_argv[command_argc]; // argv[0] in this case is the command itself, unlike network command handlers... might change one of these two later to match
- uint64_t i = 0;
- while (offset < argv[1].len) {
- command_argv[i].data = argv[1].data+offset;
- uint64_t start = offset;
- while (offset < argv[1].len && argv[1].data[offset] != ' ')
- offset++;
- command_argv[i].len = offset - start;
- while (offset < argv[1].len && argv[1].data[offset] == ' ')
- offset++;
- i++;
- }
- argv[1].data += old_offset;
- argv[1].len -= old_offset;
- struct command_def *cmd = get_table_index(user_commands, command_argv[0]);
- if (cmd) {
- if (!cmd->local_only) {
- if (cmd->privs.len != 0 && sender.len != 3) { // servers always count as oper :P
- if (!user) {
- WRITES(2, STRING("User is unknown!\n"));
- SEND(STRING(":1HC000000 NOTICE "));
- if (argv[0].data[0] == '#')
- SEND(argv[0]);
- else
- SEND(sender);
- SEND(STRING(" :You don't seem to exist... and neither do I!\n"));
- return 1; // have already desynced
- }
- if (user->opertype.len != cmd->privs.len || memcmp(user->opertype.data, cmd->privs.data, cmd->privs.len)) {
- // TODO: complain about missing privs
- SEND(STRING(":1HC000000 NOTICE "));
- if (argv[0].data[0] == '#')
- SEND(argv[0]);
- else
- SEND(sender);
- SEND(STRING(" :You are not authorized to execute this command.\n"));
- return 0;
- }
- }
- struct string message[] = {
- user ? STRING("User ") : (server ? STRING("Server ") : STRING("An unknown user (something desycned... this shouldn't happen)")),
- user ? user->nick : (server ? server->address : STRING("")),
- STRING(" executes `"),
- argv[1],
- STRING("'"),
- };
- privmsg(STRING("1HC000000"), log_channel, sizeof(message)/sizeof(*message), message);
- return cmd->func(sender, argv[1], argv[0].data[0] == '#' ? argv[0] : sender, command_argc, command_argv, 0);
- } else {
- SEND(STRING(":1HC000000 NOTICE "));
- if (argv[0].data[0] == '#')
- SEND(argv[0]);
- else
- SEND(sender);
- SEND(STRING(" :You are not authorized to execute this command.\n"));
- WRITES(1, STRING("Not executing local-only command from a remote source!\n"));
- return 0;
- }
- } else {
- SEND(STRING(":1HC000000 NOTICE "));
- if (argv[0].data[0] == '#')
- SEND(argv[0]);
- else
- SEND(sender);
- SEND(STRING(" :Unknown command: "));
- if (argv[0].data[0] == '#')
- SEND(command_prefix);
- SEND(command_argv[0]);
- SEND(STRING("\n"));
- return 0;
- }
- }
- int part_handler(struct string sender, uint64_t argc, struct string *argv) {
- if (argc < 1) {
- WRITES(2, STRING("Invalid PART received! (Missing parameters)\n"));
- return 1;
- }
- struct channel_info *channel = get_table_index(channel_list, argv[0]);
- struct user_info *user = get_table_index(user_list, sender);
- if (user && channel && has_table_index(channel->user_list, STRING("1HC000001"))) {
- SENDCLIENT(STRING(":"));
- SENDCLIENT(user->nick);
- SENDCLIENT(STRING("!"));
- SENDCLIENT(user->ident);
- SENDCLIENT(STRING("@"));
- SENDCLIENT(user->vhost);
- SENDCLIENT(STRING(" PART "));
- SENDCLIENT(argv[0]);
- if (argc >= 2) {
- SENDCLIENT(STRING(" :"));
- SENDCLIENT(argv[1]);
- }
- SENDCLIENT(STRING("\r\n"));
- }
- if (channel)
- remove_table_index(&(channel->user_list), sender);
- return 0;
- }
- int notice_handler(struct string sender, uint64_t argc, struct string *argv) {
- if (argc < 2) {
- WRITES(2, STRING("Invalid NOTICE received! (Missing parameters)\n"));
- return 1;
- }
- struct user_info *user = get_table_index(user_list, sender);
- struct server_info *server;
- if (user)
- server = 0;
- else
- server = get_table_index(server_list, sender);
- if (!user && !server) {
- WRITES(2, STRING("Invalid NOTICE received! (Unknown source)\n"));
- return 1;
- }
- if (argv[0].data[0] == '#') {
- struct channel_info *channel = get_table_index(channel_list, argv[0]);
- if (channel && has_table_index(channel->user_list, STRING("1HC000001"))) {
- SENDCLIENT(STRING(":"));
- if (user) {
- SENDCLIENT(user->nick);
- SENDCLIENT(STRING("!"));
- SENDCLIENT(user->ident);
- SENDCLIENT(STRING("@"));
- SENDCLIENT(user->vhost);
- } else {
- SENDCLIENT(server->address);
- }
- SENDCLIENT(STRING(" NOTICE "));
- SENDCLIENT(argv[0]);
- SENDCLIENT(STRING(" :"));
- SENDCLIENT(argv[1]);
- SENDCLIENT(STRING("\r\n"));
- }
- } else if (STRING_EQ(argv[0], STRING("1HC000001"))) {
- SENDCLIENT(STRING(":"));
- if (user) {
- SENDCLIENT(user->nick);
- SENDCLIENT(STRING("!"));
- SENDCLIENT(user->ident);
- SENDCLIENT(STRING("@"));
- SENDCLIENT(user->vhost);
- } else {
- SENDCLIENT(server->address);
- }
- SENDCLIENT(STRING(" NOTICE "));
- SENDCLIENT(argv[0]);
- SENDCLIENT(STRING(" :"));
- SENDCLIENT(argv[1]);
- SENDCLIENT(STRING("\r\n"));
- }
- return 0;
- }
- int initservernetwork(void) {
- server_network_commands.array = malloc(0);
- server_list.array = malloc(0);
- user_list.array = malloc(0);
- channel_list.array = malloc(0);
- set_table_index(&server_network_commands, STRING("PING"), &ping_handler);
- set_table_index(&server_network_commands, STRING("SERVER"), &server_handler);
- set_table_index(&server_network_commands, STRING("UID"), &uid_handler);
- set_table_index(&server_network_commands, STRING("OPERTYPE"), &opertype_handler);
- set_table_index(&server_network_commands, STRING("PRIVMSG"), &privmsg_handler);
- set_table_index(&server_network_commands, STRING("QUIT"), &quit_handler);
- set_table_index(&server_network_commands, STRING("KILL"), &kill_handler);
- set_table_index(&server_network_commands, STRING("NICK"), &nick_handler);
- set_table_index(&server_network_commands, STRING("FJOIN"), &fjoin_handler);
- set_table_index(&server_network_commands, STRING("SQUIT"), &squit_handler);
- set_table_index(&server_network_commands, STRING("PART"), &part_handler);
- set_table_index(&server_network_commands, STRING("NOTICE"), ¬ice_handler);
- init_user_commands();
- int retval = connect_tls();
- if (retval != 0) {
- printf("connect_tls(): %d\n", retval);
- return 1;
- }
- // probably inefficient to be calling SSL_write this frequently, but also less effort
- SEND(STRING("CAPAB START 1202\nCAPAB END\n"));
- SEND(STRING("SERVER "));
- SEND(server_name);
- SEND(STRING(" "));
- SEND(send_password);
- SEND(STRING(" 0 1HC :HaxServ\n"));
- SEND(STRING("BURST "));
- time_t current_time = time(NULL);
- char current_time_str[21]; // C HaxServ will be deprecated long before we reach 20-digit timestamps
- snprintf(current_time_str, 21, "%ld", current_time);
- SEND(NULSTR(current_time_str));
- SEND(STRING("\n"));
- if (add_local_client(STRING("1HC000000"), nick, hostmask, nick, nick, current_time, 0) != 0)
- return 1;
- struct user_info *user_info = get_table_index(user_list, STRING("1HC000000"));
- for (uint64_t i = 0; i < num_prejoin_channels; i++) {
- struct channel_info *channel;
- channel = malloc(sizeof(*channel));
- if (!channel)
- return 1;
- *channel = (struct channel_info){
- .ts = (uint64_t)current_time,
- .topic = {.data = malloc(0), .len = 0},
- .topic_ts = 0,
- .modes = {.array = malloc(0), .len = 0},
- .user_list = {.array = malloc(0), .len = 0},
- .metadata = {.array = malloc(0), .len = 0},
- };
- set_table_index(&channel_list, prejoin_channels[i], channel);
- set_table_index(&(channel->user_list), STRING("1HC000000"), user_info);
- SEND(STRING("FJOIN "));
- SEND(prejoin_channels[i]);
- SEND(STRING(" "));
- SEND(NULSTR(current_time_str));
- SEND(STRING(" + :,1HC000000\nMODE "));
- SEND(prejoin_channels[i]);
- SEND(STRING(" +o 1HC000000\n"));
- }
- SEND(STRING("ENDBURST\n"));
- return 0;
- }
|