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.9 2000/07/12 05:59:41 priikone
24 * Major rewrite of ID Cache system. Support added for the new
25 * ID cache system. Major rewrite of ID List stuff on server. All
26 * SilcXXXList's are now called SilcXXXEntry's and they are pointers
27 * by default. A lot rewritten ID list functions.
29 * Revision 1.8 2000/07/10 05:42:59 priikone
30 * Removed command packet processing from server.c and added it to
32 * Implemented INFO command. Added support for testing that
33 * connections are registered before executing commands.
35 * Revision 1.7 2000/07/07 06:55:24 priikone
36 * Do not allow client to join twice on same channel.
38 * Revision 1.6 2000/07/06 10:20:59 priikone
39 * Cipher name in joining is not mandatory, removed check.
41 * Revision 1.5 2000/07/06 07:16:43 priikone
42 * Fixed a wrong way of sending command replies. The fixed way
43 * does comply with the protocol.
45 * Revision 1.4 2000/07/05 06:13:38 priikone
46 * Added PING, INVITE and NAMES command.
48 * Revision 1.3 2000/07/03 05:52:22 priikone
49 * Implemented LEAVE command.
51 * Revision 1.2 2000/06/28 05:06:38 priikone
52 * Shorter timeout for channel joining notify.
54 * Revision 1.1.1.1 2000/06/27 11:36:56 priikone
55 * Imported from internal CVS/Added Log headers.
60 #include "serverincludes.h"
61 #include "server_internal.h"
63 static int silc_server_is_registered(SilcServer server,
64 SilcSocketConnection sock,
65 SilcServerCommandContext cmd,
68 silc_server_command_send_status_reply(SilcServerCommandContext cmd,
70 SilcCommandStatus status);
72 silc_server_command_send_status_data(SilcServerCommandContext cmd,
74 SilcCommandStatus status,
75 unsigned int arg_type,
77 unsigned int arg_len);
78 static void silc_server_command_free(SilcServerCommandContext cmd);
80 /* Server command list. */
81 SilcServerCommand silc_command_list[] =
83 SILC_SERVER_CMD(whois, WHOIS, SILC_CF_LAG | SILC_CF_REG),
84 SILC_SERVER_CMD(whowas, WHOWAS, SILC_CF_LAG | SILC_CF_REG),
85 SILC_SERVER_CMD(identify, IDENTIFY, SILC_CF_LAG | SILC_CF_REG),
86 SILC_SERVER_CMD(nick, NICK, SILC_CF_LAG | SILC_CF_REG),
87 SILC_SERVER_CMD(list, LIST, SILC_CF_LAG | SILC_CF_REG),
88 SILC_SERVER_CMD(topic, TOPIC, SILC_CF_LAG | SILC_CF_REG),
89 SILC_SERVER_CMD(invite, INVITE, SILC_CF_LAG | SILC_CF_REG),
90 SILC_SERVER_CMD(quit, QUIT, SILC_CF_LAG | SILC_CF_REG),
91 SILC_SERVER_CMD(kill, KILL, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
92 SILC_SERVER_CMD(info, INFO, SILC_CF_LAG | SILC_CF_REG),
93 SILC_SERVER_CMD(connect, CONNECT,
94 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
95 SILC_SERVER_CMD(ping, PING, SILC_CF_LAG | SILC_CF_REG),
96 SILC_SERVER_CMD(oper, OPER, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
97 SILC_SERVER_CMD(join, JOIN, SILC_CF_LAG | SILC_CF_REG),
98 SILC_SERVER_CMD(motd, MOTD, SILC_CF_LAG | SILC_CF_REG),
99 SILC_SERVER_CMD(umode, UMODE, SILC_CF_LAG | SILC_CF_REG),
100 SILC_SERVER_CMD(cmode, CMODE, SILC_CF_LAG | SILC_CF_REG),
101 SILC_SERVER_CMD(kick, KICK, SILC_CF_LAG | SILC_CF_REG),
102 SILC_SERVER_CMD(restart, RESTART,
103 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
104 SILC_SERVER_CMD(close, CLOSE,
105 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
106 SILC_SERVER_CMD(die, DIE, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
107 SILC_SERVER_CMD(silcoper, SILCOPER,
108 SILC_CF_LAG | SILC_CF_REG | SILC_CF_SILC_OPER),
109 SILC_SERVER_CMD(leave, LEAVE, SILC_CF_LAG | SILC_CF_REG),
110 SILC_SERVER_CMD(names, NAMES, SILC_CF_LAG | SILC_CF_REG),
115 /* List of pending commands. */
116 SilcServerCommandPending *silc_command_pending = NULL;
118 /* Returns TRUE if the connection is registered. Unregistered connections
119 usually cannot send commands hence the check. */
121 static int silc_server_is_registered(SilcServer server,
122 SilcSocketConnection sock,
123 SilcServerCommandContext cmd,
127 case SILC_SOCKET_TYPE_CLIENT:
129 SilcClientEntry client = (SilcClientEntry)sock->user_data;
130 if (client->registered)
134 case SILC_SOCKET_TYPE_SERVER:
135 case SILC_SOCKET_TYPE_ROUTER:
137 SilcServerEntry serv = (SilcServerEntry)sock->user_data;
138 if (serv->registered)
146 silc_server_command_send_status_reply(cmd, command,
147 SILC_STATUS_ERR_NOT_REGISTERED);
148 silc_server_command_free(cmd);
152 /* Processes received command packet. */
154 void silc_server_command_process(SilcServer server,
155 SilcSocketConnection sock,
156 SilcPacketContext *packet)
158 SilcServerCommandContext ctx;
159 SilcServerCommand *cmd;
161 /* Allocate command context. This must be free'd by the
162 command routine receiving it. */
163 ctx = silc_calloc(1, sizeof(*ctx));
164 ctx->server = server;
166 ctx->packet = packet; /* Save original packet */
168 /* Parse the command payload in the packet */
169 ctx->payload = silc_command_parse_payload(packet->buffer);
171 SILC_LOG_ERROR(("Bad command payload, packet dropped"));
172 silc_buffer_free(packet->buffer);
177 /* Execute command. If this fails the packet is dropped. */
178 for (cmd = silc_command_list; cmd->cb; cmd++)
179 if (cmd->cmd == silc_command_get(ctx->payload)) {
181 if (!(cmd->flags & SILC_CF_REG)) {
186 if (silc_server_is_registered(server, sock, ctx, cmd->cmd)) {
193 SILC_LOG_ERROR(("Unknown command, packet dropped"));
198 silc_buffer_free(packet->buffer);
201 /* Add new pending command to the list of pending commands. Currently
202 pending commands are executed from command replies, thus we can
203 execute any command after receiving some specific command reply.
205 The argument `reply_cmd' is the command reply from where the callback
206 function is to be called, thus, it IS NOT the command to be executed. */
208 void silc_server_command_pending(SilcCommand reply_cmd,
209 SilcCommandCb callback,
212 SilcServerCommandPending *reply, *r;
214 reply = silc_calloc(1, sizeof(*reply));
215 reply->reply_cmd = reply_cmd;
216 reply->context = context;
217 reply->callback = callback;
219 if (silc_command_pending == NULL) {
220 silc_command_pending = reply;
224 for (r = silc_command_pending; r; r = r->next) {
225 if (r->next == NULL) {
232 /* Deletes pending command by reply command type. */
234 void silc_server_command_pending_del(SilcCommand reply_cmd)
236 SilcServerCommandPending *r, *tmp;
238 if (silc_command_pending) {
239 if (silc_command_pending->reply_cmd == reply_cmd) {
240 silc_free(silc_command_pending);
241 silc_command_pending = NULL;
245 for (r = silc_command_pending; r; r = r->next) {
246 if (r->next && r->next->reply_cmd == reply_cmd) {
248 r->next = r->next->next;
256 /* Free's the command context allocated before executing the command */
258 static void silc_server_command_free(SilcServerCommandContext cmd)
261 silc_command_free_payload(cmd->payload);
266 #define SILC_COMMAND_STATUS_DATA(x) \
269 /* Sends simple status message as command reply packet */
272 silc_server_command_send_status_reply(SilcServerCommandContext cmd,
274 SilcCommandStatus status)
278 SILC_LOG_DEBUG(("Sending command status %d", status));
280 buffer = silc_command_encode_reply_payload_va(command, status, 0);
281 silc_server_packet_send(cmd->server, cmd->sock,
282 SILC_PACKET_COMMAND_REPLY, 0,
283 buffer->data, buffer->len, FALSE);
284 silc_buffer_free(buffer);
287 /* Sends command status reply with one extra argument. The argument
288 type must be sent as argument. */
291 silc_server_command_send_status_data(SilcServerCommandContext cmd,
293 SilcCommandStatus status,
294 unsigned int arg_type,
296 unsigned int arg_len)
300 SILC_LOG_DEBUG(("Sending command status %d", status));
302 buffer = silc_command_encode_reply_payload_va(command, status, 1,
303 arg_type, arg, arg_len);
304 silc_server_packet_send(cmd->server, cmd->sock,
305 SILC_PACKET_COMMAND_REPLY, 0,
306 buffer->data, buffer->len, FALSE);
307 silc_buffer_free(buffer);
310 /* Server side of command WHOIS. Processes user's query and sends found
311 results as command replies back to the client. */
313 SILC_SERVER_CMD_FUNC(whois)
315 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
316 SilcServer server = cmd->server;
317 char *tmp, *nick = NULL, *server_name = NULL;
318 unsigned int argc, count = 0, len;
319 SilcClientEntry entry;
321 unsigned char *id_string;
323 SILC_LOG_DEBUG(("Start"));
325 argc = silc_command_get_arg_num(cmd->payload);
327 silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
328 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
332 silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
333 SILC_STATUS_ERR_TOO_MANY_PARAMS);
337 /* Get the nickname@server string and parse it. */
338 tmp = silc_command_get_first_arg(cmd->payload, NULL);
340 if (strchr(tmp, '@')) {
341 len = strcspn(tmp, "@");
342 nick = silc_calloc(len + 1, sizeof(char));
343 memcpy(nick, tmp, len);
344 server_name = silc_calloc(strlen(tmp) - len, sizeof(char));
345 memcpy(server_name, tmp + len + 1, strlen(tmp) - len - 1);
350 silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
351 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
355 /* Get the max count of reply messages allowed */
357 tmp = silc_command_get_next_arg(cmd->payload, NULL);
359 silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
360 SILC_STATUS_ERR_TOO_MANY_PARAMS);
364 silc_free(server_name);
370 /* Then, make the query from our local client list */
371 entry = silc_idlist_find_client_by_nickname(server->local_list,
375 /* If we are normal server and are connected to a router we will
376 make global query from the router. */
377 if (server->server_type == SILC_SERVER && !server->standalone) {
382 /* If we are router then we will check our global list as well. */
383 if (server->server_type == SILC_ROUTER) {
385 silc_idlist_find_client_by_nickname(server->global_list,
388 silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
389 SILC_STATUS_ERR_NO_SUCH_NICK,
390 3, tmp, strlen(tmp));
396 silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
397 SILC_STATUS_ERR_NO_SUCH_NICK,
398 3, tmp, strlen(tmp));
403 /* XXX, works only for local server info */
405 /* Send WHOIS reply */
406 id_string = silc_id_id2str(entry->id, SILC_ID_CLIENT);
407 tmp = silc_command_get_first_arg(cmd->payload, NULL);
410 if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
411 char nh[256], uh[256];
412 SilcSocketConnection hsock;
414 memset(uh, 0, sizeof(uh));
415 memset(nh, 0, sizeof(nh));
417 strncat(nh, entry->nickname, strlen(entry->nickname));
419 len = entry->router ? strlen(entry->router->server_name) :
420 strlen(server->server_name);
421 strncat(nh, entry->router ? entry->router->server_name :
422 server->server_name, len);
424 strncat(uh, entry->username, strlen(entry->username));
426 hsock = (SilcSocketConnection)entry->connection;
427 len = hsock->hostname ? strlen(hsock->hostname) : strlen(hsock->ip);
428 strncat(uh, hsock->hostname ? hsock->hostname : hsock->ip, len);
433 silc_command_encode_reply_payload_va(SILC_COMMAND_WHOIS,
435 2, id_string, SILC_ID_CLIENT_LEN,
439 strlen(entry->userinfo));
442 silc_command_encode_reply_payload_va(SILC_COMMAND_WHOIS,
444 2, id_string, SILC_ID_CLIENT_LEN,
451 silc_command_encode_reply_payload_va(SILC_COMMAND_WHOIS,
453 2, id_string, SILC_ID_CLIENT_LEN,
455 strlen(entry->nickname),
456 4, tmp, strlen(tmp)); /* XXX */
458 silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
459 0, packet->data, packet->len, FALSE);
461 silc_free(id_string);
462 silc_buffer_free(packet);
465 silc_server_command_free(cmd);
468 SILC_SERVER_CMD_FUNC(whowas)
472 SILC_SERVER_CMD_FUNC(identify)
474 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
475 SilcServer server = cmd->server;
476 char *tmp, *nick = NULL, *server_name = NULL;
477 unsigned int argc, count = 0, len;
478 SilcClientEntry entry;
480 unsigned char *id_string;
482 SILC_LOG_DEBUG(("Start"));
484 argc = silc_command_get_arg_num(cmd->payload);
486 silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
487 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
491 silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
492 SILC_STATUS_ERR_TOO_MANY_PARAMS);
496 /* Get the nickname@server string and parse it. */
497 tmp = silc_command_get_first_arg(cmd->payload, NULL);
499 if (strchr(tmp, '@')) {
500 len = strcspn(tmp, "@");
501 nick = silc_calloc(len + 1, sizeof(char));
502 memcpy(nick, tmp, len);
503 server_name = silc_calloc(strlen(tmp) - len, sizeof(char));
504 memcpy(server_name, tmp + len + 1, strlen(tmp) - len - 1);
509 silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
510 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
514 /* Get the max count of reply messages allowed */
516 tmp = silc_command_get_next_arg(cmd->payload, NULL);
518 silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
519 SILC_STATUS_ERR_TOO_MANY_PARAMS);
525 /* Then, make the query from our local client list */
526 entry = silc_idlist_find_client_by_nickname(server->local_list,
530 /* If we are normal server and are connected to a router we will
531 make global query from the router. */
532 if (server->server_type == SILC_SERVER && !server->standalone) {
533 SilcBuffer buffer = cmd->packet->buffer;
535 SILC_LOG_DEBUG(("Requesting identify from router"));
537 /* Send IDENTIFY command to our router */
538 silc_buffer_push(buffer, buffer->data - buffer->head);
539 silc_server_packet_forward(server, (SilcSocketConnection)
540 server->id_entry->router->connection,
541 buffer->data, buffer->len, TRUE);
545 /* If we are router then we will check our global list as well. */
546 if (server->server_type == SILC_ROUTER) {
548 silc_idlist_find_client_by_nickname(server->global_list,
551 silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
552 SILC_STATUS_ERR_NO_SUCH_NICK,
553 3, tmp, strlen(tmp));
559 silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
560 SILC_STATUS_ERR_NO_SUCH_NICK,
561 3, tmp, strlen(tmp));
566 /* Send IDENTIFY reply */
567 id_string = silc_id_id2str(entry->id, SILC_ID_CLIENT);
568 tmp = silc_command_get_first_arg(cmd->payload, NULL);
569 packet = silc_command_encode_reply_payload_va(SILC_COMMAND_IDENTIFY,
573 3, nick, strlen(nick));
575 if (cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED) {
576 void *id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
577 silc_server_packet_send_dest(server, cmd->sock,
578 SILC_PACKET_COMMAND_REPLY, 0,
579 id, cmd->packet->src_id_type,
580 packet->data, packet->len, FALSE);
584 silc_server_packet_send(server, cmd->sock,
585 SILC_PACKET_COMMAND_REPLY, 0,
586 packet->data, packet->len, FALSE);
588 silc_free(id_string);
589 silc_buffer_free(packet);
595 silc_free(server_name);
596 silc_server_command_free(cmd);
599 /* Checks string for bad characters and returns TRUE if they are found. */
601 static int silc_server_command_bad_chars(char *nick)
603 if (strchr(nick, '\\')) return TRUE;
604 if (strchr(nick, '\"')) return TRUE;
605 if (strchr(nick, '´')) return TRUE;
606 if (strchr(nick, '`')) return TRUE;
607 if (strchr(nick, '\'')) return TRUE;
608 if (strchr(nick, '*')) return TRUE;
609 if (strchr(nick, '/')) return TRUE;
610 if (strchr(nick, '@')) return TRUE;
615 /* Server side of command NICK. Sets nickname for user. Setting
616 nickname causes generation of a new client ID for the client. The
617 new client ID is sent to the client after changing the nickname. */
619 SILC_SERVER_CMD_FUNC(nick)
621 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
622 SilcClientEntry id_entry = (SilcClientEntry)cmd->sock->user_data;
623 SilcServer server = cmd->server;
625 SilcClientID *new_id;
629 SILC_LOG_DEBUG(("Start"));
631 /* Check number of arguments */
632 if (silc_command_get_arg_num(cmd->payload) < 1) {
633 silc_server_command_send_status_reply(cmd, SILC_COMMAND_NICK,
634 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
639 nick = silc_command_get_arg_type(cmd->payload, 1, NULL);
640 if (silc_server_command_bad_chars(nick) == TRUE) {
641 silc_server_command_send_status_reply(cmd, SILC_COMMAND_NICK,
642 SILC_STATUS_ERR_BAD_NICKNAME);
646 /* Create new Client ID */
647 silc_id_create_client_id(cmd->server->id, cmd->server->rng,
648 cmd->server->md5hash, nick,
651 /* Send notify about nickname change to our router. We send the new
652 ID and ask to replace it with the old one. */
653 if (cmd->server->server_type == SILC_SERVER && !cmd->server->standalone)
654 silc_server_send_replace_id(server, server->id_entry->router->connection,
656 SILC_ID_CLIENT, SILC_ID_CLIENT_LEN,
657 new_id, SILC_ID_CLIENT, SILC_ID_CLIENT_LEN);
659 /* If we are router we have to distribute the new Client ID to all
661 if (cmd->server->server_type == SILC_ROUTER && !cmd->server->standalone)
662 silc_server_send_replace_id(server, server->id_entry->router->connection,
664 SILC_ID_CLIENT, SILC_ID_CLIENT_LEN,
665 new_id, SILC_ID_CLIENT, SILC_ID_CLIENT_LEN);
667 /* Remove old cache entry */
668 silc_idcache_del_by_id(server->local_list->clients, SILC_ID_CLIENT,
673 memset(id_entry->id, 0, SILC_ID_CLIENT_LEN);
674 silc_free(id_entry->id);
677 /* Save the nickname as this client is our local client */
678 if (id_entry->nickname)
679 silc_free(id_entry->nickname);
681 id_entry->nickname = strdup(nick);
682 id_entry->id = new_id;
684 /* Update client cache */
685 silc_idcache_add(server->local_list->clients, id_entry->nickname,
686 SILC_ID_CLIENT, id_entry->id, (void *)id_entry, TRUE);
688 /* Send the new Client ID as reply command back to client */
689 id_string = silc_id_id2str(id_entry->id, SILC_ID_CLIENT);
690 packet = silc_command_encode_reply_payload_va(SILC_COMMAND_NICK,
694 silc_server_packet_send(cmd->server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
695 0, packet->data, packet->len, FALSE);
697 silc_free(id_string);
698 silc_buffer_free(packet);
701 silc_server_command_free(cmd);
704 SILC_SERVER_CMD_FUNC(list)
708 SILC_SERVER_CMD_FUNC(topic)
712 /* Server side of INVITE command. Invites some client to join some channel. */
714 SILC_SERVER_CMD_FUNC(invite)
716 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
717 SilcServer server = cmd->server;
718 SilcSocketConnection sock = cmd->sock, dest_sock;
719 SilcClientEntry sender, dest;
720 SilcClientID *dest_id;
721 SilcChannelEntry channel;
722 SilcChannelID *channel_id;
723 unsigned int argc, len;
724 unsigned char *id_string;
726 /* Check number of arguments */
727 argc = silc_command_get_arg_num(cmd->payload);
729 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
730 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
734 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
735 SILC_STATUS_ERR_TOO_MANY_PARAMS);
739 /* Get destination ID */
740 id_string = silc_command_get_arg_type(cmd->payload, 1, &len);
742 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
743 SILC_STATUS_ERR_NO_CLIENT_ID);
746 dest_id = silc_id_str2id(id_string, SILC_ID_CLIENT);
749 id_string = silc_command_get_arg_type(cmd->payload, 2, &len);
751 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
752 SILC_STATUS_ERR_NO_CHANNEL_ID);
755 channel_id = silc_id_str2id(id_string, SILC_ID_CHANNEL);
757 /* Check whether the channel exists */
758 channel = silc_idlist_find_channel_by_id(server->local_list, channel_id);
760 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
761 SILC_STATUS_ERR_NO_SUCH_CHANNEL);
765 /* Check whether the sender of this command is on the channel. */
766 sender = (SilcClientEntry )sock->user_data;
767 if (!silc_server_client_on_channel(sender, channel)) {
768 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
769 SILC_STATUS_ERR_NOT_ON_CHANNEL);
773 /* Check whether the channel is invite-only channel. If yes then the
774 sender of this command must be at least channel operator. */
777 /* Find the connection data for the destination. If it is local we will
778 send it directly otherwise we will send it to router for routing. */
779 dest = silc_idlist_find_client_by_id(server->local_list, dest_id);
781 dest_sock = (SilcSocketConnection)dest->connection;
783 dest_sock = silc_server_get_route(server, dest_id, SILC_ID_CLIENT);
785 /* Check whether the requested client is already on the channel. */
786 /* XXX if we are normal server we don't know about global clients on
787 the channel thus we must request it (NAMES command), check from
788 local cache as well. */
789 if (silc_server_client_on_channel(dest, channel)) {
790 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
791 SILC_STATUS_ERR_USER_ON_CHANNEL);
795 /* Send notify to the client that is invited to the channel */
796 silc_server_send_notify_dest(server, dest_sock, dest_id, SILC_ID_CLIENT,
797 "%s invites you to channel %s",
798 sender->nickname, channel->channel_name);
800 /* Send command reply */
801 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
805 silc_server_command_free(cmd);
808 /* Quits connection to client. This gets called if client won't
809 close the connection even when it has issued QUIT command. */
811 SILC_TASK_CALLBACK(silc_server_command_quit_cb)
813 SilcServer server = (SilcServer)context;
814 SilcSocketConnection sock = server->sockets[fd];
816 /* Free all client specific data, such as client entry and entires
817 on channels this client may be on. */
818 silc_server_free_sock_user_data(server, sock);
820 /* Close the connection on our side */
821 silc_server_close_connection(server, sock);
824 /* Quits SILC session. This is the normal way to disconnect client. */
826 SILC_SERVER_CMD_FUNC(quit)
828 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
829 SilcServer server = cmd->server;
830 SilcSocketConnection sock = cmd->sock;
832 SILC_LOG_DEBUG(("Start"));
834 /* We quit the connection with little timeout */
835 silc_task_register(server->timeout_queue, sock->sock,
836 silc_server_command_quit_cb, server,
837 0, 300000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
839 silc_server_command_free(cmd);
842 SILC_SERVER_CMD_FUNC(kill)
846 /* Server side of command INFO. This sends information about us to
847 the client. If client requested specific server we will send the
848 command to that server. */
850 SILC_SERVER_CMD_FUNC(info)
852 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
853 SilcServer server = cmd->server;
856 unsigned char *id_string;
857 char info_string[256], *dest_server;
859 argc = silc_command_get_arg_num(cmd->payload);
861 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
862 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
866 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
867 SILC_STATUS_ERR_TOO_MANY_PARAMS);
871 /* Get server name */
872 dest_server = silc_command_get_arg_type(cmd->payload, 1, NULL);
874 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
875 SILC_STATUS_ERR_NO_SUCH_SERVER);
879 if (!strncasecmp(dest_server, server->server_name, strlen(dest_server))) {
881 memset(info_string, 0, sizeof(info_string));
882 snprintf(info_string, sizeof(info_string),
883 "location: %s server: %s admin: %s <%s>",
884 server->config->admin_info->location,
885 server->config->admin_info->server_type,
886 server->config->admin_info->admin_name,
887 server->config->admin_info->admin_email);
889 id_string = silc_id_id2str(server->id, SILC_ID_SERVER);
892 silc_command_encode_reply_payload_va(SILC_COMMAND_INFO,
894 2, id_string, SILC_ID_SERVER_LEN,
896 strlen(info_string));
897 silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
898 packet->data, packet->len, FALSE);
900 silc_free(id_string);
901 silc_buffer_free(packet);
903 /* Send this command to the requested server */
905 if (server->server_type == SILC_SERVER && !server->standalone) {
909 if (server->server_type == SILC_ROUTER) {
915 silc_server_command_free(cmd);
918 SILC_SERVER_CMD_FUNC(connect)
922 /* Server side of command PING. This just replies to the ping. */
924 SILC_SERVER_CMD_FUNC(ping)
926 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
927 SilcServer server = cmd->server;
930 unsigned char *id_string;
932 argc = silc_command_get_arg_num(cmd->payload);
934 silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
935 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
939 silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
940 SILC_STATUS_ERR_TOO_MANY_PARAMS);
945 id_string = silc_command_get_arg_type(cmd->payload, 1, NULL);
947 silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
948 SILC_STATUS_ERR_NO_SERVER_ID);
951 id = silc_id_str2id(id_string, SILC_ID_SERVER);
953 if (!SILC_ID_SERVER_COMPARE(id, server->id)) {
955 silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
958 silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
959 SILC_STATUS_ERR_NO_SUCH_SERVER);
966 silc_server_command_free(cmd);
969 SILC_SERVER_CMD_FUNC(oper)
978 SilcChannelEntry channel;
980 } JoinInternalContext;
982 SILC_TASK_CALLBACK(silc_server_command_join_notify)
984 JoinInternalContext *ctx = (JoinInternalContext *)context;
986 if (ctx->channel->key && ctx->channel->key_len) {
987 silc_server_send_notify_to_channel(ctx->server, ctx->channel,
988 "%s (%s@%s) has joined channel %s",
989 ctx->nickname, ctx->username,
990 ctx->hostname, ctx->channel_name);
993 silc_task_register(ctx->server->timeout_queue, fd,
994 silc_server_command_join_notify, context,
995 0, 300000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
999 /* Assembles NAMES command and executes it. This is called when client
1000 joins to a channel and we wan't to send NAMES command reply to the
1003 void silc_server_command_send_names(SilcServer server,
1004 SilcSocketConnection sock,
1005 SilcChannelEntry channel)
1007 SilcServerCommandContext cmd;
1009 unsigned char *id_string;
1011 id_string = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
1012 buffer = silc_command_encode_payload_va(SILC_COMMAND_NAMES, 1,
1013 1, id_string, SILC_ID_CHANNEL_LEN);
1015 cmd = silc_calloc(1, sizeof(*cmd));
1016 cmd->payload = silc_command_parse_payload(buffer);
1017 cmd->server = server;
1019 cmd->pending = FALSE;
1021 silc_server_command_names((void *)cmd);
1022 silc_free(id_string);
1026 /* Server side of command JOIN. Joins client into requested channel. If
1027 the channel does not exist it will be created. */
1029 SILC_SERVER_CMD_FUNC(join)
1031 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1032 SilcServer server = cmd->server;
1033 SilcSocketConnection sock = cmd->sock;
1034 SilcBuffer buffer = cmd->packet->buffer;
1035 int argc, i, tmp_len;
1036 char *tmp, *channel_name = NULL, *cipher = NULL, *id_string = NULL;
1037 unsigned char *passphrase, mode[4];
1038 SilcChannelEntry channel;
1039 SilcServerID *router_id;
1041 SilcClientEntry client;
1043 SILC_LOG_DEBUG(("Start"));
1045 /* Check number of parameters */
1046 argc = silc_command_get_arg_num(cmd->payload);
1048 silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
1049 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1053 silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
1054 SILC_STATUS_ERR_TOO_MANY_PARAMS);
1058 /* Get channel name */
1059 tmp = silc_command_get_arg_type(cmd->payload, 1, &tmp_len);
1060 channel_name = silc_calloc(tmp_len + 1, sizeof(*channel_name));
1061 memcpy(channel_name, tmp, tmp_len);
1062 if (silc_server_command_bad_chars(tmp) == TRUE) {
1063 silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
1064 SILC_STATUS_ERR_BAD_CHANNEL);
1065 silc_free(channel_name);
1069 /* Get passphrase */
1070 tmp = silc_command_get_arg_type(cmd->payload, 2, &tmp_len);
1072 passphrase = silc_calloc(tmp_len, sizeof(*passphrase));
1073 memcpy(passphrase, tmp, tmp_len);
1076 /* Get cipher name */
1077 cipher = silc_command_get_arg_type(cmd->payload, 3, NULL);
1079 /* See if the channel exists */
1081 silc_idlist_find_channel_by_name(server->local_list, channel_name);
1083 /* Channel not found */
1085 /* If we are standalone server we don't have a router, we just create
1086 the channel by ourselves. */
1087 if (server->standalone) {
1088 router_id = server->id;
1089 channel = silc_server_new_channel(server, router_id,
1090 cipher, channel_name);
1097 /* No channel ID found, the channel does not exist on our server.
1098 We send JOIN command to our router which will handle the joining
1099 procedure (either creates the channel if it doesn't exist or
1100 joins the client to it) - if we are normal server. */
1101 if (server->server_type == SILC_SERVER) {
1103 /* Forward the original JOIN command to the router */
1104 silc_buffer_push(buffer, buffer->data - buffer->head);
1105 silc_server_packet_forward(server, (SilcSocketConnection)
1106 server->id_entry->router->connection,
1107 buffer->data, buffer->len, TRUE);
1109 /* Add the command to be pending. It will be re-executed after
1110 router has replied back to us. */
1111 cmd->pending = TRUE;
1112 silc_server_command_pending(SILC_COMMAND_JOIN,
1113 silc_server_command_join, context);
1118 /* If we are router and the channel does not exist we will check our
1119 global list for the channel. */
1120 if (!channel && server->server_type == SILC_ROUTER) {
1122 /* Notify all routers about the new channel in SILC network. */
1123 if (!server->standalone) {
1125 silc_server_send_new_id(server, server->id_entry->router->connection,
1127 xxx, SILC_ID_CHANNEL, SILC_ID_CHANNEL_LEN);
1135 /* If the JOIN request was forwarded to us we will make a bit slower
1136 query to get the client pointer. Otherwise, we get the client pointer
1138 if (!(cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED)) {
1139 client = (SilcClientEntry)sock->user_data;
1141 void *id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
1142 client = silc_idlist_find_client_by_id(server->local_list, id);
1150 /* Check whether the client already is on the channel */
1151 if (silc_server_client_on_channel(client, channel)) {
1152 silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
1153 SILC_STATUS_ERR_USER_ON_CHANNEL);
1154 silc_free(channel_name);
1158 /* Join the client to the channel */
1159 i = channel->user_list_count;
1160 channel->user_list = silc_realloc(channel->user_list,
1161 sizeof(*channel->user_list) * (i + 1));
1162 channel->user_list[i].mode = SILC_CHANNEL_UMODE_NONE;
1163 channel->user_list[i].client = client;
1164 channel->user_list_count++;
1166 /* Add the channel to client's channel list */
1167 i = client->channel_count;
1168 client->channel = silc_realloc(client->channel,
1169 sizeof(*client->channel) * (i + 1));
1170 client->channel[i] = channel;
1171 client->channel_count++;
1173 /* Notify router about new user on channel. If we are normal server
1174 we send it to our router, if we are router we send it to our
1176 if (!server->standalone) {
1180 /* Send command reply to the client. Client receives the Channe ID,
1181 channel mode and possibly other information in this reply packet. */
1182 if (!cmd->pending) {
1183 id_string = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
1184 SILC_PUT32_MSB(channel->mode, mode);
1186 if (!channel->topic)
1188 silc_command_encode_reply_payload_va(SILC_COMMAND_JOIN,
1191 strlen(channel_name),
1192 3, id_string, SILC_ID_CHANNEL_LEN,
1196 silc_command_encode_reply_payload_va(SILC_COMMAND_JOIN,
1199 strlen(channel_name),
1200 3, id_string, SILC_ID_CHANNEL_LEN,
1203 strlen(channel->topic));
1205 if (cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED) {
1206 void *id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
1207 silc_server_packet_send_dest(cmd->server, cmd->sock,
1208 SILC_PACKET_COMMAND_REPLY, 0,
1209 id, cmd->packet->src_id_type,
1210 packet->data, packet->len, FALSE);
1213 silc_server_packet_send(server, sock, SILC_PACKET_COMMAND_REPLY, 0,
1214 packet->data, packet->len, FALSE);
1216 silc_buffer_free(packet);
1219 /* Send channel key to the client. Client cannot start transmitting
1220 to the channel until we have sent the key. */
1221 if (!cmd->pending) {
1222 tmp_len = strlen(channel->channel_key->cipher->name);
1224 silc_channel_key_encode_payload(SILC_ID_CHANNEL_LEN,
1226 channel->channel_key->cipher->name,
1227 channel->key_len / 8, channel->key);
1229 silc_server_packet_send(server, sock, SILC_PACKET_CHANNEL_KEY, 0,
1230 packet->data, packet->len, FALSE);
1231 silc_buffer_free(packet);
1235 silc_free(id_string);
1237 /* Finally, send notify message to all clients on the channel about
1238 new user on the channel. */
1239 if (!(cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED)) {
1240 if (!cmd->pending) {
1241 silc_server_send_notify_to_channel(server, channel,
1242 "%s (%s@%s) has joined channel %s",
1243 client->nickname, client->username,
1244 sock->hostname ? sock->hostname :
1245 sock->ip, channel_name);
1247 /* This is pending command request. Send the notify after we have
1248 received the key for the channel from the router. */
1249 JoinInternalContext *ctx = silc_calloc(1, sizeof(*ctx));
1250 ctx->channel_name = channel_name;
1251 ctx->nickname = client->nickname;
1252 ctx->username = client->username;
1253 ctx->hostname = sock->hostname ? sock->hostname : sock->ip;
1254 ctx->channel = channel;
1255 ctx->server = server;
1256 silc_task_register(server->timeout_queue, sock->sock,
1257 silc_server_command_join_notify, ctx,
1258 0, 10000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
1262 /* Send NAMES command reply to the joined channel so the user sees who
1263 is currently on the channel. */
1264 silc_server_command_send_names(server, sock, channel);
1267 silc_server_command_free(cmd);
1270 /* Server side of command MOTD. Sends servers current "message of the
1271 day" to the client. */
1273 SILC_SERVER_CMD_FUNC(motd)
1276 SILC_LOG_DEBUG(("Start"));
1280 SILC_SERVER_CMD_FUNC(umode)
1284 SILC_SERVER_CMD_FUNC(cmode)
1288 SILC_SERVER_CMD_FUNC(kick)
1292 SILC_SERVER_CMD_FUNC(restart)
1296 SILC_SERVER_CMD_FUNC(close)
1300 SILC_SERVER_CMD_FUNC(die)
1304 SILC_SERVER_CMD_FUNC(silcoper)
1308 /* Server side command of LEAVE. Removes client from a channel. */
1310 SILC_SERVER_CMD_FUNC(leave)
1312 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1313 SilcServer server = cmd->server;
1314 SilcSocketConnection sock = cmd->sock;
1315 SilcClientEntry id_entry = (SilcClientEntry)cmd->sock->user_data;
1317 SilcChannelEntry channel;
1319 unsigned int i, argc, key_len;
1320 unsigned char *tmp, channel_key[32];
1322 SILC_LOG_DEBUG(("Start"));
1324 argc = silc_command_get_arg_num(cmd->payload);
1326 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1327 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1331 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1332 SILC_STATUS_ERR_TOO_MANY_PARAMS);
1336 /* Get Channel ID */
1337 tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
1339 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1340 SILC_STATUS_ERR_NO_CHANNEL_ID);
1343 id = silc_id_str2id(tmp, SILC_ID_CHANNEL);
1345 /* Get channel entry */
1346 channel = silc_idlist_find_channel_by_id(server->local_list, id);
1348 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1349 SILC_STATUS_ERR_NO_SUCH_CHANNEL);
1353 /* Check whether this client is on the channel */
1354 if (!silc_server_client_on_channel(id_entry, channel)) {
1355 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1356 SILC_STATUS_ERR_NOT_ON_CHANNEL);
1360 /* Remove client from channel */
1361 i = silc_server_remove_from_one_channel(server, sock, channel, id_entry);
1362 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1365 /* If the channel does not exist anymore we won't send anything */
1369 /* Re-generate channel key */
1370 key_len = channel->key_len / 8;
1371 for (i = 0; i < key_len; i++)
1372 channel_key[i] = silc_rng_get_byte(server->rng);
1373 channel->channel_key->cipher->set_key(channel->channel_key->context,
1374 channel_key, key_len);
1375 memset(channel->key, 0, key_len);
1376 silc_free(channel->key);
1377 channel->key = silc_calloc(key_len, sizeof(*channel->key));
1378 memcpy(channel->key, channel_key, key_len);
1379 memset(channel_key, 0, sizeof(channel_key));
1381 /* Encode channel key payload to be distributed on the channel */
1383 silc_channel_key_encode_payload(SILC_ID_CHANNEL_LEN, tmp,
1384 strlen(channel->channel_key->cipher->name),
1385 channel->channel_key->cipher->name,
1386 key_len, channel->key);
1388 /* If we are normal server then we will send it to our router. If we
1389 are router we will send it to all local servers that has clients on
1391 if (server->server_type == SILC_SERVER) {
1392 if (!server->standalone)
1393 silc_server_packet_send(server,
1394 cmd->server->id_entry->router->connection,
1395 SILC_PACKET_CHANNEL_KEY, 0, packet->data,
1401 /* Send to locally connected clients on the channel */
1402 silc_server_packet_send_local_channel(server, channel,
1403 SILC_PACKET_CHANNEL_KEY, 0,
1404 packet->data, packet->len, FALSE);
1406 silc_buffer_free(packet);
1410 silc_server_command_free(cmd);
1413 /* Server side of command NAMES. Resolves clients and their names currently
1414 joined on the requested channel. The name list is sent back to the
1417 SILC_SERVER_CMD_FUNC(names)
1419 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1420 SilcServer server = cmd->server;
1421 SilcChannelEntry channel;
1424 unsigned int i, len, len2, argc;
1426 char *name_list = NULL, *n;
1427 SilcBuffer client_id_list;
1429 SILC_LOG_DEBUG(("Start"));
1431 argc = silc_command_get_arg_num(cmd->payload);
1433 silc_server_command_send_status_reply(cmd, SILC_COMMAND_NAMES,
1434 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1438 silc_server_command_send_status_reply(cmd, SILC_COMMAND_NAMES,
1439 SILC_STATUS_ERR_TOO_MANY_PARAMS);
1443 /* Get Channel ID */
1444 tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
1446 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1447 SILC_STATUS_ERR_NO_CHANNEL_ID);
1450 id = silc_id_str2id(tmp, SILC_ID_CHANNEL);
1452 /* Check whether the channel exists. If we are normal server and the
1453 channel does not exist we will send this same command to our router
1454 which will know if the channel exists. */
1455 channel = silc_idlist_find_channel_by_id(server->local_list, id);
1457 if (server->server_type == SILC_SERVER && !server->standalone) {
1458 /* XXX Send names command */
1460 cmd->pending = TRUE;
1461 silc_server_command_pending(SILC_COMMAND_NAMES,
1462 silc_server_command_names, context);
1466 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
1467 SILC_STATUS_ERR_NO_SUCH_CHANNEL);
1471 /* Assemble the name list now */
1474 for (i = 0; i < channel->user_list_count; i++) {
1475 if (!channel->user_list[i].client)
1478 n = channel->user_list[i].client->nickname;
1482 name_list = silc_realloc(name_list, sizeof(*name_list) * (len + 1));
1483 memcpy(name_list + (len - len2), n, len2);
1486 if (i == channel->user_list_count - 1)
1488 memcpy(name_list + len, ",", 1);
1493 /* Assemble the Client ID list now */
1494 client_id_list = silc_buffer_alloc(SILC_ID_CLIENT_LEN *
1495 channel->user_list_count);
1496 silc_buffer_pull_tail(client_id_list, (SILC_ID_CLIENT_LEN *
1497 channel->user_list_count));
1498 for (i = 0; i < channel->user_list_count; i++) {
1499 unsigned char *id_string;
1501 if (!channel->user_list[i].client)
1504 id_string = silc_id_id2str(channel->user_list[i].client->id,
1506 silc_buffer_format(client_id_list,
1507 SILC_STR_UI_XNSTRING(id_string, SILC_ID_CLIENT_LEN),
1509 silc_buffer_pull(client_id_list, SILC_ID_CLIENT_LEN);
1510 silc_free(id_string);
1512 silc_buffer_push(client_id_list,
1513 client_id_list->data - client_id_list->head);
1516 packet = silc_command_encode_reply_payload_va(SILC_COMMAND_NAMES,
1518 2, tmp, SILC_ID_CHANNEL_LEN,
1521 4, client_id_list->data,
1522 client_id_list->len);
1523 silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
1524 packet->data, packet->len, FALSE);
1526 silc_buffer_free(packet);
1527 silc_free(name_list);
1528 silc_buffer_free(client_id_list);
1532 silc_server_command_free(cmd);