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.
22 #include "serverincludes.h"
23 #include "server_internal.h"
25 static int silc_server_is_registered(SilcServer server,
26 SilcSocketConnection sock,
27 SilcServerCommandContext cmd,
30 silc_server_command_send_status_reply(SilcServerCommandContext cmd,
32 SilcCommandStatus status);
34 silc_server_command_send_status_data(SilcServerCommandContext cmd,
36 SilcCommandStatus status,
37 unsigned int arg_type,
39 unsigned int arg_len);
40 static void silc_server_command_free(SilcServerCommandContext cmd);
42 /* Server command list. */
43 SilcServerCommand silc_command_list[] =
45 SILC_SERVER_CMD(whois, WHOIS, SILC_CF_LAG | SILC_CF_REG),
46 SILC_SERVER_CMD(whowas, WHOWAS, SILC_CF_LAG | SILC_CF_REG),
47 SILC_SERVER_CMD(identify, IDENTIFY, SILC_CF_LAG | SILC_CF_REG),
48 SILC_SERVER_CMD(nick, NICK, SILC_CF_LAG | SILC_CF_REG),
49 SILC_SERVER_CMD(list, LIST, SILC_CF_LAG | SILC_CF_REG),
50 SILC_SERVER_CMD(topic, TOPIC, SILC_CF_LAG | SILC_CF_REG),
51 SILC_SERVER_CMD(invite, INVITE, SILC_CF_LAG | SILC_CF_REG),
52 SILC_SERVER_CMD(quit, QUIT, SILC_CF_LAG | SILC_CF_REG),
53 SILC_SERVER_CMD(kill, KILL, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
54 SILC_SERVER_CMD(info, INFO, SILC_CF_LAG | SILC_CF_REG),
55 SILC_SERVER_CMD(connect, CONNECT,
56 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
57 SILC_SERVER_CMD(ping, PING, SILC_CF_LAG | SILC_CF_REG),
58 SILC_SERVER_CMD(oper, OPER, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
59 SILC_SERVER_CMD(join, JOIN, SILC_CF_LAG | SILC_CF_REG),
60 SILC_SERVER_CMD(motd, MOTD, SILC_CF_LAG | SILC_CF_REG),
61 SILC_SERVER_CMD(umode, UMODE, SILC_CF_LAG | SILC_CF_REG),
62 SILC_SERVER_CMD(cmode, CMODE, SILC_CF_LAG | SILC_CF_REG),
63 SILC_SERVER_CMD(kick, KICK, SILC_CF_LAG | SILC_CF_REG),
64 SILC_SERVER_CMD(restart, RESTART,
65 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
66 SILC_SERVER_CMD(close, CLOSE,
67 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
68 SILC_SERVER_CMD(die, DIE, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
69 SILC_SERVER_CMD(silcoper, SILCOPER,
70 SILC_CF_LAG | SILC_CF_REG | SILC_CF_SILC_OPER),
71 SILC_SERVER_CMD(leave, LEAVE, SILC_CF_LAG | SILC_CF_REG),
72 SILC_SERVER_CMD(names, NAMES, SILC_CF_LAG | SILC_CF_REG),
77 /* List of pending commands. */
78 SilcServerCommandPending *silc_command_pending = NULL;
80 /* Returns TRUE if the connection is registered. Unregistered connections
81 usually cannot send commands hence the check. */
83 static int silc_server_is_registered(SilcServer server,
84 SilcSocketConnection sock,
85 SilcServerCommandContext cmd,
89 case SILC_SOCKET_TYPE_CLIENT:
91 SilcClientEntry client = (SilcClientEntry)sock->user_data;
92 if (client->registered)
96 case SILC_SOCKET_TYPE_SERVER:
97 case SILC_SOCKET_TYPE_ROUTER:
99 SilcServerEntry serv = (SilcServerEntry)sock->user_data;
100 if (serv->registered)
108 silc_server_command_send_status_reply(cmd, command,
109 SILC_STATUS_ERR_NOT_REGISTERED);
110 silc_server_command_free(cmd);
114 /* Processes received command packet. */
116 void silc_server_command_process(SilcServer server,
117 SilcSocketConnection sock,
118 SilcPacketContext *packet)
120 SilcServerCommandContext ctx;
121 SilcServerCommand *cmd;
123 /* Check whether it is allowed for this connection to execute any
125 if (sock->type == SILC_SOCKET_TYPE_CLIENT) {
127 SilcClientEntry client = (SilcClientEntry)sock->user_data;
132 /* Allow only one command executed in 2 seconds. */
133 curtime = time(NULL);
134 if (client->last_command && (curtime - client->last_command) < 2)
137 /* Update access time */
138 client->last_command = curtime;
141 /* Allocate command context. This must be free'd by the
142 command routine receiving it. */
143 ctx = silc_calloc(1, sizeof(*ctx));
144 ctx->server = server;
146 ctx->packet = packet; /* Save original packet */
148 /* Parse the command payload in the packet */
149 ctx->payload = silc_command_payload_parse(packet->buffer);
151 SILC_LOG_ERROR(("Bad command payload, packet dropped"));
152 silc_buffer_free(packet->buffer);
156 ctx->args = silc_command_get_args(ctx->payload);
158 /* Execute command. If this fails the packet is dropped. */
159 for (cmd = silc_command_list; cmd->cb; cmd++)
160 if (cmd->cmd == silc_command_get(ctx->payload)) {
162 if (!(cmd->flags & SILC_CF_REG)) {
167 if (silc_server_is_registered(server, sock, ctx, cmd->cmd)) {
174 SILC_LOG_ERROR(("Unknown command, packet dropped"));
180 silc_buffer_free(packet->buffer);
183 /* Add new pending command to the list of pending commands. Currently
184 pending commands are executed from command replies, thus we can
185 execute any command after receiving some specific command reply.
187 The argument `reply_cmd' is the command reply from where the callback
188 function is to be called, thus, it IS NOT the command to be executed. */
190 void silc_server_command_pending(SilcCommand reply_cmd,
191 SilcCommandCb callback,
194 SilcServerCommandPending *reply, *r;
196 reply = silc_calloc(1, sizeof(*reply));
197 reply->reply_cmd = reply_cmd;
198 reply->context = context;
199 reply->callback = callback;
201 if (silc_command_pending == NULL) {
202 silc_command_pending = reply;
206 for (r = silc_command_pending; r; r = r->next) {
207 if (r->next == NULL) {
214 /* Deletes pending command by reply command type. */
216 void silc_server_command_pending_del(SilcCommand reply_cmd)
218 SilcServerCommandPending *r, *tmp;
220 if (silc_command_pending) {
221 if (silc_command_pending->reply_cmd == reply_cmd) {
222 silc_free(silc_command_pending);
223 silc_command_pending = NULL;
227 for (r = silc_command_pending; r; r = r->next) {
228 if (r->next && r->next->reply_cmd == reply_cmd) {
230 r->next = r->next->next;
238 /* Free's the command context allocated before executing the command */
240 static void silc_server_command_free(SilcServerCommandContext cmd)
243 silc_command_free_payload(cmd->payload);
248 /* Sends simple status message as command reply packet */
251 silc_server_command_send_status_reply(SilcServerCommandContext cmd,
253 SilcCommandStatus status)
257 SILC_LOG_DEBUG(("Sending command status %d", status));
259 buffer = silc_command_reply_payload_encode_va(command, status, 0, 0);
260 silc_server_packet_send(cmd->server, cmd->sock,
261 SILC_PACKET_COMMAND_REPLY, 0,
262 buffer->data, buffer->len, FALSE);
263 silc_buffer_free(buffer);
266 /* Sends command status reply with one extra argument. The argument
267 type must be sent as argument. */
270 silc_server_command_send_status_data(SilcServerCommandContext cmd,
272 SilcCommandStatus status,
273 unsigned int arg_type,
275 unsigned int arg_len)
279 SILC_LOG_DEBUG(("Sending command status %d", status));
281 buffer = silc_command_reply_payload_encode_va(command, status, 0, 1,
282 arg_type, arg, arg_len);
283 silc_server_packet_send(cmd->server, cmd->sock,
284 SILC_PACKET_COMMAND_REPLY, 0,
285 buffer->data, buffer->len, FALSE);
286 silc_buffer_free(buffer);
289 /* Server side of command WHOIS. Processes user's query and sends found
290 results as command replies back to the client. */
292 SILC_SERVER_CMD_FUNC(whois)
294 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
295 SilcServer server = cmd->server;
296 char *tmp, *nick = NULL, *server_name = NULL;
297 unsigned int i, argc, count = 0, len, clients_count;
298 SilcClientEntry entry;
300 unsigned char *id_string;
301 SilcClientEntry *clients;
302 SilcCommandStatus status;
304 SILC_LOG_DEBUG(("Start"));
306 argc = silc_argument_get_arg_num(cmd->args);
308 silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
309 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
313 silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
314 SILC_STATUS_ERR_TOO_MANY_PARAMS);
318 /* Get the nickname@server string and parse it. */
319 tmp = silc_argument_get_first_arg(cmd->args, NULL);
321 if (strchr(tmp, '@')) {
322 len = strcspn(tmp, "@");
323 nick = silc_calloc(len + 1, sizeof(char));
324 memcpy(nick, tmp, len);
325 server_name = silc_calloc(strlen(tmp) - len, sizeof(char));
326 memcpy(server_name, tmp + len + 1, strlen(tmp) - len - 1);
331 silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
332 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
336 /* Get the max count of reply messages allowed */
338 tmp = silc_argument_get_next_arg(cmd->args, NULL);
340 silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
341 SILC_STATUS_ERR_TOO_MANY_PARAMS);
345 silc_free(server_name);
351 /* Get all clients matching that nickname */
352 clients = silc_idlist_get_clients_by_nickname(server->local_list,
357 /* If we are normal server and are connected to a router we will
358 make global query from the router. */
359 if (server->server_type == SILC_SERVER && !server->standalone) {
364 /* If we are router then we will check our global list as well. */
365 if (server->server_type == SILC_ROUTER) {
367 silc_idlist_find_client_by_nickname(server->global_list,
370 silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
371 SILC_STATUS_ERR_NO_SUCH_NICK,
372 3, tmp, strlen(tmp));
378 silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
379 SILC_STATUS_ERR_NO_SUCH_NICK,
380 3, tmp, strlen(tmp));
385 /* XXX, works only for local server info */
388 status = SILC_STATUS_OK;
389 if (clients_count > 1)
390 status = SILC_STATUS_LIST_START;
392 for (i = 0; i < clients_count; i++) {
395 if (count && i - 1 == count)
398 if (clients_count > 2)
399 status = SILC_STATUS_LIST_ITEM;
401 if (clients_count > 1 && i == clients_count - 1)
402 status = SILC_STATUS_LIST_END;
404 /* Send WHOIS reply */
405 id_string = silc_id_id2str(entry->id, SILC_ID_CLIENT);
406 tmp = silc_argument_get_first_arg(cmd->args, NULL);
409 if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
410 char nh[256], uh[256];
411 unsigned char idle[4];
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);
430 SILC_PUT32_MSB((time(NULL) - entry->last_receive), idle);
435 silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
437 2, id_string, SILC_ID_CLIENT_LEN,
441 strlen(entry->userinfo),
445 silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
447 2, id_string, SILC_ID_CLIENT_LEN,
455 silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
457 2, id_string, SILC_ID_CLIENT_LEN,
459 strlen(entry->nickname),
460 4, tmp, strlen(tmp)); /* XXX */
462 silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
463 0, packet->data, packet->len, FALSE);
465 silc_free(id_string);
466 silc_buffer_free(packet);
470 silc_server_command_free(cmd);
473 SILC_SERVER_CMD_FUNC(whowas)
477 SILC_SERVER_CMD_FUNC(identify)
479 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
480 SilcServer server = cmd->server;
481 char *tmp, *nick = NULL, *server_name = NULL;
482 unsigned int argc, count = 0, len;
483 SilcClientEntry entry;
485 unsigned char *id_string;
487 SILC_LOG_DEBUG(("Start"));
489 argc = silc_argument_get_arg_num(cmd->args);
491 silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
492 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
496 silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
497 SILC_STATUS_ERR_TOO_MANY_PARAMS);
501 /* Get the nickname@server string and parse it. */
502 tmp = silc_argument_get_first_arg(cmd->args, NULL);
504 if (strchr(tmp, '@')) {
505 len = strcspn(tmp, "@");
506 nick = silc_calloc(len + 1, sizeof(char));
507 memcpy(nick, tmp, len);
508 server_name = silc_calloc(strlen(tmp) - len, sizeof(char));
509 memcpy(server_name, tmp + len + 1, strlen(tmp) - len - 1);
514 silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
515 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
519 /* Get the max count of reply messages allowed */
521 tmp = silc_argument_get_next_arg(cmd->args, NULL);
523 silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
524 SILC_STATUS_ERR_TOO_MANY_PARAMS);
531 entry = silc_idlist_find_client_by_nickname(server->local_list,
534 entry = silc_idlist_find_client_by_hash(server->global_list,
535 nick, server->md5hash);
537 /* If client was not found and if we are normal server and are connected
538 to a router we will make global query from the router. */
539 if (!entry && server->server_type == SILC_SERVER && !server->standalone &&
541 SilcBuffer buffer = cmd->packet->buffer;
543 SILC_LOG_DEBUG(("Requesting identify from router"));
545 /* Send IDENTIFY command to our router */
546 silc_buffer_push(buffer, buffer->data - buffer->head);
547 silc_server_packet_forward(server, (SilcSocketConnection)
548 server->id_entry->router->connection,
549 buffer->data, buffer->len, TRUE);
553 /* If we are router we have checked our local list by nickname and our
554 global list by hash so far. It is possible that the client is still not
555 found and we'll check it from local list by hash. */
556 if (!entry && server->server_type == SILC_ROUTER)
557 entry = silc_idlist_find_client_by_hash(server->local_list,
558 nick, server->md5hash);
561 /* The client definitely does not exist */
562 silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
563 SILC_STATUS_ERR_NO_SUCH_NICK,
564 3, tmp, strlen(tmp));
568 /* Send IDENTIFY reply */
569 id_string = silc_id_id2str(entry->id, SILC_ID_CLIENT);
570 tmp = silc_argument_get_first_arg(cmd->args, NULL);
571 packet = silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY,
572 SILC_STATUS_OK, 0, 2,
575 3, nick, strlen(nick));
576 if (cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED) {
577 void *id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
578 silc_server_packet_send_dest(server, cmd->sock,
579 SILC_PACKET_COMMAND_REPLY, 0,
580 id, cmd->packet->src_id_type,
581 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);
589 silc_free(id_string);
590 silc_buffer_free(packet);
596 silc_free(server_name);
597 silc_server_command_free(cmd);
600 /* Checks string for bad characters and returns TRUE if they are found. */
602 static int silc_server_command_bad_chars(char *nick)
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;
611 if (strchr(nick, '@')) return TRUE;
616 /* Server side of command NICK. Sets nickname for user. Setting
617 nickname causes generation of a new client ID for the client. The
618 new client ID is sent to the client after changing the nickname. */
620 SILC_SERVER_CMD_FUNC(nick)
622 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
623 SilcClientEntry id_entry = (SilcClientEntry)cmd->sock->user_data;
624 SilcServer server = cmd->server;
626 SilcClientID *new_id;
630 SILC_LOG_DEBUG(("Start"));
632 /* Check number of arguments */
633 if (silc_argument_get_arg_num(cmd->args) < 1) {
634 silc_server_command_send_status_reply(cmd, SILC_COMMAND_NICK,
635 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
640 nick = silc_argument_get_arg_type(cmd->args, 1, NULL);
641 if (silc_server_command_bad_chars(nick) == TRUE) {
642 silc_server_command_send_status_reply(cmd, SILC_COMMAND_NICK,
643 SILC_STATUS_ERR_BAD_NICKNAME);
647 /* Create new Client ID */
648 silc_id_create_client_id(cmd->server->id, cmd->server->rng,
649 cmd->server->md5hash, nick,
652 /* Send notify about nickname change to our router. We send the new
653 ID and ask to replace it with the old one. */
654 if (cmd->server->server_type == SILC_SERVER && !cmd->server->standalone)
655 silc_server_send_replace_id(server, server->id_entry->router->connection,
657 SILC_ID_CLIENT, SILC_ID_CLIENT_LEN,
658 new_id, SILC_ID_CLIENT, SILC_ID_CLIENT_LEN);
660 /* If we are router we have to distribute the new Client ID to all
662 if (cmd->server->server_type == SILC_ROUTER && !cmd->server->standalone)
663 silc_server_send_replace_id(server, server->id_entry->router->connection,
665 SILC_ID_CLIENT, SILC_ID_CLIENT_LEN,
666 new_id, SILC_ID_CLIENT, SILC_ID_CLIENT_LEN);
668 /* Remove old cache entry */
669 silc_idcache_del_by_id(server->local_list->clients, SILC_ID_CLIENT,
674 memset(id_entry->id, 0, SILC_ID_CLIENT_LEN);
675 silc_free(id_entry->id);
678 /* Save the nickname as this client is our local client */
679 if (id_entry->nickname)
680 silc_free(id_entry->nickname);
682 id_entry->nickname = strdup(nick);
683 id_entry->id = new_id;
685 /* Update client cache */
686 silc_idcache_add(server->local_list->clients, id_entry->nickname,
687 SILC_ID_CLIENT, id_entry->id, (void *)id_entry, TRUE);
689 /* Send the new Client ID as reply command back to client */
690 id_string = silc_id_id2str(id_entry->id, SILC_ID_CLIENT);
691 packet = silc_command_reply_payload_encode_va(SILC_COMMAND_NICK,
692 SILC_STATUS_OK, 0, 1,
695 silc_server_packet_send(cmd->server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
696 0, packet->data, packet->len, FALSE);
698 silc_free(id_string);
699 silc_buffer_free(packet);
702 silc_server_command_free(cmd);
705 SILC_SERVER_CMD_FUNC(list)
709 /* Server side of TOPIC command. Sets topic for channel and/or returns
710 current topic to client. */
712 SILC_SERVER_CMD_FUNC(topic)
714 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
715 SilcServer server = cmd->server;
716 SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
717 SilcChannelID *channel_id;
718 SilcChannelEntry channel;
720 SilcBuffer id_payload;
721 unsigned char *tmp, *id_string;
724 /* Check number of arguments */
725 argc = silc_argument_get_arg_num(cmd->args);
727 silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
728 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
732 silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
733 SILC_STATUS_ERR_TOO_MANY_PARAMS);
738 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
740 silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
741 SILC_STATUS_ERR_NO_CHANNEL_ID);
744 channel_id = silc_id_str2id(tmp, SILC_ID_CHANNEL);
746 /* Check whether the channel exists */
747 channel = silc_idlist_find_channel_by_id(server->local_list, channel_id);
749 silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
750 SILC_STATUS_ERR_NO_SUCH_CHANNEL);
756 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
758 silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
759 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
763 if (strlen(tmp) > 256) {
764 silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
765 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
769 /* Set the topic for channel */
771 silc_free(channel->topic);
772 channel->topic = strdup(tmp);
774 id_payload = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL_LEN,
777 /* Send notify about topic change to all clients on the channel */
778 silc_server_send_notify_to_channel(server, channel,
779 SILC_NOTIFY_TYPE_TOPIC_SET, 4, FALSE,
780 "%s@%s set topic: %s",
781 id_payload->data, id_payload->len,
784 strlen(client->nickname),
786 strlen(cmd->sock->hostname));
787 silc_buffer_free(id_payload);
790 /* Send the topic to client as reply packet */
791 id_string = silc_id_id2str(channel_id, SILC_ID_CHANNEL);
793 packet = silc_command_reply_payload_encode_va(SILC_COMMAND_TOPIC,
794 SILC_STATUS_OK, 0, 2,
798 strlen(channel->topic));
800 packet = silc_command_reply_payload_encode_va(SILC_COMMAND_TOPIC,
801 SILC_STATUS_OK, 0, 1,
803 SILC_ID_CHANNEL_LEN);
804 silc_server_packet_send(cmd->server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
805 0, packet->data, packet->len, FALSE);
807 silc_free(id_string);
808 silc_buffer_free(packet);
809 silc_free(channel_id);
812 silc_server_command_free(cmd);
815 /* Server side of INVITE command. Invites some client to join some channel. */
817 SILC_SERVER_CMD_FUNC(invite)
819 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
820 SilcServer server = cmd->server;
821 SilcSocketConnection sock = cmd->sock, dest_sock;
822 SilcClientEntry sender, dest;
823 SilcClientID *dest_id;
824 SilcChannelEntry channel;
825 SilcChannelID *channel_id;
826 unsigned int argc, len;
827 unsigned char *id_string;
829 /* Check number of arguments */
830 argc = silc_argument_get_arg_num(cmd->args);
832 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
833 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
837 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
838 SILC_STATUS_ERR_TOO_MANY_PARAMS);
842 /* Get destination ID */
843 id_string = silc_argument_get_arg_type(cmd->args, 1, &len);
845 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
846 SILC_STATUS_ERR_NO_CLIENT_ID);
849 dest_id = silc_id_str2id(id_string, SILC_ID_CLIENT);
852 id_string = silc_argument_get_arg_type(cmd->args, 2, &len);
854 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
855 SILC_STATUS_ERR_NO_CHANNEL_ID);
858 channel_id = silc_id_str2id(id_string, SILC_ID_CHANNEL);
860 /* Check whether the channel exists */
861 channel = silc_idlist_find_channel_by_id(server->local_list, channel_id);
863 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
864 SILC_STATUS_ERR_NO_SUCH_CHANNEL);
868 /* Check whether the sender of this command is on the channel. */
869 sender = (SilcClientEntry )sock->user_data;
870 if (!silc_server_client_on_channel(sender, channel)) {
871 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
872 SILC_STATUS_ERR_NOT_ON_CHANNEL);
876 /* Check whether the channel is invite-only channel. If yes then the
877 sender of this command must be at least channel operator. */
880 /* Find the connection data for the destination. If it is local we will
881 send it directly otherwise we will send it to router for routing. */
882 dest = silc_idlist_find_client_by_id(server->local_list, dest_id);
884 dest_sock = (SilcSocketConnection)dest->connection;
886 dest_sock = silc_server_get_route(server, dest_id, SILC_ID_CLIENT);
888 /* Check whether the requested client is already on the channel. */
889 /* XXX if we are normal server we don't know about global clients on
890 the channel thus we must request it (NAMES command), check from
891 local cache as well. */
892 if (silc_server_client_on_channel(dest, channel)) {
893 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
894 SILC_STATUS_ERR_USER_ON_CHANNEL);
898 /* Send notify to the client that is invited to the channel */
899 silc_server_send_notify_dest(server, dest_sock, dest_id, SILC_ID_CLIENT,
900 SILC_NOTIFY_TYPE_INVITE, 2, FALSE,
901 "%s invites you to channel %s",
902 sender->nickname, strlen(sender->nickname),
903 channel->channel_name,
904 strlen(channel->channel_name));
906 /* Send command reply */
907 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
911 silc_server_command_free(cmd);
914 /* Quits connection to client. This gets called if client won't
915 close the connection even when it has issued QUIT command. */
917 SILC_TASK_CALLBACK(silc_server_command_quit_cb)
919 SilcServer server = (SilcServer)context;
920 SilcSocketConnection sock = server->sockets[fd];
922 /* Free all client specific data, such as client entry and entires
923 on channels this client may be on. */
924 silc_server_free_sock_user_data(server, sock);
926 /* Close the connection on our side */
927 silc_server_close_connection(server, sock);
930 /* Quits SILC session. This is the normal way to disconnect client. */
932 SILC_SERVER_CMD_FUNC(quit)
934 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
935 SilcServer server = cmd->server;
936 SilcSocketConnection sock = cmd->sock;
938 SILC_LOG_DEBUG(("Start"));
940 /* We quit the connection with little timeout */
941 silc_task_register(server->timeout_queue, sock->sock,
942 silc_server_command_quit_cb, server,
943 0, 300000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
945 silc_server_command_free(cmd);
948 SILC_SERVER_CMD_FUNC(kill)
952 /* Server side of command INFO. This sends information about us to
953 the client. If client requested specific server we will send the
954 command to that server. */
956 SILC_SERVER_CMD_FUNC(info)
958 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
959 SilcServer server = cmd->server;
962 unsigned char *id_string;
963 char info_string[256], *dest_server;
965 argc = silc_argument_get_arg_num(cmd->args);
967 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
968 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
972 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
973 SILC_STATUS_ERR_TOO_MANY_PARAMS);
977 /* Get server name */
978 dest_server = silc_argument_get_arg_type(cmd->args, 1, NULL);
980 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
981 SILC_STATUS_ERR_NO_SUCH_SERVER);
985 if (!strncasecmp(dest_server, server->server_name, strlen(dest_server))) {
987 memset(info_string, 0, sizeof(info_string));
988 snprintf(info_string, sizeof(info_string),
989 "location: %s server: %s admin: %s <%s>",
990 server->config->admin_info->location,
991 server->config->admin_info->server_type,
992 server->config->admin_info->admin_name,
993 server->config->admin_info->admin_email);
995 id_string = silc_id_id2str(server->id, SILC_ID_SERVER);
998 silc_command_reply_payload_encode_va(SILC_COMMAND_INFO,
999 SILC_STATUS_OK, 0, 2,
1000 2, id_string, SILC_ID_SERVER_LEN,
1002 strlen(info_string));
1003 silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
1004 packet->data, packet->len, FALSE);
1006 silc_free(id_string);
1007 silc_buffer_free(packet);
1009 /* Send this command to the requested server */
1011 if (server->server_type == SILC_SERVER && !server->standalone) {
1015 if (server->server_type == SILC_ROUTER) {
1021 silc_server_command_free(cmd);
1024 SILC_SERVER_CMD_FUNC(connect)
1028 /* Server side of command PING. This just replies to the ping. */
1030 SILC_SERVER_CMD_FUNC(ping)
1032 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1033 SilcServer server = cmd->server;
1036 unsigned char *id_string;
1038 argc = silc_argument_get_arg_num(cmd->args);
1040 silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
1041 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1045 silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
1046 SILC_STATUS_ERR_TOO_MANY_PARAMS);
1051 id_string = silc_argument_get_arg_type(cmd->args, 1, NULL);
1053 silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
1054 SILC_STATUS_ERR_NO_SERVER_ID);
1057 id = silc_id_str2id(id_string, SILC_ID_SERVER);
1059 if (!SILC_ID_SERVER_COMPARE(id, server->id)) {
1060 /* Send our reply */
1061 silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
1064 silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
1065 SILC_STATUS_ERR_NO_SUCH_SERVER);
1072 silc_server_command_free(cmd);
1075 SILC_SERVER_CMD_FUNC(oper)
1084 SilcChannelEntry channel;
1086 SilcClientEntry client;
1087 } JoinInternalContext;
1089 SILC_TASK_CALLBACK(silc_server_command_join_notify)
1091 JoinInternalContext *ctx = (JoinInternalContext *)context;
1093 if (ctx->channel->key && ctx->channel->key_len) {
1094 SilcBuffer channel_idp, client_idp;
1096 channel_idp = silc_id_payload_encode(ctx->channel->id, SILC_ID_CHANNEL_LEN,
1098 client_idp = silc_id_payload_encode(ctx->client->id, SILC_ID_CLIENT_LEN,
1101 silc_server_send_notify_to_channel(ctx->server, ctx->channel,
1102 SILC_NOTIFY_TYPE_JOIN, 6, FALSE,
1103 "%s (%s@%s) has joined channel %s",
1104 client_idp->data, client_idp->len,
1105 ctx->nickname, strlen(ctx->nickname),
1106 ctx->username, strlen(ctx->username),
1107 ctx->hostname, strlen(ctx->hostname),
1108 channel_idp->data, channel_idp->len,
1110 strlen(ctx->channel_name));
1112 silc_buffer_free(client_idp);
1113 silc_buffer_free(channel_idp);
1116 silc_task_register(ctx->server->timeout_queue, fd,
1117 silc_server_command_join_notify, context,
1118 0, 300000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
1122 /* Assembles NAMES command and executes it. This is called when client
1123 joins to a channel and we wan't to send NAMES command reply to the
1126 void silc_server_command_send_names(SilcServer server,
1127 SilcSocketConnection sock,
1128 SilcChannelEntry channel)
1130 SilcServerCommandContext cmd;
1132 unsigned char *id_string;
1134 id_string = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
1135 buffer = silc_command_payload_encode_va(SILC_COMMAND_NAMES, 0, 1,
1136 1, id_string, SILC_ID_CHANNEL_LEN);
1138 cmd = silc_calloc(1, sizeof(*cmd));
1139 cmd->payload = silc_command_payload_parse(buffer);
1140 cmd->args = silc_command_get_args(cmd->payload);
1141 cmd->server = server;
1143 cmd->pending = FALSE;
1145 silc_server_command_names((void *)cmd);
1146 silc_free(id_string);
1150 /* Server side of command JOIN. Joins client into requested channel. If
1151 the channel does not exist it will be created. */
1153 SILC_SERVER_CMD_FUNC(join)
1155 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1156 SilcServer server = cmd->server;
1157 SilcSocketConnection sock = cmd->sock;
1158 SilcBuffer buffer = cmd->packet->buffer;
1159 int argc, i, tmp_len;
1160 char *tmp, *channel_name = NULL, *cipher = NULL, *id_string = NULL;
1161 unsigned char *passphrase, mode[4];
1162 SilcChannelEntry channel;
1163 SilcServerID *router_id;
1165 SilcClientEntry client;
1167 SILC_LOG_DEBUG(("Start"));
1169 /* Check number of parameters */
1170 argc = silc_argument_get_arg_num(cmd->args);
1172 silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
1173 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1177 silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
1178 SILC_STATUS_ERR_TOO_MANY_PARAMS);
1182 /* Get channel name */
1183 tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
1184 channel_name = silc_calloc(tmp_len + 1, sizeof(*channel_name));
1185 memcpy(channel_name, tmp, tmp_len);
1186 if (silc_server_command_bad_chars(tmp) == TRUE) {
1187 silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
1188 SILC_STATUS_ERR_BAD_CHANNEL);
1189 silc_free(channel_name);
1193 /* Get passphrase */
1194 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1196 passphrase = silc_calloc(tmp_len, sizeof(*passphrase));
1197 memcpy(passphrase, tmp, tmp_len);
1200 /* Get cipher name */
1201 cipher = silc_argument_get_arg_type(cmd->args, 3, NULL);
1203 /* See if the channel exists */
1205 silc_idlist_find_channel_by_name(server->local_list, channel_name);
1207 /* Channel not found */
1209 /* If we are standalone server we don't have a router, we just create
1210 the channel by ourselves. */
1211 if (server->standalone) {
1212 router_id = server->id;
1213 channel = silc_server_new_channel(server, router_id,
1214 cipher, channel_name);
1221 /* No channel ID found, the channel does not exist on our server.
1222 We send JOIN command to our router which will handle the joining
1223 procedure (either creates the channel if it doesn't exist or
1224 joins the client to it) - if we are normal server. */
1225 if (server->server_type == SILC_SERVER) {
1227 /* Forward the original JOIN command to the router */
1228 silc_buffer_push(buffer, buffer->data - buffer->head);
1229 silc_server_packet_forward(server, (SilcSocketConnection)
1230 server->id_entry->router->connection,
1231 buffer->data, buffer->len, TRUE);
1233 /* Add the command to be pending. It will be re-executed after
1234 router has replied back to us. */
1235 cmd->pending = TRUE;
1236 silc_server_command_pending(SILC_COMMAND_JOIN,
1237 silc_server_command_join, context);
1242 /* If we are router and the channel does not exist we will check our
1243 global list for the channel. */
1244 if (!channel && server->server_type == SILC_ROUTER) {
1246 /* Notify all routers about the new channel in SILC network. */
1247 if (!server->standalone) {
1249 silc_server_send_new_id(server, server->id_entry->router->connection,
1251 xxx, SILC_ID_CHANNEL, SILC_ID_CHANNEL_LEN);
1259 /* If the JOIN request was forwarded to us we will make a bit slower
1260 query to get the client pointer. Otherwise, we get the client pointer
1262 if (!(cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED)) {
1263 client = (SilcClientEntry)sock->user_data;
1265 void *id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
1266 client = silc_idlist_find_client_by_id(server->local_list, id);
1274 /* Check whether the client already is on the channel */
1275 if (silc_server_client_on_channel(client, channel)) {
1276 silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
1277 SILC_STATUS_ERR_USER_ON_CHANNEL);
1278 silc_free(channel_name);
1282 /* Join the client to the channel */
1283 i = channel->user_list_count;
1284 channel->user_list = silc_realloc(channel->user_list,
1285 sizeof(*channel->user_list) * (i + 1));
1286 channel->user_list[i].mode = SILC_CHANNEL_UMODE_NONE;
1287 channel->user_list[i].client = client;
1288 channel->user_list_count++;
1290 /* Add the channel to client's channel list */
1291 i = client->channel_count;
1292 client->channel = silc_realloc(client->channel,
1293 sizeof(*client->channel) * (i + 1));
1294 client->channel[i] = channel;
1295 client->channel_count++;
1297 /* Notify router about new user on channel. If we are normal server
1298 we send it to our router, if we are router we send it to our
1300 if (!server->standalone) {
1304 /* Send command reply to the client. Client receives the Channe ID,
1305 channel mode and possibly other information in this reply packet. */
1306 if (!cmd->pending) {
1307 id_string = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
1308 SILC_PUT32_MSB(channel->mode, mode);
1310 if (!channel->topic)
1312 silc_command_reply_payload_encode_va(SILC_COMMAND_JOIN,
1313 SILC_STATUS_OK, 0, 3,
1315 strlen(channel_name),
1316 3, id_string, SILC_ID_CHANNEL_LEN,
1320 silc_command_reply_payload_encode_va(SILC_COMMAND_JOIN,
1321 SILC_STATUS_OK, 0, 4,
1323 strlen(channel_name),
1324 3, id_string, SILC_ID_CHANNEL_LEN,
1327 strlen(channel->topic));
1329 if (cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED) {
1330 void *id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
1331 silc_server_packet_send_dest(cmd->server, cmd->sock,
1332 SILC_PACKET_COMMAND_REPLY, 0,
1333 id, cmd->packet->src_id_type,
1334 packet->data, packet->len, FALSE);
1337 silc_server_packet_send(server, sock, SILC_PACKET_COMMAND_REPLY, 0,
1338 packet->data, packet->len, FALSE);
1340 silc_buffer_free(packet);
1343 /* Send channel key to the client. Client cannot start transmitting
1344 to the channel until we have sent the key. */
1345 if (!cmd->pending) {
1346 tmp_len = strlen(channel->channel_key->cipher->name);
1348 silc_channel_key_payload_encode(SILC_ID_CHANNEL_LEN,
1350 channel->channel_key->cipher->name,
1351 channel->key_len / 8, channel->key);
1353 silc_server_packet_send(server, sock, SILC_PACKET_CHANNEL_KEY, 0,
1354 packet->data, packet->len, FALSE);
1355 silc_buffer_free(packet);
1359 silc_free(id_string);
1361 /* Finally, send notify message to all clients on the channel about
1362 new user on the channel. */
1363 if (!(cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED)) {
1364 if (!cmd->pending) {
1365 SilcBuffer channel_idp, client_idp;
1367 channel_idp = silc_id_payload_encode(channel->id,
1368 SILC_ID_CHANNEL_LEN,
1370 client_idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT_LEN,
1373 silc_server_send_notify_to_channel(server, channel,
1374 SILC_NOTIFY_TYPE_JOIN, 6, FALSE,
1375 "%s (%s@%s) has joined channel %s",
1376 client_idp->data, client_idp->len,
1378 strlen(client->nickname),
1380 strlen(client->username),
1382 strlen(sock->hostname),
1383 channel_idp->data, channel_idp->len,
1385 strlen(channel_name));
1387 silc_buffer_free(client_idp);
1388 silc_buffer_free(channel_idp);
1390 /* This is pending command request. Send the notify after we have
1391 received the key for the channel from the router. */
1392 JoinInternalContext *ctx = silc_calloc(1, sizeof(*ctx));
1393 ctx->channel_name = channel_name;
1394 ctx->nickname = client->nickname;
1395 ctx->username = client->username;
1396 ctx->hostname = sock->hostname ? sock->hostname : sock->ip;
1397 ctx->channel = channel;
1398 ctx->server = server;
1399 ctx->client = client;
1400 silc_task_register(server->timeout_queue, sock->sock,
1401 silc_server_command_join_notify, ctx,
1402 0, 10000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
1406 /* Send NAMES command reply to the joined channel so the user sees who
1407 is currently on the channel. */
1408 silc_server_command_send_names(server, sock, channel);
1411 silc_server_command_free(cmd);
1414 /* Server side of command MOTD. Sends server's current "message of the
1415 day" to the client. */
1417 SILC_SERVER_CMD_FUNC(motd)
1419 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1420 SilcServer server = cmd->server;
1421 SilcSocketConnection sock = cmd->sock;
1426 SILC_LOG_DEBUG(("Start"));
1428 argc = silc_argument_get_arg_num(cmd->args);
1430 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1431 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1435 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1436 SILC_STATUS_ERR_TOO_MANY_PARAMS);
1440 /* XXX show currently only our motd */
1442 if (server->config && server->config->motd &&
1443 server->config->motd->motd_file) {
1446 motd = silc_file_read(server->config->motd->motd_file, &motd_len);
1451 silc_server_command_send_status_data(cmd, SILC_COMMAND_MOTD,
1457 silc_server_command_send_status_reply(cmd, SILC_COMMAND_MOTD,
1462 silc_server_command_free(cmd);
1465 SILC_SERVER_CMD_FUNC(umode)
1469 SILC_SERVER_CMD_FUNC(cmode)
1473 SILC_SERVER_CMD_FUNC(kick)
1477 SILC_SERVER_CMD_FUNC(restart)
1481 SILC_SERVER_CMD_FUNC(close)
1485 SILC_SERVER_CMD_FUNC(die)
1489 SILC_SERVER_CMD_FUNC(silcoper)
1493 /* Server side command of LEAVE. Removes client from a channel. */
1495 SILC_SERVER_CMD_FUNC(leave)
1497 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1498 SilcServer server = cmd->server;
1499 SilcSocketConnection sock = cmd->sock;
1500 SilcClientEntry id_entry = (SilcClientEntry)cmd->sock->user_data;
1502 SilcChannelEntry channel;
1504 unsigned int i, argc, key_len;
1505 unsigned char *tmp, channel_key[32];
1507 SILC_LOG_DEBUG(("Start"));
1509 argc = silc_argument_get_arg_num(cmd->args);
1511 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1512 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1516 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1517 SILC_STATUS_ERR_TOO_MANY_PARAMS);
1521 /* Get Channel ID */
1522 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1524 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1525 SILC_STATUS_ERR_NO_CHANNEL_ID);
1528 id = silc_id_str2id(tmp, SILC_ID_CHANNEL);
1530 /* Get channel entry */
1531 channel = silc_idlist_find_channel_by_id(server->local_list, id);
1533 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1534 SILC_STATUS_ERR_NO_SUCH_CHANNEL);
1538 /* Check whether this client is on the channel */
1539 if (!silc_server_client_on_channel(id_entry, channel)) {
1540 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1541 SILC_STATUS_ERR_NOT_ON_CHANNEL);
1545 /* Notify routers that they should remove this client from their list
1546 of clients on the channel. */
1547 if (!server->standalone)
1548 silc_server_send_remove_channel_user(server,
1549 server->id_entry->router->connection,
1550 server->server_type == SILC_ROUTER ?
1551 TRUE : FALSE, id_entry->id, id);
1553 /* Remove client from channel */
1554 i = silc_server_remove_from_one_channel(server, sock, channel, id_entry,
1556 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1559 /* If the channel does not exist anymore we won't send anything */
1563 /* Re-generate channel key */
1564 key_len = channel->key_len / 8;
1565 for (i = 0; i < key_len; i++)
1566 channel_key[i] = silc_rng_get_byte(server->rng);
1567 channel->channel_key->cipher->set_key(channel->channel_key->context,
1568 channel_key, key_len);
1569 memset(channel->key, 0, key_len);
1570 silc_free(channel->key);
1571 channel->key = silc_calloc(key_len, sizeof(*channel->key));
1572 memcpy(channel->key, channel_key, key_len);
1573 memset(channel_key, 0, sizeof(channel_key));
1575 /* Encode channel key payload to be distributed on the channel */
1577 silc_channel_key_payload_encode(SILC_ID_CHANNEL_LEN, tmp,
1578 strlen(channel->channel_key->cipher->name),
1579 channel->channel_key->cipher->name,
1580 key_len, channel->key);
1582 /* If we are normal server then we will send it to our router. If we
1583 are router we will send it to all local servers that has clients on
1585 if (server->server_type == SILC_SERVER) {
1586 if (!server->standalone)
1587 silc_server_packet_send(server,
1588 cmd->server->id_entry->router->connection,
1589 SILC_PACKET_CHANNEL_KEY, 0, packet->data,
1595 /* Send to locally connected clients on the channel */
1596 silc_server_packet_send_local_channel(server, channel,
1597 SILC_PACKET_CHANNEL_KEY, 0,
1598 packet->data, packet->len, FALSE);
1600 silc_buffer_free(packet);
1604 silc_server_command_free(cmd);
1607 /* Server side of command NAMES. Resolves clients and their names currently
1608 joined on the requested channel. The name list is sent back to the
1611 SILC_SERVER_CMD_FUNC(names)
1613 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1614 SilcServer server = cmd->server;
1615 SilcChannelEntry channel;
1618 unsigned int i, len, len2, argc;
1620 char *name_list = NULL, *n;
1621 SilcBuffer client_id_list;
1623 SILC_LOG_DEBUG(("Start"));
1625 argc = silc_argument_get_arg_num(cmd->args);
1627 silc_server_command_send_status_reply(cmd, SILC_COMMAND_NAMES,
1628 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1632 silc_server_command_send_status_reply(cmd, SILC_COMMAND_NAMES,
1633 SILC_STATUS_ERR_TOO_MANY_PARAMS);
1637 /* Get Channel ID */
1638 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1640 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1641 SILC_STATUS_ERR_NO_CHANNEL_ID);
1644 id = silc_id_str2id(tmp, SILC_ID_CHANNEL);
1646 /* Check whether the channel exists. If we are normal server and the
1647 channel does not exist we will send this same command to our router
1648 which will know if the channel exists. */
1649 channel = silc_idlist_find_channel_by_id(server->local_list, id);
1651 if (server->server_type == SILC_SERVER && !server->standalone) {
1652 /* XXX Send names command */
1654 cmd->pending = TRUE;
1655 silc_server_command_pending(SILC_COMMAND_NAMES,
1656 silc_server_command_names, context);
1660 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
1661 SILC_STATUS_ERR_NO_SUCH_CHANNEL);
1665 /* Assemble the name list now */
1668 for (i = 0; i < channel->user_list_count; i++) {
1669 if (!channel->user_list[i].client)
1672 n = channel->user_list[i].client->nickname;
1676 name_list = silc_realloc(name_list, sizeof(*name_list) * (len + 1));
1677 memcpy(name_list + (len - len2), n, len2);
1680 if (i == channel->user_list_count - 1)
1682 memcpy(name_list + len, ",", 1);
1689 /* Assemble the Client ID list now */
1690 client_id_list = silc_buffer_alloc(SILC_ID_CLIENT_LEN *
1691 channel->user_list_count);
1692 silc_buffer_pull_tail(client_id_list, (SILC_ID_CLIENT_LEN *
1693 channel->user_list_count));
1694 for (i = 0; i < channel->user_list_count; i++) {
1695 unsigned char *id_string;
1697 if (!channel->user_list[i].client)
1700 id_string = silc_id_id2str(channel->user_list[i].client->id,
1702 silc_buffer_format(client_id_list,
1703 SILC_STR_UI_XNSTRING(id_string, SILC_ID_CLIENT_LEN),
1705 silc_buffer_pull(client_id_list, SILC_ID_CLIENT_LEN);
1706 silc_free(id_string);
1708 silc_buffer_push(client_id_list,
1709 client_id_list->data - client_id_list->head);
1712 packet = silc_command_reply_payload_encode_va(SILC_COMMAND_NAMES,
1713 SILC_STATUS_OK, 0, 3,
1714 2, tmp, SILC_ID_CHANNEL_LEN,
1717 4, client_id_list->data,
1718 client_id_list->len);
1719 silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
1720 packet->data, packet->len, FALSE);
1722 silc_buffer_free(packet);
1723 silc_free(name_list);
1724 silc_buffer_free(client_id_list);
1728 silc_server_command_free(cmd);