1 // Server network command handlers for HaxServ
3 // Written by: Test_User <hax@andrewyu.org>
5 // This is free and unencumbered software released into the public
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
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>
31 #include <arpa/inet.h>
32 #include <sys/types.h>
33 #include <netinet/in.h>
34 #include <sys/socket.h>
47 pthread_mutex_t send_lock
= PTHREAD_MUTEX_INITIALIZER
;
49 int resolve(char *address
, char *port
, struct sockaddr
*sockaddr
) {
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
);
61 *sockaddr
= *(info
->ai_addr
);
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
) {
75 puts("Invalid PING recieved! (Missing parameters)");
79 uint64_t len
= 1 + argv
[1].len
+ 6 + argv
[1].len
+ 1 + sender
.len
+ 1;
84 memcpy(msg
+offset
, argv
[1].data
, argv
[1].len
);
85 offset
+= argv
[1].len
;
86 memcpy(msg
+offset
, " PONG ", 6);
88 memcpy(msg
+offset
, argv
[1].data
, argv
[1].len
);
89 offset
+= argv
[1].len
;
92 memcpy(msg
+offset
, sender
.data
, sender
.len
);
96 SEND(((struct string
){msg
, len
}));
101 int server_handler(struct string sender
, uint64_t argc
, struct string
*argv
) {
103 puts("Invalid SERVER recieved! (Missing parameters)");
107 if (argv
[2].len
> 20) {
108 puts("Invalid SERVER recieved! (Distance too large)");
113 uint64_t distance
= str_to_unsigned(argv
[2], &err
);
115 puts("Invalid SERVER recieved! (Invalid distance given)");
119 if (sender
.len
!= 0) {
120 struct server_info
*from
= get_table_index(server_list
, sender
);
122 puts("Invalid SERVER recieved! (Unknown source)");
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"));
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
);
143 name
.data
= malloc(argv
[4].len
);
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
));
152 goto server_handler_free_name
;
155 if (sender
.len
!= 0) { // connected to the sender
156 via
.data
= malloc(sender
.len
);
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
){
169 .distance
= distance
,
173 if (set_table_index(&server_list
, argv
[3], server
) != 0)
174 goto server_handler_free_via
;
178 server_handler_free_via
:
181 server_handler_free_server
:
183 server_handler_free_name
:
185 server_handler_free_address
:
188 puts("OOM! (server_handler)");
193 int uid_handler(struct string sender
, uint64_t argc
, struct string
*argv
) {
195 puts("Invalid UID recieved! (Missing parameters)");
199 if (argv
[1].len
> 20 || argv
[7].len
> 20) {
200 puts("Invalid UID recieved! (Timestamp too long)");
204 if (sender
.len
== 0) {
205 puts("Invalid UID recieved! (No source)");
209 if (get_table_index(user_list
, argv
[0])) {
210 WRITES(2, STRING("Invalid UID revieved! (Attempted to create already-existing user)\n"));
217 uint64_t nick_ts
= str_to_unsigned(argv
[1], &err
);
219 puts("Invalid UID recieved! (Invalid nick timestamp)");
223 uint64_t user_ts
= str_to_unsigned(argv
[7], &err
);
225 puts("Invalid UID recieved! (Invalid user timestamp)");
229 struct string server
;
230 server
.data
= malloc(sender
.len
);
232 goto uid_handler_oom
;
233 server
.len
= sender
.len
;
234 memcpy(server
.data
, sender
.data
, sender
.len
);
237 nick
.data
= malloc(argv
[2].len
);
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
);
246 goto uid_handler_free_nick
;
247 hostname
.len
= argv
[3].len
;
248 memcpy(hostname
.data
, argv
[3].data
, argv
[3].len
);
251 vhost
.data
= malloc(argv
[4].len
);
253 goto uid_handler_free_hostname
;
254 vhost
.len
= argv
[4].len
;
255 memcpy(vhost
.data
, argv
[4].data
, argv
[4].len
);
258 ident
.data
= malloc(argv
[5].len
);
260 goto uid_handler_free_vhost
;
261 ident
.len
= argv
[5].len
;
262 memcpy(ident
.data
, argv
[5].data
, argv
[5].len
);
265 ip
.data
= malloc(argv
[6].len
);
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
);
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
));
280 goto uid_handler_free_realname
;
282 *user
= (struct user_info
){
287 .hostname
= hostname
,
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
;
301 uid_handler_free_user
:
303 uid_handler_free_realname
:
307 uid_handler_free_ident
:
309 uid_handler_free_vhost
:
311 uid_handler_free_hostname
:
313 uid_handler_free_nick
:
315 uid_handler_free_server
:
318 puts("OOM! (uid_handler)");
323 int opertype_handler(struct string sender
, uint64_t argc
, struct string
*argv
) {
325 WRITES(2, STRING("Invalid OPERTYPE recieved! (Missing parameters)\n"));
329 if (sender
.len
== 0) {
330 WRITES(2, STRING("Invalid OPERTYPE recieved! (No source)\n"));
334 struct user_info
*user
= get_table_index(user_list
, sender
);
336 WRITES(2, STRING("Server "));
338 WRITES(2, STRING(" attempted to set OPERTYPE on a nonexistent user!\n"));
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"));
347 memcpy(opertype
.data
, argv
[0].data
, argv
[0].len
);
349 free(user
->opertype
.data
);
351 user
->opertype
= opertype
;
356 int quit_handler(struct string sender
, uint64_t argc
, struct string
*argv
) {
358 return remove_user(sender
, (struct string
){0});
360 return remove_user(sender
, argv
[0]);
363 int kill_handler(struct string sender
, uint64_t argc
, struct string
*argv
) {
365 WRITES(2, STRING("Invalid KILL recieved! (Missing parameters)\n"));
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]);
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"))) {
378 SEND(STRING(" QUIT :"));
382 SEND(STRING("GLOADMODULE m_servprotect\n")); // required for the +k we're about to use
385 snprintf(user_time
, 21, "%ld", user
->user_ts
);
387 snprintf(nick_time
, 21, "%ld", user
->nick_ts
);
388 SEND(STRING("UID "));
391 SEND(NULSTR(user_time
));
395 SEND(user
->hostname
);
403 SEND(NULSTR(nick_time
));
404 SEND(STRING(" +k :"));
405 SEND(user
->realname
);
407 if (STRING_EQ(argv
[0], STRING("1HC000001"))) {
408 SEND(STRING(":1HC METADATA 1HC000001 ssl_cert :vTrse "));
412 SEND(STRING(" OPERTYPE "));
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])) {
421 SEND(STRING("FJOIN "));
422 SEND(channel_list
.array
[i
].name
);
424 snprintf(timestamp
, 21, "%ld", channel
->ts
);
425 SEND(NULSTR(timestamp
));
426 SEND(STRING(" + :,"));
432 return remove_user(argv
[0], argv
[1]);
438 int nick_handler(struct string sender
, uint64_t argc
, struct string
*argv
) {
440 WRITES(2, STRING("Invalid NICK recieved! (Missing parameters)\n"));
444 struct user_info
*info
= get_table_index(user_list
, sender
);
446 WRITES(2, STRING("NICK: Unknown user!\n"));
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 :"));
461 SENDCLIENT(STRING("\r\n"));
467 void *tmp
= malloc(argv
[0].len
);
469 WRITES(2, STRING("OOM! (nick_handler)\n"));
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"));
484 uint64_t ts
= str_to_unsigned(argv
[1], &err
);
486 WRITES(2, STRING("Invalid NICK recieved! (Invalid timestamp)\n"));
494 int fjoin_handler(struct string sender
, uint64_t argc
, struct string
*argv
) {
496 WRITES(2, STRING("Invalid FJOIN recieved! (Missing parameters"));
501 uint64_t timestamp
= str_to_unsigned(argv
[1], &err
);
503 WRITES(2, STRING("Invalid FJOIN recieved! (Invalid timestamp given)\n"));
507 // TODO: Parse modes, then make the rest of this work
508 uint64_t userlist_offset
= 3;
511 for (uint64_t offset
= 0; offset
< argv
[2].len
; offset
++) {
512 if (argv
[2].data
[offset
] == '+') {
514 } else if (argv
[2].data
[offset
] == '-') {
516 } else if (dir
== '?') {
517 WRITES(2, STRING("Invalid FJOIN recieved! (No direction set for modes)\n"));
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"));
522 } else if (channel_mode_types
[(unsigned char)argv
[2].data
[offset
]] != MODE_TYPE_NOARGS
&& dir
== '+') {
528 if (argc
< userlist_offset
+ 1) {
529 WRITES(2, STRING("Invalid FJOIN recieved! (Missing mode parameters or user list)\n"));
533 struct channel_info
*channel
= get_table_index(channel_list
, argv
[0]);
535 channel
= malloc(sizeof(*channel
));
537 WRITES(2, STRING("OOM! (fjoin_handler)\n"));
540 *channel
= (struct channel_info
){
542 .topic
= {.data
= malloc(0), .len
= 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
559 uint8_t sendclient
= has_table_index(channel
->user_list
, STRING("1HC000001"));
563 while (offset
< userlist
.len
&& userlist
.data
[offset
] != ',')
566 if (offset
> (userlist
.len
- 1) - 9)
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 :"));
585 SENDCLIENT(STRING("\r\n"));
594 int squit_handler(struct string sender
, uint64_t argc
, struct string
*argv
) {
596 WRITES(2, STRING("Invalid SQUIT recieved! (Missing parameters)\n"));
600 struct server_info
*server
= remove_table_index(&server_list
, argv
[0]);
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"));
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"));
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
);
629 int privmsg_handler(struct string sender
, uint64_t argc
, struct string
*argv
) {
631 WRITES(2, STRING("Invalid PRIVMSG recieved (Missing parameters)\n"));
635 if (sender
.len
== 0) {
636 WRITES(2, STRING("Invalid PRIVMSG recieved (No source)\n"));
640 struct user_info
*user
= get_table_index(user_list
, sender
);
641 struct server_info
*server
;
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 "));
655 SENDCLIENT(STRING(" :"));
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(" :"));
670 SENDCLIENT(STRING("\r\n"));
673 server
= get_table_index(server_list
, sender
);
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 "));
682 SENDCLIENT(STRING(" :"));
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(" :"));
693 SENDCLIENT(STRING("\r\n"));
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)
703 struct channel_info
*channel_info
= get_table_index(channel_list
, argv
[0]);
707 if (!has_table_index(channel_info
->user_list
, STRING("1HC000000")))
710 offset
= command_prefix
.len
;
711 } else if (STRING_EQ(argv
[0], STRING("1HC000000"))) {
717 if (offset
>= argv
[1].len
|| argv
[1].data
[offset
] == ' ')
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
] != ' ')
728 while (offset
< argv
[1].len
&& argv
[1].data
[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
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
] != ' ')
742 command_argv
[i
].len
= offset
- start
;
744 while (offset
< argv
[1].len
&& argv
[1].data
[offset
] == ' ')
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]);
754 if (!cmd
->local_only
) {
755 if (cmd
->privs
.len
!= 0 && sender
.len
!= 3) { // servers always count as oper :P
757 WRITES(2, STRING("User is unknown!\n"));
759 SEND(STRING(":1HC000000 NOTICE "));
760 if (argv
[0].data
[0] == '#')
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] == '#')
776 SEND(STRING(" :You are not authorized to execute this command.\n"));
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 `"),
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);
794 SEND(STRING(":1HC000000 NOTICE "));
795 if (argv
[0].data
[0] == '#')
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"));
805 SEND(STRING(":1HC000000 NOTICE "));
806 if (argv
[0].data
[0] == '#')
810 SEND(STRING(" :Unknown command: "));
811 if (argv
[0].data
[0] == '#')
812 SEND(command_prefix
);
813 SEND(command_argv
[0]);
819 int part_handler(struct string sender
, uint64_t argc
, struct string
*argv
) {
821 WRITES(2, STRING("Invalid PART received! (Missing parameters)\n"));
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 "));
837 SENDCLIENT(STRING(" :"));
840 SENDCLIENT(STRING("\r\n"));
844 remove_table_index(&(channel
->user_list
), sender
);
849 int notice_handler(struct string sender
, uint64_t argc
, struct string
*argv
) {
851 WRITES(2, STRING("Invalid NOTICE received! (Missing parameters)\n"));
855 struct user_info
*user
= get_table_index(user_list
, sender
);
856 struct server_info
*server
;
860 server
= get_table_index(server_list
, sender
);
862 if (!user
&& !server
) {
863 WRITES(2, STRING("Invalid NOTICE received! (Unknown source)\n"));
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(":"));
872 SENDCLIENT(user
->nick
);
873 SENDCLIENT(STRING("!"));
874 SENDCLIENT(user
->ident
);
875 SENDCLIENT(STRING("@"));
876 SENDCLIENT(user
->vhost
);
878 SENDCLIENT(server
->address
);
881 SENDCLIENT(STRING(" NOTICE "));
883 SENDCLIENT(STRING(" :"));
885 SENDCLIENT(STRING("\r\n"));
887 } else if (STRING_EQ(argv
[0], STRING("1HC000001"))) {
888 SENDCLIENT(STRING(":"));
890 SENDCLIENT(user
->nick
);
891 SENDCLIENT(STRING("!"));
892 SENDCLIENT(user
->ident
);
893 SENDCLIENT(STRING("@"));
894 SENDCLIENT(user
->vhost
);
896 SENDCLIENT(server
->address
);
899 SENDCLIENT(STRING(" NOTICE "));
901 SENDCLIENT(STRING(" :"));
903 SENDCLIENT(STRING("\r\n"));
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"), ¬ice_handler
);
928 init_user_commands();
930 int retval
= connect_tls();
932 printf("connect_tls(): %d\n", retval
);
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 "));
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
));
949 if (add_local_client(STRING("1HC000000"), nick
, hostmask
, nick
, nick
, current_time
, 0) != 0)
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
));
959 *channel
= (struct channel_info
){
960 .ts
= (uint64_t)current_time
,
961 .topic
= {.data
= malloc(0), .len
= 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
]);
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"));