free bugs [fixed]
[coupserv.git] / server_network.c
blob10b2023b66e3cfa006672c7926ca06d567445979
1 // Server network command handlers for HaxServ
2 //
3 // Written by: Test_User <hax@andrewyu.org>
4 //
5 // This is free and unencumbered software released into the public
6 // domain.
7 //
8 // Anyone is free to copy, modify, publish, use, compile, sell, or
9 // distribute this software, either in source code form or as a compiled
10 // binary, for any purpose, commercial or non-commercial, and by any
11 // means.
13 // In jurisdictions that recognize copyright laws, the author or authors
14 // of this software dedicate any and all copyright interest in the
15 // software to the public domain. We make this dedication for the benefit
16 // of the public at large and to the detriment of our heirs and
17 // successors. We intend this dedication to be an overt act of
18 // relinquishment in perpetuity of all present and future rights to this
19 // software under copyright law.
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
24 // IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
25 // OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
26 // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27 // OTHER DEALINGS IN THE SOFTWARE.
29 #include <gnutls/gnutls.h>
30 #include <netdb.h>
31 #include <arpa/inet.h>
32 #include <sys/types.h>
33 #include <netinet/in.h>
34 #include <sys/socket.h>
35 #include <string.h>
36 #include <stdlib.h>
37 #include <stdio.h>
39 #include "network.h"
40 #include "types.h"
41 #include "table.h"
42 #include "tls.h"
43 #include "config.h"
44 #include "utils.h"
45 #include "commands.h"
47 pthread_mutex_t send_lock = PTHREAD_MUTEX_INITIALIZER;
49 int resolve(char *address, char *port, struct sockaddr *sockaddr) {
50 int success;
51 struct addrinfo hints = {0}, *info;
53 hints.ai_family = AF_INET;
54 hints.ai_socktype = SOCK_STREAM;
55 hints.ai_protocol = IPPROTO_TCP;
56 hints.ai_flags = AI_NUMERICSERV | AI_ADDRCONFIG;
58 success = getaddrinfo(address, port, &hints, &info);
60 if (success == 0) {
61 *sockaddr = *(info->ai_addr);
62 freeaddrinfo(info);
65 return success;
68 struct table server_network_commands = {0};
69 struct table server_list = {0};
70 struct table user_list = {0};
71 struct table channel_list = {0};
73 int ping_handler(struct string sender, uint64_t argc, struct string *argv) {
74 if (argc < 2) {
75 puts("Invalid PING recieved! (Missing parameters)");
76 return 1;
79 uint64_t len = 1 + argv[1].len + 6 + argv[1].len + 1 + sender.len + 1;
80 char msg[len];
81 uint64_t offset = 0;
82 msg[0] = ':';
83 offset++;
84 memcpy(msg+offset, argv[1].data, argv[1].len);
85 offset += argv[1].len;
86 memcpy(msg+offset, " PONG ", 6);
87 offset += 6;
88 memcpy(msg+offset, argv[1].data, argv[1].len);
89 offset += argv[1].len;
90 msg[offset] = ' ';
91 offset++;
92 memcpy(msg+offset, sender.data, sender.len);
93 offset += sender.len;
94 msg[offset] = '\n';
96 SEND(((struct string){msg, len}));
98 return 0;
101 int server_handler(struct string sender, uint64_t argc, struct string *argv) {
102 if (argc < 5) {
103 puts("Invalid SERVER recieved! (Missing parameters)");
104 return 1;
107 if (argv[2].len > 20) {
108 puts("Invalid SERVER recieved! (Distance too large)");
109 return 1;
112 char err;
113 uint64_t distance = str_to_unsigned(argv[2], &err);
114 if (err) {
115 puts("Invalid SERVER recieved! (Invalid distance given)");
116 return 1;
119 if (sender.len != 0) {
120 struct server_info *from = get_table_index(server_list, sender);
121 if (!from) {
122 puts("Invalid SERVER recieved! (Unknown source)");
123 return 1;
126 distance += from->distance + 1;
129 if (get_table_index(server_list, argv[3]) != 0) {
130 WRITES(2, STRING("Invalid SERVER recieved! (Duplicate SID already connected)\n"));
131 return 1;
134 struct string address;
135 address.data = malloc(argv[0].len);
136 if (address.data == 0)
137 goto server_handler_oom;
139 address.len = argv[0].len;
140 memcpy(address.data, argv[0].data, argv[0].len);
142 struct string name;
143 name.data = malloc(argv[4].len);
144 if (name.data == 0)
145 goto server_handler_free_address;
147 name.len = argv[4].len;
148 memcpy(name.data, argv[4].data, argv[4].len);
150 struct server_info *server = malloc(sizeof(*server));
151 if (server == 0)
152 goto server_handler_free_name;
154 struct string via;
155 if (sender.len != 0) { // connected to the sender
156 via.data = malloc(sender.len);
157 if (!via.data)
158 goto server_handler_free_server;
160 via.len = sender.len;
161 memcpy(via.data, sender.data, sender.len);
162 } else { // connected directly to us
163 via = (struct string){0};
166 *server = (struct server_info){
167 .name = name,
168 .address = address,
169 .distance = distance,
170 .via = via,
173 if (set_table_index(&server_list, argv[3], server) != 0)
174 goto server_handler_free_via;
176 return 0;
178 server_handler_free_via:
179 if (sender.len != 0)
180 free(via.data);
181 server_handler_free_server:
182 free(server);
183 server_handler_free_name:
184 free(name.data);
185 server_handler_free_address:
186 free(address.data);
187 server_handler_oom:
188 puts("OOM! (server_handler)");
190 return 1;
193 int uid_handler(struct string sender, uint64_t argc, struct string *argv) {
194 if (argc < 10) {
195 puts("Invalid UID recieved! (Missing parameters)");
196 return 1;
199 if (argv[1].len > 20 || argv[7].len > 20) {
200 puts("Invalid UID recieved! (Timestamp too long)");
201 return 1;
204 if (sender.len == 0) {
205 puts("Invalid UID recieved! (No source)");
206 return 1;
209 if (get_table_index(user_list, argv[0])) {
210 WRITES(2, STRING("Invalid UID revieved! (Attempted to create already-existing user)\n"));
211 return 1;
214 // TODO: modes
216 char err;
217 uint64_t nick_ts = str_to_unsigned(argv[1], &err);
218 if (err) {
219 puts("Invalid UID recieved! (Invalid nick timestamp)");
220 return 1;
223 uint64_t user_ts = str_to_unsigned(argv[7], &err);
224 if (err) {
225 puts("Invalid UID recieved! (Invalid user timestamp)");
226 return 1;
229 struct string server;
230 server.data = malloc(sender.len);
231 if (!server.data)
232 goto uid_handler_oom;
233 server.len = sender.len;
234 memcpy(server.data, sender.data, sender.len);
236 struct string nick;
237 nick.data = malloc(argv[2].len);
238 if (!nick.data)
239 goto uid_handler_free_server;
240 nick.len = argv[2].len;
241 memcpy(nick.data, argv[2].data, argv[2].len);
243 struct string hostname;
244 hostname.data = malloc(argv[3].len);
245 if (!hostname.data)
246 goto uid_handler_free_nick;
247 hostname.len = argv[3].len;
248 memcpy(hostname.data, argv[3].data, argv[3].len);
250 struct string vhost;
251 vhost.data = malloc(argv[4].len);
252 if (!vhost.data)
253 goto uid_handler_free_hostname;
254 vhost.len = argv[4].len;
255 memcpy(vhost.data, argv[4].data, argv[4].len);
257 struct string ident;
258 ident.data = malloc(argv[5].len);
259 if (!ident.data)
260 goto uid_handler_free_vhost;
261 ident.len = argv[5].len;
262 memcpy(ident.data, argv[5].data, argv[5].len);
264 struct string ip;
265 ip.data = malloc(argv[6].len);
266 if (!ip.data)
267 goto uid_handler_free_ident;
268 ip.len = argv[6].len;
269 memcpy(ip.data, argv[6].data, argv[6].len);
271 struct string realname;
272 realname.data = malloc(argv[argc - 1].len);
273 if (!realname.data)
274 goto uid_handler_free_ip;
275 realname.len = argv[argc - 1].len;
276 memcpy(realname.data, argv[argc - 1].data, argv[argc - 1].len);
278 struct user_info *user = malloc(sizeof(*user));
279 if (!user)
280 goto uid_handler_free_realname;
282 *user = (struct user_info){
283 .nick_ts = nick_ts,
284 .user_ts = user_ts,
285 .server = server,
286 .nick = nick,
287 .hostname = hostname,
288 .vhost = vhost,
289 .ident = ident,
290 .ip = ip,
291 .realname = realname,
292 .opertype = {.data = malloc(0), .len = 0},
293 .metadata = {.array = malloc(0), .len = 0},
296 if (set_table_index(&user_list, argv[0], user) != 0)
297 goto uid_handler_free_user;
299 return 0;
301 uid_handler_free_user:
302 free(user);
303 uid_handler_free_realname:
304 free(realname.data);
305 uid_handler_free_ip:
306 free(ip.data);
307 uid_handler_free_ident:
308 free(ident.data);
309 uid_handler_free_vhost:
310 free(vhost.data);
311 uid_handler_free_hostname:
312 free(hostname.data);
313 uid_handler_free_nick:
314 free(nick.data);
315 uid_handler_free_server:
316 free(server.data);
317 uid_handler_oom:
318 puts("OOM! (uid_handler)");
320 return 1;
323 int opertype_handler(struct string sender, uint64_t argc, struct string *argv) {
324 if (argc < 1) {
325 WRITES(2, STRING("Invalid OPERTYPE recieved! (Missing parameters)\n"));
326 return 1;
329 if (sender.len == 0) {
330 WRITES(2, STRING("Invalid OPERTYPE recieved! (No source)\n"));
331 return 1;
334 struct user_info *user = get_table_index(user_list, sender);
335 if (!user) {
336 WRITES(2, STRING("Server "));
337 WRITES(2, sender);
338 WRITES(2, STRING(" attempted to set OPERTYPE on a nonexistent user!\n"));
339 return 1;
342 struct string opertype = {.data = malloc(argv[0].len), .len = argv[0].len};
343 if (!opertype.data) {
344 WRITES(2, STRING("OOM! (opertype_handler)\n"));
345 return 1;
347 memcpy(opertype.data, argv[0].data, argv[0].len);
349 free(user->opertype.data);
351 user->opertype = opertype;
353 return 0;
356 int quit_handler(struct string sender, uint64_t argc, struct string *argv) {
357 if (argc < 1)
358 return remove_user(sender, (struct string){0});
359 else
360 return remove_user(sender, argv[0]);
363 int kill_handler(struct string sender, uint64_t argc, struct string *argv) {
364 if (argc < 2) {
365 WRITES(2, STRING("Invalid KILL recieved! (Missing parameters)\n"));
366 return 1;
369 // TODO: Get accurate list of what got killed, what to rejoin, etc
371 struct user_info *user = get_table_index(user_list, argv[0]);
372 if (!user)
373 return 0; // TODO: Currently not all local users are considered; fix that, then make this give an error
375 if (STRING_EQ(user->server, STRING("1HC"))) {
376 SEND(STRING(":"));
377 SEND(argv[0]);
378 SEND(STRING(" QUIT :"));
379 SEND(argv[1]);
380 SEND(STRING("\n"));
382 SEND(STRING("GLOADMODULE m_servprotect\n")); // required for the +k we're about to use
384 char user_time[21];
385 snprintf(user_time, 21, "%ld", user->user_ts);
386 char nick_time[21];
387 snprintf(nick_time, 21, "%ld", user->nick_ts);
388 SEND(STRING("UID "));
389 SEND(argv[0]);
390 SEND(STRING(" "));
391 SEND(NULSTR(user_time));
392 SEND(STRING(" "));
393 SEND(user->nick);
394 SEND(STRING(" "));
395 SEND(user->hostname);
396 SEND(STRING(" "));
397 SEND(user->vhost);
398 SEND(STRING(" "));
399 SEND(user->ident);
400 SEND(STRING(" "));
401 SEND(user->ip);
402 SEND(STRING(" "));
403 SEND(NULSTR(nick_time));
404 SEND(STRING(" +k :"));
405 SEND(user->realname);
406 SEND(STRING("\n"));
407 if (STRING_EQ(argv[0], STRING("1HC000001"))) {
408 SEND(STRING(":1HC METADATA 1HC000001 ssl_cert :vTrse "));
409 SEND(client_cert);
410 SEND(STRING("\n:"));
411 SEND(argv[0]);
412 SEND(STRING(" OPERTYPE "));
413 SEND(opertype);
414 SEND(STRING("\n"));
417 for (uint64_t i = 0; i < channel_list.len; i++) {
418 struct channel_info *channel = channel_list.array[i].ptr;
419 if (has_table_index(channel->user_list, argv[0])) {
420 char timestamp[21];
421 SEND(STRING("FJOIN "));
422 SEND(channel_list.array[i].name);
423 SEND(STRING(" "));
424 snprintf(timestamp, 21, "%ld", channel->ts);
425 SEND(NULSTR(timestamp));
426 SEND(STRING(" + :,"));
427 SEND(argv[0]);
428 SEND(STRING("\n"));
431 } else {
432 return remove_user(argv[0], argv[1]);
435 return 0;
438 int nick_handler(struct string sender, uint64_t argc, struct string *argv) {
439 if (argc < 2) {
440 WRITES(2, STRING("Invalid NICK recieved! (Missing parameters)\n"));
441 return 1;
444 struct user_info *info = get_table_index(user_list, sender);
445 if (!info) {
446 WRITES(2, STRING("NICK: Unknown user!\n"));
447 return 1;
450 for (uint64_t i = 0; i < channel_list.len; i++) { // TODO: More efficient way of doing this
451 struct channel_info *channel = channel_list.array[i].ptr;
452 if (has_table_index(channel->user_list, sender) && has_table_index(channel->user_list, STRING("1HC000001"))) {
453 SENDCLIENT(STRING(":"));
454 SENDCLIENT(info->nick);
455 SENDCLIENT(STRING("!"));
456 SENDCLIENT(info->ident);
457 SENDCLIENT(STRING("@"));
458 SENDCLIENT(info->vhost);
459 SENDCLIENT(STRING(" NICK :"));
460 SENDCLIENT(argv[0]);
461 SENDCLIENT(STRING("\r\n"));
463 break;
467 void *tmp = malloc(argv[0].len);
468 if (!tmp) {
469 WRITES(2, STRING("OOM! (nick_handler)\n"));
470 return 1;
472 memcpy(tmp, argv[0].data, argv[0].len);
474 free(info->nick.data);
475 info->nick.data = tmp;
476 info->nick.len = argv[0].len;
478 if (argv[1].len > 20) {
479 WRITES(2, STRING("Invalid NICK recieved! (Timestamp too long)\n"));
480 return 1;
483 char err;
484 uint64_t ts = str_to_unsigned(argv[1], &err);
485 if (err) {
486 WRITES(2, STRING("Invalid NICK recieved! (Invalid timestamp)\n"));
487 return 1;
489 info->nick_ts = ts;
491 return 0;
494 int fjoin_handler(struct string sender, uint64_t argc, struct string *argv) {
495 if (argc < 4) {
496 WRITES(2, STRING("Invalid FJOIN recieved! (Missing parameters"));
497 return 1;
500 char err;
501 uint64_t timestamp = str_to_unsigned(argv[1], &err);
502 if (err) {
503 WRITES(2, STRING("Invalid FJOIN recieved! (Invalid timestamp given)\n"));
504 return 1;
507 // TODO: Parse modes, then make the rest of this work
508 uint64_t userlist_offset = 3;
510 char dir = '?';
511 for (uint64_t offset = 0; offset < argv[2].len; offset++) {
512 if (argv[2].data[offset] == '+') {
513 dir = '+';
514 } else if (argv[2].data[offset] == '-') {
515 dir = '-';
516 } else if (dir == '?') {
517 WRITES(2, STRING("Invalid FJOIN recieved! (No direction set for modes)\n"));
518 return 1;
519 } else if (channel_mode_types[(unsigned char)argv[2].data[offset]] == MODE_TYPE_UNKNOWN) {
520 WRITES(2, STRING("Invalid FJOIN recieved! (Unknown mode set on the channel)\n"));
521 return 1;
522 } else if (channel_mode_types[(unsigned char)argv[2].data[offset]] != MODE_TYPE_NOARGS && dir == '+') {
523 userlist_offset++;
528 if (argc < userlist_offset + 1) {
529 WRITES(2, STRING("Invalid FJOIN recieved! (Missing mode parameters or user list)\n"));
530 return 1;
533 struct channel_info *channel = get_table_index(channel_list, argv[0]);
534 if (!channel) {
535 channel = malloc(sizeof(*channel));
536 if (!channel) {
537 WRITES(2, STRING("OOM! (fjoin_handler)\n"));
538 return 1;
540 *channel = (struct channel_info){
541 .ts = timestamp,
542 .topic = {.data = malloc(0), .len = 0},
543 .topic_ts = 0,
544 .modes = {.array = malloc(0), .len = 0},
545 .user_list = {.array = malloc(0), .len = 0},
546 .metadata = {.array = malloc(0), .len = 0},
549 set_table_index(&channel_list, argv[0], channel);
551 if (timestamp < channel->ts)
552 channel->ts = timestamp;
554 struct string userlist = argv[userlist_offset];
556 if (userlist.len < 10) // Not enough for any users
557 return 0;
559 uint8_t sendclient = has_table_index(channel->user_list, STRING("1HC000001"));
561 uint64_t offset = 0;
562 while (1) {
563 while (offset < userlist.len && userlist.data[offset] != ',')
564 offset++;
566 if (offset > (userlist.len - 1) - 9)
567 break;
569 offset++;
571 struct string user = {.data = &(userlist.data[offset]), .len = 9};
572 struct user_info *user_info = get_table_index(user_list, user);
574 set_table_index(&(channel->user_list), user, user_info);
576 if (user_info && sendclient) {
577 SENDCLIENT(STRING(":"));
578 SENDCLIENT(user_info->nick);
579 SENDCLIENT(STRING("!"));
580 SENDCLIENT(user_info->ident);
581 SENDCLIENT(STRING("@"));
582 SENDCLIENT(user_info->vhost);
583 SENDCLIENT(STRING(" JOIN :"));
584 SENDCLIENT(argv[0]);
585 SENDCLIENT(STRING("\r\n"));
588 offset += 10;
591 return 0;
594 int squit_handler(struct string sender, uint64_t argc, struct string *argv) {
595 if (argc < 1) {
596 WRITES(2, STRING("Invalid SQUIT recieved! (Missing parameters)\n"));
597 return 1;
600 struct server_info *server = remove_table_index(&server_list, argv[0]);
601 if (!server) {
602 WRITES(2, STRING("Invalid SQUIT received! (Unknown server)\n"));
603 WRITES(2, STRING("Known servers:\r\n"));
604 for (uint64_t i = 0; i < server_list.len; i++) {
605 WRITES(2, server_list.array[i].name);
606 WRITES(2, STRING("\r\n"));
608 return 1;
611 for (uint64_t i = 0; i < user_list.len;) {
612 struct user_info *info = user_list.array[i].ptr;
613 if (STRING_EQ(info->server, argv[0])) {
614 remove_user(user_list.array[i].name, STRING("*.net *.split"));
615 } else {
616 i++; // removal of the user from the table shifts the next user into place for us
620 free(server->name.data);
621 free(server->address.data);
622 if (server->via.data != 0)
623 free(server->via.data);
624 free(server);
626 return 0;
629 int privmsg_handler(struct string sender, uint64_t argc, struct string *argv) {
630 if (argc < 2) {
631 WRITES(2, STRING("Invalid PRIVMSG recieved (Missing parameters)\n"));
632 return 1;
635 if (sender.len == 0) {
636 WRITES(2, STRING("Invalid PRIVMSG recieved (No source)\n"));
637 return 1;
640 struct user_info *user = get_table_index(user_list, sender);
641 struct server_info *server;
642 if (user) {
643 server = 0;
644 if (argv[0].data[0] == '#') {
645 struct channel_info *channel = get_table_index(channel_list, argv[0]);
646 if (channel && has_table_index(channel->user_list, STRING("1HC000001"))) {
647 SENDCLIENT(STRING(":"));
648 SENDCLIENT(user->nick);
649 SENDCLIENT(STRING("!"));
650 SENDCLIENT(user->ident);
651 SENDCLIENT(STRING("@"));
652 SENDCLIENT(user->vhost);
653 SENDCLIENT(STRING(" PRIVMSG "));
654 SENDCLIENT(argv[0]);
655 SENDCLIENT(STRING(" :"));
656 SENDCLIENT(argv[1]);
657 SENDCLIENT(STRING("\r\n"));
659 } else if (STRING_EQ(argv[0], STRING("1HC000001"))) {
660 SENDCLIENT(STRING(":"));
661 SENDCLIENT(user->nick);
662 SENDCLIENT(STRING("!"));
663 SENDCLIENT(user->ident);
664 SENDCLIENT(STRING("@"));
665 SENDCLIENT(user->vhost);
666 SENDCLIENT(STRING(" PRIVMSG "));
667 SENDCLIENT(client_nick);
668 SENDCLIENT(STRING(" :"));
669 SENDCLIENT(argv[1]);
670 SENDCLIENT(STRING("\r\n"));
672 } else {
673 server = get_table_index(server_list, sender);
674 if (server) {
675 if (argv[0].data[0] == '#') {
676 struct channel_info *channel = get_table_index(channel_list, argv[0]);
677 if (channel && has_table_index(channel->user_list, STRING("1HC000001"))) {
678 SENDCLIENT(STRING(":"));
679 SENDCLIENT(server->address);
680 SENDCLIENT(STRING(" PRIVMSG "));
681 SENDCLIENT(argv[0]);
682 SENDCLIENT(STRING(" :"));
683 SENDCLIENT(argv[1]);
684 SENDCLIENT(STRING("\r\n"));
686 } else if (STRING_EQ(argv[0], STRING("1HC000001"))) {
687 SENDCLIENT(STRING(":"));
688 SENDCLIENT(server->address);
689 SENDCLIENT(STRING(" PRIVMSG "));
690 SENDCLIENT(client_nick);
691 SENDCLIENT(STRING(" :"));
692 SENDCLIENT(argv[1]);
693 SENDCLIENT(STRING("\r\n"));
698 uint64_t offset;
699 if (argv[0].data[0] == '#') {
700 if (argv[1].len < command_prefix.len || memcmp(argv[1].data, command_prefix.data, command_prefix.len) != 0)
701 return 0;
703 struct channel_info *channel_info = get_table_index(channel_list, argv[0]);
704 if (!channel_info)
705 return 0;
707 if (!has_table_index(channel_info->user_list, STRING("1HC000000")))
708 return 0;
710 offset = command_prefix.len;
711 } else if (STRING_EQ(argv[0], STRING("1HC000000"))) {
712 offset = 0;
713 } else {
714 return 0;
717 if (offset >= argv[1].len || argv[1].data[offset] == ' ')
718 return 0;
720 uint64_t command_argc = 0;
721 uint64_t old_offset = offset;
722 while (offset < argv[1].len) {
723 while (offset < argv[1].len && argv[1].data[offset] != ' ')
724 offset++;
726 command_argc++;
728 while (offset < argv[1].len && argv[1].data[offset] == ' ')
729 offset++;
731 offset = old_offset;
733 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
734 uint64_t i = 0;
735 while (offset < argv[1].len) {
736 command_argv[i].data = argv[1].data+offset;
737 uint64_t start = offset;
739 while (offset < argv[1].len && argv[1].data[offset] != ' ')
740 offset++;
742 command_argv[i].len = offset - start;
744 while (offset < argv[1].len && argv[1].data[offset] == ' ')
745 offset++;
747 i++;
750 argv[1].data += old_offset;
751 argv[1].len -= old_offset;
752 struct command_def *cmd = get_table_index(user_commands, command_argv[0]);
753 if (cmd) {
754 if (!cmd->local_only) {
755 if (cmd->privs.len != 0 && sender.len != 3) { // servers always count as oper :P
756 if (!user) {
757 WRITES(2, STRING("User is unknown!\n"));
759 SEND(STRING(":1HC000000 NOTICE "));
760 if (argv[0].data[0] == '#')
761 SEND(argv[0]);
762 else
763 SEND(sender);
764 SEND(STRING(" :You don't seem to exist... and neither do I!\n"));
766 return 1; // have already desynced
769 if (user->opertype.len != cmd->privs.len || memcmp(user->opertype.data, cmd->privs.data, cmd->privs.len)) {
770 // TODO: complain about missing privs
771 SEND(STRING(":1HC000000 NOTICE "));
772 if (argv[0].data[0] == '#')
773 SEND(argv[0]);
774 else
775 SEND(sender);
776 SEND(STRING(" :You are not authorized to execute this command.\n"));
778 return 0;
782 struct string message[] = {
783 user ? STRING("User ") : (server ? STRING("Server ") : STRING("An unknown user (something desycned... this shouldn't happen)")),
784 user ? user->nick : (server ? server->address : STRING("")),
785 STRING(" executes `"),
786 argv[1],
787 STRING("'"),
790 privmsg(STRING("1HC000000"), log_channel, sizeof(message)/sizeof(*message), message);
792 return cmd->func(sender, argv[1], argv[0].data[0] == '#' ? argv[0] : sender, command_argc, command_argv, 0);
793 } else {
794 SEND(STRING(":1HC000000 NOTICE "));
795 if (argv[0].data[0] == '#')
796 SEND(argv[0]);
797 else
798 SEND(sender);
799 SEND(STRING(" :You are not authorized to execute this command.\n"));
801 WRITES(1, STRING("Not executing local-only command from a remote source!\n"));
802 return 0;
804 } else {
805 SEND(STRING(":1HC000000 NOTICE "));
806 if (argv[0].data[0] == '#')
807 SEND(argv[0]);
808 else
809 SEND(sender);
810 SEND(STRING(" :Unknown command: "));
811 if (argv[0].data[0] == '#')
812 SEND(command_prefix);
813 SEND(command_argv[0]);
814 SEND(STRING("\n"));
815 return 0;
819 int part_handler(struct string sender, uint64_t argc, struct string *argv) {
820 if (argc < 1) {
821 WRITES(2, STRING("Invalid PART received! (Missing parameters)\n"));
822 return 1;
825 struct channel_info *channel = get_table_index(channel_list, argv[0]);
826 struct user_info *user = get_table_index(user_list, sender);
827 if (user && channel && has_table_index(channel->user_list, STRING("1HC000001"))) {
828 SENDCLIENT(STRING(":"));
829 SENDCLIENT(user->nick);
830 SENDCLIENT(STRING("!"));
831 SENDCLIENT(user->ident);
832 SENDCLIENT(STRING("@"));
833 SENDCLIENT(user->vhost);
834 SENDCLIENT(STRING(" PART "));
835 SENDCLIENT(argv[0]);
836 if (argc >= 2) {
837 SENDCLIENT(STRING(" :"));
838 SENDCLIENT(argv[1]);
840 SENDCLIENT(STRING("\r\n"));
843 if (channel)
844 remove_table_index(&(channel->user_list), sender);
846 return 0;
849 int notice_handler(struct string sender, uint64_t argc, struct string *argv) {
850 if (argc < 2) {
851 WRITES(2, STRING("Invalid NOTICE received! (Missing parameters)\n"));
852 return 1;
855 struct user_info *user = get_table_index(user_list, sender);
856 struct server_info *server;
857 if (user)
858 server = 0;
859 else
860 server = get_table_index(server_list, sender);
862 if (!user && !server) {
863 WRITES(2, STRING("Invalid NOTICE received! (Unknown source)\n"));
864 return 1;
867 if (argv[0].data[0] == '#') {
868 struct channel_info *channel = get_table_index(channel_list, argv[0]);
869 if (channel && has_table_index(channel->user_list, STRING("1HC000001"))) {
870 SENDCLIENT(STRING(":"));
871 if (user) {
872 SENDCLIENT(user->nick);
873 SENDCLIENT(STRING("!"));
874 SENDCLIENT(user->ident);
875 SENDCLIENT(STRING("@"));
876 SENDCLIENT(user->vhost);
877 } else {
878 SENDCLIENT(server->address);
881 SENDCLIENT(STRING(" NOTICE "));
882 SENDCLIENT(argv[0]);
883 SENDCLIENT(STRING(" :"));
884 SENDCLIENT(argv[1]);
885 SENDCLIENT(STRING("\r\n"));
887 } else if (STRING_EQ(argv[0], STRING("1HC000001"))) {
888 SENDCLIENT(STRING(":"));
889 if (user) {
890 SENDCLIENT(user->nick);
891 SENDCLIENT(STRING("!"));
892 SENDCLIENT(user->ident);
893 SENDCLIENT(STRING("@"));
894 SENDCLIENT(user->vhost);
895 } else {
896 SENDCLIENT(server->address);
899 SENDCLIENT(STRING(" NOTICE "));
900 SENDCLIENT(argv[0]);
901 SENDCLIENT(STRING(" :"));
902 SENDCLIENT(argv[1]);
903 SENDCLIENT(STRING("\r\n"));
906 return 0;
909 int initservernetwork(void) {
910 server_network_commands.array = malloc(0);
911 server_list.array = malloc(0);
912 user_list.array = malloc(0);
913 channel_list.array = malloc(0);
915 set_table_index(&server_network_commands, STRING("PING"), &ping_handler);
916 set_table_index(&server_network_commands, STRING("SERVER"), &server_handler);
917 set_table_index(&server_network_commands, STRING("UID"), &uid_handler);
918 set_table_index(&server_network_commands, STRING("OPERTYPE"), &opertype_handler);
919 set_table_index(&server_network_commands, STRING("PRIVMSG"), &privmsg_handler);
920 set_table_index(&server_network_commands, STRING("QUIT"), &quit_handler);
921 set_table_index(&server_network_commands, STRING("KILL"), &kill_handler);
922 set_table_index(&server_network_commands, STRING("NICK"), &nick_handler);
923 set_table_index(&server_network_commands, STRING("FJOIN"), &fjoin_handler);
924 set_table_index(&server_network_commands, STRING("SQUIT"), &squit_handler);
925 set_table_index(&server_network_commands, STRING("PART"), &part_handler);
926 set_table_index(&server_network_commands, STRING("NOTICE"), &notice_handler);
928 init_user_commands();
930 int retval = connect_tls();
931 if (retval != 0) {
932 printf("connect_tls(): %d\n", retval);
933 return 1;
936 // probably inefficient to be calling SSL_write this frequently, but also less effort
937 SEND(STRING("CAPAB START 1202\nCAPAB END\n"));
938 SEND(STRING("SERVER "));
939 SEND(server_name);
940 SEND(STRING(" "));
941 SEND(send_password);
942 SEND(STRING(" 0 1HC :HaxServ\n"));
943 SEND(STRING("BURST "));
944 time_t current_time = time(NULL);
945 char current_time_str[21]; // C HaxServ will be deprecated long before we reach 20-digit timestamps
946 snprintf(current_time_str, 21, "%ld", current_time);
947 SEND(NULSTR(current_time_str));
948 SEND(STRING("\n"));
949 if (add_local_client(STRING("1HC000000"), nick, hostmask, nick, nick, current_time, 0) != 0)
950 return 1;
952 struct user_info *user_info = get_table_index(user_list, STRING("1HC000000"));
954 for (uint64_t i = 0; i < num_prejoin_channels; i++) {
955 struct channel_info *channel;
956 channel = malloc(sizeof(*channel));
957 if (!channel)
958 return 1;
959 *channel = (struct channel_info){
960 .ts = (uint64_t)current_time,
961 .topic = {.data = malloc(0), .len = 0},
962 .topic_ts = 0,
963 .modes = {.array = malloc(0), .len = 0},
964 .user_list = {.array = malloc(0), .len = 0},
965 .metadata = {.array = malloc(0), .len = 0},
967 set_table_index(&channel_list, prejoin_channels[i], channel);
968 set_table_index(&(channel->user_list), STRING("1HC000000"), user_info);
969 SEND(STRING("FJOIN "));
970 SEND(prejoin_channels[i]);
971 SEND(STRING(" "));
972 SEND(NULSTR(current_time_str));
973 SEND(STRING(" + :,1HC000000\nMODE "));
974 SEND(prejoin_channels[i]);
975 SEND(STRING(" +o 1HC000000\n"));
978 SEND(STRING("ENDBURST\n"));
980 return 0;