5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
7 Copyright (C) 1997 - 2000 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
23 * Revision 1.12 2000/07/26 07:05:11 priikone
24 * Fixed the server to server (server to router actually) connections
25 * and made the private message work inside a cell. Added functin
26 * silc_server_replace_id.
28 * Revision 1.11 2000/07/19 07:08:09 priikone
29 * Added version detection support to SKE.
31 * Revision 1.10 2000/07/17 11:47:30 priikone
32 * Added command lagging support. Added idle counting support.
34 * Revision 1.9 2000/07/12 05:59:41 priikone
35 * Major rewrite of ID Cache system. Support added for the new
36 * ID cache system. Major rewrite of ID List stuff on server. All
37 * SilcXXXList's are now called SilcXXXEntry's and they are pointers
38 * by default. A lot rewritten ID list functions.
40 * Revision 1.8 2000/07/10 05:42:59 priikone
41 * Removed command packet processing from server.c and added it to
43 * Implemented INFO command. Added support for testing that
44 * connections are registered before executing commands.
46 * Revision 1.7 2000/07/07 06:55:24 priikone
47 * Do not allow client to join twice on same channel.
49 * Revision 1.6 2000/07/06 10:20:59 priikone
50 * Cipher name in joining is not mandatory, removed check.
52 * Revision 1.5 2000/07/06 07:16:43 priikone
53 * Fixed a wrong way of sending command replies. The fixed way
54 * does comply with the protocol.
56 * Revision 1.4 2000/07/05 06:13:38 priikone
57 * Added PING, INVITE and NAMES command.
59 * Revision 1.3 2000/07/03 05:52:22 priikone
60 * Implemented LEAVE command.
62 * Revision 1.2 2000/06/28 05:06:38 priikone
63 * Shorter timeout for channel joining notify.
65 * Revision 1.1.1.1 2000/06/27 11:36:56 priikone
66 * Imported from internal CVS/Added Log headers.
71 #include "serverincludes.h"
72 #include "server_internal.h"
74 static int silc_server_is_registered(SilcServer server,
75 SilcSocketConnection sock,
76 SilcServerCommandContext cmd,
79 silc_server_command_send_status_reply(SilcServerCommandContext cmd,
81 SilcCommandStatus status);
83 silc_server_command_send_status_data(SilcServerCommandContext cmd,
85 SilcCommandStatus status,
86 unsigned int arg_type,
88 unsigned int arg_len);
89 static void silc_server_command_free(SilcServerCommandContext cmd);
91 /* Server command list. */
92 SilcServerCommand silc_command_list[] =
94 SILC_SERVER_CMD(whois, WHOIS, SILC_CF_LAG | SILC_CF_REG),
95 SILC_SERVER_CMD(whowas, WHOWAS, SILC_CF_LAG | SILC_CF_REG),
96 SILC_SERVER_CMD(identify, IDENTIFY, SILC_CF_LAG | SILC_CF_REG),
97 SILC_SERVER_CMD(nick, NICK, SILC_CF_LAG | SILC_CF_REG),
98 SILC_SERVER_CMD(list, LIST, SILC_CF_LAG | SILC_CF_REG),
99 SILC_SERVER_CMD(topic, TOPIC, SILC_CF_LAG | SILC_CF_REG),
100 SILC_SERVER_CMD(invite, INVITE, SILC_CF_LAG | SILC_CF_REG),
101 SILC_SERVER_CMD(quit, QUIT, SILC_CF_LAG | SILC_CF_REG),
102 SILC_SERVER_CMD(kill, KILL, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
103 SILC_SERVER_CMD(info, INFO, SILC_CF_LAG | SILC_CF_REG),
104 SILC_SERVER_CMD(connect, CONNECT,
105 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
106 SILC_SERVER_CMD(ping, PING, SILC_CF_LAG | SILC_CF_REG),
107 SILC_SERVER_CMD(oper, OPER, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
108 SILC_SERVER_CMD(join, JOIN, SILC_CF_LAG | SILC_CF_REG),
109 SILC_SERVER_CMD(motd, MOTD, SILC_CF_LAG | SILC_CF_REG),
110 SILC_SERVER_CMD(umode, UMODE, SILC_CF_LAG | SILC_CF_REG),
111 SILC_SERVER_CMD(cmode, CMODE, SILC_CF_LAG | SILC_CF_REG),
112 SILC_SERVER_CMD(kick, KICK, SILC_CF_LAG | SILC_CF_REG),
113 SILC_SERVER_CMD(restart, RESTART,
114 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
115 SILC_SERVER_CMD(close, CLOSE,
116 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
117 SILC_SERVER_CMD(die, DIE, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
118 SILC_SERVER_CMD(silcoper, SILCOPER,
119 SILC_CF_LAG | SILC_CF_REG | SILC_CF_SILC_OPER),
120 SILC_SERVER_CMD(leave, LEAVE, SILC_CF_LAG | SILC_CF_REG),
121 SILC_SERVER_CMD(names, NAMES, SILC_CF_LAG | SILC_CF_REG),
126 /* List of pending commands. */
127 SilcServerCommandPending *silc_command_pending = NULL;
129 /* Returns TRUE if the connection is registered. Unregistered connections
130 usually cannot send commands hence the check. */
132 static int silc_server_is_registered(SilcServer server,
133 SilcSocketConnection sock,
134 SilcServerCommandContext cmd,
138 case SILC_SOCKET_TYPE_CLIENT:
140 SilcClientEntry client = (SilcClientEntry)sock->user_data;
141 if (client->registered)
145 case SILC_SOCKET_TYPE_SERVER:
146 case SILC_SOCKET_TYPE_ROUTER:
148 SilcServerEntry serv = (SilcServerEntry)sock->user_data;
149 if (serv->registered)
157 silc_server_command_send_status_reply(cmd, command,
158 SILC_STATUS_ERR_NOT_REGISTERED);
159 silc_server_command_free(cmd);
163 /* Processes received command packet. */
165 void silc_server_command_process(SilcServer server,
166 SilcSocketConnection sock,
167 SilcPacketContext *packet)
169 SilcServerCommandContext ctx;
170 SilcServerCommand *cmd;
172 /* Check whether it is allowed for this connection to execute any
174 if (sock->type == SILC_SOCKET_TYPE_CLIENT) {
176 SilcClientEntry client = (SilcClientEntry)sock->user_data;
181 /* Allow only one command executed in 2 seconds. */
182 curtime = time(NULL);
183 if (client->last_command && (curtime - client->last_command) < 2)
186 /* Update access time */
187 client->last_command = curtime;
190 /* Allocate command context. This must be free'd by the
191 command routine receiving it. */
192 ctx = silc_calloc(1, sizeof(*ctx));
193 ctx->server = server;
195 ctx->packet = packet; /* Save original packet */
197 /* Parse the command payload in the packet */
198 ctx->payload = silc_command_parse_payload(packet->buffer);
200 SILC_LOG_ERROR(("Bad command payload, packet dropped"));
201 silc_buffer_free(packet->buffer);
206 /* Execute command. If this fails the packet is dropped. */
207 for (cmd = silc_command_list; cmd->cb; cmd++)
208 if (cmd->cmd == silc_command_get(ctx->payload)) {
210 if (!(cmd->flags & SILC_CF_REG)) {
215 if (silc_server_is_registered(server, sock, ctx, cmd->cmd)) {
222 SILC_LOG_ERROR(("Unknown command, packet dropped"));
228 silc_buffer_free(packet->buffer);
231 /* Add new pending command to the list of pending commands. Currently
232 pending commands are executed from command replies, thus we can
233 execute any command after receiving some specific command reply.
235 The argument `reply_cmd' is the command reply from where the callback
236 function is to be called, thus, it IS NOT the command to be executed. */
238 void silc_server_command_pending(SilcCommand reply_cmd,
239 SilcCommandCb callback,
242 SilcServerCommandPending *reply, *r;
244 reply = silc_calloc(1, sizeof(*reply));
245 reply->reply_cmd = reply_cmd;
246 reply->context = context;
247 reply->callback = callback;
249 if (silc_command_pending == NULL) {
250 silc_command_pending = reply;
254 for (r = silc_command_pending; r; r = r->next) {
255 if (r->next == NULL) {
262 /* Deletes pending command by reply command type. */
264 void silc_server_command_pending_del(SilcCommand reply_cmd)
266 SilcServerCommandPending *r, *tmp;
268 if (silc_command_pending) {
269 if (silc_command_pending->reply_cmd == reply_cmd) {
270 silc_free(silc_command_pending);
271 silc_command_pending = NULL;
275 for (r = silc_command_pending; r; r = r->next) {
276 if (r->next && r->next->reply_cmd == reply_cmd) {
278 r->next = r->next->next;
286 /* Free's the command context allocated before executing the command */
288 static void silc_server_command_free(SilcServerCommandContext cmd)
291 silc_command_free_payload(cmd->payload);
296 #define SILC_COMMAND_STATUS_DATA(x) \
299 /* Sends simple status message as command reply packet */
302 silc_server_command_send_status_reply(SilcServerCommandContext cmd,
304 SilcCommandStatus status)
308 SILC_LOG_DEBUG(("Sending command status %d", status));
310 buffer = silc_command_encode_reply_payload_va(command, status, 0);
311 silc_server_packet_send(cmd->server, cmd->sock,
312 SILC_PACKET_COMMAND_REPLY, 0,
313 buffer->data, buffer->len, FALSE);
314 silc_buffer_free(buffer);
317 /* Sends command status reply with one extra argument. The argument
318 type must be sent as argument. */
321 silc_server_command_send_status_data(SilcServerCommandContext cmd,
323 SilcCommandStatus status,
324 unsigned int arg_type,
326 unsigned int arg_len)
330 SILC_LOG_DEBUG(("Sending command status %d", status));
332 buffer = silc_command_encode_reply_payload_va(command, status, 1,
333 arg_type, arg, arg_len);
334 silc_server_packet_send(cmd->server, cmd->sock,
335 SILC_PACKET_COMMAND_REPLY, 0,
336 buffer->data, buffer->len, FALSE);
337 silc_buffer_free(buffer);
340 /* Server side of command WHOIS. Processes user's query and sends found
341 results as command replies back to the client. */
343 SILC_SERVER_CMD_FUNC(whois)
345 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
346 SilcServer server = cmd->server;
347 char *tmp, *nick = NULL, *server_name = NULL;
348 unsigned int argc, count = 0, len;
349 SilcClientEntry entry;
351 unsigned char *id_string;
353 SILC_LOG_DEBUG(("Start"));
355 argc = silc_command_get_arg_num(cmd->payload);
357 silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
358 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
362 silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
363 SILC_STATUS_ERR_TOO_MANY_PARAMS);
367 /* Get the nickname@server string and parse it. */
368 tmp = silc_command_get_first_arg(cmd->payload, NULL);
370 if (strchr(tmp, '@')) {
371 len = strcspn(tmp, "@");
372 nick = silc_calloc(len + 1, sizeof(char));
373 memcpy(nick, tmp, len);
374 server_name = silc_calloc(strlen(tmp) - len, sizeof(char));
375 memcpy(server_name, tmp + len + 1, strlen(tmp) - len - 1);
380 silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
381 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
385 /* Get the max count of reply messages allowed */
387 tmp = silc_command_get_next_arg(cmd->payload, NULL);
389 silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
390 SILC_STATUS_ERR_TOO_MANY_PARAMS);
394 silc_free(server_name);
400 /* Then, make the query from our local client list */
401 entry = silc_idlist_find_client_by_nickname(server->local_list,
405 /* If we are normal server and are connected to a router we will
406 make global query from the router. */
407 if (server->server_type == SILC_SERVER && !server->standalone) {
412 /* If we are router then we will check our global list as well. */
413 if (server->server_type == SILC_ROUTER) {
415 silc_idlist_find_client_by_nickname(server->global_list,
418 silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
419 SILC_STATUS_ERR_NO_SUCH_NICK,
420 3, tmp, strlen(tmp));
426 silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
427 SILC_STATUS_ERR_NO_SUCH_NICK,
428 3, tmp, strlen(tmp));
433 /* XXX, works only for local server info */
435 /* Send WHOIS reply */
436 id_string = silc_id_id2str(entry->id, SILC_ID_CLIENT);
437 tmp = silc_command_get_first_arg(cmd->payload, NULL);
440 if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
441 char nh[256], uh[256];
442 unsigned char idle[4];
443 SilcSocketConnection hsock;
445 memset(uh, 0, sizeof(uh));
446 memset(nh, 0, sizeof(nh));
448 strncat(nh, entry->nickname, strlen(entry->nickname));
450 len = entry->router ? strlen(entry->router->server_name) :
451 strlen(server->server_name);
452 strncat(nh, entry->router ? entry->router->server_name :
453 server->server_name, len);
455 strncat(uh, entry->username, strlen(entry->username));
457 hsock = (SilcSocketConnection)entry->connection;
458 len = hsock->hostname ? strlen(hsock->hostname) : strlen(hsock->ip);
459 strncat(uh, hsock->hostname ? hsock->hostname : hsock->ip, len);
461 SILC_PUT32_MSB((time(NULL) - entry->last_receive), idle);
466 silc_command_encode_reply_payload_va(SILC_COMMAND_WHOIS,
468 2, id_string, SILC_ID_CLIENT_LEN,
472 strlen(entry->userinfo),
476 silc_command_encode_reply_payload_va(SILC_COMMAND_WHOIS,
478 2, id_string, SILC_ID_CLIENT_LEN,
486 silc_command_encode_reply_payload_va(SILC_COMMAND_WHOIS,
488 2, id_string, SILC_ID_CLIENT_LEN,
490 strlen(entry->nickname),
491 4, tmp, strlen(tmp)); /* XXX */
493 silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
494 0, packet->data, packet->len, FALSE);
496 silc_free(id_string);
497 silc_buffer_free(packet);
500 silc_server_command_free(cmd);
503 SILC_SERVER_CMD_FUNC(whowas)
507 SILC_SERVER_CMD_FUNC(identify)
509 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
510 SilcServer server = cmd->server;
511 char *tmp, *nick = NULL, *server_name = NULL;
512 unsigned int argc, count = 0, len;
513 SilcClientEntry entry;
515 unsigned char *id_string;
517 SILC_LOG_DEBUG(("Start"));
519 argc = silc_command_get_arg_num(cmd->payload);
521 silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
522 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
526 silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
527 SILC_STATUS_ERR_TOO_MANY_PARAMS);
531 /* Get the nickname@server string and parse it. */
532 tmp = silc_command_get_first_arg(cmd->payload, NULL);
534 if (strchr(tmp, '@')) {
535 len = strcspn(tmp, "@");
536 nick = silc_calloc(len + 1, sizeof(char));
537 memcpy(nick, tmp, len);
538 server_name = silc_calloc(strlen(tmp) - len, sizeof(char));
539 memcpy(server_name, tmp + len + 1, strlen(tmp) - len - 1);
544 silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
545 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
549 /* Get the max count of reply messages allowed */
551 tmp = silc_command_get_next_arg(cmd->payload, NULL);
553 silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
554 SILC_STATUS_ERR_TOO_MANY_PARAMS);
561 entry = silc_idlist_find_client_by_nickname(server->local_list,
564 entry = silc_idlist_find_client_by_hash(server->global_list,
565 nick, server->md5hash);
567 /* If client was not found and if we are normal server and are connected
568 to a router we will make global query from the router. */
569 if (!entry && server->server_type == SILC_SERVER && !server->standalone &&
571 SilcBuffer buffer = cmd->packet->buffer;
573 SILC_LOG_DEBUG(("Requesting identify from router"));
575 /* Send IDENTIFY command to our router */
576 silc_buffer_push(buffer, buffer->data - buffer->head);
577 silc_server_packet_forward(server, (SilcSocketConnection)
578 server->id_entry->router->connection,
579 buffer->data, buffer->len, TRUE);
583 /* If we are router we have checked our local list by nickname and our
584 global list by hash so far. It is possible that the client is still not
585 found and we'll check it from local list by hash. */
586 if (!entry && server->server_type == SILC_ROUTER)
587 entry = silc_idlist_find_client_by_hash(server->local_list,
588 nick, server->md5hash);
591 /* The client definitely does not exist */
592 silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
593 SILC_STATUS_ERR_NO_SUCH_NICK,
594 3, tmp, strlen(tmp));
598 /* Send IDENTIFY reply */
599 id_string = silc_id_id2str(entry->id, SILC_ID_CLIENT);
600 tmp = silc_command_get_first_arg(cmd->payload, NULL);
601 packet = silc_command_encode_reply_payload_va(SILC_COMMAND_IDENTIFY,
605 3, nick, strlen(nick));
606 if (cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED) {
607 void *id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
608 silc_server_packet_send_dest(server, cmd->sock,
609 SILC_PACKET_COMMAND_REPLY, 0,
610 id, cmd->packet->src_id_type,
611 packet->data, packet->len, FALSE);
614 silc_server_packet_send(server, cmd->sock,
615 SILC_PACKET_COMMAND_REPLY, 0,
616 packet->data, packet->len, FALSE);
619 silc_free(id_string);
620 silc_buffer_free(packet);
626 silc_free(server_name);
627 silc_server_command_free(cmd);
630 /* Checks string for bad characters and returns TRUE if they are found. */
632 static int silc_server_command_bad_chars(char *nick)
634 if (strchr(nick, '\\')) return TRUE;
635 if (strchr(nick, '\"')) return TRUE;
636 if (strchr(nick, '´')) return TRUE;
637 if (strchr(nick, '`')) return TRUE;
638 if (strchr(nick, '\'')) return TRUE;
639 if (strchr(nick, '*')) return TRUE;
640 if (strchr(nick, '/')) return TRUE;
641 if (strchr(nick, '@')) return TRUE;
646 /* Server side of command NICK. Sets nickname for user. Setting
647 nickname causes generation of a new client ID for the client. The
648 new client ID is sent to the client after changing the nickname. */
650 SILC_SERVER_CMD_FUNC(nick)
652 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
653 SilcClientEntry id_entry = (SilcClientEntry)cmd->sock->user_data;
654 SilcServer server = cmd->server;
656 SilcClientID *new_id;
660 SILC_LOG_DEBUG(("Start"));
662 /* Check number of arguments */
663 if (silc_command_get_arg_num(cmd->payload) < 1) {
664 silc_server_command_send_status_reply(cmd, SILC_COMMAND_NICK,
665 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
670 nick = silc_command_get_arg_type(cmd->payload, 1, NULL);
671 if (silc_server_command_bad_chars(nick) == TRUE) {
672 silc_server_command_send_status_reply(cmd, SILC_COMMAND_NICK,
673 SILC_STATUS_ERR_BAD_NICKNAME);
677 /* Create new Client ID */
678 silc_id_create_client_id(cmd->server->id, cmd->server->rng,
679 cmd->server->md5hash, nick,
682 /* Send notify about nickname change to our router. We send the new
683 ID and ask to replace it with the old one. */
684 if (cmd->server->server_type == SILC_SERVER && !cmd->server->standalone)
685 silc_server_send_replace_id(server, server->id_entry->router->connection,
687 SILC_ID_CLIENT, SILC_ID_CLIENT_LEN,
688 new_id, SILC_ID_CLIENT, SILC_ID_CLIENT_LEN);
690 /* If we are router we have to distribute the new Client ID to all
692 if (cmd->server->server_type == SILC_ROUTER && !cmd->server->standalone)
693 silc_server_send_replace_id(server, server->id_entry->router->connection,
695 SILC_ID_CLIENT, SILC_ID_CLIENT_LEN,
696 new_id, SILC_ID_CLIENT, SILC_ID_CLIENT_LEN);
698 /* Remove old cache entry */
699 silc_idcache_del_by_id(server->local_list->clients, SILC_ID_CLIENT,
704 memset(id_entry->id, 0, SILC_ID_CLIENT_LEN);
705 silc_free(id_entry->id);
708 /* Save the nickname as this client is our local client */
709 if (id_entry->nickname)
710 silc_free(id_entry->nickname);
712 id_entry->nickname = strdup(nick);
713 id_entry->id = new_id;
715 /* Update client cache */
716 silc_idcache_add(server->local_list->clients, id_entry->nickname,
717 SILC_ID_CLIENT, id_entry->id, (void *)id_entry, TRUE);
719 /* Send the new Client ID as reply command back to client */
720 id_string = silc_id_id2str(id_entry->id, SILC_ID_CLIENT);
721 packet = silc_command_encode_reply_payload_va(SILC_COMMAND_NICK,
725 silc_server_packet_send(cmd->server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
726 0, packet->data, packet->len, FALSE);
728 silc_free(id_string);
729 silc_buffer_free(packet);
732 silc_server_command_free(cmd);
735 SILC_SERVER_CMD_FUNC(list)
739 SILC_SERVER_CMD_FUNC(topic)
743 /* Server side of INVITE command. Invites some client to join some channel. */
745 SILC_SERVER_CMD_FUNC(invite)
747 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
748 SilcServer server = cmd->server;
749 SilcSocketConnection sock = cmd->sock, dest_sock;
750 SilcClientEntry sender, dest;
751 SilcClientID *dest_id;
752 SilcChannelEntry channel;
753 SilcChannelID *channel_id;
754 unsigned int argc, len;
755 unsigned char *id_string;
757 /* Check number of arguments */
758 argc = silc_command_get_arg_num(cmd->payload);
760 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
761 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
765 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
766 SILC_STATUS_ERR_TOO_MANY_PARAMS);
770 /* Get destination ID */
771 id_string = silc_command_get_arg_type(cmd->payload, 1, &len);
773 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
774 SILC_STATUS_ERR_NO_CLIENT_ID);
777 dest_id = silc_id_str2id(id_string, SILC_ID_CLIENT);
780 id_string = silc_command_get_arg_type(cmd->payload, 2, &len);
782 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
783 SILC_STATUS_ERR_NO_CHANNEL_ID);
786 channel_id = silc_id_str2id(id_string, SILC_ID_CHANNEL);
788 /* Check whether the channel exists */
789 channel = silc_idlist_find_channel_by_id(server->local_list, channel_id);
791 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
792 SILC_STATUS_ERR_NO_SUCH_CHANNEL);
796 /* Check whether the sender of this command is on the channel. */
797 sender = (SilcClientEntry )sock->user_data;
798 if (!silc_server_client_on_channel(sender, channel)) {
799 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
800 SILC_STATUS_ERR_NOT_ON_CHANNEL);
804 /* Check whether the channel is invite-only channel. If yes then the
805 sender of this command must be at least channel operator. */
808 /* Find the connection data for the destination. If it is local we will
809 send it directly otherwise we will send it to router for routing. */
810 dest = silc_idlist_find_client_by_id(server->local_list, dest_id);
812 dest_sock = (SilcSocketConnection)dest->connection;
814 dest_sock = silc_server_get_route(server, dest_id, SILC_ID_CLIENT);
816 /* Check whether the requested client is already on the channel. */
817 /* XXX if we are normal server we don't know about global clients on
818 the channel thus we must request it (NAMES command), check from
819 local cache as well. */
820 if (silc_server_client_on_channel(dest, channel)) {
821 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
822 SILC_STATUS_ERR_USER_ON_CHANNEL);
826 /* Send notify to the client that is invited to the channel */
827 silc_server_send_notify_dest(server, dest_sock, dest_id, SILC_ID_CLIENT,
828 "%s invites you to channel %s",
829 sender->nickname, channel->channel_name);
831 /* Send command reply */
832 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
836 silc_server_command_free(cmd);
839 /* Quits connection to client. This gets called if client won't
840 close the connection even when it has issued QUIT command. */
842 SILC_TASK_CALLBACK(silc_server_command_quit_cb)
844 SilcServer server = (SilcServer)context;
845 SilcSocketConnection sock = server->sockets[fd];
847 /* Free all client specific data, such as client entry and entires
848 on channels this client may be on. */
849 silc_server_free_sock_user_data(server, sock);
851 /* Close the connection on our side */
852 silc_server_close_connection(server, sock);
855 /* Quits SILC session. This is the normal way to disconnect client. */
857 SILC_SERVER_CMD_FUNC(quit)
859 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
860 SilcServer server = cmd->server;
861 SilcSocketConnection sock = cmd->sock;
863 SILC_LOG_DEBUG(("Start"));
865 /* We quit the connection with little timeout */
866 silc_task_register(server->timeout_queue, sock->sock,
867 silc_server_command_quit_cb, server,
868 0, 300000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
870 silc_server_command_free(cmd);
873 SILC_SERVER_CMD_FUNC(kill)
877 /* Server side of command INFO. This sends information about us to
878 the client. If client requested specific server we will send the
879 command to that server. */
881 SILC_SERVER_CMD_FUNC(info)
883 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
884 SilcServer server = cmd->server;
887 unsigned char *id_string;
888 char info_string[256], *dest_server;
890 argc = silc_command_get_arg_num(cmd->payload);
892 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
893 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
897 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
898 SILC_STATUS_ERR_TOO_MANY_PARAMS);
902 /* Get server name */
903 dest_server = silc_command_get_arg_type(cmd->payload, 1, NULL);
905 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
906 SILC_STATUS_ERR_NO_SUCH_SERVER);
910 if (!strncasecmp(dest_server, server->server_name, strlen(dest_server))) {
912 memset(info_string, 0, sizeof(info_string));
913 snprintf(info_string, sizeof(info_string),
914 "location: %s server: %s admin: %s <%s>",
915 server->config->admin_info->location,
916 server->config->admin_info->server_type,
917 server->config->admin_info->admin_name,
918 server->config->admin_info->admin_email);
920 id_string = silc_id_id2str(server->id, SILC_ID_SERVER);
923 silc_command_encode_reply_payload_va(SILC_COMMAND_INFO,
925 2, id_string, SILC_ID_SERVER_LEN,
927 strlen(info_string));
928 silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
929 packet->data, packet->len, FALSE);
931 silc_free(id_string);
932 silc_buffer_free(packet);
934 /* Send this command to the requested server */
936 if (server->server_type == SILC_SERVER && !server->standalone) {
940 if (server->server_type == SILC_ROUTER) {
946 silc_server_command_free(cmd);
949 SILC_SERVER_CMD_FUNC(connect)
953 /* Server side of command PING. This just replies to the ping. */
955 SILC_SERVER_CMD_FUNC(ping)
957 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
958 SilcServer server = cmd->server;
961 unsigned char *id_string;
963 argc = silc_command_get_arg_num(cmd->payload);
965 silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
966 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
970 silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
971 SILC_STATUS_ERR_TOO_MANY_PARAMS);
976 id_string = silc_command_get_arg_type(cmd->payload, 1, NULL);
978 silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
979 SILC_STATUS_ERR_NO_SERVER_ID);
982 id = silc_id_str2id(id_string, SILC_ID_SERVER);
984 if (!SILC_ID_SERVER_COMPARE(id, server->id)) {
986 silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
989 silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
990 SILC_STATUS_ERR_NO_SUCH_SERVER);
997 silc_server_command_free(cmd);
1000 SILC_SERVER_CMD_FUNC(oper)
1009 SilcChannelEntry channel;
1011 } JoinInternalContext;
1013 SILC_TASK_CALLBACK(silc_server_command_join_notify)
1015 JoinInternalContext *ctx = (JoinInternalContext *)context;
1017 if (ctx->channel->key && ctx->channel->key_len) {
1018 silc_server_send_notify_to_channel(ctx->server, ctx->channel,
1019 "%s (%s@%s) has joined channel %s",
1020 ctx->nickname, ctx->username,
1021 ctx->hostname, ctx->channel_name);
1024 silc_task_register(ctx->server->timeout_queue, fd,
1025 silc_server_command_join_notify, context,
1026 0, 300000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
1030 /* Assembles NAMES command and executes it. This is called when client
1031 joins to a channel and we wan't to send NAMES command reply to the
1034 void silc_server_command_send_names(SilcServer server,
1035 SilcSocketConnection sock,
1036 SilcChannelEntry channel)
1038 SilcServerCommandContext cmd;
1040 unsigned char *id_string;
1042 id_string = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
1043 buffer = silc_command_encode_payload_va(SILC_COMMAND_NAMES, 1,
1044 1, id_string, SILC_ID_CHANNEL_LEN);
1046 cmd = silc_calloc(1, sizeof(*cmd));
1047 cmd->payload = silc_command_parse_payload(buffer);
1048 cmd->server = server;
1050 cmd->pending = FALSE;
1052 silc_server_command_names((void *)cmd);
1053 silc_free(id_string);
1057 /* Server side of command JOIN. Joins client into requested channel. If
1058 the channel does not exist it will be created. */
1060 SILC_SERVER_CMD_FUNC(join)
1062 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1063 SilcServer server = cmd->server;
1064 SilcSocketConnection sock = cmd->sock;
1065 SilcBuffer buffer = cmd->packet->buffer;
1066 int argc, i, tmp_len;
1067 char *tmp, *channel_name = NULL, *cipher = NULL, *id_string = NULL;
1068 unsigned char *passphrase, mode[4];
1069 SilcChannelEntry channel;
1070 SilcServerID *router_id;
1072 SilcClientEntry client;
1074 SILC_LOG_DEBUG(("Start"));
1076 /* Check number of parameters */
1077 argc = silc_command_get_arg_num(cmd->payload);
1079 silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
1080 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1084 silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
1085 SILC_STATUS_ERR_TOO_MANY_PARAMS);
1089 /* Get channel name */
1090 tmp = silc_command_get_arg_type(cmd->payload, 1, &tmp_len);
1091 channel_name = silc_calloc(tmp_len + 1, sizeof(*channel_name));
1092 memcpy(channel_name, tmp, tmp_len);
1093 if (silc_server_command_bad_chars(tmp) == TRUE) {
1094 silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
1095 SILC_STATUS_ERR_BAD_CHANNEL);
1096 silc_free(channel_name);
1100 /* Get passphrase */
1101 tmp = silc_command_get_arg_type(cmd->payload, 2, &tmp_len);
1103 passphrase = silc_calloc(tmp_len, sizeof(*passphrase));
1104 memcpy(passphrase, tmp, tmp_len);
1107 /* Get cipher name */
1108 cipher = silc_command_get_arg_type(cmd->payload, 3, NULL);
1110 /* See if the channel exists */
1112 silc_idlist_find_channel_by_name(server->local_list, channel_name);
1114 /* Channel not found */
1116 /* If we are standalone server we don't have a router, we just create
1117 the channel by ourselves. */
1118 if (server->standalone) {
1119 router_id = server->id;
1120 channel = silc_server_new_channel(server, router_id,
1121 cipher, channel_name);
1128 /* No channel ID found, the channel does not exist on our server.
1129 We send JOIN command to our router which will handle the joining
1130 procedure (either creates the channel if it doesn't exist or
1131 joins the client to it) - if we are normal server. */
1132 if (server->server_type == SILC_SERVER) {
1134 /* Forward the original JOIN command to the router */
1135 silc_buffer_push(buffer, buffer->data - buffer->head);
1136 silc_server_packet_forward(server, (SilcSocketConnection)
1137 server->id_entry->router->connection,
1138 buffer->data, buffer->len, TRUE);
1140 /* Add the command to be pending. It will be re-executed after
1141 router has replied back to us. */
1142 cmd->pending = TRUE;
1143 silc_server_command_pending(SILC_COMMAND_JOIN,
1144 silc_server_command_join, context);
1149 /* If we are router and the channel does not exist we will check our
1150 global list for the channel. */
1151 if (!channel && server->server_type == SILC_ROUTER) {
1153 /* Notify all routers about the new channel in SILC network. */
1154 if (!server->standalone) {
1156 silc_server_send_new_id(server, server->id_entry->router->connection,
1158 xxx, SILC_ID_CHANNEL, SILC_ID_CHANNEL_LEN);
1166 /* If the JOIN request was forwarded to us we will make a bit slower
1167 query to get the client pointer. Otherwise, we get the client pointer
1169 if (!(cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED)) {
1170 client = (SilcClientEntry)sock->user_data;
1172 void *id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
1173 client = silc_idlist_find_client_by_id(server->local_list, id);
1181 /* Check whether the client already is on the channel */
1182 if (silc_server_client_on_channel(client, channel)) {
1183 silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
1184 SILC_STATUS_ERR_USER_ON_CHANNEL);
1185 silc_free(channel_name);
1189 /* Join the client to the channel */
1190 i = channel->user_list_count;
1191 channel->user_list = silc_realloc(channel->user_list,
1192 sizeof(*channel->user_list) * (i + 1));
1193 channel->user_list[i].mode = SILC_CHANNEL_UMODE_NONE;
1194 channel->user_list[i].client = client;
1195 channel->user_list_count++;
1197 /* Add the channel to client's channel list */
1198 i = client->channel_count;
1199 client->channel = silc_realloc(client->channel,
1200 sizeof(*client->channel) * (i + 1));
1201 client->channel[i] = channel;
1202 client->channel_count++;
1204 /* Notify router about new user on channel. If we are normal server
1205 we send it to our router, if we are router we send it to our
1207 if (!server->standalone) {
1211 /* Send command reply to the client. Client receives the Channe ID,
1212 channel mode and possibly other information in this reply packet. */
1213 if (!cmd->pending) {
1214 id_string = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
1215 SILC_PUT32_MSB(channel->mode, mode);
1217 if (!channel->topic)
1219 silc_command_encode_reply_payload_va(SILC_COMMAND_JOIN,
1222 strlen(channel_name),
1223 3, id_string, SILC_ID_CHANNEL_LEN,
1227 silc_command_encode_reply_payload_va(SILC_COMMAND_JOIN,
1230 strlen(channel_name),
1231 3, id_string, SILC_ID_CHANNEL_LEN,
1234 strlen(channel->topic));
1236 if (cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED) {
1237 void *id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
1238 silc_server_packet_send_dest(cmd->server, cmd->sock,
1239 SILC_PACKET_COMMAND_REPLY, 0,
1240 id, cmd->packet->src_id_type,
1241 packet->data, packet->len, FALSE);
1244 silc_server_packet_send(server, sock, SILC_PACKET_COMMAND_REPLY, 0,
1245 packet->data, packet->len, FALSE);
1247 silc_buffer_free(packet);
1250 /* Send channel key to the client. Client cannot start transmitting
1251 to the channel until we have sent the key. */
1252 if (!cmd->pending) {
1253 tmp_len = strlen(channel->channel_key->cipher->name);
1255 silc_channel_key_encode_payload(SILC_ID_CHANNEL_LEN,
1257 channel->channel_key->cipher->name,
1258 channel->key_len / 8, channel->key);
1260 silc_server_packet_send(server, sock, SILC_PACKET_CHANNEL_KEY, 0,
1261 packet->data, packet->len, FALSE);
1262 silc_buffer_free(packet);
1266 silc_free(id_string);
1268 /* Finally, send notify message to all clients on the channel about
1269 new user on the channel. */
1270 if (!(cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED)) {
1271 if (!cmd->pending) {
1272 silc_server_send_notify_to_channel(server, channel,
1273 "%s (%s@%s) has joined channel %s",
1274 client->nickname, client->username,
1275 sock->hostname ? sock->hostname :
1276 sock->ip, channel_name);
1278 /* This is pending command request. Send the notify after we have
1279 received the key for the channel from the router. */
1280 JoinInternalContext *ctx = silc_calloc(1, sizeof(*ctx));
1281 ctx->channel_name = channel_name;
1282 ctx->nickname = client->nickname;
1283 ctx->username = client->username;
1284 ctx->hostname = sock->hostname ? sock->hostname : sock->ip;
1285 ctx->channel = channel;
1286 ctx->server = server;
1287 silc_task_register(server->timeout_queue, sock->sock,
1288 silc_server_command_join_notify, ctx,
1289 0, 10000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
1293 /* Send NAMES command reply to the joined channel so the user sees who
1294 is currently on the channel. */
1295 silc_server_command_send_names(server, sock, channel);
1298 silc_server_command_free(cmd);
1301 /* Server side of command MOTD. Sends servers current "message of the
1302 day" to the client. */
1304 SILC_SERVER_CMD_FUNC(motd)
1307 SILC_LOG_DEBUG(("Start"));
1311 SILC_SERVER_CMD_FUNC(umode)
1315 SILC_SERVER_CMD_FUNC(cmode)
1319 SILC_SERVER_CMD_FUNC(kick)
1323 SILC_SERVER_CMD_FUNC(restart)
1327 SILC_SERVER_CMD_FUNC(close)
1331 SILC_SERVER_CMD_FUNC(die)
1335 SILC_SERVER_CMD_FUNC(silcoper)
1339 /* Server side command of LEAVE. Removes client from a channel. */
1341 SILC_SERVER_CMD_FUNC(leave)
1343 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1344 SilcServer server = cmd->server;
1345 SilcSocketConnection sock = cmd->sock;
1346 SilcClientEntry id_entry = (SilcClientEntry)cmd->sock->user_data;
1348 SilcChannelEntry channel;
1350 unsigned int i, argc, key_len;
1351 unsigned char *tmp, channel_key[32];
1353 SILC_LOG_DEBUG(("Start"));
1355 argc = silc_command_get_arg_num(cmd->payload);
1357 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1358 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1362 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1363 SILC_STATUS_ERR_TOO_MANY_PARAMS);
1367 /* Get Channel ID */
1368 tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
1370 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1371 SILC_STATUS_ERR_NO_CHANNEL_ID);
1374 id = silc_id_str2id(tmp, SILC_ID_CHANNEL);
1376 /* Get channel entry */
1377 channel = silc_idlist_find_channel_by_id(server->local_list, id);
1379 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1380 SILC_STATUS_ERR_NO_SUCH_CHANNEL);
1384 /* Check whether this client is on the channel */
1385 if (!silc_server_client_on_channel(id_entry, channel)) {
1386 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1387 SILC_STATUS_ERR_NOT_ON_CHANNEL);
1391 /* Remove client from channel */
1392 i = silc_server_remove_from_one_channel(server, sock, channel, id_entry);
1393 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1396 /* If the channel does not exist anymore we won't send anything */
1400 /* Re-generate channel key */
1401 key_len = channel->key_len / 8;
1402 for (i = 0; i < key_len; i++)
1403 channel_key[i] = silc_rng_get_byte(server->rng);
1404 channel->channel_key->cipher->set_key(channel->channel_key->context,
1405 channel_key, key_len);
1406 memset(channel->key, 0, key_len);
1407 silc_free(channel->key);
1408 channel->key = silc_calloc(key_len, sizeof(*channel->key));
1409 memcpy(channel->key, channel_key, key_len);
1410 memset(channel_key, 0, sizeof(channel_key));
1412 /* Encode channel key payload to be distributed on the channel */
1414 silc_channel_key_encode_payload(SILC_ID_CHANNEL_LEN, tmp,
1415 strlen(channel->channel_key->cipher->name),
1416 channel->channel_key->cipher->name,
1417 key_len, channel->key);
1419 /* If we are normal server then we will send it to our router. If we
1420 are router we will send it to all local servers that has clients on
1422 if (server->server_type == SILC_SERVER) {
1423 if (!server->standalone)
1424 silc_server_packet_send(server,
1425 cmd->server->id_entry->router->connection,
1426 SILC_PACKET_CHANNEL_KEY, 0, packet->data,
1432 /* Send to locally connected clients on the channel */
1433 silc_server_packet_send_local_channel(server, channel,
1434 SILC_PACKET_CHANNEL_KEY, 0,
1435 packet->data, packet->len, FALSE);
1437 silc_buffer_free(packet);
1441 silc_server_command_free(cmd);
1444 /* Server side of command NAMES. Resolves clients and their names currently
1445 joined on the requested channel. The name list is sent back to the
1448 SILC_SERVER_CMD_FUNC(names)
1450 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1451 SilcServer server = cmd->server;
1452 SilcChannelEntry channel;
1455 unsigned int i, len, len2, argc;
1457 char *name_list = NULL, *n;
1458 SilcBuffer client_id_list;
1460 SILC_LOG_DEBUG(("Start"));
1462 argc = silc_command_get_arg_num(cmd->payload);
1464 silc_server_command_send_status_reply(cmd, SILC_COMMAND_NAMES,
1465 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1469 silc_server_command_send_status_reply(cmd, SILC_COMMAND_NAMES,
1470 SILC_STATUS_ERR_TOO_MANY_PARAMS);
1474 /* Get Channel ID */
1475 tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
1477 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1478 SILC_STATUS_ERR_NO_CHANNEL_ID);
1481 id = silc_id_str2id(tmp, SILC_ID_CHANNEL);
1483 /* Check whether the channel exists. If we are normal server and the
1484 channel does not exist we will send this same command to our router
1485 which will know if the channel exists. */
1486 channel = silc_idlist_find_channel_by_id(server->local_list, id);
1488 if (server->server_type == SILC_SERVER && !server->standalone) {
1489 /* XXX Send names command */
1491 cmd->pending = TRUE;
1492 silc_server_command_pending(SILC_COMMAND_NAMES,
1493 silc_server_command_names, context);
1497 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
1498 SILC_STATUS_ERR_NO_SUCH_CHANNEL);
1502 /* Assemble the name list now */
1505 for (i = 0; i < channel->user_list_count; i++) {
1506 if (!channel->user_list[i].client)
1509 n = channel->user_list[i].client->nickname;
1513 name_list = silc_realloc(name_list, sizeof(*name_list) * (len + 1));
1514 memcpy(name_list + (len - len2), n, len2);
1517 if (i == channel->user_list_count - 1)
1519 memcpy(name_list + len, ",", 1);
1524 /* Assemble the Client ID list now */
1525 client_id_list = silc_buffer_alloc(SILC_ID_CLIENT_LEN *
1526 channel->user_list_count);
1527 silc_buffer_pull_tail(client_id_list, (SILC_ID_CLIENT_LEN *
1528 channel->user_list_count));
1529 for (i = 0; i < channel->user_list_count; i++) {
1530 unsigned char *id_string;
1532 if (!channel->user_list[i].client)
1535 id_string = silc_id_id2str(channel->user_list[i].client->id,
1537 silc_buffer_format(client_id_list,
1538 SILC_STR_UI_XNSTRING(id_string, SILC_ID_CLIENT_LEN),
1540 silc_buffer_pull(client_id_list, SILC_ID_CLIENT_LEN);
1541 silc_free(id_string);
1543 silc_buffer_push(client_id_list,
1544 client_id_list->data - client_id_list->head);
1547 packet = silc_command_encode_reply_payload_va(SILC_COMMAND_NAMES,
1549 2, tmp, SILC_ID_CHANNEL_LEN,
1552 4, client_id_list->data,
1553 client_id_list->len);
1554 silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
1555 packet->data, packet->len, FALSE);
1557 silc_buffer_free(packet);
1558 silc_free(name_list);
1559 silc_buffer_free(client_id_list);
1563 silc_server_command_free(cmd);